Introduce get_by_id like IC into get_by_val when the given name is String or Symbol
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 7 Aug 2015 02:08:07 +0000 (02:08 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 7 Aug 2015 02:08:07 +0000 (02:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=147480

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This patch adds get_by_id IC to get_by_val operation by caching the string / symbol id.
The IC site only caches one id. After checking that the given id is the same to the
cached one, we perform the get_by_id IC onto it.
And by collecting IC StructureStubInfo information, we pass it to the DFG and DFG
compiles get_by_val op code into CheckIdent (with edge type check) and GetById related
operations when the given get_by_val leverages the property load with the cached id.

To ensure the incoming value is the expected id, in DFG layer, we use SymbolUse and
StringIdentUse to enforce the type. To use it, this patch implements SymbolUse.
This can be leveraged to optimize symbol operations in DFG.

And since byValInfo is frequently used, we align the byValInfo design to the stubInfo like one.
Allocated by the Bag and operations take the raw byValInfo pointer directly instead of performing
binary search onto m_byValInfos. And by storing ArrayProfile* under the ByValInfo, we replaced the
argument ArrayProfile* in the operations with ByValInfo*.

* bytecode/ByValInfo.h:
(JSC::ByValInfo::ByValInfo):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::getByValInfoMap):
(JSC::CodeBlock::addByValInfo):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::getByValInfo): Deleted.
(JSC::CodeBlock::setNumberOfByValInfos): Deleted.
(JSC::CodeBlock::numberOfByValInfos): Deleted.
(JSC::CodeBlock::byValInfo): Deleted.
* bytecode/ExitKind.cpp:
(JSC::exitKindToString):
* bytecode/ExitKind.h:
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFor):
(JSC::GetByIdStatus::computeForStubInfo):
(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
* bytecode/GetByIdStatus.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::observeUseKindOnNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasUidOperand):
(JSC::DFG::Node::uidOperand):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCheckIdent):
(JSC::DFG::SpeculativeJIT::speculateSymbol):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isCell):
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::compileNode):
(JSC::FTL::DFG::LowerDFGToLLVM::compileCheckIdent):
(JSC::FTL::DFG::LowerDFGToLLVM::lowSymbol):
(JSC::FTL::DFG::LowerDFGToLLVM::speculate):
(JSC::FTL::DFG::LowerDFGToLLVM::isNotSymbol):
(JSC::FTL::DFG::LowerDFGToLLVM::speculateSymbol):
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
* jit/JIT.h:
(JSC::ByValCompilationInfo::ByValCompilationInfo):
(JSC::JIT::compileGetByValWithCachedId):
* jit/JITInlines.h:
(JSC::JIT::callOperation):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_has_indexed_property):
(JSC::JIT::emitSlow_op_has_indexed_property):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_has_indexed_property):
(JSC::JIT::emitSlow_op_has_indexed_property):
* jit/JITOperations.cpp:
(JSC::getByVal):
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitGetByValWithCachedId):
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitSlow_op_put_by_val):
(JSC::JIT::privateCompileGetByVal):
(JSC::JIT::privateCompileGetByValWithCachedId):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitGetByValWithCachedId):
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitSlow_op_put_by_val):
* runtime/Symbol.h:
* tests/stress/get-by-val-with-string-constructor.js: Added.
(Hello):
(get Hello.prototype.generate):
(ok):
* tests/stress/get-by-val-with-string-exit.js: Added.
(shouldBe):
(getByVal):
(getStr1):
(getStr2):
* tests/stress/get-by-val-with-string-generated.js: Added.
(shouldBe):
(getByVal):
(getStr1):
(getStr2):
* tests/stress/get-by-val-with-string-getter.js: Added.
(object.get hello):
(ok):
* tests/stress/get-by-val-with-string.js: Added.
(shouldBe):
(getByVal):
(getStr1):
(getStr2):
* tests/stress/get-by-val-with-symbol-constructor.js: Added.
(Hello):
(get Hello.prototype.generate):
(ok):
* tests/stress/get-by-val-with-symbol-exit.js: Added.
(shouldBe):
(getByVal):
(getSym1):
(getSym2):
* tests/stress/get-by-val-with-symbol-getter.js: Added.
(object.get hello):
(.get ok):
* tests/stress/get-by-val-with-symbol.js: Added.
(shouldBe):
(getByVal):
(getSym1):
(getSym2):

LayoutTests:

Add synthetic benchmarks that replaces normal property load with symbol/string keyed load.

* js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-expected.txt: Added.
* js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple-expected.txt: Added.
* js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple.html: Added.
* js/regress/get-by-val-with-string-bimorphic-check-structure-elimination.html: Added.
* js/regress/get-by-val-with-string-chain-from-try-block-expected.txt: Added.
* js/regress/get-by-val-with-string-chain-from-try-block.html: Added.
* js/regress/get-by-val-with-string-check-structure-elimination-expected.txt: Added.
* js/regress/get-by-val-with-string-check-structure-elimination.html: Added.
* js/regress/get-by-val-with-string-proto-or-self-expected.txt: Added.
* js/regress/get-by-val-with-string-proto-or-self.html: Added.
* js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple-expected.txt: Added.
* js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.html: Added.
* js/regress/get-by-val-with-string-self-or-proto-expected.txt: Added.
* js/regress/get-by-val-with-string-self-or-proto.html: Added.
* js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-expected.txt: Added.
* js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple-expected.txt: Added.
* js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.html: Added.
* js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination.html: Added.
* js/regress/get-by-val-with-symbol-chain-from-try-block-expected.txt: Added.
* js/regress/get-by-val-with-symbol-chain-from-try-block.html: Added.
* js/regress/get-by-val-with-symbol-check-structure-elimination-expected.txt: Added.
* js/regress/get-by-val-with-symbol-check-structure-elimination.html: Added.
* js/regress/get-by-val-with-symbol-proto-or-self-expected.txt: Added.
* js/regress/get-by-val-with-symbol-proto-or-self.html: Added.
* js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple-expected.txt: Added.
* js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.html: Added.
* js/regress/get-by-val-with-symbol-self-or-proto-expected.txt: Added.
* js/regress/get-by-val-with-symbol-self-or-proto.html: Added.
* js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination-simple.js: Added.
* js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination.js: Added.
* js/regress/script-tests/get-by-val-with-string-chain-from-try-block.js: Added.
(A):
(B):
(C):
(D):
(E):
(F):
(G):
(foo):
* js/regress/script-tests/get-by-val-with-string-check-structure-elimination.js: Added.
* js/regress/script-tests/get-by-val-with-string-proto-or-self.js: Added.
(foo):
(bar):
(Foo):
* js/regress/script-tests/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.js: Added.
* js/regress/script-tests/get-by-val-with-string-self-or-proto.js: Added.
(foo):
(bar):
(Foo):
* js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.js: Added.
* js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination.js: Added.
* js/regress/script-tests/get-by-val-with-symbol-chain-from-try-block.js: Added.
(A):
(B):
(C):
(D):
(E):
(F):
(G):
(foo):
* js/regress/script-tests/get-by-val-with-symbol-check-structure-elimination.js: Added.
* js/regress/script-tests/get-by-val-with-symbol-proto-or-self.js: Added.
(foo):
(bar):
(Foo):
* js/regress/script-tests/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.js: Added.
* js/regress/script-tests/get-by-val-with-symbol-self-or-proto.js: Added.
(foo):
(bar):
(Foo):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188105 268f45cc-cd09-0410-ab3c-d52691b4dbfc

