DFG string conversions and allocations should be inlined
https://bugs.webkit.org/show_bug.cgi?id=112376
Source/JavaScriptCore:
Reviewed by Geoffrey Garen.
This turns new String(), String(), String.prototype.valueOf(), and
String.prototype.toString() into intrinsics. It gives the DFG the ability to handle
conversions from StringObject to JSString and vice-versa, and also gives it the
ability to handle cases where a variable may be either a StringObject or a JSString.
To do this, I added StringObject to value profiling (and removed the stale
distinction between Myarguments and Foreignarguments). I also cleaned up ToPrimitive
handling, using some of the new functionality but also taking advantage of the
existence of Identity(String:@a).
This is a 2% SunSpider speed-up. Also there are some speed-ups on V8v7 and Kraken.
On microbenchmarks that stress new String() this is a 14x speed-up.
* CMakeLists.txt:
* DerivedSources.make:
* DerivedSources.pri:
* GNUmakefile.list.am:
* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::hasExitSite):
(JSC):
* bytecode/DFGExitProfile.cpp:
(JSC::DFG::ExitProfile::hasExitSite):
(DFG):
* bytecode/DFGExitProfile.h:
(ExitProfile):
(JSC::DFG::ExitProfile::hasExitSite):
* bytecode/ExitKind.cpp:
(JSC::exitKindToString):
* bytecode/ExitKind.h:
* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationToAbbreviatedString):
(JSC::speculationFromClassInfo):
* bytecode/SpeculatedType.h:
(JSC):
(JSC::isStringObjectSpeculation):
(JSC::isStringOrStringObjectSpeculation):
* create_hash_table:
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
* dfg/DFGAbstractState.h:
(JSC::DFG::AbstractState::filterEdgeByUse):
* dfg/DFGByteCodeParser.cpp:
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::emitArgumentPhantoms):
(DFG):
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::putStructureStoreElimination):
* dfg/DFGEdge.h:
(JSC::DFG::Edge::shift):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::isStringPrototypeMethodSane):
(FixupPhase):
(JSC::DFG::FixupPhase::canOptimizeStringObjectAccess):
(JSC::DFG::FixupPhase::observeUseKindOnNode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::hasGlobalExitSite):
(Graph):
(JSC::DFG::Graph::hasExitSite):
(JSC::DFG::Graph::clobbersWorld):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToToString):
(Node):
(JSC::DFG::Node::hasStructure):
(JSC::DFG::Node::shouldSpeculateStringObject):
(JSC::DFG::Node::shouldSpeculateStringOrStringObject):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileToStringOnCell):
(DFG):
(JSC::DFG::SpeculativeJIT::compileNewStringObject):
(JSC::DFG::SpeculativeJIT::speculateObject):
(JSC::DFG::SpeculativeJIT::speculateObjectOrOther):
(JSC::DFG::SpeculativeJIT::speculateString):
(JSC::DFG::SpeculativeJIT::speculateStringObject):
(JSC::DFG::SpeculativeJIT::speculateStringOrStringObject):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
(SpeculativeJIT):
(JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
(DFG):
(JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
* interpreter/CallFrame.h:
(JSC::ExecState::regExpPrototypeTable):
* runtime/CommonIdentifiers.h:
* runtime/Intrinsic.h:
* runtime/JSDestructibleObject.h:
(JSDestructibleObject):
(JSC::JSDestructibleObject::classInfoOffset):
* runtime/JSGlobalData.cpp:
(JSC):
(JSC::JSGlobalData::JSGlobalData):
(JSC::JSGlobalData::~JSGlobalData):
* runtime/JSGlobalData.h:
(JSGlobalData):
* runtime/JSObject.cpp:
* runtime/JSObject.h:
(JSC):
* runtime/JSWrapperObject.h:
(JSC::JSWrapperObject::allocationSize):
(JSWrapperObject):
(JSC::JSWrapperObject::internalValueOffset):
(JSC::JSWrapperObject::internalValueCellOffset):
* runtime/StringPrototype.cpp:
(JSC):
(JSC::StringPrototype::finishCreation):
(JSC::StringPrototype::create):
* runtime/StringPrototype.h:
(StringPrototype):
LayoutTests:
Reviewed by Geoffrey Garen.
* fast/js/dfg-to-string-bad-toString-expected.txt: Added.
* fast/js/dfg-to-string-bad-toString.html: Added.
* fast/js/dfg-to-string-bad-valueOf-expected.txt: Added.
* fast/js/dfg-to-string-bad-valueOf.html: Added.
* fast/js/dfg-to-string-int-expected.txt: Added.
* fast/js/dfg-to-string-int-or-string-expected.txt: Added.
* fast/js/dfg-to-string-int-or-string.html: Added.
* fast/js/dfg-to-string-int.html: Added.
* fast/js/dfg-to-string-side-effect-clobbers-toString-expected.txt: Added.
* fast/js/dfg-to-string-side-effect-clobbers-toString.html: Added.
* fast/js/dfg-to-string-side-effect-expected.txt: Added.
* fast/js/dfg-to-string-side-effect.html: Added.
* fast/js/dfg-to-string-toString-becomes-bad-expected.txt: Added.
* fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype-expected.txt: Added.
* fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.html: Added.
* fast/js/dfg-to-string-toString-becomes-bad.html: Added.
* fast/js/dfg-to-string-toString-in-string-expected.txt: Added.
* fast/js/dfg-to-string-toString-in-string.html: Added.
* fast/js/dfg-to-string-valueOf-becomes-bad-expected.txt: Added.
* fast/js/dfg-to-string-valueOf-becomes-bad.html: Added.
* fast/js/dfg-to-string-valueOf-in-string-expected.txt: Added.
* fast/js/dfg-to-string-valueOf-in-string.html: Added.
* fast/js/jsc-test-list:
* fast/js/regress/script-tests/string-concat-object.js: Added.
(foo):
* fast/js/regress/script-tests/string-concat-pair-object.js: Added.
(foo):
* fast/js/regress/script-tests/string-concat-pair-simple.js: Added.
(foo):
* fast/js/regress/script-tests/string-concat-simple.js: Added.
(foo):
* fast/js/regress/script-tests/string-cons-repeat.js: Added.
(foo):
* fast/js/regress/script-tests/string-cons-tower.js: Added.
(foo):
* fast/js/regress/string-concat-object-expected.txt: Added.
* fast/js/regress/string-concat-object.html: Added.
* fast/js/regress/string-concat-pair-object-expected.txt: Added.
* fast/js/regress/string-concat-pair-object.html: Added.
* fast/js/regress/string-concat-pair-simple-expected.txt: Added.
* fast/js/regress/string-concat-pair-simple.html: Added.
* fast/js/regress/string-concat-simple-expected.txt: Added.
* fast/js/regress/string-concat-simple.html: Added.
* fast/js/regress/string-cons-repeat-expected.txt: Added.
* fast/js/regress/string-cons-repeat.html: Added.
* fast/js/regress/string-cons-tower-expected.txt: Added.
* fast/js/regress/string-cons-tower.html: Added.
* fast/js/script-tests/dfg-to-string-bad-toString.js: Added.
(String.prototype.toString):
(foo):
* fast/js/script-tests/dfg-to-string-bad-valueOf.js: Added.
(String.prototype.valueOf):
(foo):
* fast/js/script-tests/dfg-to-string-int-or-string.js: Added.
(foo):
* fast/js/script-tests/dfg-to-string-int.js: Added.
(foo):
* fast/js/script-tests/dfg-to-string-side-effect-clobbers-toString.js: Added.
(foo):
* fast/js/script-tests/dfg-to-string-side-effect.js: Added.
(foo):
* fast/js/script-tests/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.js: Added.
(foo):
(.String.prototype.toString):
* fast/js/script-tests/dfg-to-string-toString-becomes-bad.js: Added.
(foo):
(.String.prototype.toString):
* fast/js/script-tests/dfg-to-string-toString-in-string.js: Added.
(foo):
(.argument.toString):
* fast/js/script-tests/dfg-to-string-valueOf-becomes-bad.js: Added.
(foo):
(.String.prototype.valueOf):
* fast/js/script-tests/dfg-to-string-valueOf-in-string.js: Added.
(foo):
(.argument.valueOf):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@146089 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 8b3b66f..7805d66 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -333,7 +333,6 @@
runtime/RegExpObject.cpp
runtime/RegExpPrototype.cpp
runtime/StringConstructor.cpp
- runtime/StringPrototype.cpp
)
set(JavaScriptCore_LIBRARIES
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 5040431..da3702b 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,139 @@
+2013-03-15 Filip Pizlo <fpizlo@apple.com>
+
+ DFG string conversions and allocations should be inlined
+ https://bugs.webkit.org/show_bug.cgi?id=112376
+
+ Reviewed by Geoffrey Garen.
+
+ This turns new String(), String(), String.prototype.valueOf(), and
+ String.prototype.toString() into intrinsics. It gives the DFG the ability to handle
+ conversions from StringObject to JSString and vice-versa, and also gives it the
+ ability to handle cases where a variable may be either a StringObject or a JSString.
+ To do this, I added StringObject to value profiling (and removed the stale
+ distinction between Myarguments and Foreignarguments). I also cleaned up ToPrimitive
+ handling, using some of the new functionality but also taking advantage of the
+ existence of Identity(String:@a).
+
+ This is a 2% SunSpider speed-up. Also there are some speed-ups on V8v7 and Kraken.
+ On microbenchmarks that stress new String() this is a 14x speed-up.
+
+ * CMakeLists.txt:
+ * DerivedSources.make:
+ * DerivedSources.pri:
+ * GNUmakefile.list.am:
+ * bytecode/CodeBlock.h:
+ (CodeBlock):
+ (JSC::CodeBlock::hasExitSite):
+ (JSC):
+ * bytecode/DFGExitProfile.cpp:
+ (JSC::DFG::ExitProfile::hasExitSite):
+ (DFG):
+ * bytecode/DFGExitProfile.h:
+ (ExitProfile):
+ (JSC::DFG::ExitProfile::hasExitSite):
+ * bytecode/ExitKind.cpp:
+ (JSC::exitKindToString):
+ * bytecode/ExitKind.h:
+ * bytecode/SpeculatedType.cpp:
+ (JSC::dumpSpeculation):
+ (JSC::speculationToAbbreviatedString):
+ (JSC::speculationFromClassInfo):
+ * bytecode/SpeculatedType.h:
+ (JSC):
+ (JSC::isStringObjectSpeculation):
+ (JSC::isStringOrStringObjectSpeculation):
+ * create_hash_table:
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::executeEffects):
+ * dfg/DFGAbstractState.h:
+ (JSC::DFG::AbstractState::filterEdgeByUse):
+ * dfg/DFGByteCodeParser.cpp:
+ (ByteCodeParser):
+ (JSC::DFG::ByteCodeParser::handleCall):
+ (JSC::DFG::ByteCodeParser::emitArgumentPhantoms):
+ (DFG):
+ (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::putStructureStoreElimination):
+ * dfg/DFGEdge.h:
+ (JSC::DFG::Edge::shift):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ (JSC::DFG::FixupPhase::isStringPrototypeMethodSane):
+ (FixupPhase):
+ (JSC::DFG::FixupPhase::canOptimizeStringObjectAccess):
+ (JSC::DFG::FixupPhase::observeUseKindOnNode):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::hasGlobalExitSite):
+ (Graph):
+ (JSC::DFG::Graph::hasExitSite):
+ (JSC::DFG::Graph::clobbersWorld):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::convertToToString):
+ (Node):
+ (JSC::DFG::Node::hasStructure):
+ (JSC::DFG::Node::shouldSpeculateStringObject):
+ (JSC::DFG::Node::shouldSpeculateStringOrStringObject):
+ * dfg/DFGNodeType.h:
+ (DFG):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileToStringOnCell):
+ (DFG):
+ (JSC::DFG::SpeculativeJIT::compileNewStringObject):
+ (JSC::DFG::SpeculativeJIT::speculateObject):
+ (JSC::DFG::SpeculativeJIT::speculateObjectOrOther):
+ (JSC::DFG::SpeculativeJIT::speculateString):
+ (JSC::DFG::SpeculativeJIT::speculateStringObject):
+ (JSC::DFG::SpeculativeJIT::speculateStringOrStringObject):
+ (JSC::DFG::SpeculativeJIT::speculate):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ (SpeculativeJIT):
+ (JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
+ (DFG):
+ (JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGUseKind.cpp:
+ (WTF::printInternal):
+ * dfg/DFGUseKind.h:
+ (JSC::DFG::typeFilterFor):
+ * interpreter/CallFrame.h:
+ (JSC::ExecState::regExpPrototypeTable):
+ * runtime/CommonIdentifiers.h:
+ * runtime/Intrinsic.h:
+ * runtime/JSDestructibleObject.h:
+ (JSDestructibleObject):
+ (JSC::JSDestructibleObject::classInfoOffset):
+ * runtime/JSGlobalData.cpp:
+ (JSC):
+ (JSC::JSGlobalData::JSGlobalData):
+ (JSC::JSGlobalData::~JSGlobalData):
+ * runtime/JSGlobalData.h:
+ (JSGlobalData):
+ * runtime/JSObject.cpp:
+ * runtime/JSObject.h:
+ (JSC):
+ * runtime/JSWrapperObject.h:
+ (JSC::JSWrapperObject::allocationSize):
+ (JSWrapperObject):
+ (JSC::JSWrapperObject::internalValueOffset):
+ (JSC::JSWrapperObject::internalValueCellOffset):
+ * runtime/StringPrototype.cpp:
+ (JSC):
+ (JSC::StringPrototype::finishCreation):
+ (JSC::StringPrototype::create):
+ * runtime/StringPrototype.h:
+ (StringPrototype):
+
2013-03-18 Filip Pizlo <fpizlo@apple.com>
ObjectPrototype properties should be eagerly created rather than lazily via static tables
diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make
index 55a76e2..517063d 100644
--- a/Source/JavaScriptCore/DerivedSources.make
+++ b/Source/JavaScriptCore/DerivedSources.make
@@ -1,4 +1,4 @@
-# Copyright (C) 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+# Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -55,7 +55,6 @@
RegExpJitTables.h \
RegExpObject.lut.h \
StringConstructor.lut.h \
- StringPrototype.lut.h \
docs/bytecode.html \
udis86_itab.h \
#
diff --git a/Source/JavaScriptCore/DerivedSources.pri b/Source/JavaScriptCore/DerivedSources.pri
index d637569..c27c15f 100644
--- a/Source/JavaScriptCore/DerivedSources.pri
+++ b/Source/JavaScriptCore/DerivedSources.pri
@@ -24,7 +24,6 @@
runtime/RegExpObject.cpp \
runtime/RegExpPrototype.cpp \
runtime/StringConstructor.cpp \
- runtime/StringPrototype.cpp \
KEYWORDLUT_FILES += \
parser/Keywords.table
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index f418387..14117fc 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -28,7 +28,6 @@
DerivedSources/JavaScriptCore/RegExpObject.lut.h \
DerivedSources/JavaScriptCore/RegExpPrototype.lut.h \
DerivedSources/JavaScriptCore/StringConstructor.lut.h \
- DerivedSources/JavaScriptCore/StringPrototype.lut.h \
DerivedSources/JavaScriptCore/LLIntDesiredOffsets.h \
DerivedSources/JavaScriptCore/LLIntAssembly.h
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index f5f5312..1c7c58a 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -787,6 +787,8 @@
ASSERT(JITCode::isBaselineCode(getJITType()));
return m_exitProfile.add(site);
}
+
+ bool hasExitSite(const DFG::FrequentExitSite& site) const { return m_exitProfile.hasExitSite(site); }
DFG::ExitProfile& exitProfile() { return m_exitProfile; }
@@ -1389,7 +1391,7 @@
return baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame);
return baselineCodeBlock;
}
-
+
inline int CodeBlock::argumentIndexAfterCapture(size_t argument)
{
if (argument >= static_cast<size_t>(symbolTable()->parameterCount()))
diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.cpp b/Source/JavaScriptCore/bytecode/DFGExitProfile.cpp
index 9f7e901..d36878f 100644
--- a/Source/JavaScriptCore/bytecode/DFGExitProfile.cpp
+++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.cpp
@@ -70,6 +70,18 @@
return result;
}
+bool ExitProfile::hasExitSite(const FrequentExitSite& site) const
+{
+ if (!m_frequentExitSites)
+ return false;
+
+ for (unsigned i = m_frequentExitSites->size(); i--;) {
+ if (m_frequentExitSites->at(i) == site)
+ return true;
+ }
+ return false;
+}
+
QueryableExitProfile::QueryableExitProfile(const ExitProfile& profile)
{
if (!profile.m_frequentExitSites)
diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.h b/Source/JavaScriptCore/bytecode/DFGExitProfile.h
index 61466f4..fe7b2f9 100644
--- a/Source/JavaScriptCore/bytecode/DFGExitProfile.h
+++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.h
@@ -133,6 +133,20 @@
// meant to only be used from debugging/profiling code.
Vector<FrequentExitSite> exitSitesFor(unsigned bytecodeIndex);
+ // This is O(n) and should be called on less-frequently executed code paths
+ // in the compiler. It should be strictly cheaper than building a
+ // QueryableExitProfile, if you really expect this to be called infrequently
+ // and you believe that there are few exit sites.
+ bool hasExitSite(const FrequentExitSite&) const;
+ bool hasExitSite(ExitKind kind) const
+ {
+ return hasExitSite(FrequentExitSite(kind));
+ }
+ bool hasExitSite(unsigned bytecodeIndex, ExitKind kind) const
+ {
+ return hasExitSite(FrequentExitSite(bytecodeIndex, kind));
+ }
+
private:
friend class QueryableExitProfile;
diff --git a/Source/JavaScriptCore/bytecode/ExitKind.cpp b/Source/JavaScriptCore/bytecode/ExitKind.cpp
index faa6348..a8d9045 100644
--- a/Source/JavaScriptCore/bytecode/ExitKind.cpp
+++ b/Source/JavaScriptCore/bytecode/ExitKind.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -64,6 +64,8 @@
return "InadequateCoverage";
case ArgumentsEscaped:
return "ArgumentsEscaped";
+ case NotStringObject:
+ return "NotStringObject";
case Uncountable:
return "Uncountable";
case UncountableWatchpoint:
diff --git a/Source/JavaScriptCore/bytecode/ExitKind.h b/Source/JavaScriptCore/bytecode/ExitKind.h
index f28995f0..8b34f4e 100644
--- a/Source/JavaScriptCore/bytecode/ExitKind.h
+++ b/Source/JavaScriptCore/bytecode/ExitKind.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -44,6 +44,7 @@
StoreToHoleOrOutOfBounds, // We're simultaneously speculating that we're in bounds and not accessing a hole, and one of those things didn't pan out.
InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage.
ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to.
+ NotStringObject, // We exited because we shouldn't have attempted to optimize string object access.
Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
UncountableWatchpoint // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves.
};
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
index 7b78592..0e33b65 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,6 +33,7 @@
#include "JSArray.h"
#include "JSFunction.h"
#include "Operations.h"
+#include "StringObject.h"
#include "ValueProfile.h"
#include <wtf/BoundsCheckedPointer.h>
#include <wtf/StringPrintStream.h>
@@ -120,13 +121,8 @@
else
isTop = false;
- if (value & SpecMyArguments)
- myOut.print("Myarguments");
- else
- isTop = false;
-
- if (value & SpecForeignArguments)
- myOut.print("Foreignarguments");
+ if (value & SpecArguments)
+ myOut.print("Arguments");
else
isTop = false;
@@ -135,6 +131,11 @@
else
isTop = false;
+ if (value & SpecStringObject)
+ myOut.print("Stringobject");
+ else
+ isTop = false;
+
if (value & SpecInt32)
myOut.print("Int");
else
@@ -197,10 +198,12 @@
return "<Float32array>";
if (isFloat64ArraySpeculation(prediction))
return "<Float64array>";
- if (isMyArgumentsSpeculation(prediction))
- return "<Myarguments>";
if (isArgumentsSpeculation(prediction))
return "<Arguments>";
+ if (isStringObjectSpeculation(prediction))
+ return "<StringObject>";
+ if (isStringOrStringObjectSpeculation(prediction))
+ return "<StringOrStringObject>";
if (isObjectSpeculation(prediction))
return "<Object>";
if (isCellSpeculation(prediction))
@@ -232,11 +235,13 @@
return SpecArray;
if (classInfo == &Arguments::s_info)
- return SpecArguments; // Cannot distinguish between MyArguments and ForeignArguments at this stage. That happens in the flow analysis.
+ return SpecArguments;
+
+ if (classInfo == &StringObject::s_info)
+ return SpecStringObject;
if (classInfo->isSubClassOf(&JSFunction::s_info))
return SpecFunction;
-
if (classInfo->typedArrayStorageType != TypedArrayNone) {
switch (classInfo->typedArrayStorageType) {
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h
index 5854f5c..b50b7ce 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.h
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -49,9 +49,8 @@
static const SpeculatedType SpecUint32Array = 0x00000400; // It's definitely an Uint32Array or one of its subclasses.
static const SpeculatedType SpecFloat32Array = 0x00000800; // It's definitely an Uint16Array or one of its subclasses.
static const SpeculatedType SpecFloat64Array = 0x00001000; // It's definitely an Uint16Array or one of its subclasses.
-static const SpeculatedType SpecMyArguments = 0x00002000; // It's definitely an Arguments object, and it's definitely the one for my current frame.
-static const SpeculatedType SpecForeignArguments = 0x00004000; // It's definitely an Arguments object, and it's definitely not mine.
-static const SpeculatedType SpecArguments = 0x00006000; // It's definitely an Arguments object.
+static const SpeculatedType SpecArguments = 0x00002000; // It's definitely an Arguments object.
+static const SpeculatedType SpecStringObject = 0x00004000; // It's definitely a StringObject.
static const SpeculatedType SpecObjectOther = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
static const SpeculatedType SpecObject = 0x0000ffff; // Bitmask used for testing for any kind of object prediction.
static const SpeculatedType SpecString = 0x00010000; // It's definitely a JSString.
@@ -214,9 +213,14 @@
return !!(value & (SpecArray | SpecOther)) && !(value & ~(SpecArray | SpecOther));
}
-inline bool isMyArgumentsSpeculation(SpeculatedType value)
+inline bool isStringObjectSpeculation(SpeculatedType value)
{
- return value == SpecMyArguments;
+ return value == SpecStringObject;
+}
+
+inline bool isStringOrStringObjectSpeculation(SpeculatedType value)
+{
+ return !!value && !(value & ~(SpecString | SpecStringObject));
}
inline bool isInt32Speculation(SpeculatedType value)
diff --git a/Source/JavaScriptCore/create_hash_table b/Source/JavaScriptCore/create_hash_table
index cb2809d..875018c 100755
--- a/Source/JavaScriptCore/create_hash_table
+++ b/Source/JavaScriptCore/create_hash_table
@@ -271,8 +271,6 @@
}
my $intrinsic = "NoIntrinsic";
- $intrinsic = "CharCodeAtIntrinsic" if ($key eq "charCodeAt");
- $intrinsic = "CharAtIntrinsic" if ($key eq "charAt");
$intrinsic = "FromCharCodeIntrinsic" if ($key eq "fromCharCode");
if ($name eq "mathTable") {
$intrinsic = "MinIntrinsic" if ($key eq "min");
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index a9e718c..74358ac 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -33,6 +33,7 @@
#include "GetByIdStatus.h"
#include "Operations.h"
#include "PutByIdStatus.h"
+#include "StringObject.h"
namespace JSC { namespace DFG {
@@ -769,7 +770,7 @@
RELEASE_ASSERT_NOT_REACHED();
break;
}
- forNode(node).set(SpecString);
+ forNode(node).set(m_graph.m_globalData.stringStructure.get());
break;
}
@@ -857,7 +858,7 @@
case StringCharAt:
node->setCanExit(true);
- forNode(node).set(SpecString);
+ forNode(node).set(m_graph.m_globalData.stringStructure.get());
break;
case GetByVal: {
@@ -876,7 +877,7 @@
forNode(node).makeTop();
break;
case Array::String:
- forNode(node).set(SpecString);
+ forNode(node).set(m_graph.m_globalData.stringStructure.get());
break;
case Array::Arguments:
forNode(node).makeTop();
@@ -1031,11 +1032,8 @@
break;
}
- if (node->child1().useKind() == Int32Use) {
- forNode(node).set(SpecInt32);
- break;
- }
-
+ ASSERT(node->child1().useKind() == UntypedUse);
+
AbstractValue& source = forNode(node->child1());
AbstractValue& destination = forNode(node);
@@ -1060,6 +1058,8 @@
// ToPrimitive will currently forget string constants. But that's not a big
// deal since we don't do any optimization on those currently.
+ clobberWorld(node->codeOrigin, indexInBlock);
+
SpeculatedType type = source.m_type;
if (type & ~(SpecNumber | SpecString | SpecBoolean)) {
type &= (SpecNumber | SpecString | SpecBoolean);
@@ -1068,9 +1068,38 @@
destination.set(type);
break;
}
+
+ case ToString: {
+ switch (node->child1().useKind()) {
+ case StringObjectUse:
+ // This also filters that the StringObject has the primordial StringObject
+ // structure.
+ forNode(node->child1()).filter(m_graph.globalObjectFor(node->codeOrigin)->stringObjectStructure());
+ node->setCanExit(true); // We could be more precise but it's likely not worth it.
+ break;
+ case StringOrStringObjectUse:
+ node->setCanExit(true); // We could be more precise but it's likely not worth it.
+ break;
+ case CellUse:
+ case UntypedUse:
+ clobberWorld(node->codeOrigin, indexInBlock);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ forNode(node).set(m_graph.m_globalData.stringStructure.get());
+ break;
+ }
+
+ case NewStringObject: {
+ ASSERT(node->structure()->classInfo() == &StringObject::s_info);
+ forNode(node).set(node->structure());
+ break;
+ }
case StrCat:
- forNode(node).set(SpecString);
+ forNode(node).set(m_graph.m_globalData.stringStructure.get());
break;
case NewArray:
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h
index e6334e1..de1f17d 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h
@@ -190,6 +190,7 @@
case KnownInt32Use:
case KnownNumberUse:
case KnownCellUse:
+ case KnownStringUse:
ASSERT(!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())));
break;
default:
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index ab25c23..634d1055c 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -39,6 +39,7 @@
#include "PreciseJumpTargets.h"
#include "PutByIdStatus.h"
#include "ResolveGlobalStatus.h"
+#include "StringConstructor.h"
#include <wtf/CommaPrinter.h>
#include <wtf/HashMap.h>
#include <wtf/MathExtras.h>
@@ -164,6 +165,7 @@
// Handle calls. This resolves issues surrounding inlining and intrinsics.
void handleCall(Interpreter*, Instruction* currentInstruction, NodeType op, CodeSpecializationKind);
void emitFunctionChecks(const CallLinkStatus&, Node* callTarget, int registerOffset, CodeSpecializationKind);
+ void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind);
// Handle inlining. Return true if it succeeded, false if we need to plant a call.
bool handleInlining(bool usesResult, Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind);
// Handle setting the result of an intrinsic.
@@ -1206,9 +1208,14 @@
}
if (InternalFunction* function = callLinkStatus.internalFunction()) {
- if (handleConstantInternalFunction(usesResult, resultOperand, function, registerOffset, argumentCountIncludingThis, prediction, kind))
+ if (handleConstantInternalFunction(usesResult, resultOperand, function, registerOffset, argumentCountIncludingThis, prediction, kind)) {
+ // This phantoming has to be *after* the code for the intrinsic, to signify that
+ // the inputs must be kept alive whatever exits the intrinsic may do.
+ addToGraph(Phantom, callTarget);
+ emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind);
return;
-
+ }
+
// Can only handle this using the generic call handler.
addCall(interpreter, currentInstruction, op);
return;
@@ -1219,14 +1226,10 @@
emitFunctionChecks(callLinkStatus, callTarget, registerOffset, kind);
if (handleIntrinsic(usesResult, resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction)) {
- // Need to keep all inputs alive for OSR, and need to ensure that we get
- // backwards propagation of NodeUsedAsValue. Note that inlining doesn't
- // need to do this because it already Flushes the arguments, which has a
- // similar effect.
+ // This phantoming has to be *after* the code for the intrinsic, to signify that
+ // the inputs must be kept alive whatever exits the intrinsic may do.
addToGraph(Phantom, callTarget);
- for (int i = 0; i < argumentCountIncludingThis; ++i)
- addToGraph(Phantom, get(registerOffset + argumentToOperand(i)));
-
+ emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind);
return;
}
} else if (handleInlining(usesResult, callTarget, resultOperand, callLinkStatus, registerOffset, argumentCountIncludingThis, nextOffset, kind))
@@ -1261,6 +1264,12 @@
}
}
+void ByteCodeParser::emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind kind)
+{
+ for (int i = kind == CodeForCall ? 0 : 1; i < argumentCountIncludingThis; ++i)
+ addToGraph(Phantom, get(registerOffset + argumentToOperand(i)));
+}
+
bool ByteCodeParser::handleInlining(bool usesResult, Node* callTargetNode, int resultOperand, const CallLinkStatus& callLinkStatus, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind kind)
{
// First, the really simple checks: do we have an actual JS function?
@@ -1628,7 +1637,6 @@
// is good enough.
UNUSED_PARAM(prediction); // Remove this once we do more things.
- UNUSED_PARAM(kind); // Remove this once we do more things.
if (function->classInfo() == &ArrayConstructor::s_info) {
if (argumentCountIncludingThis == 2) {
@@ -1644,6 +1652,19 @@
usesResult, resultOperand,
addToGraph(Node::VarArg, NewArray, OpInfo(ArrayWithUndecided), OpInfo(0)));
return true;
+ } else if (function->classInfo() == &StringConstructor::s_info) {
+ Node* result;
+
+ if (argumentCountIncludingThis <= 1)
+ result = cellConstant(m_globalData->smallStrings.emptyString());
+ else
+ result = addToGraph(ToString, get(registerOffset + argumentToOperand(1)));
+
+ if (kind == CodeForConstruct)
+ result = addToGraph(NewStringObject, OpInfo(function->globalObject()->stringObjectStructure()), result);
+
+ setIntrinsicResult(usesResult, resultOperand, result);
+ return true;
}
return false;
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 800ef51..2b23e19 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -576,6 +576,8 @@
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
case TypeOf:
+ case ToString:
+ case NewStringObject:
return 0;
case GetIndexedPropertyStorage:
diff --git a/Source/JavaScriptCore/dfg/DFGEdge.h b/Source/JavaScriptCore/dfg/DFGEdge.h
index caa3b21..eb835b0 100644
--- a/Source/JavaScriptCore/dfg/DFGEdge.h
+++ b/Source/JavaScriptCore/dfg/DFGEdge.h
@@ -148,7 +148,7 @@
friend class AdjacencyList;
#if USE(JSVALUE64)
- static uint32_t shift() { return 5; }
+ static uint32_t shift() { return 6; }
static uintptr_t makeWord(Node* node, UseKind useKind, ProofStatus proofStatus)
{
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 4b0bbf3..6e8d922 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -526,13 +526,69 @@
}
case ToPrimitive: {
- if (node->child1()->shouldSpeculateInteger())
+ if (node->child1()->shouldSpeculateInteger()) {
setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+ node->convertToIdentity();
+ break;
+ }
+
+ if (node->child1()->shouldSpeculateString()) {
+ setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
+ node->convertToIdentity();
+ break;
+ }
+
+ if (node->child1()->shouldSpeculateStringObject()
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
+ setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
+ node->convertToToString();
+ break;
+ }
+
+ if (node->child1()->shouldSpeculateStringOrStringObject()
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
+ setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
+ node->convertToToString();
+ break;
+ }
+
// FIXME: Add string speculation here.
// https://bugs.webkit.org/show_bug.cgi?id=110175
break;
}
+ case ToString: {
+ if (node->child1()->shouldSpeculateString()) {
+ setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
+ node->convertToIdentity();
+ break;
+ }
+
+ if (node->child1()->shouldSpeculateStringObject()
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
+ setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
+ break;
+ }
+
+ if (node->child1()->shouldSpeculateStringOrStringObject()
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
+ setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
+ break;
+ }
+
+ if (node->child1()->shouldSpeculateCell()) {
+ setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+ break;
+ }
+
+ break;
+ }
+
+ case NewStringObject: {
+ setUseKindAndUnboxIfProfitable<KnownStringUse>(node->child1());
+ break;
+ }
+
case NewArray: {
for (unsigned i = m_graph.varArgNumChildren(node); i--;) {
node->setIndexingType(
@@ -806,6 +862,58 @@
#endif
}
+ bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, const Identifier& ident)
+ {
+ unsigned attributesUnused;
+ JSCell* specificValue;
+ PropertyOffset offset = stringPrototypeStructure->get(
+ globalData(), ident, attributesUnused, specificValue);
+ if (!isValidOffset(offset))
+ return false;
+
+ if (!specificValue)
+ return false;
+
+ if (!specificValue->inherits(&JSFunction::s_info))
+ return false;
+
+ JSFunction* function = jsCast<JSFunction*>(specificValue);
+ if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
+ return false;
+
+ return true;
+ }
+
+ bool canOptimizeStringObjectAccess(const CodeOrigin& codeOrigin)
+ {
+ if (m_graph.hasExitSite(codeOrigin, NotStringObject))
+ return false;
+
+ Structure* stringObjectStructure = m_graph.globalObjectFor(codeOrigin)->stringObjectStructure();
+ ASSERT(stringObjectStructure->storedPrototype().isObject());
+ ASSERT(stringObjectStructure->storedPrototype().asCell()->classInfo() == &StringPrototype::s_info);
+
+ JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype());
+ Structure* stringPrototypeStructure = stringPrototypeObject->structure();
+ if (stringPrototypeStructure->transitionWatchpointSetHasBeenInvalidated())
+ return false;
+
+ if (stringPrototypeStructure->isDictionary())
+ return false;
+
+ // We're being conservative here. We want DFG's ToString on StringObject to be
+ // used in both numeric contexts (that would call valueOf()) and string contexts
+ // (that would call toString()). We don't want the DFG to have to distinguish
+ // between the two, just because that seems like it would get confusing. So we
+ // just require both methods to be sane.
+ if (!isStringPrototypeMethodSane(stringPrototypeStructure, globalData().propertyNames->valueOf))
+ return false;
+ if (!isStringPrototypeMethodSane(stringPrototypeStructure, globalData().propertyNames->toString))
+ return false;
+
+ return true;
+ }
+
void fixupSetLocalsInBlock(BasicBlock* block)
{
if (!block)
@@ -974,6 +1082,9 @@
case CellUse:
case ObjectUse:
case StringUse:
+ case KnownStringUse:
+ case StringObjectUse:
+ case StringOrStringObjectUse:
if (alwaysUnboxSimplePrimitives()
|| isCellSpeculation(variable->prediction()))
m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 605a5a2..45bf669 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -376,6 +376,16 @@
return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
}
+ bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
+ {
+ return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(exitKind));
+ }
+
+ bool hasExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
+ {
+ return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(codeOrigin.bytecodeIndex, exitKind));
+ }
+
int argumentsRegisterFor(const CodeOrigin& codeOrigin)
{
if (!codeOrigin.inlineCallFrame)
@@ -522,6 +532,18 @@
case PutByVal:
case PutByValAlias:
return !byValIsPure(node);
+ case ToString:
+ switch (node->child1().useKind()) {
+ case StringObjectUse:
+ case StringOrStringObjectUse:
+ return false;
+ case CellUse:
+ case UntypedUse:
+ return true;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return true;
+ }
default:
RELEASE_ASSERT_NOT_REACHED();
return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst.
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 06e9915..505d7a2 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -349,6 +349,12 @@
children.setChild1(Edge(phi));
}
+ void convertToToString()
+ {
+ ASSERT(m_op == ToPrimitive);
+ m_op = ToString;
+ }
+
JSCell* weakConstant()
{
ASSERT(op() == WeakJSConstant);
@@ -844,6 +850,7 @@
case ForwardStructureTransitionWatchpoint:
case ArrayifyToStructure:
case NewObject:
+ case NewStringObject:
return true;
default:
return false;
@@ -1120,6 +1127,16 @@
return isStringSpeculation(prediction());
}
+ bool shouldSpeculateStringObject()
+ {
+ return isStringObjectSpeculation(prediction());
+ }
+
+ bool shouldSpeculateStringOrStringObject()
+ {
+ return isStringOrStringObjectSpeculation(prediction());
+ }
+
bool shouldSpeculateFinalObject()
{
return isFinalObjectSpeculation(prediction());
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index afada5d..775928c 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -222,6 +222,8 @@
macro(TypeOf, NodeResultJS) \
macro(LogicalNot, NodeResultBoolean) \
macro(ToPrimitive, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
+ macro(ToString, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
+ macro(NewStringObject, NodeResultJS) \
macro(StrCat, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
\
/* Nodes used for activations. Activation support works by having it anchored at */\
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 4ccb911..10bcc9b 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1547,6 +1547,30 @@
return string->value(exec).impl();
}
+JSCell* DFG_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure)
+{
+ JSGlobalData& globalData = exec->globalData();
+ NativeCallFrameTracer tracer(&globalData, exec);
+
+ return StringObject::create(exec, structure, string);
+}
+
+JSCell* DFG_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell)
+{
+ JSGlobalData& globalData = exec->globalData();
+ NativeCallFrameTracer tracer(&globalData, exec);
+
+ return JSValue(cell).toString(exec);
+}
+
+JSCell* DFG_OPERATION operationToString(ExecState* exec, EncodedJSValue value)
+{
+ JSGlobalData& globalData = exec->globalData();
+ NativeCallFrameTracer tracer(&globalData, exec);
+
+ return JSValue::decode(value).toString(exec);
+}
+
double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b)
{
return fmod(a, b);
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 99ed55a..9d57d55 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -85,6 +85,8 @@
typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_EIcf)(ExecState*, InlineCallFrame*);
+typedef JSCell* DFG_OPERATION (*C_DFGOperation_EJ)(ExecState*, EncodedJSValue);
+typedef JSCell* DFG_OPERATION (*C_DFGOperation_EJssSt)(ExecState*, JSString*, Structure*);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_EOZ)(ExecState*, JSObject*, int32_t);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_ESt)(ExecState*, Structure*);
typedef double DFG_OPERATION (*D_DFGOperation_DD)(double, double);
@@ -212,6 +214,9 @@
char* DFG_OPERATION operationRageEnsureContiguous(ExecState*, JSCell*);
char* DFG_OPERATION operationEnsureArrayStorage(ExecState*, JSCell*);
StringImpl* DFG_OPERATION operationResolveRope(ExecState*, JSString*);
+JSCell* DFG_OPERATION operationNewStringObject(ExecState*, JSString*, Structure*);
+JSCell* DFG_OPERATION operationToStringOnCell(ExecState*, JSCell*);
+JSCell* DFG_OPERATION operationToString(ExecState*, EncodedJSValue);
// This method is used to lookup an exception hander, keyed by faultLocation, which is
// the return location from one of the calls out to one of the helper operations above.
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 815cbe2..8a4e0de 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -413,7 +413,8 @@
}
case StringCharAt:
- case StrCat: {
+ case StrCat:
+ case ToString: {
changed |= setPrediction(SpecString);
break;
}
@@ -439,6 +440,11 @@
break;
}
+ case NewStringObject: {
+ changed |= setPrediction(SpecStringObject);
+ break;
+ }
+
case CreateArguments: {
changed |= setPrediction(SpecArguments);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 345b275..4f83dad 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -3922,6 +3922,115 @@
return temporary.gpr();
}
+void SpeculativeJIT::compileToStringOnCell(Node* node)
+{
+ SpeculateCellOperand op1(this, node->child1());
+ GPRReg op1GPR = op1.gpr();
+
+ switch (node->child1().useKind()) {
+ case StringObjectUse: {
+ GPRTemporary result(this);
+ GPRReg resultGPR = result.gpr();
+
+ if (!m_state.forNode(node->child1()).m_currentKnownStructure.isSubsetOf(StructureSet(m_jit.globalObjectFor(node->codeOrigin)->stringObjectStructure()))) {
+ speculateStringObject(op1GPR);
+ m_state.forNode(node->child1()).filter(SpecStringObject);
+ }
+ m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
+ cellResult(resultGPR, node);
+ break;
+ }
+
+ case StringOrStringObjectUse: {
+ GPRTemporary result(this);
+ GPRReg resultGPR = result.gpr();
+
+ m_jit.loadPtr(JITCompiler::Address(op1GPR, JSCell::structureOffset()), resultGPR);
+ JITCompiler::Jump isString = m_jit.branchPtr(
+ JITCompiler::Equal, resultGPR, TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+
+ speculateStringObjectForStructure(resultGPR);
+
+ m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
+
+ JITCompiler::Jump done = m_jit.jump();
+ isString.link(&m_jit);
+ m_jit.move(op1GPR, resultGPR);
+ done.link(&m_jit);
+
+ m_state.forNode(node->child1()).filter(SpecString | SpecStringObject);
+
+ cellResult(resultGPR, node);
+ break;
+ }
+
+ case CellUse: {
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ // We flush registers instead of silent spill/fill because in this mode we
+ // believe that most likely the input is not a string, and we need to take
+ // slow path.
+ flushRegisters();
+ JITCompiler::Jump done;
+ if (node->child1()->prediction() & SpecString) {
+ done = m_jit.branchPtr(
+ JITCompiler::Equal,
+ JITCompiler::Address(op1GPR, JSCell::structureOffset()),
+ TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+ }
+ callOperation(operationToStringOnCell, resultGPR, op1GPR);
+ if (done.isSet())
+ done.link(&m_jit);
+ cellResult(resultGPR, node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+}
+
+void SpeculativeJIT::compileNewStringObject(Node* node)
+{
+ SpeculateCellOperand operand(this, node->child1());
+
+ GPRTemporary result(this);
+ GPRTemporary scratch1(this);
+ GPRTemporary scratch2(this);
+
+ GPRReg operandGPR = operand.gpr();
+ GPRReg resultGPR = result.gpr();
+ GPRReg scratch1GPR = scratch1.gpr();
+ GPRReg scratch2GPR = scratch2.gpr();
+
+ JITCompiler::JumpList slowPath;
+
+ emitAllocateJSObject<StringObject>(
+ resultGPR, TrustedImmPtr(node->structure()), TrustedImmPtr(0), scratch1GPR, scratch2GPR,
+ slowPath);
+
+ m_jit.storePtr(
+ TrustedImmPtr(&StringObject::s_info),
+ JITCompiler::Address(resultGPR, JSDestructibleObject::classInfoOffset()));
+#if USE(JSVALUE64)
+ m_jit.store64(
+ operandGPR, JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset()));
+#else
+ m_jit.store32(
+ TrustedImm32(JSValue::CellTag),
+ JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(
+ operandGPR,
+ JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+#endif
+
+ addSlowPathGenerator(slowPathCall(
+ slowPath, this, operationNewStringObject, resultGPR, operandGPR, node->structure()));
+
+ cellResult(resultGPR, node);
+}
+
void SpeculativeJIT::speculateInt32(Edge edge)
{
if (!needsTypeCheck(edge, SpecInt32))
@@ -3973,10 +4082,11 @@
return;
SpeculateCellOperand operand(this, edge);
+ GPRReg gpr = operand.gpr();
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(operand.gpr()), edge, SpecObject, m_jit.branchPtr(
+ JSValueSource::unboxedCell(gpr), edge, SpecObject, m_jit.branchPtr(
MacroAssembler::Equal,
- MacroAssembler::Address(operand.gpr(), JSCell::structureOffset()),
+ MacroAssembler::Address(gpr, JSCell::structureOffset()),
MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
}
@@ -3993,7 +4103,7 @@
MacroAssembler::Jump notCell = m_jit.branchTest64(
MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister);
DFG_TYPE_CHECK(
- JSValueRegs(operand.gpr()), edge, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ JSValueRegs(gpr), edge, (~SpecCell) | SpecObject, m_jit.branchPtr(
MacroAssembler::Equal,
MacroAssembler::Address(gpr, JSCell::structureOffset()),
MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
@@ -4042,13 +4152,58 @@
return;
SpeculateCellOperand operand(this, edge);
+ GPRReg gpr = operand.gpr();
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(operand.gpr()), edge, SpecString, m_jit.branchPtr(
+ JSValueSource::unboxedCell(gpr), edge, SpecString, m_jit.branchPtr(
MacroAssembler::NotEqual,
- MacroAssembler::Address(operand.gpr(), JSCell::structureOffset()),
+ MacroAssembler::Address(gpr, JSCell::structureOffset()),
MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
}
+void SpeculativeJIT::speculateStringObject(GPRReg gpr)
+{
+ speculateStringObjectForStructure(JITCompiler::Address(gpr, JSCell::structureOffset()));
+}
+
+void SpeculativeJIT::speculateStringObject(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecStringObject))
+ return;
+
+ SpeculateCellOperand operand(this, edge);
+ GPRReg gpr = operand.gpr();
+ if (!needsTypeCheck(edge, SpecStringObject))
+ return;
+
+ speculateStringObject(gpr);
+ m_state.forNode(edge).filter(SpecStringObject);
+}
+
+void SpeculativeJIT::speculateStringOrStringObject(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecString | SpecStringObject))
+ return;
+
+ SpeculateCellOperand operand(this, edge);
+ GPRReg gpr = operand.gpr();
+ if (!needsTypeCheck(edge, SpecString | SpecStringObject))
+ return;
+
+ GPRTemporary structure(this);
+ GPRReg structureGPR = structure.gpr();
+
+ m_jit.loadPtr(JITCompiler::Address(gpr, JSCell::structureOffset()), structureGPR);
+
+ JITCompiler::Jump isString = m_jit.branchPtr(
+ JITCompiler::Equal, structureGPR, TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+
+ speculateStringObjectForStructure(structureGPR);
+
+ isString.link(&m_jit);
+
+ m_state.forNode(edge).filter(SpecString | SpecStringObject);
+}
+
void SpeculativeJIT::speculateNotCell(Edge edge)
{
if (!needsTypeCheck(edge, ~SpecCell))
@@ -4107,6 +4262,9 @@
case KnownCellUse:
ASSERT(!needsTypeCheck(edge, SpecCell));
break;
+ case KnownStringUse:
+ ASSERT(!needsTypeCheck(edge, SpecString));
+ break;
case Int32Use:
speculateInt32(edge);
break;
@@ -4131,6 +4289,12 @@
case StringUse:
speculateString(edge);
break;
+ case StringObjectUse:
+ speculateStringObject(edge);
+ break;
+ case StringOrStringObjectUse:
+ speculateStringOrStringObject(edge);
+ break;
case NotCellUse:
speculateNotCell(edge);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 8ea520c..e352d2e 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1085,6 +1085,16 @@
m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_EJssSt operation, GPRReg result, GPRReg arg1, Structure* structure)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(structure));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(C_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
+ {
+ m_jit.setupArgumentsWithExecState(arg1);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(S_DFGOperation_J operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArguments(arg1);
@@ -1473,6 +1483,16 @@
m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_EJssSt operation, GPRReg result, GPRReg arg1, Structure* structure)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(structure));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(C_DFGOperation_EJ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
+ {
+ m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(S_DFGOperation_J operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
{
m_jit.setupArguments(arg1Payload, arg1Tag);
@@ -2031,6 +2051,9 @@
void emitObjectOrOtherBranch(Edge value, BlockIndex taken, BlockIndex notTaken);
void emitBranch(Node*);
+ void compileToStringOnCell(Node*);
+ void compileNewStringObject(Node*);
+
void compileIntegerCompare(Node*, MacroAssembler::RelationalCondition);
void compileDoubleCompare(Node*, MacroAssembler::DoubleCondition);
@@ -2204,6 +2227,11 @@
void speculateObject(Edge);
void speculateObjectOrOther(Edge);
void speculateString(Edge);
+ template<typename StructureLocationType>
+ void speculateStringObjectForStructure(StructureLocationType);
+ void speculateStringObject(GPRReg);
+ void speculateStringObject(Edge);
+ void speculateStringOrStringObject(Edge);
void speculateNotCell(Edge);
void speculateOther(Edge);
void speculate(Node*, Edge);
@@ -2838,7 +2866,7 @@
, m_gprOrInvalid(InvalidGPRReg)
{
ASSERT(m_jit);
- ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == CellUse || edge.useKind() == KnownCellUse || edge.useKind() == ObjectUse || edge.useKind() == StringUse));
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == CellUse || edge.useKind() == KnownCellUse || edge.useKind() == ObjectUse || edge.useKind() == StringUse || edge.useKind() == KnownStringUse || edge.useKind() == StringObjectUse || edge.useKind() == StringOrStringObjectUse));
if (jit->isFilled(node()))
gpr();
}
@@ -2924,6 +2952,21 @@
GPRReg m_gprOrInvalid;
};
+template<typename StructureLocationType>
+void SpeculativeJIT::speculateStringObjectForStructure(StructureLocationType structureLocation)
+{
+ Structure* stringObjectStructure =
+ m_jit.globalObjectFor(m_currentNode->codeOrigin)->stringObjectStructure();
+ Structure* stringPrototypeStructure = stringObjectStructure->storedPrototype().asCell()->structure();
+ ASSERT(stringPrototypeStructure->transitionWatchpointSetIsStillValid());
+
+ speculationCheck(
+ NotStringObject, JSValueRegs(), 0,
+ m_jit.branchPtr(
+ JITCompiler::NotEqual, structureLocation, TrustedImmPtr(stringObjectStructure)));
+ stringPrototypeStructure->addTransitionWatchpoint(speculationWatchpoint(NotStringObject));
+}
+
#define DFG_TYPE_CHECK(source, edge, typesPassedThrough, jumpToFail) do { \
if (!needsTypeCheck((edge), (typesPassedThrough))) \
break; \
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index c13cf87..e56784c 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -1099,7 +1099,7 @@
#endif
AbstractValue& value = m_state.forNode(edge);
SpeculatedType type = value.m_type;
- ASSERT(edge.useKind() != KnownCellUse || !(value.m_type & ~SpecCell));
+ ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCell));
value.filter(SpecCell);
VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
@@ -3258,58 +3258,73 @@
}
case ToPrimitive: {
- switch (node->child1().useKind()) {
- case Int32Use: {
- // It's really profitable to speculate integer, since it's really cheap,
- // it means we don't have to do any real work, and we emit a lot less code.
+ RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
+ JSValueOperand op1(this, node->child1());
+ GPRTemporary resultTag(this, op1);
+ GPRTemporary resultPayload(this, op1, false);
+
+ GPRReg op1TagGPR = op1.tagGPR();
+ GPRReg op1PayloadGPR = op1.payloadGPR();
+ GPRReg resultTagGPR = resultTag.gpr();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+
+ op1.use();
+
+ if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean))) {
+ m_jit.move(op1TagGPR, resultTagGPR);
+ m_jit.move(op1PayloadGPR, resultPayloadGPR);
+ } else {
+ MacroAssembler::Jump alreadyPrimitive = m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
+ MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
- SpeculateIntegerOperand op1(this, node->child1());
- GPRTemporary result(this, op1);
+ alreadyPrimitive.link(&m_jit);
+ m_jit.move(op1TagGPR, resultTagGPR);
+ m_jit.move(op1PayloadGPR, resultPayloadGPR);
- ASSERT(op1.format() == DataFormatInteger);
- m_jit.move(op1.gpr(), result.gpr());
-
- integerResult(result.gpr(), node);
- break;
+ addSlowPathGenerator(
+ slowPathCall(
+ notPrimitive, this, operationToPrimitive,
+ JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));
}
-
- case UntypedUse: {
+
+ jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
+ break;
+ }
+
+ case ToString: {
+ if (node->child1().useKind() == UntypedUse) {
JSValueOperand op1(this, node->child1());
- GPRTemporary resultTag(this, op1);
- GPRTemporary resultPayload(this, op1, false);
-
- GPRReg op1TagGPR = op1.tagGPR();
GPRReg op1PayloadGPR = op1.payloadGPR();
- GPRReg resultTagGPR = resultTag.gpr();
- GPRReg resultPayloadGPR = resultPayload.gpr();
-
- op1.use();
-
- if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean))) {
- m_jit.move(op1TagGPR, resultTagGPR);
- m_jit.move(op1PayloadGPR, resultPayloadGPR);
- } else {
- MacroAssembler::Jump alreadyPrimitive = m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
- MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+ GPRReg op1TagGPR = op1.tagGPR();
- alreadyPrimitive.link(&m_jit);
- m_jit.move(op1TagGPR, resultTagGPR);
- m_jit.move(op1PayloadGPR, resultPayloadGPR);
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
- addSlowPathGenerator(
- slowPathCall(
- notPrimitive, this, operationToPrimitive,
- JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));
+ flushRegisters();
+
+ JITCompiler::Jump done;
+ if (node->child1()->prediction() & SpecString) {
+ JITCompiler::Jump slowPath = m_jit.branch32(
+ JITCompiler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
+ done = m_jit.branchPtr(
+ JITCompiler::Equal,
+ JITCompiler::Address(op1PayloadGPR, JSCell::structureOffset()),
+ TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+ slowPath.link(&m_jit);
}
+ callOperation(operationToString, resultGPR, op1TagGPR, op1PayloadGPR);
+ if (done.isSet())
+ done.link(&m_jit);
+ cellResult(resultGPR, node);
+ break;
+ }
- jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
- break;
- }
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
+ compileToStringOnCell(node);
+ break;
+ }
+
+ case NewStringObject: {
+ compileNewStringObject(node);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 087aaa2..157549e 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -1125,7 +1125,7 @@
#endif
AbstractValue& value = m_state.forNode(edge);
SpeculatedType type = value.m_type;
- ASSERT(edge.useKind() != KnownCellUse || !(value.m_type & ~SpecCell));
+ ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCell));
value.filter(SpecCell);
VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
@@ -3188,52 +3188,65 @@
}
case ToPrimitive: {
- switch (node->child1().useKind()) {
- case Int32Use: {
- // It's really profitable to speculate integer, since it's really cheap,
- // it means we don't have to do any real work, and we emit a lot less code.
+ RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
+ JSValueOperand op1(this, node->child1());
+ GPRTemporary result(this, op1);
+
+ GPRReg op1GPR = op1.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ op1.use();
+
+ if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean)))
+ m_jit.move(op1GPR, resultGPR);
+ else {
+ MacroAssembler::Jump alreadyPrimitive = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
+ MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
- SpeculateIntegerOperand op1(this, node->child1());
- GPRTemporary result(this, op1);
+ alreadyPrimitive.link(&m_jit);
+ m_jit.move(op1GPR, resultGPR);
- m_jit.move(op1.gpr(), result.gpr());
- if (op1.format() == DataFormatInteger)
- m_jit.or64(GPRInfo::tagTypeNumberRegister, result.gpr());
-
- jsValueResult(result.gpr(), node);
- break;
+ addSlowPathGenerator(
+ slowPathCall(notPrimitive, this, operationToPrimitive, resultGPR, op1GPR));
}
- case UntypedUse: {
+ jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
+ break;
+ }
+
+ case ToString: {
+ if (node->child1().useKind() == UntypedUse) {
JSValueOperand op1(this, node->child1());
- GPRTemporary result(this, op1);
-
GPRReg op1GPR = op1.gpr();
+
+ GPRResult result(this);
GPRReg resultGPR = result.gpr();
-
- op1.use();
-
- if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean)))
- m_jit.move(op1GPR, resultGPR);
- else {
- MacroAssembler::Jump alreadyPrimitive = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
- MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
- alreadyPrimitive.link(&m_jit);
- m_jit.move(op1GPR, resultGPR);
+ flushRegisters();
- addSlowPathGenerator(
- slowPathCall(notPrimitive, this, operationToPrimitive, resultGPR, op1GPR));
+ JITCompiler::Jump done;
+ if (node->child1()->prediction() & SpecString) {
+ JITCompiler::Jump slowPath = m_jit.branchTest64(
+ JITCompiler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
+ done = m_jit.branchPtr(
+ JITCompiler::Equal,
+ JITCompiler::Address(op1GPR, JSCell::structureOffset()),
+ TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+ slowPath.link(&m_jit);
}
+ callOperation(operationToString, resultGPR, op1GPR);
+ if (done.isSet())
+ done.link(&m_jit);
+ cellResult(resultGPR, node);
+ break;
+ }
- jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
- break;
- }
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
+ compileToStringOnCell(node);
+ break;
+ }
+
+ case NewStringObject: {
+ compileNewStringObject(node);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.cpp b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
index bb81920..bfba754 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.cpp
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
@@ -71,6 +71,15 @@
case StringUse:
out.print("String");
break;
+ case KnownStringUse:
+ out.print("KnownString");
+ break;
+ case StringObjectUse:
+ out.print("StringObject");
+ break;
+ case StringOrStringObjectUse:
+ out.print("StringOrStringObject");
+ break;
case NotCellUse:
out.print("NotCell");
break;
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.h b/Source/JavaScriptCore/dfg/DFGUseKind.h
index 74b0ca2..afe3d354 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.h
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.h
@@ -48,6 +48,9 @@
ObjectUse,
ObjectOrOtherUse,
StringUse,
+ KnownStringUse,
+ StringObjectUse,
+ StringOrStringObjectUse,
NotCellUse,
OtherUse,
LastUseKind // Must always be the last entry in the enum, as it is used to denote the number of enum elements.
@@ -76,7 +79,12 @@
case ObjectOrOtherUse:
return SpecObject | SpecOther;
case StringUse:
+ case KnownStringUse:
return SpecString;
+ case StringObjectUse:
+ return SpecStringObject;
+ case StringOrStringObjectUse:
+ return SpecString | SpecStringObject;
case NotCellUse:
return ~SpecCell;
case OtherUse:
diff --git a/Source/JavaScriptCore/interpreter/CallFrame.h b/Source/JavaScriptCore/interpreter/CallFrame.h
index 9852b31..716115ba 100644
--- a/Source/JavaScriptCore/interpreter/CallFrame.h
+++ b/Source/JavaScriptCore/interpreter/CallFrame.h
@@ -94,7 +94,6 @@
static const HashTable* regExpTable(CallFrame* callFrame) { return callFrame->globalData().regExpTable; }
static const HashTable* regExpConstructorTable(CallFrame* callFrame) { return callFrame->globalData().regExpConstructorTable; }
static const HashTable* regExpPrototypeTable(CallFrame* callFrame) { return callFrame->globalData().regExpPrototypeTable; }
- static const HashTable* stringTable(CallFrame* callFrame) { return callFrame->globalData().stringTable; }
static const HashTable* stringConstructorTable(CallFrame* callFrame) { return callFrame->globalData().stringConstructorTable; }
static CallFrame* create(Register* callFrameBase) { return static_cast<CallFrame*>(callFrameBase); }
diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h
index 73244e7..76fb92a 100644
--- a/Source/JavaScriptCore/runtime/Intrinsic.h
+++ b/Source/JavaScriptCore/runtime/Intrinsic.h
@@ -47,6 +47,7 @@
LogIntrinsic,
RegExpExecIntrinsic,
RegExpTestIntrinsic,
+ StringPrototypeValueOfIntrinsic
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSDestructibleObject.h b/Source/JavaScriptCore/runtime/JSDestructibleObject.h
index b8479be..7eb4548 100644
--- a/Source/JavaScriptCore/runtime/JSDestructibleObject.h
+++ b/Source/JavaScriptCore/runtime/JSDestructibleObject.h
@@ -14,6 +14,8 @@
static const bool needsDestruction = true;
const ClassInfo* classInfo() const { return m_classInfo; }
+
+ static ptrdiff_t classInfoOffset() { return OBJECT_OFFSETOF(JSDestructibleObject, m_classInfo); }
protected:
JSDestructibleObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index 36f2ffd..7ff2de1 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -97,7 +97,6 @@
extern const HashTable regExpTable;
extern const HashTable regExpConstructorTable;
extern const HashTable regExpPrototypeTable;
-extern const HashTable stringTable;
extern const HashTable stringConstructorTable;
// Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either
@@ -158,7 +157,6 @@
, regExpTable(fastNew<HashTable>(JSC::regExpTable))
, regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
, regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
- , stringTable(fastNew<HashTable>(JSC::stringTable))
, stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
, identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
, propertyNames(new CommonIdentifiers(this))
@@ -288,7 +286,6 @@
regExpTable->deleteTable();
regExpConstructorTable->deleteTable();
regExpPrototypeTable->deleteTable();
- stringTable->deleteTable();
stringConstructorTable->deleteTable();
fastDelete(const_cast<HashTable*>(arrayConstructorTable));
@@ -307,7 +304,6 @@
fastDelete(const_cast<HashTable*>(regExpTable));
fastDelete(const_cast<HashTable*>(regExpConstructorTable));
fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
- fastDelete(const_cast<HashTable*>(stringTable));
fastDelete(const_cast<HashTable*>(stringConstructorTable));
opaqueJSClassData.clear();
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h
index 570d85d..9a59d14 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.h
@@ -230,7 +230,6 @@
const HashTable* regExpTable;
const HashTable* regExpConstructorTable;
const HashTable* regExpPrototypeTable;
- const HashTable* stringTable;
const HashTable* stringConstructorTable;
Strong<Structure> structureStructure;
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index bd88b4d..bb87763 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2007 Eric Seidel (eric@webkit.org)
*
* This library is free software; you can redistribute it and/or
@@ -30,6 +30,7 @@
#include "CopyVisitorInlines.h"
#include "DatePrototype.h"
#include "ErrorConstructor.h"
+#include "Executable.h"
#include "GetterSetter.h"
#include "IndexingHeaderInlines.h"
#include "JSFunction.h"
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index d8532b1..17566f8 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -1454,10 +1454,16 @@
// Helper for defining native functions, if you're not using a static hash table.
// Use this macro from within finishCreation() methods in prototypes. This assumes
// you've defined variables called exec, globalObject, and globalData, and they
-// have the expected meanings. This also assumes that the function you're defining
-// doesn't have an intrinsic.
+// have the expected meanings.
+#define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \
+ putDirectNativeFunction(\
+ exec, globalObject, Identifier(exec, #jsName), (length), cppName, \
+ (intrinsic), (attributes))
+
+// As above, but this assumes that the function you're defining doesn't have an
+// intrinsic.
#define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
- putDirectNativeFunction(exec, globalObject, globalData.propertyNames->jsName, (length), cppName, NoIntrinsic, (attributes))
+ JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.h b/Source/JavaScriptCore/runtime/JSWrapperObject.h
index 72bc187..f108c9e 100644
--- a/Source/JavaScriptCore/runtime/JSWrapperObject.h
+++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h
@@ -32,6 +32,12 @@
public:
typedef JSDestructibleObject Base;
+ static size_t allocationSize(size_t inlineCapacity)
+ {
+ ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+ return sizeof(JSWrapperObject);
+ }
+
JSValue internalValue() const;
void setInternalValue(JSGlobalData&, JSValue);
@@ -39,6 +45,16 @@
{
return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
}
+
+ static ptrdiff_t internalValueOffset() { return OBJECT_OFFSETOF(JSWrapperObject, m_internalValue); }
+ static ptrdiff_t internalValueCellOffset()
+ {
+#if USE(JSVALUE64)
+ return internalValueOffset();
+#else
+ return internalValueOffset() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload);
+#endif
+ }
protected:
explicit JSWrapperObject(JSGlobalData&, Structure*);
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
index 25f9897..d810812 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2009 Torch Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -82,56 +82,7 @@
static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
-}
-
-#include "StringPrototype.lut.h"
-
-namespace JSC {
-
-const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, ExecState::stringTable, CREATE_METHOD_TABLE(StringPrototype) };
-
-/* Source for StringPrototype.lut.h
-@begin stringTable 26
- toString stringProtoFuncToString DontEnum|Function 0
- valueOf stringProtoFuncToString DontEnum|Function 0
- charAt stringProtoFuncCharAt DontEnum|Function 1
- charCodeAt stringProtoFuncCharCodeAt DontEnum|Function 1
- concat stringProtoFuncConcat DontEnum|Function 1
- indexOf stringProtoFuncIndexOf DontEnum|Function 1
- lastIndexOf stringProtoFuncLastIndexOf DontEnum|Function 1
- match stringProtoFuncMatch DontEnum|Function 1
- replace stringProtoFuncReplace DontEnum|Function 2
- search stringProtoFuncSearch DontEnum|Function 1
- slice stringProtoFuncSlice DontEnum|Function 2
- split stringProtoFuncSplit DontEnum|Function 2
- substr stringProtoFuncSubstr DontEnum|Function 2
- substring stringProtoFuncSubstring DontEnum|Function 2
- toLowerCase stringProtoFuncToLowerCase DontEnum|Function 0
- toUpperCase stringProtoFuncToUpperCase DontEnum|Function 0
- localeCompare stringProtoFuncLocaleCompare DontEnum|Function 1
-
- # toLocaleLowerCase and toLocaleUpperCase are currently identical to toLowerCase and toUpperCase
- toLocaleLowerCase stringProtoFuncToLowerCase DontEnum|Function 0
- toLocaleUpperCase stringProtoFuncToUpperCase DontEnum|Function 0
-
- big stringProtoFuncBig DontEnum|Function 0
- small stringProtoFuncSmall DontEnum|Function 0
- blink stringProtoFuncBlink DontEnum|Function 0
- bold stringProtoFuncBold DontEnum|Function 0
- fixed stringProtoFuncFixed DontEnum|Function 0
- italics stringProtoFuncItalics DontEnum|Function 0
- strike stringProtoFuncStrike DontEnum|Function 0
- sub stringProtoFuncSub DontEnum|Function 0
- sup stringProtoFuncSup DontEnum|Function 0
- fontcolor stringProtoFuncFontcolor DontEnum|Function 1
- fontsize stringProtoFuncFontsize DontEnum|Function 1
- anchor stringProtoFuncAnchor DontEnum|Function 1
- link stringProtoFuncLink DontEnum|Function 1
- trim stringProtoFuncTrim DontEnum|Function 0
- trimLeft stringProtoFuncTrimLeft DontEnum|Function 0
- trimRight stringProtoFuncTrimRight DontEnum|Function 0
-@end
-*/
+const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringPrototype) };
// ECMA 15.5.4
StringPrototype::StringPrototype(ExecState* exec, Structure* structure)
@@ -139,23 +90,59 @@
{
}
-void StringPrototype::finishCreation(ExecState* exec, JSGlobalObject*, JSString* nameAndMessage)
+void StringPrototype::finishCreation(ExecState* exec, JSGlobalObject* globalObject, JSString* nameAndMessage)
{
- Base::finishCreation(exec->globalData(), nameAndMessage);
+ JSGlobalData& globalData = exec->globalData();
+
+ Base::finishCreation(globalData, nameAndMessage);
ASSERT(inherits(&s_info));
+ JSC_NATIVE_INTRINSIC_FUNCTION(toString, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
+ JSC_NATIVE_INTRINSIC_FUNCTION(valueOf, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
+ JSC_NATIVE_INTRINSIC_FUNCTION(charAt, stringProtoFuncCharAt, DontEnum, 1, CharAtIntrinsic);
+ JSC_NATIVE_INTRINSIC_FUNCTION(charCodeAt, stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic);
+ JSC_NATIVE_FUNCTION(concat, stringProtoFuncConcat, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(indexOf, stringProtoFuncIndexOf, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(lastIndexOf, stringProtoFuncLastIndexOf, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(match, stringProtoFuncMatch, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(replace, stringProtoFuncReplace, DontEnum, 2);
+ JSC_NATIVE_FUNCTION(search, stringProtoFuncSearch, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(slice, stringProtoFuncSlice, DontEnum, 2);
+ JSC_NATIVE_FUNCTION(split, stringProtoFuncSplit, DontEnum, 2);
+ JSC_NATIVE_FUNCTION(substr, stringProtoFuncSubstr, DontEnum, 2);
+ JSC_NATIVE_FUNCTION(substring, stringProtoFuncSubstring, DontEnum, 2);
+ JSC_NATIVE_FUNCTION(toLowerCase, stringProtoFuncToLowerCase, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(toUpperCase, stringProtoFuncToUpperCase, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(localeCompare, stringProtoFuncLocaleCompare, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(toLocaleLowerCase, stringProtoFuncToLowerCase, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(toLocaleUpperCase, stringProtoFuncToUpperCase, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(big, stringProtoFuncBig, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(small, stringProtoFuncSmall, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(blink, stringProtoFuncBlink, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(bold, stringProtoFuncBold, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(fixed, stringProtoFuncFixed, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(italics, stringProtoFuncItalics, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(strike, stringProtoFuncStrike, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(sub, stringProtoFuncSub, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(sup, stringProtoFuncSup, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(fontcolor, stringProtoFuncFontcolor, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(fontsize, stringProtoFuncFontsize, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(anchor, stringProtoFuncAnchor, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(link, stringProtoFuncLink, DontEnum, 1);
+ JSC_NATIVE_FUNCTION(trim, stringProtoFuncTrim, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(trimLeft, stringProtoFuncTrimLeft, DontEnum, 0);
+ JSC_NATIVE_FUNCTION(trimRight, stringProtoFuncTrimRight, DontEnum, 0);
+
// The constructor will be added later, after StringConstructor has been built
putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
}
-bool StringPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
+StringPrototype* StringPrototype::create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
{
- return getStaticFunctionSlot<StringObject>(exec, ExecState::stringTable(exec), jsCast<StringPrototype*>(cell), propertyName, slot);
-}
-
-bool StringPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
-{
- return getStaticFunctionDescriptor<StringObject>(exec, ExecState::stringTable(exec), jsCast<StringPrototype*>(object), propertyName, descriptor);
+ JSString* empty = jsEmptyString(exec);
+ StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(*exec->heap())) StringPrototype(exec, structure);
+ prototype->finishCreation(exec, globalObject, empty);
+ return prototype;
}
// ------------------------------ Functions --------------------------
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.h b/Source/JavaScriptCore/runtime/StringPrototype.h
index b846c7b..6d36804 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.h
+++ b/Source/JavaScriptCore/runtime/StringPrototype.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -34,16 +34,7 @@
public:
typedef StringObject Base;
- static StringPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
- {
- JSString* empty = jsEmptyString(exec);
- StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(*exec->heap())) StringPrototype(exec, structure);
- prototype->finishCreation(exec, globalObject, empty);
- return prototype;
- }
-
- static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ static StringPrototype* create(ExecState*, JSGlobalObject*, Structure*);
static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
{
@@ -54,7 +45,7 @@
protected:
void finishCreation(ExecState*, JSGlobalObject*, JSString*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | StringObject::StructureFlags;
+ static const unsigned StructureFlags = StringObject::StructureFlags;
};