89 files changed:
LayoutTests/ChangeLog
LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-chain-from-try-block-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-chain-from-try-block.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-check-structure-elimination-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-check-structure-elimination.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-proto-or-self-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-proto-or-self.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-self-or-proto-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-string-self-or-proto.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-chain-from-try-block-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-chain-from-try-block.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-check-structure-elimination-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-check-structure-elimination.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-proto-or-self-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-proto-or-self.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.html [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-self-or-proto-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/get-by-val-with-symbol-self-or-proto.html [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination-simple.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-string-chain-from-try-block.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-string-check-structure-elimination.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-string-proto-or-self.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-string-self-or-proto.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-symbol-chain-from-try-block.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-symbol-check-structure-elimination.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-symbol-proto-or-self.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/get-by-val-with-symbol-self-or-proto.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/ByValInfo.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/ExitKind.cpp
Source/JavaScriptCore/bytecode/ExitKind.h
Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
Source/JavaScriptCore/bytecode/GetByIdStatus.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGUseKind.cpp
Source/JavaScriptCore/dfg/DFGUseKind.h
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITInlines.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/runtime/Symbol.h
Source/JavaScriptCore/tests/stress/get-by-val-with-string-constructor.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/get-by-val-with-string-exit.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/get-by-val-with-string-generated.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/get-by-val-with-string-getter.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/get-by-val-with-string.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/get-by-val-with-symbol-constructor.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/get-by-val-with-symbol-exit.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/get-by-val-with-symbol-getter.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/get-by-val-with-symbol.js [new file with mode: 0644]

index 99976cd..b2c24b2 100644 (file)
@@ -1,3 +1,83 @@
+2015-08-06  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Introduce get_by_id like IC into get_by_val when the given name is String or Symbol
+        https://bugs.webkit.org/show_bug.cgi?id=147480
+
+        Reviewed by Filip Pizlo.
+
+        Add synthetic benchmarks that replaces normal property load with symbol/string keyed load.
+
+        * js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-expected.txt: Added.
+        * js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple-expected.txt: Added.
+        * js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple.html: Added.
+        * js/regress/get-by-val-with-string-bimorphic-check-structure-elimination.html: Added.
+        * js/regress/get-by-val-with-string-chain-from-try-block-expected.txt: Added.
+        * js/regress/get-by-val-with-string-chain-from-try-block.html: Added.
+        * js/regress/get-by-val-with-string-check-structure-elimination-expected.txt: Added.
+        * js/regress/get-by-val-with-string-check-structure-elimination.html: Added.
+        * js/regress/get-by-val-with-string-proto-or-self-expected.txt: Added.
+        * js/regress/get-by-val-with-string-proto-or-self.html: Added.
+        * js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple-expected.txt: Added.
+        * js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.html: Added.
+        * js/regress/get-by-val-with-string-self-or-proto-expected.txt: Added.
+        * js/regress/get-by-val-with-string-self-or-proto.html: Added.
+        * js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-expected.txt: Added.
+        * js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple-expected.txt: Added.
+        * js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.html: Added.
+        * js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination.html: Added.
+        * js/regress/get-by-val-with-symbol-chain-from-try-block-expected.txt: Added.
+        * js/regress/get-by-val-with-symbol-chain-from-try-block.html: Added.
+        * js/regress/get-by-val-with-symbol-check-structure-elimination-expected.txt: Added.
+        * js/regress/get-by-val-with-symbol-check-structure-elimination.html: Added.
+        * js/regress/get-by-val-with-symbol-proto-or-self-expected.txt: Added.
+        * js/regress/get-by-val-with-symbol-proto-or-self.html: Added.
+        * js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple-expected.txt: Added.
+        * js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.html: Added.
+        * js/regress/get-by-val-with-symbol-self-or-proto-expected.txt: Added.
+        * js/regress/get-by-val-with-symbol-self-or-proto.html: Added.
+        * js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination-simple.js: Added.
+        * js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination.js: Added.
+        * js/regress/script-tests/get-by-val-with-string-chain-from-try-block.js: Added.
+        (A):
+        (B):
+        (C):
+        (D):
+        (E):
+        (F):
+        (G):
+        (foo):
+        * js/regress/script-tests/get-by-val-with-string-check-structure-elimination.js: Added.
+        * js/regress/script-tests/get-by-val-with-string-proto-or-self.js: Added.
+        (foo):
+        (bar):
+        (Foo):
+        * js/regress/script-tests/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.js: Added.
+        * js/regress/script-tests/get-by-val-with-string-self-or-proto.js: Added.
+        (foo):
+        (bar):
+        (Foo):
+        * js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.js: Added.
+        * js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination.js: Added.
+        * js/regress/script-tests/get-by-val-with-symbol-chain-from-try-block.js: Added.
+        (A):
+        (B):
+        (C):
+        (D):
+        (E):
+        (F):
+        (G):
+        (foo):
+        * js/regress/script-tests/get-by-val-with-symbol-check-structure-elimination.js: Added.
+        * js/regress/script-tests/get-by-val-with-symbol-proto-or-self.js: Added.
+        (foo):
+        (bar):
+        (Foo):
+        * js/regress/script-tests/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.js: Added.
+        * js/regress/script-tests/get-by-val-with-symbol-self-or-proto.js: Added.
+        (foo):
+        (bar):
+        (Foo):
+
 2015-08-06  Keith Miller  <keith_miller@apple.com>
 
         The JSONP parser incorrectly parses -0 as +0.
diff --git a/LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-expected.txt b/LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-expected.txt
new file mode 100644 (file)
index 0000000..accf43a
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-string-bimorphic-check-structure-elimination
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple-expected.txt b/LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple-expected.txt
new file mode 100644 (file)
index 0000000..1b37c50
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-string-bimorphic-check-structure-elimination-simple
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple.html b/LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination-simple.html
new file mode 100644 (file)
index 0000000..0482c45
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination.html b/LayoutTests/js/regress/get-by-val-with-string-bimorphic-check-structure-elimination.html
new file mode 100644 (file)
index 0000000..e9ef141
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-string-chain-from-try-block-expected.txt b/LayoutTests/js/regress/get-by-val-with-string-chain-from-try-block-expected.txt
new file mode 100644 (file)
index 0000000..216a667
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-string-chain-from-try-block
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-string-chain-from-try-block.html b/LayoutTests/js/regress/get-by-val-with-string-chain-from-try-block.html
new file mode 100644 (file)
index 0000000..e6c963a
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-string-chain-from-try-block.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-string-check-structure-elimination-expected.txt b/LayoutTests/js/regress/get-by-val-with-string-check-structure-elimination-expected.txt
new file mode 100644 (file)
index 0000000..eec0fc7
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-string-check-structure-elimination
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-string-check-structure-elimination.html b/LayoutTests/js/regress/get-by-val-with-string-check-structure-elimination.html
new file mode 100644 (file)
index 0000000..836f58d
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-string-check-structure-elimination.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-string-proto-or-self-expected.txt b/LayoutTests/js/regress/get-by-val-with-string-proto-or-self-expected.txt
new file mode 100644 (file)
index 0000000..bef92c9
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-string-proto-or-self
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-string-proto-or-self.html b/LayoutTests/js/regress/get-by-val-with-string-proto-or-self.html
new file mode 100644 (file)
index 0000000..76ab611
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-string-proto-or-self.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple-expected.txt b/LayoutTests/js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple-expected.txt
new file mode 100644 (file)
index 0000000..9b1aa57
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.html b/LayoutTests/js/regress/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.html
new file mode 100644 (file)
index 0000000..d3751b6
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-string-self-or-proto-expected.txt b/LayoutTests/js/regress/get-by-val-with-string-self-or-proto-expected.txt
new file mode 100644 (file)
index 0000000..0421713
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-string-self-or-proto
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-string-self-or-proto.html b/LayoutTests/js/regress/get-by-val-with-string-self-or-proto.html
new file mode 100644 (file)
index 0000000..d04a6b9
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-string-self-or-proto.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-expected.txt b/LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-expected.txt
new file mode 100644 (file)
index 0000000..4100c5d
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-symbol-bimorphic-check-structure-elimination
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple-expected.txt b/LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple-expected.txt
new file mode 100644 (file)
index 0000000..4390ed9
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.html b/LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.html
new file mode 100644 (file)
index 0000000..0482c45
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination.html b/LayoutTests/js/regress/get-by-val-with-symbol-bimorphic-check-structure-elimination.html
new file mode 100644 (file)
index 0000000..e9ef141
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-chain-from-try-block-expected.txt b/LayoutTests/js/regress/get-by-val-with-symbol-chain-from-try-block-expected.txt
new file mode 100644 (file)
index 0000000..c754bb0
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-symbol-chain-from-try-block
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-chain-from-try-block.html b/LayoutTests/js/regress/get-by-val-with-symbol-chain-from-try-block.html
new file mode 100644 (file)
index 0000000..7975f99
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-symbol-chain-from-try-block.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-check-structure-elimination-expected.txt b/LayoutTests/js/regress/get-by-val-with-symbol-check-structure-elimination-expected.txt
new file mode 100644 (file)
index 0000000..431494a
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-symbol-check-structure-elimination
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-check-structure-elimination.html b/LayoutTests/js/regress/get-by-val-with-symbol-check-structure-elimination.html
new file mode 100644 (file)
index 0000000..d9bfaca
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-symbol-check-structure-elimination.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-proto-or-self-expected.txt b/LayoutTests/js/regress/get-by-val-with-symbol-proto-or-self-expected.txt
new file mode 100644 (file)
index 0000000..a15d262
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-symbol-proto-or-self
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-proto-or-self.html b/LayoutTests/js/regress/get-by-val-with-symbol-proto-or-self.html
new file mode 100644 (file)
index 0000000..55815ce
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-symbol-proto-or-self.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple-expected.txt b/LayoutTests/js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple-expected.txt
new file mode 100644 (file)
index 0000000..f4605c0
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.html b/LayoutTests/js/regress/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.html
new file mode 100644 (file)
index 0000000..65ce462
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-self-or-proto-expected.txt b/LayoutTests/js/regress/get-by-val-with-symbol-self-or-proto-expected.txt
new file mode 100644 (file)
index 0000000..0766910
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/get-by-val-with-symbol-self-or-proto
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/get-by-val-with-symbol-self-or-proto.html b/LayoutTests/js/regress/get-by-val-with-symbol-self-or-proto.html
new file mode 100644 (file)
index 0000000..ff5f3d7
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/get-by-val-with-symbol-self-or-proto.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination-simple.js b/LayoutTests/js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination-simple.js
new file mode 100644 (file)
index 0000000..92589f1
--- /dev/null
@@ -0,0 +1,14 @@
+(function() {
+    var a = 'a', l = 'l';
+    var o = {[a]:1};
+    var p = {[a]:2, [l]:13};
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i) {
+        result ^= o[a];
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != 0)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination.js b/LayoutTests/js/regress/script-tests/get-by-val-with-string-bimorphic-check-structure-elimination.js
new file mode 100644 (file)
index 0000000..db59401
--- /dev/null
@@ -0,0 +1,14 @@
+(function() {
+    var a = 'a', b = 'b', c = 'c', d = 'd', e = 'e', f = 'f', g = 'g', h = 'h', i = 'i', j = 'j', k = 'k', l = 'l';
+    var o = {[a]:1, [b]:2, [c]:3, [d]:4, [e]:5, [f]:6, [g]:7, [h]:8, [i]:9, [j]:10, [k]:11};
+    var p = {[a]:2, [b]:3, [c]:4, [d]:5, [e]:6, [f]:7, [g]:8, [h]:9, [i]:10, [j]:11, [k]:12, [l]:13};
+    var result = 0;
+    for (var index = 0; index < 1000000; ++index) {
+        result += o[a] ^ o[b] ^ o[c] ^ o[d] ^ o[e] ^ o[f] ^ o[g] ^ o[h] ^ o[i] ^ o[j] ^ o[k];
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != 6500000)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-string-chain-from-try-block.js b/LayoutTests/js/regress/script-tests/get-by-val-with-string-chain-from-try-block.js
new file mode 100644 (file)
index 0000000..df970fe
--- /dev/null
@@ -0,0 +1,49 @@
+var f = 'f';
+
+function A() { }
+
+A.prototype = {[f]:42};
+
+function B() { }
+
+B.prototype = new A();
+
+function C() { }
+
+C.prototype = new B();
+
+function D() { }
+
+D.prototype = new C();
+
+function E() { }
+
+E.prototype = new D();
+
+function F() { }
+
+F.prototype = new E();
+
+function G() { }
+
+G.prototype = new F();
+
+function foo(o) {
+    try {
+        var result = 0;
+        for (var i = 0; i < 1000; ++i)
+            result += o[f];
+        return result;
+    } catch (e) {
+        return 52;
+    }
+}
+
+var result = 0;
+
+for (var i = 0; i < 1000; ++i)
+    result += foo(new G());
+
+if (result != 42000000)
+    throw "Error: bad result: " + result;
+
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-string-check-structure-elimination.js b/LayoutTests/js/regress/script-tests/get-by-val-with-string-check-structure-elimination.js
new file mode 100644 (file)
index 0000000..bb88aa5
--- /dev/null
@@ -0,0 +1,9 @@
+(function() {
+    var a = 'a', b = 'b', c = 'c', d = 'd', e = 'e', f = 'f', g = 'g', h = 'h', i = 'i', j = 'j', k = 'k';
+    var o = {[a]:1, [b]:2, [c]:3, [d]:4, [e]:5, [f]:6, [g]:7, [h]:8, [i]:9, [j]:10, [k]:11};
+    var result = 0;
+    for (var index = 0; index < 1000000; ++index)
+        result += o[a] ^ o[b] | o[c] ^ o[d] & o[e] ^ o[f] | o[g] ^ o[h] & o[i] ^ o[j] | o[k];
+    if (result != 15000000)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-string-proto-or-self.js b/LayoutTests/js/regress/script-tests/get-by-val-with-string-proto-or-self.js
new file mode 100644 (file)
index 0000000..ef7493b
--- /dev/null
@@ -0,0 +1,24 @@
+var f = 'f';
+
+function foo(o) {
+    return o[f];
+}
+
+function bar(a) {
+    var result = 0;
+    for (var i = 0; i < 2000000; ++i) {
+        for (var j = 0; j < a.length; ++j)
+            result += foo(a[j]);
+    }
+    return result;
+}
+
+function Foo() {
+}
+
+Foo.prototype[f] = 42;
+
+var result = bar([new Foo(), {[f]:24}]);
+
+if (result != 132000000)
+    throw "Error bad result: " + result;
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.js b/LayoutTests/js/regress/script-tests/get-by-val-with-string-quadmorphic-check-structure-elimination-simple.js
new file mode 100644 (file)
index 0000000..991dce3
--- /dev/null
@@ -0,0 +1,22 @@
+(function() {
+    var a = 'a';
+    var l = 'l';
+    var b = 'b';
+    var c = 'c';
+
+    var o = {[a]:1};
+    var p = {[a]:2, [l]:13};
+    var q = {[a]:3, [b]:3};
+    var r = {[a]:4, [c]:5};
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i) {
+        result ^= o[a];
+        var tmp = o;
+        o = p;
+        p = q;
+        q = r;
+        r = tmp;
+    }
+    if (result != 0)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-string-self-or-proto.js b/LayoutTests/js/regress/script-tests/get-by-val-with-string-self-or-proto.js
new file mode 100644 (file)
index 0000000..9bec107
--- /dev/null
@@ -0,0 +1,24 @@
+var f = 'f';
+
+function foo(o) {
+    return o[f];
+}
+
+function bar(a) {
+    var result = 0;
+    for (var i = 0; i < 2000000; ++i) {
+        for (var j = 0; j < a.length; ++j)
+            result += foo(a[j]);
+    }
+    return result;
+}
+
+function Foo() {
+}
+
+Foo.prototype[f] = 42;
+
+var result = bar([{[f]:24}, new Foo()]);
+
+if (result != 132000000)
+    throw "Error bad result: " + result;
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.js b/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination-simple.js
new file mode 100644 (file)
index 0000000..e85d32a
--- /dev/null
@@ -0,0 +1,14 @@
+(function() {
+    var a = Symbol(), l = Symbol();
+    var o = {[a]:1};
+    var p = {[a]:2, [l]:13};
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i) {
+        result ^= o[a];
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != 0)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination.js b/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-bimorphic-check-structure-elimination.js
new file mode 100644 (file)
index 0000000..fbbe971
--- /dev/null
@@ -0,0 +1,14 @@
+(function() {
+    var a = Symbol(), b = Symbol(), c = Symbol(), d = Symbol(), e = Symbol(), f = Symbol(), g = Symbol(), h = Symbol(), i = Symbol(), j = Symbol(), k = Symbol(), l = Symbol();
+    var o = {[a]:1, [b]:2, [c]:3, [d]:4, [e]:5, [f]:6, [g]:7, [h]:8, [i]:9, [j]:10, [k]:11};
+    var p = {[a]:2, [b]:3, [c]:4, [d]:5, [e]:6, [f]:7, [g]:8, [h]:9, [i]:10, [j]:11, [k]:12, [l]: 13};
+    var result = 0;
+    for (var index = 0; index < 1000000; ++index) {
+        result += o[a] ^ o[b] ^ o[c] ^ o[d] ^ o[e] ^ o[f] ^ o[g] ^ o[h] ^ o[i] ^ o[j] ^ o[k];
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != 6500000)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-chain-from-try-block.js b/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-chain-from-try-block.js
new file mode 100644 (file)
index 0000000..3f8ac78
--- /dev/null
@@ -0,0 +1,49 @@
+var f = Symbol("Cocoa");
+
+function A() { }
+
+A.prototype = {[f]:42};
+
+function B() { }
+
+B.prototype = new A();
+
+function C() { }
+
+C.prototype = new B();
+
+function D() { }
+
+D.prototype = new C();
+
+function E() { }
+
+E.prototype = new D();
+
+function F() { }
+
+F.prototype = new E();
+
+function G() { }
+
+G.prototype = new F();
+
+function foo(o) {
+    try {
+        var result = 0;
+        for (var i = 0; i < 1000; ++i)
+            result += o[f];
+        return result;
+    } catch (e) {
+        return 52;
+    }
+}
+
+var result = 0;
+
+for (var i = 0; i < 1000; ++i)
+    result += foo(new G());
+
+if (result != 42000000)
+    throw "Error: bad result: " + result;
+
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-check-structure-elimination.js b/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-check-structure-elimination.js
new file mode 100644 (file)
index 0000000..9d59fd8
--- /dev/null
@@ -0,0 +1,9 @@
+(function() {
+    var a = Symbol(), b = Symbol(), c = Symbol(), d = Symbol(), e = Symbol(), f = Symbol(), g = Symbol(), h = Symbol(), i = Symbol(), j = Symbol(), k = Symbol();
+    var o = {[a]:1, [b]:2, [c]:3, [d]:4, [e]:5, [f]:6, [g]:7, [h]:8, [i]:9, [j]:10, [k]:11};
+    var result = 0;
+    for (var index = 0; index < 1000000; ++index)
+        result += o[a] ^ o[b] | o[c] ^ o[d] & o[e] ^ o[f] | o[g] ^ o[h] & o[i] ^ o[j] | o[k];
+    if (result != 15000000)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-proto-or-self.js b/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-proto-or-self.js
new file mode 100644 (file)
index 0000000..e2f82ab
--- /dev/null
@@ -0,0 +1,24 @@
+var f = Symbol("Cocoa");
+
+function foo(o) {
+    return o[f];
+}
+
+function bar(a) {
+    var result = 0;
+    for (var i = 0; i < 2000000; ++i) {
+        for (var j = 0; j < a.length; ++j)
+            result += foo(a[j]);
+    }
+    return result;
+}
+
+function Foo() {
+}
+
+Foo.prototype[f] = 42;
+
+var result = bar([new Foo(), {[f]:24}]);
+
+if (result != 132000000)
+    throw "Error bad result: " + result;
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.js b/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-quadmorphic-check-structure-elimination-simple.js
new file mode 100644 (file)
index 0000000..a58362a
--- /dev/null
@@ -0,0 +1,22 @@
+(function() {
+    var a = Symbol("Cocoa");
+    var l = Symbol();
+    var b = Symbol();
+    var c = Symbol();
+
+    var o = {[a]:1};
+    var p = {[a]:2, [l]:13};
+    var q = {[a]:3, [b]:3};
+    var r = {[a]:4, [c]:5};
+    var result = 0;
+    for (var i = 0; i < 1000000; ++i) {
+        result ^= o[a];
+        var tmp = o;
+        o = p;
+        p = q;
+        q = r;
+        r = tmp;
+    }
+    if (result != 0)
+        throw "Error: bad result: " + result;
+})();
diff --git a/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-self-or-proto.js b/LayoutTests/js/regress/script-tests/get-by-val-with-symbol-self-or-proto.js
new file mode 100644 (file)
index 0000000..3008c36
--- /dev/null
@@ -0,0 +1,24 @@
+var f = Symbol('Cocoa');
+
+function foo(o) {
+    return o[f];
+}
+
+function bar(a) {
+    var result = 0;
+    for (var i = 0; i < 2000000; ++i) {
+        for (var j = 0; j < a.length; ++j)
+            result += foo(a[j]);
+    }
+    return result;
+}
+
+function Foo() {
+}
+
+Foo.prototype[f] = 42;
+
+var result = bar([{[f]:24}, new Foo()]);
+
+if (result != 132000000)
+    throw "Error bad result: " + result;
index 99548ef..f023574 100644 (file)
@@ -1,3 +1,162 @@
+2015-08-06  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Introduce get_by_id like IC into get_by_val when the given name is String or Symbol
+        https://bugs.webkit.org/show_bug.cgi?id=147480
+
+        Reviewed by Filip Pizlo.
+
+        This patch adds get_by_id IC to get_by_val operation by caching the string / symbol id.
+        The IC site only caches one id. After checking that the given id is the same to the
+        cached one, we perform the get_by_id IC onto it.
+        And by collecting IC StructureStubInfo information, we pass it to the DFG and DFG
+        compiles get_by_val op code into CheckIdent (with edge type check) and GetById related
+        operations when the given get_by_val leverages the property load with the cached id.
+
+        To ensure the incoming value is the expected id, in DFG layer, we use SymbolUse and
+        StringIdentUse to enforce the type. To use it, this patch implements SymbolUse.
+        This can be leveraged to optimize symbol operations in DFG.
+
+        And since byValInfo is frequently used, we align the byValInfo design to the stubInfo like one.
+        Allocated by the Bag and operations take the raw byValInfo pointer directly instead of performing
+        binary search onto m_byValInfos. And by storing ArrayProfile* under the ByValInfo, we replaced the
+        argument ArrayProfile* in the operations with ByValInfo*.
+
+        * bytecode/ByValInfo.h:
+        (JSC::ByValInfo::ByValInfo):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::getByValInfoMap):
+        (JSC::CodeBlock::addByValInfo):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::getByValInfo): Deleted.
+        (JSC::CodeBlock::setNumberOfByValInfos): Deleted.
+        (JSC::CodeBlock::numberOfByValInfos): Deleted.
+        (JSC::CodeBlock::byValInfo): Deleted.
+        * bytecode/ExitKind.cpp:
+        (JSC::exitKindToString):
+        * bytecode/ExitKind.h:
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeFor):
+        (JSC::GetByIdStatus::computeForStubInfo):
+        (JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
+        * bytecode/GetByIdStatus.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::observeUseKindOnNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasUidOperand):
+        (JSC::DFG::Node::uidOperand):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::SafeToExecuteEdge::operator()):
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileCheckIdent):
+        (JSC::DFG::SpeculativeJIT::speculateSymbol):
+        (JSC::DFG::SpeculativeJIT::speculate):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGUseKind.cpp:
+        (WTF::printInternal):
+        * dfg/DFGUseKind.h:
+        (JSC::DFG::typeFilterFor):
+        (JSC::DFG::isCell):
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileCheckIdent):
+        (JSC::FTL::DFG::LowerDFGToLLVM::lowSymbol):
+        (JSC::FTL::DFG::LowerDFGToLLVM::speculate):
+        (JSC::FTL::DFG::LowerDFGToLLVM::isNotSymbol):
+        (JSC::FTL::DFG::LowerDFGToLLVM::speculateSymbol):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompile):
+        * jit/JIT.h:
+        (JSC::ByValCompilationInfo::ByValCompilationInfo):
+        (JSC::JIT::compileGetByValWithCachedId):
+        * jit/JITInlines.h:
+        (JSC::JIT::callOperation):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_has_indexed_property):
+        (JSC::JIT::emitSlow_op_has_indexed_property):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_has_indexed_property):
+        (JSC::JIT::emitSlow_op_has_indexed_property):
+        * jit/JITOperations.cpp:
+        (JSC::getByVal):
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emitGetByValWithCachedId):
+        (JSC::JIT::emitSlow_op_get_by_val):
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::emitSlow_op_put_by_val):
+        (JSC::JIT::privateCompileGetByVal):
+        (JSC::JIT::privateCompileGetByValWithCachedId):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emitGetByValWithCachedId):
+        (JSC::JIT::emitSlow_op_get_by_val):
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::emitSlow_op_put_by_val):
+        * runtime/Symbol.h:
+        * tests/stress/get-by-val-with-string-constructor.js: Added.
+        (Hello):
+        (get Hello.prototype.generate):
+        (ok):
+        * tests/stress/get-by-val-with-string-exit.js: Added.
+        (shouldBe):
+        (getByVal):
+        (getStr1):
+        (getStr2):
+        * tests/stress/get-by-val-with-string-generated.js: Added.
+        (shouldBe):
+        (getByVal):
+        (getStr1):
+        (getStr2):
+        * tests/stress/get-by-val-with-string-getter.js: Added.
+        (object.get hello):
+        (ok):
+        * tests/stress/get-by-val-with-string.js: Added.
+        (shouldBe):
+        (getByVal):
+        (getStr1):
+        (getStr2):
+        * tests/stress/get-by-val-with-symbol-constructor.js: Added.
+        (Hello):
+        (get Hello.prototype.generate):
+        (ok):
+        * tests/stress/get-by-val-with-symbol-exit.js: Added.
+        (shouldBe):
+        (getByVal):
+        (getSym1):
+        (getSym2):
+        * tests/stress/get-by-val-with-symbol-getter.js: Added.
+        (object.get hello):
+        (.get ok):
+        * tests/stress/get-by-val-with-symbol.js: Added.
+        (shouldBe):
+        (getByVal):
+        (getSym1):
+        (getSym2):
+
 2015-08-05  Filip Pizlo  <fpizlo@apple.com>
 
         Lightweight locks should be adaptive
index d988516..67541fd 100644 (file)
 #ifndef ByValInfo_h
 #define ByValInfo_h
 
-#if ENABLE(JIT)
-
 #include "ClassInfo.h"
 #include "CodeLocation.h"
+#include "CodeOrigin.h"
 #include "IndexingType.h"
 #include "JITStubRoutine.h"
 #include "Structure.h"
+#include "StructureStubInfo.h"
 
 namespace JSC {
 
+#if ENABLE(JIT)
+
 enum JITArrayMode {
     JITInt32,
     JITDouble,
@@ -201,24 +203,33 @@ inline JITArrayMode jitArrayModeForStructure(Structure* structure)
 
 struct ByValInfo {
     ByValInfo() { }
-    
-    ByValInfo(unsigned bytecodeIndex, CodeLocationJump badTypeJump, JITArrayMode arrayMode, int16_t badTypeJumpToDone, int16_t returnAddressToSlowPath)
+
+    ByValInfo(unsigned bytecodeIndex, CodeLocationJump notIndexJump, CodeLocationJump badTypeJump, JITArrayMode arrayMode, ArrayProfile* arrayProfile, int16_t badTypeJumpToDone, int16_t returnAddressToSlowPath)
         : bytecodeIndex(bytecodeIndex)
+        , notIndexJump(notIndexJump)
         , badTypeJump(badTypeJump)
         , arrayMode(arrayMode)
+        , arrayProfile(arrayProfile)
         , badTypeJumpToDone(badTypeJumpToDone)
         , returnAddressToSlowPath(returnAddressToSlowPath)
         , slowPathCount(0)
+        , stubInfo(nullptr)
+        , tookSlowPath(false)
     {
     }
-    
+
     unsigned bytecodeIndex;
+    CodeLocationJump notIndexJump;
     CodeLocationJump badTypeJump;
     JITArrayMode arrayMode; // The array mode that was baked into the inline JIT code.
+    ArrayProfile* arrayProfile;
     int16_t badTypeJumpToDone;
     int16_t returnAddressToSlowPath;
     unsigned slowPathCount;
     RefPtr<JITStubRoutine> stubRoutine;
+    Identifier cachedId;
+    StructureStubInfo* stubInfo;
+    bool tookSlowPath;
 };
 
 inline unsigned getByValInfoBytecodeIndex(ByValInfo* info)
@@ -226,9 +237,15 @@ inline unsigned getByValInfoBytecodeIndex(ByValInfo* info)
     return info->bytecodeIndex;
 }
 
-} // namespace JSC
+typedef HashMap<CodeOrigin, ByValInfo*, CodeOriginApproximateHash> ByValInfoMap;
+
+#else // ENABLE(JIT)
+
+typedef HashMap<int, void*> ByValInfoMap;
 
 #endif // ENABLE(JIT)
 
+} // namespace JSC
+
 #endif // ByValInfo_h
 
index d6c6b86..1d23b28 100644 (file)
@@ -2673,6 +2673,22 @@ void CodeBlock::getCallLinkInfoMap(CallLinkInfoMap& result)
     getCallLinkInfoMap(locker, result);
 }
 
+void CodeBlock::getByValInfoMap(const ConcurrentJITLocker&, ByValInfoMap& result)
+{
+#if ENABLE(JIT)
+    for (auto* byValInfo : m_byValInfos)
+        result.add(CodeOrigin(byValInfo->bytecodeIndex), byValInfo);
+#else
+    UNUSED_PARAM(result);
+#endif
+}
+
+void CodeBlock::getByValInfoMap(ByValInfoMap& result)
+{
+    ConcurrentJITLocker locker(m_lock);
+    getByValInfoMap(locker, result);
+}
+
 #if ENABLE(JIT)
 StructureStubInfo* CodeBlock::addStubInfo()
 {
@@ -2689,6 +2705,12 @@ StructureStubInfo* CodeBlock::findStubInfo(CodeOrigin codeOrigin)
     return nullptr;
 }
 
+ByValInfo* CodeBlock::addByValInfo()
+{
+    ConcurrentJITLocker locker(m_lock);
+    return m_byValInfos.add();
+}
+
 CallLinkInfo* CodeBlock::addCallLinkInfo()
 {
     ConcurrentJITLocker locker(m_lock);
index 6c3a115..960791d 100644 (file)
@@ -200,6 +200,9 @@ public:
     
     void getCallLinkInfoMap(const ConcurrentJITLocker&, CallLinkInfoMap& result);
     void getCallLinkInfoMap(CallLinkInfoMap& result);
+
+    void getByValInfoMap(const ConcurrentJITLocker&, ByValInfoMap& result);
+    void getByValInfoMap(ByValInfoMap& result);
     
 #if ENABLE(JIT)
     StructureStubInfo* addStubInfo();
@@ -211,11 +214,8 @@ public:
     StructureStubInfo* findStubInfo(CodeOrigin);
 
     void resetStub(StructureStubInfo&);
-    
-    ByValInfo& getByValInfo(unsigned bytecodeIndex)
-    {
-        return *(binarySearch<ByValInfo, unsigned>(m_byValInfos, m_byValInfos.size(), bytecodeIndex, getByValInfoBytecodeIndex));
-    }
+
+    ByValInfo* addByValInfo();
 
     CallLinkInfo* addCallLinkInfo();
     Bag<CallLinkInfo>::iterator callLinkInfosBegin() { return m_callLinkInfos.begin(); }
@@ -367,12 +367,6 @@ public:
 
     String nameForRegister(VirtualRegister);
 
-#if ENABLE(JIT)
-    void setNumberOfByValInfos(size_t size) { m_byValInfos.resizeToFit(size); }
-    size_t numberOfByValInfos() const { return m_byValInfos.size(); }
-    ByValInfo& byValInfo(size_t index) { return m_byValInfos[index]; }
-#endif
-
     unsigned numberOfArgumentValueProfiles()
     {
         ASSERT(m_numParameters >= 0);
@@ -1016,7 +1010,7 @@ private:
     RefPtr<JITCode> m_jitCode;
 #if ENABLE(JIT)
     Bag<StructureStubInfo> m_stubInfos;
-    Vector<ByValInfo> m_byValInfos;
+    Bag<ByValInfo> m_byValInfos;
     Bag<CallLinkInfo> m_callLinkInfos;
     SentinelLinkedList<CallLinkInfo, BasicRawSentinelNode<CallLinkInfo>> m_incomingCalls;
     SentinelLinkedList<PolymorphicCallNode, BasicRawSentinelNode<PolymorphicCallNode>> m_incomingPolymorphicCalls;
index 4f79f2c..2524300 100644 (file)
@@ -40,6 +40,8 @@ const char* exitKindToString(ExitKind kind)
         return "BadType";
     case BadCell:
         return "BadCell";
+    case BadIdent:
+        return "BadIdent";
     case BadExecutable:
         return "BadExecutable";
     case BadCache:
index 59cbbf5..6f8c512 100644 (file)
@@ -32,6 +32,7 @@ enum ExitKind : uint8_t {
     ExitKindUnset,
     BadType, // We exited because a type prediction was wrong.
     BadCell, // We exited because we made an incorrect assumption about what cell we would see. Usually used for function checks.
+    BadIdent, // We exited because we made an incorrect assumption about what identifier we would see. Usually used for cached Id check in get_by_val.
     BadExecutable, // We exited because we made an incorrect assumption about what executable we would see.
     BadCache, // We exited because an inline cache was wrong.
     BadConstantCache, // We exited because a cache on a weak constant (usually a prototype) was wrong.
index 1d97c9f..89e5035 100644 (file)
@@ -98,7 +98,7 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& m
     GetByIdStatus result;
 
 #if ENABLE(DFG_JIT)
-    result = computeForStubInfo(
+    result = computeForStubInfoWithoutExitSiteFeedback(
         locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid,
         CallLinkStatus::computeExitSiteData(locker, profiledBlock, bytecodeIndex));
     
@@ -116,7 +116,20 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& m
 }
 
 #if ENABLE(JIT)
-GetByIdStatus GetByIdStatus::computeForStubInfo(
+GetByIdStatus GetByIdStatus::computeForStubInfo(const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, CodeOrigin codeOrigin, UniquedStringImpl* uid)
+{
+    GetByIdStatus result = GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
+        locker, profiledBlock, stubInfo, uid,
+        CallLinkStatus::computeExitSiteData(locker, profiledBlock, codeOrigin.bytecodeIndex));
+
+    if (!result.takesSlowPath() && GetByIdStatus::hasExitSite(locker, profiledBlock, codeOrigin.bytecodeIndex))
+        return GetByIdStatus(result.makesCalls() ? GetByIdStatus::MakesCalls : GetByIdStatus::TakesSlowPath, true);
+    return result;
+}
+#endif // ENABLE(JIT)
+
+#if ENABLE(JIT)
+GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
     const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, UniquedStringImpl* uid,
     CallLinkStatus::ExitSiteData callExitSiteData)
 {
@@ -242,7 +255,7 @@ GetByIdStatus GetByIdStatus::computeFor(
         GetByIdStatus result;
         {
             ConcurrentJITLocker locker(dfgBlock->m_lock);
-            result = computeForStubInfo(
+            result = computeForStubInfoWithoutExitSiteFeedback(
                 locker, dfgBlock, dfgMap.get(codeOrigin), uid, exitSiteData);
         }
         
index 32372cd..d7f0ae4 100644 (file)
@@ -71,7 +71,11 @@ public:
     static GetByIdStatus computeFor(const StructureSet&, UniquedStringImpl* uid);
     
     static GetByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, UniquedStringImpl* uid);
-    
+
+#if ENABLE(JIT)
+    static GetByIdStatus computeForStubInfo(const ConcurrentJITLocker&, CodeBlock* baselineBlock, StructureStubInfo*, CodeOrigin, UniquedStringImpl* uid);
+#endif
+
     State state() const { return m_state; }
     
     bool isSet() const { return m_state != NoInformation; }
@@ -95,7 +99,7 @@ private:
     static bool hasExitSite(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex);
 #endif
 #if ENABLE(JIT)
-    static GetByIdStatus computeForStubInfo(
+    static GetByIdStatus computeForStubInfoWithoutExitSiteFeedback(
         const ConcurrentJITLocker&, CodeBlock* profiledBlock, StructureStubInfo*,
         UniquedStringImpl* uid, CallLinkStatus::ExitSiteData);
 #endif
index 3734c76..229087d 100644 (file)
@@ -2163,6 +2163,32 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
 
+    case CheckIdent: {
+        AbstractValue& value = forNode(node->child1());
+        UniquedStringImpl* uid = node->uidOperand();
+        ASSERT(uid->isSymbol() ? !(value.m_type & ~SpecSymbol) : !(value.m_type & ~SpecStringIdent)); // Edge filtering should have already ensured this.
+
+        JSValue childConstant = value.value();
+        if (childConstant) {
+            if (uid->isSymbol()) {
+                ASSERT(childConstant.isSymbol());
+                if (asSymbol(childConstant)->privateName().uid() == uid) {
+                    m_state.setFoundConstants(true);
+                    break;
+                }
+            } else {
+                ASSERT(childConstant.isString());
+                if (asString(childConstant)->tryGetValueImpl() == uid) {
+                    m_state.setFoundConstants(true);
+                    break;
+                }
+            }
+        }
+
+        filter(value, uid->isSymbol() ? SpecSymbol : SpecStringIdent);
+        break;
+    }
+
     case CheckInBounds: {
         JSValue left = forNode(node->child1()).value();
         JSValue right = forNode(node->child2()).value();
index 56422b1..268a757 100644 (file)
@@ -969,6 +969,7 @@ private:
         
         CallLinkInfoMap m_callLinkInfos;
         StubInfoMap m_stubInfos;
+        ByValInfoMap m_byValInfos;
         
         // Did we see any returns? We need to handle the (uncommon but necessary)
         // case where a procedure that does not return was inlined.
@@ -3397,12 +3398,35 @@ bool ByteCodeParser::parseBlock(unsigned limit)
 
         case op_get_by_val: {
             SpeculatedType prediction = getPredictionWithoutOSRExit();
-            
+
             Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
-            ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read);
             Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
-            Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property);
-            set(VirtualRegister(currentInstruction[1].u.operand), getByVal);
+            bool compiledAsGetById = false;
+            {
+                ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
+                ByValInfo* byValInfo = m_inlineStackTop->m_byValInfos.get(CodeOrigin(currentCodeOrigin().bytecodeIndex));
+                // FIXME: When the bytecode is not compiled in the baseline JIT, byValInfo becomes null.
+                // At that time, there is no information.
+                if (byValInfo && byValInfo->stubInfo && !byValInfo->tookSlowPath && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent)) {
+                    compiledAsGetById = true;
+                    unsigned identifierNumber = m_graph.identifiers().ensure(byValInfo->cachedId.impl());
+                    UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber];
+
+                    addToGraph(CheckIdent, OpInfo(uid), property);
+
+                    GetByIdStatus getByIdStatus = GetByIdStatus::computeForStubInfo(
+                        locker, m_inlineStackTop->m_profiledBlock,
+                        byValInfo->stubInfo, currentCodeOrigin(), uid);
+
+                    handleGetById(currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus);
+                }
+            }
+
+            if (!compiledAsGetById) {
+                ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read);
+                Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property);
+                set(VirtualRegister(currentInstruction[1].u.operand), getByVal);
+            }
 
             NEXT_OPCODE(op_get_by_val);
         }
@@ -4305,6 +4329,7 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
         if (m_profiledBlock->hasBaselineJITProfiling()) {
             m_profiledBlock->getStubInfoMap(locker, m_stubInfos);
             m_profiledBlock->getCallLinkInfoMap(locker, m_callLinkInfos);
+            m_profiledBlock->getByValInfoMap(locker, m_byValInfos);
         }
     }
     
index 296749d..46f5fe4 100644 (file)
@@ -268,6 +268,10 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         def(PureValue(CheckNotEmpty, AdjacencyList(AdjacencyList::Fixed, node->child1())));
         return;
 
+    case CheckIdent:
+        def(PureValue(CheckIdent, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->uidOperand()));
+        return;
+
     case ConstantStoragePointer:
         def(PureValue(node, node->storagePointer()));
         return;
index ba4c035..3d85caa 100644 (file)
@@ -208,6 +208,33 @@ private:
                 break;
             }
 
+            case CheckIdent: {
+                UniquedStringImpl* uid = node->uidOperand();
+                JSValue childConstant = m_state.forNode(node->child1()).value();
+                const UniquedStringImpl* constantUid = nullptr;
+                if (childConstant) {
+                    if (uid->isSymbol()) {
+                        if (childConstant.isSymbol())
+                            constantUid = asSymbol(childConstant)->privateName().uid();
+                    } else {
+                        if (childConstant.isString()) {
+                            // Since we already filtered the value with StringIdentUse,
+                            // the held impl is always atomic.
+                            if (const auto* impl = asString(childConstant)->tryGetValueImpl()) {
+                                ASSERT(impl->isAtomic());
+                                constantUid = static_cast<const UniquedStringImpl*>(impl);
+                            }
+                        }
+                    }
+                }
+
+                if (constantUid == uid) {
+                    node->remove();
+                    eliminated = true;
+                }
+                break;
+            }
+
             case CheckInBounds: {
                 JSValue left = m_state.forNode(node->child1()).value();
                 JSValue right = m_state.forNode(node->child2()).value();
index 08ffb2a..e470b8d 100644 (file)
@@ -107,6 +107,7 @@ bool doesGC(Graph& graph, Node* node)
     case VarInjectionWatchpoint:
     case CheckCell:
     case CheckNotEmpty:
+    case CheckIdent:
     case RegExpExec:
     case RegExpTest:
     case CompareLess:
index c442310..d6a9790 100644 (file)
@@ -1012,6 +1012,15 @@ private:
             fixEdge<CellUse>(node->child1());
             break;
         }
+
+        case CheckIdent: {
+            UniquedStringImpl* uid = node->uidOperand();
+            if (uid->isSymbol())
+                fixEdge<SymbolUse>(node->child1());
+            else
+                fixEdge<StringIdentUse>(node->child1());
+            break;
+        }
             
         case Arrayify:
         case ArrayifyToStructure: {
@@ -1760,6 +1769,7 @@ private:
         case FunctionUse:
         case StringUse:
         case KnownStringUse:
+        case SymbolUse:
         case StringObjectUse:
         case StringOrStringObjectUse:
             if (alwaysUnboxSimplePrimitives()
index 28cab05..83fcf5c 100644 (file)
@@ -1328,6 +1328,17 @@ struct Node {
         return reinterpret_cast<void*>(m_opInfo);
     }
 
+    bool hasUidOperand()
+    {
+        return op() == CheckIdent;
+    }
+
+    UniquedStringImpl* uidOperand()
+    {
+        ASSERT(hasUidOperand());
+        return reinterpret_cast<UniquedStringImpl*>(m_opInfo);
+    }
+
     bool hasTransition()
     {
         switch (op()) {
index 62e7ca9..e9bf727 100644 (file)
@@ -209,6 +209,7 @@ namespace JSC { namespace DFG {
     macro(CheckNotEmpty, NodeMustGenerate) \
     macro(CheckBadCell, NodeMustGenerate) \
     macro(CheckInBounds, NodeMustGenerate) \
+    macro(CheckIdent, NodeMustGenerate) \
     \
     /* Optimizations for array mutation. */\
     macro(ArrayPush, NodeResultJS | NodeMustGenerate) \
index 76af6a2..36f2df7 100644 (file)
@@ -649,6 +649,7 @@ private:
         case CheckStructure:
         case CheckCell:
         case CheckNotEmpty:
+        case CheckIdent:
         case CheckBadCell:
         case PutStructure:
         case VarInjectionWatchpoint:
index 0c0a277..b2d07d5 100644 (file)
@@ -59,6 +59,7 @@ public:
         case ObjectOrOtherUse:
         case StringIdentUse:
         case StringUse:
+        case SymbolUse:
         case StringObjectUse:
         case StringOrStringObjectUse:
         case NotStringVarUse:
@@ -188,6 +189,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case CheckCell:
     case CheckBadCell:
     case CheckNotEmpty:
+    case CheckIdent:
     case RegExpExec:
     case RegExpTest:
     case CompareLess:
index f3f8af7..0537363 100644 (file)
@@ -4576,6 +4576,31 @@ void SpeculativeJIT::compileGetArrayLength(Node* node)
     } }
 }
 
+void SpeculativeJIT::compileCheckIdent(Node* node)
+{
+    SpeculateCellOperand operand(this, node->child1());
+    UniquedStringImpl* uid = node->uidOperand();
+    if (uid->isSymbol()) {
+        speculateSymbol(node->child1(), operand.gpr());
+        speculationCheck(
+            BadIdent, JSValueSource(), nullptr,
+            m_jit.branchPtr(
+                JITCompiler::NotEqual,
+                JITCompiler::Address(operand.gpr(), Symbol::offsetOfPrivateName()),
+                TrustedImmPtr(uid)));
+    } else {
+        speculateString(node->child1(), operand.gpr());
+        speculateStringIdent(node->child1(), operand.gpr());
+        speculationCheck(
+            BadIdent, JSValueSource(), nullptr,
+            m_jit.branchPtr(
+                JITCompiler::NotEqual,
+                JITCompiler::Address(operand.gpr(), JSString::offsetOfValue()),
+                TrustedImmPtr(uid)));
+    }
+    noResult(node);
+}
+
 void SpeculativeJIT::compileNewFunction(Node* node)
 {
     SpeculateCellOperand scope(this, node->child1());
@@ -5731,6 +5756,20 @@ void SpeculativeJIT::speculateNotStringVar(Edge edge)
     notCell.link(&m_jit);
 }
 
+void SpeculativeJIT::speculateSymbol(Edge edge, GPRReg cell)
+{
+    DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, SpecSymbol, m_jit.branchIfNotSymbol(cell));
+}
+
+void SpeculativeJIT::speculateSymbol(Edge edge)
+{
+    if (!needsTypeCheck(edge, SpecSymbol))
+        return;
+
+    SpeculateCellOperand operand(this, edge);
+    speculateSymbol(edge, operand.gpr());
+}
+
 void SpeculativeJIT::speculateNotCell(Edge edge)
 {
     if (!needsTypeCheck(edge, ~SpecCell))
@@ -5842,6 +5881,9 @@ void SpeculativeJIT::speculate(Node*, Edge edge)
     case StringUse:
         speculateString(edge);
         break;
+    case SymbolUse:
+        speculateSymbol(edge);
+        break;
     case StringObjectUse:
         speculateStringObject(edge);
         break;
index a5c4454..545ff2a 100644 (file)
@@ -2191,6 +2191,8 @@ public:
     void compileSkipScope(Node*);
 
     void compileGetArrayLength(Node*);
+
+    void compileCheckIdent(Node*);
     
     void compileValueRep(Node*);
     void compileDoubleRep(Node*);
@@ -2406,6 +2408,8 @@ public:
     void speculateStringObject(Edge, GPRReg);
     void speculateStringObject(Edge);
     void speculateStringOrStringObject(Edge);
+    void speculateSymbol(Edge, GPRReg cell);
+    void speculateSymbol(Edge);
     void speculateNotCell(Edge);
     void speculateOther(Edge);
     void speculateMisc(Edge, JSValueRegs);
index 5042905..12ab8d0 100644 (file)
@@ -3820,6 +3820,10 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case CheckIdent:
+        compileCheckIdent(node);
+        break;
+
     case GetExecutable: {
         SpeculateCellOperand function(this, node->child1());
         GPRTemporary result(this, Reuse, function);
index 770bda5..13c7c87 100644 (file)
@@ -3850,6 +3850,10 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case CheckIdent:
+        compileCheckIdent(node);
+        break;
+
     case GetExecutable: {
         SpeculateCellOperand function(this, node->child1());
         GPRTemporary result(this, Reuse, function);
index efa104f..936ef55 100644 (file)
@@ -97,6 +97,9 @@ void printInternal(PrintStream& out, UseKind useKind)
     case KnownStringUse:
         out.print("KnownString");
         return;
+    case SymbolUse:
+        out.print("Symbol");
+        return;
     case StringObjectUse:
         out.print("StringObject");
         return;
index ebf99da..289b783 100644 (file)
@@ -57,6 +57,7 @@ enum UseKind {
     StringIdentUse,
     StringUse,
     KnownStringUse,
+    SymbolUse,
     StringObjectUse,
     StringOrStringObjectUse,
     NotStringVarUse,
@@ -117,6 +118,8 @@ inline SpeculatedType typeFilterFor(UseKind useKind)
     case StringUse:
     case KnownStringUse:
         return SpecString;
+    case SymbolUse:
+        return SpecSymbol;
     case StringObjectUse:
         return SpecStringObject;
     case StringOrStringObjectUse:
@@ -196,6 +199,7 @@ inline bool isCell(UseKind kind)
     case StringIdentUse:
     case StringUse:
     case KnownStringUse:
+    case SymbolUse:
     case StringObjectUse:
     case StringOrStringObjectUse:
         return true;
index 912754d..581f4cb 100644 (file)
@@ -87,7 +87,8 @@ namespace JSC { namespace FTL {
     macro(Structure_classInfo, Structure::classInfoOffset()) \
     macro(Structure_globalObject, Structure::globalObjectOffset()) \
     macro(Structure_prototype, Structure::prototypeOffset()) \
-    macro(Structure_structureID, Structure::structureIDOffset())
+    macro(Structure_structureID, Structure::structureIDOffset()) \
+    macro(Symbol_privateName, Symbol::offsetOfPrivateName())
 
 #define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \
     macro(DirectArguments_storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \
index 62728c7..b493f30 100644 (file)
@@ -118,6 +118,7 @@ inline CapabilityLevel canCompile(Node* node)
     case CheckCell:
     case CheckBadCell:
     case CheckNotEmpty:
+    case CheckIdent:
     case StringCharCodeAt:
     case AllocatePropertyStorage:
     case ReallocatePropertyStorage:
@@ -415,6 +416,7 @@ CapabilityLevel canCompile(Graph& graph)
                 case KnownStringUse:
                 case StringObjectUse:
                 case StringOrStringObjectUse:
+                case SymbolUse:
                 case FinalObjectUse:
                 case NotCellUse:
                 case OtherUse:
index 5fb4e24..a1b19bf 100644 (file)
@@ -532,6 +532,9 @@ private:
         case CheckBadCell:
             compileCheckBadCell();
             break;
+        case CheckIdent:
+            compileCheckIdent();
+            break;
         case GetExecutable:
             compileGetExecutable();
             break;
@@ -2029,6 +2032,20 @@ private:
         speculate(TDZFailure, noValue(), nullptr, m_out.isZero64(lowJSValue(m_node->child1())));
     }
 
+    void compileCheckIdent()
+    {
+        UniquedStringImpl* uid = m_node->uidOperand();
+        if (uid->isSymbol()) {
+            LValue symbol = lowSymbol(m_node->child1());
+            LValue stringImpl = m_out.loadPtr(symbol, m_heaps.Symbol_privateName);
+            speculate(BadIdent, noValue(), nullptr, m_out.notEqual(stringImpl, m_out.constIntPtr(uid)));
+        } else {
+            LValue string = lowStringIdent(m_node->child1());
+            LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
+            speculate(BadIdent, noValue(), nullptr, m_out.notEqual(stringImpl, m_out.constIntPtr(uid)));
+        }
+    }
+
     void compileGetExecutable()
     {
         LValue cell = lowCell(m_node->child1());
@@ -7020,7 +7037,16 @@ private:
         speculateStringIdent(edge, string, stringImpl);
         return stringImpl;
     }
-    
+
+    LValue lowSymbol(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+    {
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == SymbolUse);
+
+        LValue result = lowCell(edge, mode);
+        speculateSymbol(edge, result);
+        return result;
+    }
+
     LValue lowNonNullObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
     {
         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
@@ -7417,6 +7443,9 @@ private:
         case StringIdentUse:
             speculateStringIdent(edge);
             break;
+        case SymbolUse:
+            speculateSymbol(edge);
+            break;
         case StringObjectUse:
             speculateStringObject(edge);
             break;
@@ -7513,7 +7542,16 @@ private:
             m_out.load32(cell, m_heaps.JSCell_structureID),
             m_out.constInt32(vm().stringStructure->id()));
     }
-    
+
+    LValue isNotSymbol(LValue cell, SpeculatedType type = SpecFullTop)
+    {
+        if (LValue proven = isProvenValue(type & SpecCell, ~SpecSymbol))
+            return proven;
+        return m_out.notEqual(
+            m_out.load32(cell, m_heaps.JSCell_structureID),
+            m_out.constInt32(vm().symbolStructure->id()));
+    }
+
     LValue isArrayType(LValue cell, ArrayMode arrayMode)
     {
         switch (arrayMode.type()) {
@@ -7736,7 +7774,17 @@ private:
             NotStringObject, noValue(), 0,
             m_out.notEqual(structureID, weakStructureID(stringObjectStructure)));
     }
-    
+
+    void speculateSymbol(Edge edge, LValue cell)
+    {
+        FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecSymbol | ~SpecCell, isNotSymbol(cell));
+    }
+
+    void speculateSymbol(Edge edge)
+    {
+        speculateSymbol(edge, lowCell(edge));
+    }
+
     void speculateNonNullObject(Edge edge, LValue cell)
     {
         FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecObject, isNotObject(cell));
index 5823d01..c505af0 100644 (file)
@@ -657,17 +657,22 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
     for (unsigned i = m_putByIds.size(); i--;)
         m_putByIds[i].finalize(patchBuffer);
 
-    m_codeBlock->setNumberOfByValInfos(m_byValCompilationInfo.size());
-    for (unsigned i = 0; i < m_byValCompilationInfo.size(); ++i) {
-        CodeLocationJump badTypeJump = CodeLocationJump(patchBuffer.locationOf(m_byValCompilationInfo[i].badTypeJump));
-        CodeLocationLabel doneTarget = patchBuffer.locationOf(m_byValCompilationInfo[i].doneTarget);
-        CodeLocationLabel slowPathTarget = patchBuffer.locationOf(m_byValCompilationInfo[i].slowPathTarget);
-        CodeLocationCall returnAddress = patchBuffer.locationOf(m_byValCompilationInfo[i].returnAddress);
-        
-        m_codeBlock->byValInfo(i) = ByValInfo(
-            m_byValCompilationInfo[i].bytecodeIndex,
+    for (const auto& byValCompilationInfo : m_byValCompilationInfo) {
+        PatchableJump patchableNotIndexJump = byValCompilationInfo.notIndexJump;
+        CodeLocationJump notIndexJump = CodeLocationJump();
+        if (Jump(patchableNotIndexJump).isSet())
+            notIndexJump = CodeLocationJump(patchBuffer.locationOf(patchableNotIndexJump));
+        CodeLocationJump badTypeJump = CodeLocationJump(patchBuffer.locationOf(byValCompilationInfo.badTypeJump));
+        CodeLocationLabel doneTarget = patchBuffer.locationOf(byValCompilationInfo.doneTarget);
+        CodeLocationLabel slowPathTarget = patchBuffer.locationOf(byValCompilationInfo.slowPathTarget);
+        CodeLocationCall returnAddress = patchBuffer.locationOf(byValCompilationInfo.returnAddress);
+
+        *byValCompilationInfo.byValInfo = ByValInfo(
+            byValCompilationInfo.bytecodeIndex,
+            notIndexJump,
             badTypeJump,
-            m_byValCompilationInfo[i].arrayMode,
+            byValCompilationInfo.arrayMode,
+            byValCompilationInfo.arrayProfile,
             differenceBetweenCodePtr(badTypeJump, doneTarget),
             differenceBetweenCodePtr(returnAddress, slowPathTarget));
     }
index a0507f6..8ca0857 100644 (file)
@@ -149,17 +149,23 @@ namespace JSC {
     struct ByValCompilationInfo {
         ByValCompilationInfo() { }
         
-        ByValCompilationInfo(unsigned bytecodeIndex, MacroAssembler::PatchableJump badTypeJump, JITArrayMode arrayMode, MacroAssembler::Label doneTarget)
-            : bytecodeIndex(bytecodeIndex)
+        ByValCompilationInfo(ByValInfo* byValInfo, unsigned bytecodeIndex, MacroAssembler::PatchableJump notIndexJump, MacroAssembler::PatchableJump badTypeJump, JITArrayMode arrayMode, ArrayProfile* arrayProfile, MacroAssembler::Label doneTarget)
+            : byValInfo(byValInfo)
+            , bytecodeIndex(bytecodeIndex)
+            , notIndexJump(notIndexJump)
             , badTypeJump(badTypeJump)
             , arrayMode(arrayMode)
+            , arrayProfile(arrayProfile)
             , doneTarget(doneTarget)
         {
         }
-        
+
+        ByValInfo* byValInfo;
         unsigned bytecodeIndex;
+        MacroAssembler::PatchableJump notIndexJump;
         MacroAssembler::PatchableJump badTypeJump;
         JITArrayMode arrayMode;
+        ArrayProfile* arrayProfile;
         MacroAssembler::Label doneTarget;
         MacroAssembler::Label slowPathTarget;
         MacroAssembler::Call returnAddress;
@@ -204,6 +210,13 @@ namespace JSC {
             jit.privateCompileGetByVal(byValInfo, returnAddress, arrayMode);
         }
 
+        static void compileGetByValWithCachedId(VM* vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, const Identifier& propertyName)
+        {
+            JIT jit(vm, codeBlock);
+            jit.m_bytecodeOffset = byValInfo->bytecodeIndex;
+            jit.privateCompileGetByValWithCachedId(byValInfo, returnAddress, propertyName);
+        }
+
         static void compilePutByVal(VM* vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
         {
             JIT jit(vm, codeBlock);
@@ -246,6 +259,7 @@ namespace JSC {
         CompilationResult privateCompile(JITCompilationEffort);
         
         void privateCompileGetByVal(ByValInfo*, ReturnAddressPtr, JITArrayMode);
+        void privateCompileGetByValWithCachedId(ByValInfo*, ReturnAddressPtr, const Identifier&);
         void privateCompilePutByVal(ByValInfo*, ReturnAddressPtr, JITArrayMode);
 
         void privateCompileHasIndexedProperty(ByValInfo*, ReturnAddressPtr, JITArrayMode);
@@ -371,7 +385,9 @@ namespace JSC {
         JumpList emitArrayStoragePutByVal(Instruction*, PatchableJump& badType);
         JumpList emitIntTypedArrayPutByVal(Instruction*, PatchableJump& badType, TypedArrayType);
         JumpList emitFloatTypedArrayPutByVal(Instruction*, PatchableJump& badType, TypedArrayType);
-        
+
+        JITGetByIdGenerator emitGetByValWithCachedId(Instruction*, const Identifier&, JumpList& doneCases, JumpList& slowCases);
+
         enum FinalObjectMode { MayBeFinal, KnownNotFinal };
 
         template <typename T> Jump branchStructure(RelationalCondition, T leftHandSide, Structure*);
@@ -701,6 +717,7 @@ namespace JSC {
         MacroAssembler::Call callOperation(J_JITOperation_EJIdc, int, GPRReg, const Identifier*);
         MacroAssembler::Call callOperation(J_JITOperation_EJJ, int, GPRReg, GPRReg);
         MacroAssembler::Call callOperation(J_JITOperation_EJJAp, int, GPRReg, GPRReg, ArrayProfile*);
+        MacroAssembler::Call callOperation(J_JITOperation_EJJBy, int, GPRReg, GPRReg, ByValInfo*);
         MacroAssembler::Call callOperation(C_JITOperation_EJsc, GPRReg);
         MacroAssembler::Call callOperation(J_JITOperation_EJscC, int, GPRReg, JSCell*);
         MacroAssembler::Call callOperation(C_JITOperation_EJscZ, GPRReg, int32_t);
@@ -745,6 +762,7 @@ namespace JSC {
 #endif
         MacroAssembler::Call callOperation(V_JITOperation_EJJJ, RegisterID, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EJJJAp, RegisterID, RegisterID, RegisterID, ArrayProfile*);
+        MacroAssembler::Call callOperation(V_JITOperation_EJJJBy, RegisterID, RegisterID, RegisterID, ByValInfo*);
         MacroAssembler::Call callOperation(V_JITOperation_EJZJ, RegisterID, int32_t, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EJZ, RegisterID, int32_t);
         MacroAssembler::Call callOperation(V_JITOperation_EPc, Instruction*);
@@ -761,6 +779,7 @@ namespace JSC {
         MacroAssembler::Call callOperation(J_JITOperation_EJIdc, int, GPRReg, GPRReg, const Identifier*);
         MacroAssembler::Call callOperation(J_JITOperation_EJJ, int, GPRReg, GPRReg, GPRReg, GPRReg);
         MacroAssembler::Call callOperation(J_JITOperation_EJJAp, int, GPRReg, GPRReg, GPRReg, GPRReg, ArrayProfile*);
+        MacroAssembler::Call callOperation(J_JITOperation_EJJBy, int, GPRReg, GPRReg, GPRReg, GPRReg, ByValInfo*);
         MacroAssembler::Call callOperation(P_JITOperation_EJS, GPRReg, GPRReg, size_t);
         MacroAssembler::Call callOperation(S_JITOperation_EJ, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(S_JITOperation_EJJ, RegisterID, RegisterID, RegisterID, RegisterID);
@@ -768,6 +787,7 @@ namespace JSC {
         MacroAssembler::Call callOperation(V_JITOperation_EJ, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EJJJ, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EJJJAp, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, ArrayProfile*);
+        MacroAssembler::Call callOperation(V_JITOperation_EJJJBy, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, ByValInfo*);
         MacroAssembler::Call callOperation(V_JITOperation_EJZ, RegisterID, RegisterID, int32_t);
         MacroAssembler::Call callOperation(V_JITOperation_EJZJ, RegisterID, RegisterID, int32_t, RegisterID, RegisterID);
         MacroAssembler::Call callOperation(V_JITOperation_EZJ, int32_t, RegisterID, RegisterID);
index a49484a..acd8c89 100644 (file)
@@ -411,6 +411,12 @@ ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJAp oper
     return appendCallWithExceptionCheck(operation);
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJBy operation, RegisterID regOp1, RegisterID regOp2, RegisterID regOp3, ByValInfo* byValInfo)
+{
+    setupArgumentsWithExecState(regOp1, regOp2, regOp3, TrustedImmPtr(byValInfo));
+    return appendCallWithExceptionCheck(operation);
+}
+
 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EZJ operation, int dst, GPRReg arg)
 {
     setupArgumentsWithExecState(TrustedImm32(dst), arg);
@@ -459,6 +465,12 @@ ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJAp opera
     return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJBy operation, int dst, GPRReg arg1, GPRReg arg2, ByValInfo* byValInfo)
+{
+    setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(byValInfo));
+    return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
+}
+
 ALWAYS_INLINE MacroAssembler::Call JIT::callOperationNoExceptionCheck(V_JITOperation_EJ operation, GPRReg arg1)
 {
     setupArgumentsWithExecState(arg1);
@@ -600,6 +612,12 @@ ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJAp opera
     return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJBy operation, int dst, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, ByValInfo* byValInfo)
+{
+    setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag, TrustedImmPtr(byValInfo));
+    return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
+}
+
 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(JIT::WithProfileTag, J_JITOperation_EJJ operation, int dst, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload)
 {
     setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag);
@@ -666,6 +684,12 @@ ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJAp oper
     return appendCallWithExceptionCheck(operation);
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJBy operation, RegisterID regOp1Tag, RegisterID regOp1Payload, RegisterID regOp2Tag, RegisterID regOp2Payload, RegisterID regOp3Tag, RegisterID regOp3Payload, ByValInfo* byValInfo)
+{
+    setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG regOp1Payload, regOp1Tag, SH4_32BIT_DUMMY_ARG regOp2Payload, regOp2Tag, regOp3Payload, regOp3Tag, TrustedImmPtr(byValInfo));
+    return appendCallWithExceptionCheck(operation);
+}
+
 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EZJ operation, int dst, RegisterID regOp1Tag, RegisterID regOp1Payload)
 {
     setupArgumentsWithExecState(TrustedImm32(dst), regOp1Payload, regOp1Tag);
index 0dc3985..1a4ef74 100644 (file)
@@ -1068,6 +1068,7 @@ void JIT::emit_op_has_indexed_property(Instruction* currentInstruction)
     int base = currentInstruction[2].u.operand;
     int property = currentInstruction[3].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_codeBlock->addByValInfo();
     
     emitGetVirtualRegisters(base, regT0, property, regT1);
 
@@ -1099,7 +1100,7 @@ void JIT::emit_op_has_indexed_property(Instruction* currentInstruction)
     
     emitPutVirtualRegister(dst);
     
-    m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
+    m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeOffset, PatchableJump(), badType, mode, profile, done));
 }
 
 void JIT::emitSlow_op_has_indexed_property(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -1107,7 +1108,7 @@ void JIT::emitSlow_op_has_indexed_property(Instruction* currentInstruction, Vect
     int dst = currentInstruction[1].u.operand;
     int base = currentInstruction[2].u.operand;
     int property = currentInstruction[3].u.operand;
-    ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;
     
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
     linkSlowCase(iter); // base array check
@@ -1118,7 +1119,7 @@ void JIT::emitSlow_op_has_indexed_property(Instruction* currentInstruction, Vect
     
     emitGetVirtualRegister(base, regT0);
     emitGetVirtualRegister(property, regT1);
-    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT0, regT1, profile);
+    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT0, regT1, byValInfo);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
index 57062e9..099bde0 100644 (file)
@@ -1068,6 +1068,7 @@ void JIT::emit_op_has_indexed_property(Instruction* currentInstruction)
     int base = currentInstruction[2].u.operand;
     int property = currentInstruction[3].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_codeBlock->addByValInfo();
     
     emitLoadPayload(base, regT0);
     emitJumpSlowCaseIfNotJSCell(base);
@@ -1100,7 +1101,7 @@ void JIT::emit_op_has_indexed_property(Instruction* currentInstruction)
     
     emitStoreBool(dst, regT0);
     
-    m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
+    m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeOffset, PatchableJump(), badType, mode, profile, done));
 }
 
 void JIT::emitSlow_op_has_indexed_property(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -1108,7 +1109,7 @@ void JIT::emitSlow_op_has_indexed_property(Instruction* currentInstruction, Vect
     int dst = currentInstruction[1].u.operand;
     int base = currentInstruction[2].u.operand;
     int property = currentInstruction[3].u.operand;
-    ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;
     
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
     linkSlowCase(iter); // base array check
@@ -1119,7 +1120,7 @@ void JIT::emitSlow_op_has_indexed_property(Instruction* currentInstruction, Vect
     
     emitLoad(base, regT1, regT0);
     emitLoad(property, regT3, regT2);
-    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2, profile);
+    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2, byValInfo);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
index 484eff1..4b9e24a 100644 (file)
@@ -478,7 +478,7 @@ void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObj
     base->putDirect(vm, offset, JSValue::decode(value));
 }
 
-static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value, ArrayProfile* arrayProfile)
+static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value, ByValInfo* byValInfo)
 {
     VM& vm = callFrame->vm();
     if (LIKELY(subscript.isUInt32())) {
@@ -488,7 +488,7 @@ static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript,
             if (object->canSetIndexQuickly(i))
                 object->setIndexQuickly(callFrame->vm(), i, value);
             else {
-                arrayProfile->setOutOfBounds();
+                byValInfo->arrayProfile->setOutOfBounds();
                 object->methodTable(vm)->putByIndex(object, callFrame, i, value, callFrame->codeBlock()->isStrictMode());
             }
         } else
@@ -502,7 +502,7 @@ static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript,
     }
 }
 
-static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value, ArrayProfile* arrayProfile)
+static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value, ByValInfo* byValInfo)
 {
     bool isStrictMode = callFrame->codeBlock()->isStrictMode();
     if (LIKELY(subscript.isUInt32())) {
@@ -514,7 +514,7 @@ static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue s
             return;
         }
 
-        arrayProfile->setOutOfBounds();
+        byValInfo->arrayProfile->setOutOfBounds();
         baseObject->putDirectIndex(callFrame, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
         return;
     }
@@ -540,7 +540,7 @@ static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue s
         baseObject->putDirect(callFrame->vm(), property, value, slot);
     }
 }
-void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
+void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -554,21 +554,19 @@ void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBase
         JSObject* object = asObject(baseValue);
         bool didOptimize = false;
 
-        unsigned bytecodeOffset = exec->locationAsBytecodeOffset();
-        ASSERT(bytecodeOffset);
-        ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1);
-        ASSERT(!byValInfo.stubRoutine);
+        ASSERT(exec->locationAsBytecodeOffset());
+        ASSERT(!byValInfo->stubRoutine);
 
         Structure* structure = object->structure(vm);
         if (hasOptimizableIndexing(structure)) {
             // Attempt to optimize.
             JITArrayMode arrayMode = jitArrayModeForStructure(structure);
-            if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) {
+            if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo->arrayMode) {
                 CodeBlock* codeBlock = exec->codeBlock();
                 ConcurrentJITLocker locker(codeBlock->m_lock);
-                arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
+                byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
 
-                JIT::compilePutByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
+                JIT::compilePutByVal(&vm, exec->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
                 didOptimize = true;
             }
         }
@@ -579,7 +577,7 @@ void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBase
             // that intercepts indexed get, then don't even wait until 10 times. For cases
             // where we see non-index-intercepting objects, this gives 10 iterations worth of
             // opportunity for us to observe that the get_by_val may be polymorphic.
-            if (++byValInfo.slowPathCount >= 10
+            if (++byValInfo->slowPathCount >= 10
                 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
                 // Don't ever try to optimize.
                 ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationPutByValGeneric));
@@ -587,10 +585,10 @@ void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBase
         }
     }
 
-    putByVal(exec, baseValue, subscript, value, arrayProfile);
+    putByVal(exec, baseValue, subscript, value, byValInfo);
 }
 
-void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
+void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo)
 {
     VM& vm = callFrame->vm();
     NativeCallFrameTracer tracer(&vm, callFrame);
@@ -603,22 +601,20 @@ void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue
     if (subscript.isInt32()) {
         // See if it's worth optimizing at all.
         bool didOptimize = false;
-        
-        unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
-        ASSERT(bytecodeOffset);
-        ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1);
-        ASSERT(!byValInfo.stubRoutine);
+
+        ASSERT(callFrame->locationAsBytecodeOffset());
+        ASSERT(!byValInfo->stubRoutine);
 
         Structure* structure = object->structure(vm);
         if (hasOptimizableIndexing(structure)) {
             // Attempt to optimize.
             JITArrayMode arrayMode = jitArrayModeForStructure(structure);
-            if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) {
+            if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo->arrayMode) {
                 CodeBlock* codeBlock = callFrame->codeBlock();
                 ConcurrentJITLocker locker(codeBlock->m_lock);
-                arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
+                byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
 
-                JIT::compileDirectPutByVal(&vm, callFrame->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
+                JIT::compileDirectPutByVal(&vm, callFrame->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
                 didOptimize = true;
             }
         }
@@ -629,17 +625,17 @@ void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue
             // that intercepts indexed get, then don't even wait until 10 times. For cases
             // where we see non-index-intercepting objects, this gives 10 iterations worth of
             // opportunity for us to observe that the get_by_val may be polymorphic.
-            if (++byValInfo.slowPathCount >= 10
+            if (++byValInfo->slowPathCount >= 10
                 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
                 // Don't ever try to optimize.
                 ctiPatchCallByReturnAddress(callFrame->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationDirectPutByValGeneric));
             }
         }
     }
-    directPutByVal(callFrame, object, subscript, value, arrayProfile);
+    directPutByVal(callFrame, object, subscript, value, byValInfo);
 }
 
-void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
+void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -648,11 +644,11 @@ void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue enco
     JSValue subscript = JSValue::decode(encodedSubscript);
     JSValue value = JSValue::decode(encodedValue);
 
-    putByVal(exec, baseValue, subscript, value, arrayProfile);
+    putByVal(exec, baseValue, subscript, value, byValInfo);
 }
 
 
-void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
+void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -661,7 +657,7 @@ void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValu
     JSValue subscript = JSValue::decode(encodedSubscript);
     JSValue value = JSValue::decode(encodedValue);
     RELEASE_ASSERT(baseValue.isObject());
-    directPutByVal(exec, asObject(baseValue), subscript, value, arrayProfile);
+    directPutByVal(exec, asObject(baseValue), subscript, value, byValInfo);
 }
 
 EncodedJSValue JIT_OPERATION operationCallEval(ExecState* exec, ExecState* execCallee)
@@ -1429,34 +1425,41 @@ static bool canAccessArgumentIndexQuickly(JSObject& object, uint32_t index)
     return false;
 }
 
-static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ArrayProfile* arrayProfile, ReturnAddressPtr returnAddress)
+static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ByValInfo* byValInfo, ReturnAddressPtr returnAddress)
 {
     if (LIKELY(baseValue.isCell() && subscript.isString())) {
         VM& vm = exec->vm();
         Structure& structure = *baseValue.asCell()->structure(vm);
         if (JSCell::canUseFastGetOwnProperty(structure)) {
             if (RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec)) {
-                if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
+                if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get())) {
+                    ASSERT(exec->locationAsBytecodeOffset());
+                    if (byValInfo->stubInfo && byValInfo->cachedId.impl() != existingAtomicString)
+                        byValInfo->tookSlowPath = true;
                     return result;
+                }
             }
         }
     }
 
     if (subscript.isUInt32()) {
+        ASSERT(exec->locationAsBytecodeOffset());
+        byValInfo->tookSlowPath = true;
+
         uint32_t i = subscript.asUInt32();
         if (isJSString(baseValue)) {
             if (asString(baseValue)->canGetIndex(i)) {
                 ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString));
                 return asString(baseValue)->getIndex(exec, i);
             }
-            arrayProfile->setOutOfBounds();
+            byValInfo->arrayProfile->setOutOfBounds();
         } else if (baseValue.isObject()) {
             JSObject* object = asObject(baseValue);
             if (object->canGetIndexQuickly(i))
                 return object->getIndexQuickly(i);
 
             if (!canAccessArgumentIndexQuickly(*object, i))
-                arrayProfile->setOutOfBounds();
+                byValInfo->arrayProfile->setOutOfBounds();
         }
 
         return baseValue.get(exec, i);
@@ -1468,74 +1471,91 @@ static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, A
     auto property = subscript.toPropertyKey(exec);
     if (exec->hadException())
         return jsUndefined();
+
+    ASSERT(exec->locationAsBytecodeOffset());
+    if (byValInfo->stubInfo && byValInfo->cachedId != property)
+        byValInfo->tookSlowPath = true;
+
     return baseValue.get(exec, property);
 }
 
 extern "C" {
     
-EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
+EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
     JSValue baseValue = JSValue::decode(encodedBase);
     JSValue subscript = JSValue::decode(encodedSubscript);
 
-    JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS));
+    JSValue result = getByVal(exec, baseValue, subscript, byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS));
     return JSValue::encode(result);
 }
 
-EncodedJSValue JIT_OPERATION operationGetByValOptimize(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
+EncodedJSValue JIT_OPERATION operationGetByValOptimize(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
     JSValue baseValue = JSValue::decode(encodedBase);
     JSValue subscript = JSValue::decode(encodedSubscript);
-    
+
     if (baseValue.isObject() && subscript.isInt32()) {
         // See if it's worth optimizing this at all.
         JSObject* object = asObject(baseValue);
         bool didOptimize = false;
 
-        unsigned bytecodeOffset = exec->locationAsBytecodeOffset();
-        ASSERT(bytecodeOffset);
-        ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1);
-        ASSERT(!byValInfo.stubRoutine);
-        
+        ASSERT(exec->locationAsBytecodeOffset());
+        ASSERT(!byValInfo->stubRoutine);
+
         if (hasOptimizableIndexing(object->structure(vm))) {
             // Attempt to optimize.
             Structure* structure = object->structure(vm);
             JITArrayMode arrayMode = jitArrayModeForStructure(structure);
-            if (arrayMode != byValInfo.arrayMode) {
+            if (arrayMode != byValInfo->arrayMode) {
                 // If we reached this case, we got an interesting array mode we did not expect when we compiled.
                 // Let's update the profile to do better next time.
                 CodeBlock* codeBlock = exec->codeBlock();
                 ConcurrentJITLocker locker(codeBlock->m_lock);
-                arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
+                byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
 
-                JIT::compileGetByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
+                JIT::compileGetByVal(&vm, exec->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
                 didOptimize = true;
             }
         }
-        
+
         if (!didOptimize) {
             // If we take slow path more than 10 times without patching then make sure we
             // never make that mistake again. Or, if we failed to patch and we have some object
             // that intercepts indexed get, then don't even wait until 10 times. For cases
             // where we see non-index-intercepting objects, this gives 10 iterations worth of
             // opportunity for us to observe that the get_by_val may be polymorphic.
-            if (++byValInfo.slowPathCount >= 10
+            if (++byValInfo->slowPathCount >= 10
                 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
                 // Don't ever try to optimize.
                 ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValGeneric));
             }
         }
     }
-    
-    JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS));
+
+    if (baseValue.isObject() && (subscript.isSymbol() || subscript.isString())) {
+        const Identifier propertyName = subscript.toPropertyKey(exec);
+
+        if (!subscript.isString() || !parseIndex(propertyName)) {
+            ASSERT(exec->locationAsBytecodeOffset());
+            ASSERT(!byValInfo->stubRoutine);
+            JIT::compileGetByValWithCachedId(&vm, exec->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), propertyName);
+        }
+
+        PropertySlot slot(baseValue);
+        bool hasResult = baseValue.getPropertySlot(exec, propertyName, slot);
+        return JSValue::encode(hasResult ? slot.getValue(exec, propertyName) : jsUndefined());
+    }
+
+    JSValue result = getByVal(exec, baseValue, subscript, byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS));
     return JSValue::encode(result);
 }
-    
-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
+
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -1548,16 +1568,14 @@ EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec,
     JSObject* object = asObject(baseValue);
     bool didOptimize = false;
 
-    unsigned bytecodeOffset = exec->locationAsBytecodeOffset();
-    ASSERT(bytecodeOffset);
-    ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1);
-    ASSERT(!byValInfo.stubRoutine);
+    ASSERT(exec->locationAsBytecodeOffset());
+    ASSERT(!byValInfo->stubRoutine);
     
     if (hasOptimizableIndexing(object->structure(vm))) {
         // Attempt to optimize.
         JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm));
-        if (arrayMode != byValInfo.arrayMode) {
-            JIT::compileHasIndexedProperty(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
+        if (arrayMode != byValInfo->arrayMode) {
+            JIT::compileHasIndexedProperty(&vm, exec->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
             didOptimize = true;
         }
     }
@@ -1568,10 +1586,10 @@ EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec,
         // that intercepts indexed get, then don't even wait until 10 times. For cases
         // where we see non-index-intercepting objects, this gives 10 iterations worth of
         // opportunity for us to observe that the get_by_val may be polymorphic.
-        if (++byValInfo.slowPathCount >= 10
+        if (++byValInfo->slowPathCount >= 10
             || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
             // Don't ever try to optimize.
-            ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationHasIndexedPropertyGeneric)); 
+            ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationHasIndexedPropertyGeneric));
         }
     }
 
@@ -1580,11 +1598,11 @@ EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec,
         return JSValue::encode(JSValue(JSValue::JSTrue));
 
     if (!canAccessArgumentIndexQuickly(*object, index))
-        arrayProfile->setOutOfBounds();
+        byValInfo->arrayProfile->setOutOfBounds();
     return JSValue::encode(jsBoolean(object->hasProperty(exec, index)));
 }
     
-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -1600,11 +1618,11 @@ EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec,
         return JSValue::encode(JSValue(JSValue::JSTrue));
 
     if (!canAccessArgumentIndexQuickly(*object, index))
-        arrayProfile->setOutOfBounds();
+        byValInfo->arrayProfile->setOutOfBounds();
     return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32())));
 }
     
-EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
+EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
@@ -1619,10 +1637,8 @@ EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSV
         else {
             result = baseValue.get(exec, i);
             if (!isJSString(baseValue)) {
-                unsigned bytecodeOffset = exec->locationAsBytecodeOffset();
-                ASSERT(bytecodeOffset);
-                ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1);
-                ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(byValInfo.stubRoutine ? operationGetByValGeneric : operationGetByValOptimize));
+                ASSERT(exec->locationAsBytecodeOffset());
+                ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(byValInfo->stubRoutine ? operationGetByValGeneric : operationGetByValOptimize));
             }
         }
     } else {
index cacff2c..c6d28c6 100644 (file)
@@ -58,6 +58,7 @@ extern "C" {
     A: JSArray*
     Aap: ArrayAllocationProfile*
     Ap: ArrayProfile*
+    By: ByValInfo*
     C: JSCell*
     Cb: CodeBlock*
     Cli: CallLinkInfo*
@@ -113,6 +114,7 @@ typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJI)(ExecState*, EncodedJS
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJIdc)(ExecState*, EncodedJSValue, const Identifier*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJAp)(ExecState*, EncodedJSValue, EncodedJSValue, ArrayProfile*);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJBy)(ExecState*, EncodedJSValue, EncodedJSValue, ByValInfo*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJssZ)(ExecState*, JSString*, int32_t);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJP)(ExecState*, EncodedJSValue, void*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EP)(ExecState*, void*);
@@ -195,6 +197,7 @@ typedef void JIT_OPERATION (*V_JITOperation_EJIdJ)(ExecState*, EncodedJSValue, I
 typedef void JIT_OPERATION (*V_JITOperation_EJIdJJ)(ExecState*, EncodedJSValue, Identifier*, EncodedJSValue, EncodedJSValue);
 typedef void JIT_OPERATION (*V_JITOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
 typedef void JIT_OPERATION (*V_JITOperation_EJJJAp)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*);
+typedef void JIT_OPERATION (*V_JITOperation_EJJJBy)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*);
 typedef void JIT_OPERATION (*V_JITOperation_EJPP)(ExecState*, EncodedJSValue, void*, void*);
 typedef void JIT_OPERATION (*V_JITOperation_EJZJ)(ExecState*, EncodedJSValue, int32_t, EncodedJSValue);
 typedef void JIT_OPERATION (*V_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
@@ -259,10 +262,10 @@ void JIT_OPERATION operationPutByIdNonStrictBuildList(ExecState*, StructureStubI
 void JIT_OPERATION operationPutByIdDirectStrictBuildList(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL;
 void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL;
 void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL;
-void JIT_OPERATION operationPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
-void JIT_OPERATION operationDirectPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
-void JIT_OPERATION operationPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
-void JIT_OPERATION operationDirectPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
+void JIT_OPERATION operationPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*) WTF_INTERNAL;
+void JIT_OPERATION operationDirectPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*) WTF_INTERNAL;
+void JIT_OPERATION operationPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*) WTF_INTERNAL;
+void JIT_OPERATION operationDirectPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationCallEval(ExecState*, ExecState*) WTF_INTERNAL;
 char* JIT_OPERATION operationLinkCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
 char* JIT_OPERATION operationLinkPolymorphicCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
@@ -310,11 +313,11 @@ void JIT_OPERATION operationPopScope(ExecState*, int32_t) WTF_INTERNAL;
 void JIT_OPERATION operationProfileDidCall(ExecState*, EncodedJSValue) WTF_INTERNAL;
 void JIT_OPERATION operationProfileWillCall(ExecState*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationCheckHasInstance(ExecState*, EncodedJSValue, EncodedJSValue baseVal) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationGetByValOptimize(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationGetByValString(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValOptimize(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValString(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationDeleteById(ExecState*, EncodedJSValue base, const Identifier*) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationGetPNames(ExecState*, JSObject*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState*, EncodedJSValue, EncodedJSValue proto) WTF_INTERNAL;
index 4ef06d9..73deb96 100644 (file)
@@ -98,10 +98,24 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     int base = currentInstruction[2].u.operand;
     int property = currentInstruction[3].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
-    
+    ByValInfo* byValInfo = m_codeBlock->addByValInfo();
+
     emitGetVirtualRegisters(base, regT0, property, regT1);
-    emitJumpSlowCaseIfNotImmediateInteger(regT1);
 
+    emitJumpSlowCaseIfNotJSCell(regT0, base);
+
+    // FIXME: patchableBranch64 could reduce the following 2 jumps into 1. Like,
+    //
+    // PatchableJump notIndex = emitJumpIfNotImmediateInteger(regT1);
+    //
+    // To use patchableBranch64, we need to fix the existing patchableBranchPtr in ARM64
+    // and introduce patchableBranch64 helper function for 64bit environments.
+    // https://bugs.webkit.org/show_bug.cgi?id=147761
+    Jump isIndex = emitJumpIfImmediateInteger(regT1);
+    PatchableJump notIndex = patchableJump();
+    addSlowCase(notIndex);
+
+    isIndex.link(this);
     // This is technically incorrect - we're zero-extending an int32.  On the hot path this doesn't matter.
     // We check the value as if it was a uint32 against the m_vectorLength - which will always fail if
     // number was signed since m_vectorLength is always less than intmax (since the total allocation
@@ -110,7 +124,6 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     // extending since it makes it easier to re-tag the value in the slow case.
     zeroExtend32ToPtr(regT1, regT1);
 
-    emitJumpSlowCaseIfNotJSCell(regT0, base);
     emitArrayProfilingSiteWithCell(regT0, regT2, profile);
     and32(TrustedImm32(IndexingShapeMask), regT2);
 
@@ -149,8 +162,8 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
 
     emitValueProfilingSite();
     emitPutVirtualRegister(dst);
-    
-    m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
+
+    m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeOffset, notIndex, badType, mode, profile, done));
 }
 
 JIT::JumpList JIT::emitDoubleLoad(Instruction*, PatchableJump& badType)
@@ -195,15 +208,52 @@ JIT::JumpList JIT::emitArrayStorageLoad(Instruction*, PatchableJump& badType)
     return slowCases;
 }
 
+JITGetByIdGenerator JIT::emitGetByValWithCachedId(Instruction* currentInstruction, const Identifier& propertyName, JumpList& doneCases, JumpList& slowCases)
+{
+    // base: regT0
+    // property: regT1
+    // scratch: regT3
+
+    int dst = currentInstruction[1].u.operand;
+
+    slowCases.append(emitJumpIfNotJSCell(regT1));
+    if (propertyName.isSymbol()) {
+        slowCases.append(branchStructure(NotEqual, Address(regT1, JSCell::structureIDOffset()), m_vm->symbolStructure.get()));
+        loadPtr(Address(regT1, Symbol::offsetOfPrivateName()), regT3);
+    } else {
+        slowCases.append(branchStructure(NotEqual, Address(regT1, JSCell::structureIDOffset()), m_vm->stringStructure.get()));
+        loadPtr(Address(regT1, JSString::offsetOfValue()), regT3);
+        slowCases.append(branchTestPtr(Zero, regT3));
+        slowCases.append(branchTest32(Zero, Address(regT3, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIsAtomic())));
+    }
+    slowCases.append(branchPtr(NotEqual, regT3, TrustedImmPtr(propertyName.impl())));
+
+    JITGetByIdGenerator gen(
+        m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(),
+        JSValueRegs(regT0), JSValueRegs(regT0), DontSpill);
+    gen.generateFastPath(*this);
+
+    doneCases.append(jump());
+
+    Label coldPathBegin = label();
+    gen.slowPathJump().link(this);
+
+    Call call = callOperation(WithProfile, operationGetByIdOptimize, dst, gen.stubInfo(), regT0, propertyName.impl());
+    gen.reportSlowPathCall(coldPathBegin, call);
+    doneCases.append(jump());
+
+    return gen;
+}
+
 void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     int dst = currentInstruction[1].u.operand;
     int base = currentInstruction[2].u.operand;
     int property = currentInstruction[3].u.operand;
-    ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;
     
-    linkSlowCase(iter); // property int32 check
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
+    linkSlowCase(iter); // property int32 check
     Jump nonCell = jump();
     linkSlowCase(iter); // base array check
     Jump notString = branchStructure(NotEqual, 
@@ -224,7 +274,7 @@ void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCas
     
     emitGetVirtualRegister(base, regT0);
     emitGetVirtualRegister(property, regT1);
-    Call call = callOperation(operationGetByValOptimize, dst, regT0, regT1, profile);
+    Call call = callOperation(operationGetByValOptimize, dst, regT0, regT1, byValInfo);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
@@ -263,6 +313,7 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     int base = currentInstruction[1].u.operand;
     int property = currentInstruction[2].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_codeBlock->addByValInfo();
 
     emitGetVirtualRegisters(base, regT0, property, regT1);
     emitJumpSlowCaseIfNotImmediateInteger(regT1);
@@ -299,8 +350,7 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     
     Label done = label();
     
-    m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
-
+    m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeOffset, PatchableJump(), badType, mode, profile, done));
 }
 
 JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType, IndexingType indexingShape)
@@ -399,6 +449,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
     int property = currentInstruction[2].u.operand;
     int value = currentInstruction[3].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;
 
     linkSlowCase(iter); // property int32 check
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
@@ -424,7 +475,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
     emitGetVirtualRegister(property, regT1);
     emitGetVirtualRegister(value, regT2);
     bool isDirect = m_interpreter->getOpcodeID(currentInstruction->u.opcode) == op_put_by_val_direct;
-    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT0, regT1, regT2, profile);
+    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT0, regT1, regT2, byValInfo);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
@@ -999,6 +1050,36 @@ void JIT::privateCompileGetByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(operationGetByValGeneric));
 }
 
+void JIT::privateCompileGetByValWithCachedId(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, const Identifier& propertyName)
+{
+    Instruction* currentInstruction = m_codeBlock->instructions().begin() + byValInfo->bytecodeIndex;
+
+    JumpList doneCases;
+    JumpList slowCases;
+
+    JITGetByIdGenerator gen = emitGetByValWithCachedId(currentInstruction, propertyName, doneCases, slowCases);
+
+    ConcurrentJITLocker locker(m_codeBlock->m_lock);
+    LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock);
+    patchBuffer.link(slowCases, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(returnAddress.value())).labelAtOffset(byValInfo->returnAddressToSlowPath));
+    patchBuffer.link(doneCases, byValInfo->badTypeJump.labelAtOffset(byValInfo->badTypeJumpToDone));
+    for (const auto& callSite : m_calls) {
+        if (callSite.to)
+            patchBuffer.link(callSite.from, FunctionPtr(callSite.to));
+    }
+    gen.finalize(patchBuffer);
+
+    byValInfo->stubRoutine = FINALIZE_CODE_FOR_STUB(
+        m_codeBlock, patchBuffer,
+        ("Baseline get_by_val with cached property name '%s' stub for %s, return point %p", propertyName.impl()->utf8().data(), toCString(*m_codeBlock).data(), returnAddress.value()));
+    byValInfo->cachedId = propertyName;
+    byValInfo->stubInfo = gen.stubInfo();
+
+    RepatchBuffer repatchBuffer(m_codeBlock);
+    repatchBuffer.relink(byValInfo->notIndexJump, CodeLocationLabel(byValInfo->stubRoutine->code().code()));
+    repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(operationGetByValGeneric));
+}
+
 void JIT::privateCompilePutByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
 {
     Instruction* currentInstruction = m_codeBlock->instructions().begin() + byValInfo->bytecodeIndex;
index 609ca13..a8d69ac 100644 (file)
@@ -149,11 +149,13 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     int base = currentInstruction[2].u.operand;
     int property = currentInstruction[3].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_codeBlock->addByValInfo();
     
     emitLoad2(base, regT1, regT0, property, regT3, regT2);
     
-    addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
     emitJumpSlowCaseIfNotJSCell(base, regT1);
+    PatchableJump notIndex = patchableBranch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag));
+    addSlowCase(notIndex);
     emitArrayProfilingSiteWithCell(regT0, regT1, profile);
     and32(TrustedImm32(IndexingShapeMask), regT1);
 
@@ -192,7 +194,7 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     emitValueProfilingSite();
     emitStore(dst, regT1, regT0);
     
-    m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
+    m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeOffset, notIndex, badType, mode, profile, done));
 }
 
 JIT::JumpList JIT::emitContiguousLoad(Instruction*, PatchableJump& badType, IndexingType expectedShape)
@@ -236,16 +238,53 @@ JIT::JumpList JIT::emitArrayStorageLoad(Instruction*, PatchableJump& badType)
     
     return slowCases;
 }
-    
+
+JITGetByIdGenerator JIT::emitGetByValWithCachedId(Instruction* currentInstruction, const Identifier& propertyName, JumpList& doneCases, JumpList& slowCases)
+{
+    int dst = currentInstruction[1].u.operand;
+
+    // base: tag(regT1), payload(regT0)
+    // property: tag(regT3), payload(regT2)
+    // scratch: regT4
+
+    slowCases.append(emitJumpIfNotJSCell(regT3));
+    if (propertyName.isSymbol()) {
+        slowCases.append(branchStructure(NotEqual, Address(regT2, JSCell::structureIDOffset()), m_vm->symbolStructure.get()));
+        loadPtr(Address(regT2, Symbol::offsetOfPrivateName()), regT4);
+    } else {
+        slowCases.append(branchStructure(NotEqual, Address(regT2, JSCell::structureIDOffset()), m_vm->stringStructure.get()));
+        loadPtr(Address(regT2, JSString::offsetOfValue()), regT4);
+        slowCases.append(branchTestPtr(Zero, regT4));
+        slowCases.append(branchTest32(Zero, Address(regT4, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIsAtomic())));
+    }
+    slowCases.append(branchPtr(NotEqual, regT4, TrustedImmPtr(propertyName.impl())));
+
+    JITGetByIdGenerator gen(
+        m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(),
+        JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), DontSpill);
+    gen.generateFastPath(*this);
+
+    doneCases.append(jump());
+
+    Label coldPathBegin = label();
+    gen.slowPathJump().link(this);
+
+    Call call = callOperation(WithProfile, operationGetByIdOptimize, dst, gen.stubInfo(), regT1, regT0, propertyName.impl());
+    gen.reportSlowPathCall(coldPathBegin, call);
+    doneCases.append(jump());
+
+    return gen;
+}
+
 void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     int dst = currentInstruction[1].u.operand;
     int base = currentInstruction[2].u.operand;
     int property = currentInstruction[3].u.operand;
-    ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
-    
-    linkSlowCase(iter); // property int32 check
+    ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;
+
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
+    linkSlowCase(iter); // property int32 check
 
     Jump nonCell = jump();
     linkSlowCase(iter); // base array check
@@ -265,7 +304,7 @@ void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCas
     
     emitLoad(base, regT1, regT0);
     emitLoad(property, regT3, regT2);
-    Call call = callOperation(operationGetByValOptimize, dst, regT1, regT0, regT3, regT2, profile);
+    Call call = callOperation(operationGetByValOptimize, dst, regT1, regT0, regT3, regT2, byValInfo);
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
@@ -279,6 +318,7 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     int base = currentInstruction[1].u.operand;
     int property = currentInstruction[2].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_codeBlock->addByValInfo();
     
     emitLoad2(base, regT1, regT0, property, regT3, regT2);
     
@@ -314,7 +354,7 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     
     Label done = label();
     
-    m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
+    m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeOffset, PatchableJump(), badType, mode, profile, done));
 }
 
 JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType, IndexingType indexingShape)
@@ -419,6 +459,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
     int property = currentInstruction[2].u.operand;
     int value = currentInstruction[3].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;
     
     linkSlowCase(iter); // property int32 check
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
@@ -458,7 +499,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
     emitLoad(value, regT0, regT1);
     addCallArgument(regT1);
     addCallArgument(regT0);
-    addCallArgument(TrustedImmPtr(profile));
+    addCallArgument(TrustedImmPtr(byValInfo));
     Call call = appendCallWithExceptionCheck(isDirect ? operationDirectPutByVal : operationPutByVal);
 #else
     // The register selection below is chosen to reduce register swapping on ARM.
@@ -466,7 +507,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
     emitLoad(base, regT2, regT1);
     emitLoad(property, regT3, regT0);
     emitLoad(value, regT5, regT4);
-    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT2, regT1, regT3, regT0, regT5, regT4, profile);
+    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT2, regT1, regT3, regT0, regT5, regT4, byValInfo);
 #endif
 
     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
index e5790d7..83f5de2 100644 (file)
@@ -79,6 +79,8 @@ public:
     JSObject* toObject(ExecState*, JSGlobalObject*) const;
     double toNumber(ExecState*) const;
 
+    static size_t offsetOfPrivateName() { return OBJECT_OFFSETOF(Symbol, m_privateName); }
+
 protected:
     static void destroy(JSCell*);
 
diff --git a/Source/JavaScriptCore/tests/stress/get-by-val-with-string-constructor.js b/Source/JavaScriptCore/tests/stress/get-by-val-with-string-constructor.js
new file mode 100644 (file)
index 0000000..ac58516
--- /dev/null
@@ -0,0 +1,23 @@
+var symbol = "@@species";
+function Hello() {
+}
+
+Object.defineProperty(Hello, symbol, {
+    get: function () {
+        return this;
+    }
+});
+
+Hello.prototype.generate = function () {
+    return new this.constructor[symbol]();
+};
+
+function ok() {
+    var object = new Hello();
+    if (!(object.generate() instanceof Hello))
+        throw new Error("bad instance");
+}
+noInline(ok);
+
+for (var i = 0; i < 10000; ++i)
+    ok();
diff --git a/Source/JavaScriptCore/tests/stress/get-by-val-with-string-exit.js b/Source/JavaScriptCore/tests/stress/get-by-val-with-string-exit.js
new file mode 100644 (file)
index 0000000..9aa262d
--- /dev/null
@@ -0,0 +1,34 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function getByVal(object, name)
+{
+    return object[name];
+}
+noInline(getByVal);
+
+function getStr1()
+{
+    return "hello";
+}
+noInline(getStr1);
+
+function getStr2()
+{
+    return "hello";
+}
+noInline(getStr2);
+
+var object = {
+    hello: 42
+};
+
+for (var i = 0; i < 100; ++i)
+    shouldBe(getByVal(object, i % 2 === 0 ? getStr1() : getStr2()), 42);
+shouldBe(getByVal(object, { toString() { return 'hello'; } }), 42);
+
+for (var i = 0; i < 10000; ++i)
+    shouldBe(getByVal(object, i % 2 === 0 ? getStr1() : getStr2()), 42);
+shouldBe(getByVal(object, { toString() { return 'hello'; } }), 42);
diff --git a/Source/JavaScriptCore/tests/stress/get-by-val-with-string-generated.js b/Source/JavaScriptCore/tests/stress/get-by-val-with-string-generated.js
new file mode 100644 (file)
index 0000000..e813a7e
--- /dev/null
@@ -0,0 +1,33 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function getByVal(object, name)
+{
+    return object[name];
+}
+noInline(getByVal);
+
+var value = 'lo';
+
+function getStr1()
+{
+    return "hel" + value;
+}
+noInline(getStr1);
+
+function getStr2()
+{
+    return "hello";
+}
+noInline(getStr2);
+
+var object = {
+    hello: 42,
+    world: 50
+};
+
+for (var i = 0; i < 10000; ++i)
+    shouldBe(getByVal(object, i % 2 === 0 ? getStr1() : getStr2()), 42);
+shouldBe(getByVal(object, 'world'), 50);
diff --git a/Source/JavaScriptCore/tests/stress/get-by-val-with-string-getter.js b/Source/JavaScriptCore/tests/stress/get-by-val-with-string-getter.js
new file mode 100644 (file)
index 0000000..858ec0a
--- /dev/null
@@ -0,0 +1,16 @@
+
+var object = {
+    get hello() {
+        return 42;
+    }
+};
+
+function ok() {
+    var value = 'hello';
+    if (object[value] + 20 !== 62)
+        throw new Error();
+}
+noInline(ok);
+
+for (var i = 0; i < 10000; ++i)
+    ok();
diff --git a/Source/JavaScriptCore/tests/stress/get-by-val-with-string.js b/Source/JavaScriptCore/tests/stress/get-by-val-with-string.js
new file mode 100644 (file)
index 0000000..6db33d9
--- /dev/null
@@ -0,0 +1,31 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function getByVal(object, name)
+{
+    return object[name];
+}
+noInline(getByVal);
+
+function getStr1()
+{
+    return "hello";
+}
+noInline(getStr1);
+
+function getStr2()
+{
+    return "hello";
+}
+noInline(getStr2);
+
+var object = {
+    hello: 42,
+    world: 50
+};
+
+for (var i = 0; i < 10000; ++i)
+    shouldBe(getByVal(object, i % 2 === 0 ? getStr1() : getStr2()), 42);
+shouldBe(getByVal(object, 'world'), 50);
diff --git a/Source/JavaScriptCore/tests/stress/get-by-val-with-symbol-constructor.js b/Source/JavaScriptCore/tests/stress/get-by-val-with-symbol-constructor.js
new file mode 100644 (file)
index 0000000..2895c26
--- /dev/null
@@ -0,0 +1,23 @@
+var symbol = Symbol();
+function Hello() {
+}
+
+Object.defineProperty(Hello, symbol, {
+    get: function () {
+        return this;
+    }
+});
+
+Hello.prototype.generate = function () {
+    return new this.constructor[symbol]();
+};
+
+function ok() {
+    var object = new Hello();
+    if (!(object.generate() instanceof Hello))
+        throw new Error("bad instance");
+}
+noInline(ok);
+
+for (var i = 0; i < 10000; ++i)
+    ok();
diff --git a/Source/JavaScriptCore/tests/stress/get-by-val-with-symbol-exit.js b/Source/JavaScriptCore/tests/stress/get-by-val-with-symbol-exit.js
new file mode 100644 (file)
index 0000000..c0cdcb6
--- /dev/null
@@ -0,0 +1,38 @@
+var symbol1 = Symbol();
+var symbol2 = Object.getOwnPropertySymbols({ [symbol1]: 42 })[0];
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function getByVal(object, name)
+{
+    return object[name];
+}
+noInline(getByVal);
+
+function getSym1()
+{
+    return symbol1;
+}
+noInline(getSym1);
+
+function getSym2()
+{
+    return symbol2;
+}
+noInline(getSym2);
+
+var object = {
+    [symbol1]: 42,
+    hello: 50
+};
+
+for (var i = 0; i < 100; ++i)
+    shouldBe(getByVal(object, i % 2 === 0 ? getSym1() : getSym2()), 42);
+shouldBe(getByVal(object, 'hello'), 50);
+
+for (var i = 0; i < 10000; ++i)
+    shouldBe(getByVal(object, i % 2 === 0 ? getSym1() : getSym2()), 42);
+shouldBe(getByVal(object, 'hello'), 50);
diff --git a/Source/JavaScriptCore/tests/stress/get-by-val-with-symbol-getter.js b/Source/JavaScriptCore/tests/stress/get-by-val-with-symbol-getter.js
new file mode 100644 (file)
index 0000000..7035e4b
--- /dev/null
@@ -0,0 +1,23 @@
+
+var object = {
+    get hello() {
+        return 42;
+    }
+};
+
+var symbol = Symbol();
+
+Object.defineProperty(object, symbol, {
+    get: function () {
+        return 42;
+    }
+});
+
+function ok() {
+    if (object[symbol] + 20 !== 62)
+        throw new Error();
+}
+noInline(ok);
+
+for (var i = 0; i < 10000; ++i)
+    ok();
diff --git a/Source/JavaScriptCore/tests/stress/get-by-val-with-symbol.js b/Source/JavaScriptCore/tests/stress/get-by-val-with-symbol.js
new file mode 100644 (file)
index 0000000..2c834eb
--- /dev/null
@@ -0,0 +1,33 @@
+var symbol1 = Symbol();
+var symbol2 = Object.getOwnPropertySymbols({ [symbol1]: 42 })[0];
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function getByVal(object, name)
+{
+    return object[name];
+}
+noInline(getByVal);
+
+function getSym1()
+{
+    return symbol1;
+}
+noInline(getSym1);
+
+function getSym2()
+{
+    return symbol2;
+}
+noInline(getSym2);
+
+var object = {
+    [symbol1]: 42,
+    hello: 50
+};
+
+for (var i = 0; i < 10000; ++i)
+    shouldBe(getByVal(object, i % 2 === 0 ? getSym1() : getSym2()), 42);