Unreviewed, reland InById cache
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 May 2018 04:54:31 +0000 (04:54 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 May 2018 04:54:31 +0000 (04:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185682

JSTests:

* stress/in-by-id-accessors.js: Added.
(shouldBe):
(test):
(protoGetter.__proto__.get hello):
(protoSetter.__proto__.set hello):
(i.shouldBe.test.get hello):
(i.shouldBe.test.set hello):
* stress/in-by-id-ai.js: Added.
(shouldBe):
(test):
* stress/in-by-id-custom-accessors.js: Added.
(shouldBe):
(test1):
(test2):
* stress/in-by-id-custom-values.js: Added.
(shouldBe):
(test):
* stress/in-by-id-operation.js: Added.
(shouldBe):
(test):
(selfCache):
* stress/in-by-id-proxy.js: Added.
(shouldBe):
(test):
(handler.has):

Source/JavaScriptCore:

Includes Dominik's 32bit fix.

* bytecode/AccessCase.cpp:
(JSC::AccessCase::fromStructureStubInfo):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generateImpl):
* bytecode/BytecodeDumper.cpp:
(JSC::BytecodeDumper<Block>::printInByIdCacheStatus):
(JSC::BytecodeDumper<Block>::dumpBytecode):
* bytecode/BytecodeDumper.h:
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
* bytecode/InlineAccess.cpp:
(JSC::InlineAccess::generateSelfInAccess):
* bytecode/InlineAccess.h:
* bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::initInByIdSelf):
(JSC::StructureStubInfo::deref):
(JSC::StructureStubInfo::aboutToDie):
(JSC::StructureStubInfo::reset):
(JSC::StructureStubInfo::visitWeakReferences):
(JSC::StructureStubInfo::propagateTransitions):
* bytecode/StructureStubInfo.h:
(JSC::StructureStubInfo::patchableJump):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitInByVal):
(JSC::BytecodeGenerator::emitInById):
(JSC::BytecodeGenerator::emitIn): Deleted.
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::InNode::emitBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* 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):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::addInById):
(JSC::DFG::InRecord::InRecord): Deleted.
(JSC::DFG::JITCompiler::addIn): Deleted.
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToInById):
(JSC::DFG::Node::hasIdentifier):
(JSC::DFG::Node::hasArrayMode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileInById):
(JSC::DFG::SpeculativeJIT::compileInByVal):
(JSC::DFG::SpeculativeJIT::compileIn): Deleted.
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileInByVal):
(JSC::FTL::DFG::LowerDFGToB3::compileInById):
(JSC::FTL::DFG::LowerDFGToB3::compileIn): Deleted.
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::boxBoolean):
* jit/ICStats.h:
* jit/JIT.cpp:
(JSC::JIT::JIT):
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::link):
* jit/JIT.h:
* jit/JITInlineCacheGenerator.cpp:
(JSC::JITInByIdGenerator::JITInByIdGenerator):
(JSC::JITInByIdGenerator::generateFastPath):
* jit/JITInlineCacheGenerator.h:
(JSC::JITInByIdGenerator::JITInByIdGenerator):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_in_by_id):
(JSC::JIT::emitSlow_op_in_by_id):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_in_by_id):
(JSC::JIT::emitSlow_op_in_by_id):
* jit/Repatch.cpp:
(JSC::tryCacheInByID):
(JSC::repatchInByID):
(JSC::resetInByID):
(JSC::tryCacheIn): Deleted.
(JSC::repatchIn): Deleted.
(JSC::resetIn): Deleted.
* jit/Repatch.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter64.asm:
* parser/NodeConstructors.h:
(JSC::InNode::InNode):
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
(JSC::CommonSlowPaths::opInByVal):
(JSC::CommonSlowPaths::opIn): Deleted.

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

57 files changed:
JSTests/ChangeLog
JSTests/stress/in-by-id-accessors.js [new file with mode: 0644]
JSTests/stress/in-by-id-ai.js [new file with mode: 0644]
JSTests/stress/in-by-id-custom-accessors.js [new file with mode: 0644]
JSTests/stress/in-by-id-custom-values.js [new file with mode: 0644]
JSTests/stress/in-by-id-operation.js [new file with mode: 0644]
JSTests/stress/in-by-id-proxy.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/AccessCase.cpp
Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
Source/JavaScriptCore/bytecode/BytecodeDumper.h
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/InlineAccess.cpp
Source/JavaScriptCore/bytecode/InlineAccess.h
Source/JavaScriptCore/bytecode/StructureStubInfo.cpp
Source/JavaScriptCore/bytecode/StructureStubInfo.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
Source/JavaScriptCore/dfg/DFGJITCompiler.h
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/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/AssemblyHelpers.h
Source/JavaScriptCore/jit/ICStats.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp
Source/JavaScriptCore/jit/JITInlineCacheGenerator.h
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/jit/Repatch.cpp
Source/JavaScriptCore/jit/Repatch.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/parser/NodeConstructors.h
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h

index 33bcc89..8686322 100644 (file)
@@ -1,3 +1,34 @@
+2018-05-21  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Unreviewed, reland InById cache
+        https://bugs.webkit.org/show_bug.cgi?id=185682
+
+        * stress/in-by-id-accessors.js: Added.
+        (shouldBe):
+        (test):
+        (protoGetter.__proto__.get hello):
+        (protoSetter.__proto__.set hello):
+        (i.shouldBe.test.get hello):
+        (i.shouldBe.test.set hello):
+        * stress/in-by-id-ai.js: Added.
+        (shouldBe):
+        (test):
+        * stress/in-by-id-custom-accessors.js: Added.
+        (shouldBe):
+        (test1):
+        (test2):
+        * stress/in-by-id-custom-values.js: Added.
+        (shouldBe):
+        (test):
+        * stress/in-by-id-operation.js: Added.
+        (shouldBe):
+        (test):
+        (selfCache):
+        * stress/in-by-id-proxy.js: Added.
+        (shouldBe):
+        (test):
+        (handler.has):
+
 2018-05-21  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r231998 and r232017.
diff --git a/JSTests/stress/in-by-id-accessors.js b/JSTests/stress/in-by-id-accessors.js
new file mode 100644 (file)
index 0000000..e38dd6d
--- /dev/null
@@ -0,0 +1,41 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+    var name = "hello";
+    return name in object;
+}
+noInline(test);
+
+var protoGetter = {
+    __proto__: {
+        get hello() {
+            throw new Error("out");
+        }
+    }
+};
+var protoSetter = {
+    __proto__: {
+        set hello(value) {
+            throw new Error("out");
+        }
+    }
+};
+for (var i = 0; i < 1e5; ++i) {
+    shouldBe(test({
+        get hello() {
+            throw new Error("out");
+        }
+    }), true);
+    shouldBe(test({}), false);
+    shouldBe(test(protoGetter), true);
+    shouldBe(test({
+        set hello(value) {
+            throw new Error("out");
+        }
+    }), true);
+    shouldBe(test(protoSetter), true);
+}
diff --git a/JSTests/stress/in-by-id-ai.js b/JSTests/stress/in-by-id-ai.js
new file mode 100644 (file)
index 0000000..56a11ac
--- /dev/null
@@ -0,0 +1,26 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+    var name = "hello";
+    return name in object;
+}
+noInline(test);
+
+var proto = {
+    __proto__: { hello: 2 }
+};
+for (var i = 0; i < 1e5; ++i) {
+    shouldBe(test({
+        hello: 42
+    }), true);
+    shouldBe(test({}), false);
+    shouldBe(test({
+        helloworld: 43,
+        ok: 44
+    }), false);
+    shouldBe(test(proto), true);
+}
diff --git a/JSTests/stress/in-by-id-custom-accessors.js b/JSTests/stress/in-by-id-custom-accessors.js
new file mode 100644 (file)
index 0000000..9571ec8
--- /dev/null
@@ -0,0 +1,25 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test1(object)
+{
+    return "customValue" in object;
+}
+noInline(test1);
+
+function test2(object)
+{
+    return "customAccessor" in object;
+}
+noInline(test2);
+
+var target1 = $vm.createCustomTestGetterSetter();
+var target2 = { __proto__: target1 };
+for (var i = 0; i < 1e5; ++i) {
+    shouldBe(test1(target1), true);
+    shouldBe(test1(target2), true);
+    shouldBe(test2(target1), true);
+    shouldBe(test2(target2), true);
+}
diff --git a/JSTests/stress/in-by-id-custom-values.js b/JSTests/stress/in-by-id-custom-values.js
new file mode 100644 (file)
index 0000000..684781f
--- /dev/null
@@ -0,0 +1,17 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+    return "$1" in object;
+}
+noInline(test);
+
+var target1 = RegExp;
+var target2 = { __proto__: RegExp };
+for (var i = 0; i < 1e5; ++i) {
+    shouldBe(test(target1), true);
+    shouldBe(test(target2), true);
+}
diff --git a/JSTests/stress/in-by-id-operation.js b/JSTests/stress/in-by-id-operation.js
new file mode 100644 (file)
index 0000000..95dd2c4
--- /dev/null
@@ -0,0 +1,42 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+    return "hello" in object;
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i) {
+    shouldBe(test({
+        hello: 42
+    }), true);
+    shouldBe(test({
+        hello: undefined,
+        world: 44
+    }), true);
+    shouldBe(test({
+        helloworld: 43,
+        ok: 44
+    }), false);
+}
+
+function selfCache(object)
+{
+    return "hello" in object;
+}
+noInline(selfCache);
+
+var object = {};
+object.hello = 42;
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(selfCache(object), true);
+object.world = 43;
+shouldBe(selfCache(object), true);
+object.world = 43;
+shouldBe(selfCache({ __proto__: object }), true);
+delete object.hello;
+shouldBe(selfCache(object), false);
+shouldBe(selfCache({ __proto__: object }), false);
diff --git a/JSTests/stress/in-by-id-proxy.js b/JSTests/stress/in-by-id-proxy.js
new file mode 100644 (file)
index 0000000..1e56bf2
--- /dev/null
@@ -0,0 +1,44 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+    return "hello" in object;
+}
+noInline(test);
+
+var count = 0;
+var target = null;
+var key = null;
+var handler = {
+    has(targetArg, keyArg) {
+        ++count;
+        target = targetArg;
+        key = keyArg;
+        return keyArg in targetArg;
+    }
+};
+var targetObject = {};
+var proxy = new Proxy(targetObject, handler);
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(count, i);
+    shouldBe(test(proxy), false);
+    shouldBe(target, targetObject);
+    shouldBe(key, "hello");
+}
+targetObject.hello = 42;
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(count, i + 1e4);
+    shouldBe(test(proxy), true);
+    shouldBe(target, targetObject);
+    shouldBe(key, "hello");
+}
+delete targetObject.hello;
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(count, i + 2e4);
+    shouldBe(test(proxy), false);
+    shouldBe(target, targetObject);
+    shouldBe(key, "hello");
+}
index 337266a..40211b2 100644 (file)
@@ -1,3 +1,127 @@
+2018-05-21  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Unreviewed, reland InById cache
+        https://bugs.webkit.org/show_bug.cgi?id=185682
+
+        Includes Dominik's 32bit fix.
+
+        * bytecode/AccessCase.cpp:
+        (JSC::AccessCase::fromStructureStubInfo):
+        (JSC::AccessCase::generateWithGuard):
+        (JSC::AccessCase::generateImpl):
+        * bytecode/BytecodeDumper.cpp:
+        (JSC::BytecodeDumper<Block>::printInByIdCacheStatus):
+        (JSC::BytecodeDumper<Block>::dumpBytecode):
+        * bytecode/BytecodeDumper.h:
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::finishCreation):
+        * bytecode/InlineAccess.cpp:
+        (JSC::InlineAccess::generateSelfInAccess):
+        * bytecode/InlineAccess.h:
+        * bytecode/StructureStubInfo.cpp:
+        (JSC::StructureStubInfo::initInByIdSelf):
+        (JSC::StructureStubInfo::deref):
+        (JSC::StructureStubInfo::aboutToDie):
+        (JSC::StructureStubInfo::reset):
+        (JSC::StructureStubInfo::visitWeakReferences):
+        (JSC::StructureStubInfo::propagateTransitions):
+        * bytecode/StructureStubInfo.h:
+        (JSC::StructureStubInfo::patchableJump):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitInByVal):
+        (JSC::BytecodeGenerator::emitInById):
+        (JSC::BytecodeGenerator::emitIn): Deleted.
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::InNode::emitBytecode):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * 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):
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::link):
+        * dfg/DFGJITCompiler.h:
+        (JSC::DFG::JITCompiler::addInById):
+        (JSC::DFG::InRecord::InRecord): Deleted.
+        (JSC::DFG::JITCompiler::addIn): Deleted.
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToInById):
+        (JSC::DFG::Node::hasIdentifier):
+        (JSC::DFG::Node::hasArrayMode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileInById):
+        (JSC::DFG::SpeculativeJIT::compileInByVal):
+        (JSC::DFG::SpeculativeJIT::compileIn): Deleted.
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileInByVal):
+        (JSC::FTL::DFG::LowerDFGToB3::compileInById):
+        (JSC::FTL::DFG::LowerDFGToB3::compileIn): Deleted.
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::boxBoolean):
+        * jit/ICStats.h:
+        * jit/JIT.cpp:
+        (JSC::JIT::JIT):
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        (JSC::JIT::link):
+        * jit/JIT.h:
+        * jit/JITInlineCacheGenerator.cpp:
+        (JSC::JITInByIdGenerator::JITInByIdGenerator):
+        (JSC::JITInByIdGenerator::generateFastPath):
+        * jit/JITInlineCacheGenerator.h:
+        (JSC::JITInByIdGenerator::JITInByIdGenerator):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_in_by_id):
+        (JSC::JIT::emitSlow_op_in_by_id):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_in_by_id):
+        (JSC::JIT::emitSlow_op_in_by_id):
+        * jit/Repatch.cpp:
+        (JSC::tryCacheInByID):
+        (JSC::repatchInByID):
+        (JSC::resetInByID):
+        (JSC::tryCacheIn): Deleted.
+        (JSC::repatchIn): Deleted.
+        (JSC::resetIn): Deleted.
+        * jit/Repatch.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * parser/NodeConstructors.h:
+        (JSC::InNode::InNode):
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        (JSC::CommonSlowPaths::opInByVal):
+        (JSC::CommonSlowPaths::opIn): Deleted.
+
 2018-05-21  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r231998 and r232017.
index e3239a1..c2fbe33 100644 (file)
@@ -118,6 +118,9 @@ std::unique_ptr<AccessCase> AccessCase::fromStructureStubInfo(
     case CacheType::PutByIdReplace:
         return AccessCase::create(vm, owner, Replace, stubInfo.u.byIdSelf.offset, stubInfo.u.byIdSelf.baseObjectStructure.get());
 
+    case CacheType::InByIdSelf:
+        return AccessCase::create(vm, owner, InHit, stubInfo.u.byIdSelf.offset, stubInfo.u.byIdSelf.baseObjectStructure.get());
+
     default:
         return nullptr;
     }
@@ -555,10 +558,7 @@ void AccessCase::generateWithGuard(
         jit.move(baseGPR, valueGPR);
         
         CCallHelpers::Label loop(&jit);
-        failAndIgnore = jit.branch8(
-            CCallHelpers::Equal,
-            CCallHelpers::Address(valueGPR, JSCell::typeInfoTypeOffset()),
-            CCallHelpers::TrustedImm32(ProxyObjectType));
+        failAndIgnore = jit.branchIfType(valueGPR, ProxyObjectType);
         
         jit.emitLoadStructure(vm, valueGPR, scratch2GPR, scratchGPR);
 #if USE(JSVALUE64)
@@ -680,7 +680,7 @@ void AccessCase::generateImpl(AccessGenerationState& state)
     switch (m_type) {
     case InHit:
     case InMiss:
-        jit.boxBooleanPayload(m_type == InHit, valueRegs.payloadGPR());
+        jit.boxBoolean(m_type == InHit, valueRegs);
         state.succeed();
         return;
 
index abe9a8a..3f9c59e 100644 (file)
@@ -551,6 +551,59 @@ void BytecodeDumper<Block>::printPutByIdCacheStatus(PrintStream& out, int locati
 #endif
 }
 
+template<class Block>
+void BytecodeDumper<Block>::printInByIdCacheStatus(PrintStream& out, int location, const StubInfoMap& map)
+{
+    const auto* instruction = instructionsBegin() + location;
+
+    const Identifier& ident = identifier(instruction[3].u.operand);
+
+    UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
+
+#if ENABLE(JIT)
+    if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) {
+        StructureStubInfo& stubInfo = *stubPtr;
+        if (stubInfo.resetByGC)
+            out.print(" (Reset By GC)");
+
+        out.printf(" jit(");
+
+        Structure* baseStructure = nullptr;
+        PolymorphicAccess* stub = nullptr;
+
+        switch (stubInfo.cacheType) {
+        case CacheType::InByIdSelf:
+            out.printf("self");
+            baseStructure = stubInfo.u.byIdSelf.baseObjectStructure.get();
+            break;
+        case CacheType::Stub:
+            out.printf("stub");
+            stub = stubInfo.u.stub;
+            break;
+        case CacheType::Unset:
+            out.printf("unset");
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+
+        if (baseStructure) {
+            out.printf(", ");
+            dumpStructure(out, "struct", baseStructure, ident);
+        }
+
+        if (stub)
+            out.print(", ", *stub);
+
+        out.printf(")");
+    }
+#else
+    UNUSED_PARAM(out);
+    UNUSED_PARAM(map);
+#endif
+}
+
 #if ENABLE(JIT)
 template<typename Block>
 void BytecodeDumper<Block>::dumpCallLinkStatus(PrintStream&, unsigned, const CallLinkInfoMap&)
@@ -1012,8 +1065,17 @@ void BytecodeDumper<Block>::dumpBytecode(PrintStream& out, const typename Block:
         printUnaryOp(out, location, it, "is_function");
         break;
     }
-    case op_in: {
-        printBinaryOp(out, location, it, "in");
+    case op_in_by_id: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "in_by_id");
+        out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
+        printInByIdCacheStatus(out, location, stubInfos);
+        break;
+    }
+    case op_in_by_val: {
+        printBinaryOp(out, location, it, "in_by_val");
         dumpArrayProfiling(out, it, hasPrintedProfiling);
         break;
     }
index 7cd08c9..5e8943e 100644 (file)
@@ -71,6 +71,7 @@ private:
     void printGetByIdOp(PrintStream& out, int location, const Instruction*& it);
     void printGetByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&);
     void printPutByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&);
+    void printInByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&);
     enum CacheDumpMode { DumpCaches, DontDumpCaches };
     void printCallOp(PrintStream& out, int location, const Instruction*& it, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap&);
     void printPutByIdOp(PrintStream& out, int location, const Instruction*& it, const char* op);
index 5628df5..16f1fb6 100644 (file)
@@ -80,7 +80,8 @@
             { "name" : "op_is_object_or_null", "length" : 3 },
             { "name" : "op_is_function", "length" : 3 },
             { "name" : "op_is_cell_with_type", "length" : 4 },
-            { "name" : "op_in", "length" : 5 },
+            { "name" : "op_in_by_val", "length" : 5 },
+            { "name" : "op_in_by_id", "length" : 4 },
             { "name" : "op_get_array_length", "length" : 9 },
             { "name" : "op_get_by_id", "length" : 9  },
             { "name" : "op_get_by_id_proto_load", "length" : 9 },
index 701d36c..db522ac 100644 (file)
@@ -186,6 +186,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     case op_get_by_id_unset:
     case op_get_by_id_direct:
     case op_get_array_length:
+    case op_in_by_id:
     case op_typeof:
     case op_is_empty:
     case op_is_undefined:
@@ -226,7 +227,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     case op_enumerator_structure_pname:
     case op_enumerator_generic_pname:
     case op_get_by_val:
-    case op_in:
+    case op_in_by_val:
     case op_overrides_has_instance:
     case op_instanceof:
     case op_add:
@@ -454,7 +455,8 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     case op_is_object_or_null:
     case op_is_cell_with_type:
     case op_is_function:
-    case op_in:
+    case op_in_by_id:
+    case op_in_by_val:
     case op_to_number:
     case op_to_string:
     case op_to_object:
index 8f1a4bd..cce0b6a 100644 (file)
@@ -589,7 +589,7 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
             break;
         }
 
-        case op_in:
+        case op_in_by_val:
         case op_put_by_val:
         case op_put_by_val_direct: {
             int arrayProfileIndex = pc[opLength - 1].u.operand;
index 9130b1e..660e52c 100644 (file)
@@ -276,6 +276,25 @@ bool InlineAccess::generateArrayLength(StructureStubInfo& stubInfo, JSArray* arr
     return linkedCodeInline;
 }
 
+bool InlineAccess::generateSelfInAccess(StructureStubInfo& stubInfo, Structure* structure)
+{
+    CCallHelpers jit;
+
+    GPRReg base = static_cast<GPRReg>(stubInfo.patch.baseGPR);
+    JSValueRegs value = stubInfo.valueRegs();
+
+    auto branchToSlowPath = jit.patchableBranch32(
+        MacroAssembler::NotEqual,
+        MacroAssembler::Address(base, JSCell::structureIDOffset()),
+        MacroAssembler::TrustedImm32(bitwise_cast<uint32_t>(structure->id())));
+    jit.boxBoolean(true, value);
+
+    bool linkedCodeInline = linkCodeInline("in access", jit, stubInfo, [&] (LinkBuffer& linkBuffer) {
+        linkBuffer.link(branchToSlowPath, stubInfo.slowPathStartLocation());
+    });
+    return linkedCodeInline;
+}
+
 void InlineAccess::rewireStubAsJump(StructureStubInfo& stubInfo, CodeLocationLabel<JITStubRoutinePtrTag> target)
 {
     CCallHelpers jit;
index 9948b3b..a4d0335 100644 (file)
@@ -116,6 +116,7 @@ public:
     static bool isCacheableArrayLength(StructureStubInfo&, JSArray*);
     static bool generateArrayLength(StructureStubInfo&, JSArray*);
     static void rewireStubAsJump(StructureStubInfo&, CodeLocationLabel<JITStubRoutinePtrTag>);
+    static bool generateSelfInAccess(StructureStubInfo&, Structure*);
 
     // This is helpful when determining the size of an IC on
     // various platforms. When adding a new type of IC, implement
index 45e587b..8351539 100644 (file)
@@ -82,6 +82,15 @@ void StructureStubInfo::initPutByIdReplace(CodeBlock* codeBlock, Structure* base
     u.byIdSelf.offset = offset;
 }
 
+void StructureStubInfo::initInByIdSelf(CodeBlock* codeBlock, Structure* baseObjectStructure, PropertyOffset offset)
+{
+    cacheType = CacheType::InByIdSelf;
+
+    u.byIdSelf.baseObjectStructure.set(
+        *codeBlock->vm(), codeBlock, baseObjectStructure);
+    u.byIdSelf.offset = offset;
+}
+
 void StructureStubInfo::deref()
 {
     switch (cacheType) {
@@ -91,6 +100,7 @@ void StructureStubInfo::deref()
     case CacheType::Unset:
     case CacheType::GetByIdSelf:
     case CacheType::PutByIdReplace:
+    case CacheType::InByIdSelf:
     case CacheType::ArrayLength:
         return;
     }
@@ -107,6 +117,7 @@ void StructureStubInfo::aboutToDie()
     case CacheType::Unset:
     case CacheType::GetByIdSelf:
     case CacheType::PutByIdReplace:
+    case CacheType::InByIdSelf:
     case CacheType::ArrayLength:
         return;
     }
@@ -237,7 +248,7 @@ void StructureStubInfo::reset(CodeBlock* codeBlock)
         resetPutByID(codeBlock, *this);
         break;
     case AccessType::In:
-        resetIn(*this);
+        resetInByID(codeBlock, *this);
         break;
     case AccessType::InstanceOf:
         resetInstanceOf(*this);
@@ -260,6 +271,7 @@ void StructureStubInfo::visitWeakReferences(CodeBlock* codeBlock)
     switch (cacheType) {
     case CacheType::GetByIdSelf:
     case CacheType::PutByIdReplace:
+    case CacheType::InByIdSelf:
         if (Heap::isMarked(u.byIdSelf.baseObjectStructure.get()))
             return;
         break;
@@ -283,6 +295,7 @@ bool StructureStubInfo::propagateTransitions(SlotVisitor& visitor)
         return true;
     case CacheType::GetByIdSelf:
     case CacheType::PutByIdReplace:
+    case CacheType::InByIdSelf:
         return u.byIdSelf.baseObjectStructure->markIfCheap(visitor);
     case CacheType::Stub:
         return u.stub->propagateTransitions(visitor);
index 3afe3ba..133b604 100644 (file)
@@ -58,6 +58,7 @@ enum class CacheType : int8_t {
     Unset,
     GetByIdSelf,
     PutByIdReplace,
+    InByIdSelf,
     Stub,
     ArrayLength
 };
@@ -72,6 +73,7 @@ public:
     void initGetByIdSelf(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
     void initArrayLength();
     void initPutByIdReplace(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
+    void initInByIdSelf(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
 
     AccessGenerationResult addAccessCase(const GCSafeConcurrentJSLocker&, CodeBlock*, const Identifier&, std::unique_ptr<AccessCase>);
 
@@ -176,7 +178,7 @@ public:
     StructureSet bufferedStructures;
     
     struct {
-        CodeLocationLabel<JITStubRoutinePtrTag> start; // This is either the start of the inline IC for *byId caches, or the location of patchable jump for 'in' and 'instanceof' caches.
+        CodeLocationLabel<JITStubRoutinePtrTag> start; // This is either the start of the inline IC for *byId caches. or the location of patchable jump for 'instanceof' caches.
         RegisterSet usedRegisters;
         uint32_t inlineSize;
         int32_t deltaFromStartToSlowPathCallLocation;
@@ -197,7 +199,7 @@ public:
     CodeLocationLabel<JITStubRoutinePtrTag> slowPathStartLocation() { return patch.start.labelAtOffset(patch.deltaFromStartToSlowPathStart); }
     CodeLocationJump<JSInternalPtrTag> patchableJump()
     { 
-        ASSERT(accessType == AccessType::In || accessType == AccessType::InstanceOf);
+        ASSERT(accessType == AccessType::InstanceOf);
         return patch.start.jumpAtOffset<JSInternalPtrTag>(0);
     }
 
index 6d6449b..e199e8f 100644 (file)
@@ -2667,10 +2667,10 @@ RegisterID* BytecodeGenerator::emitInstanceOfCustom(RegisterID* dst, RegisterID*
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitIn(RegisterID* dst, RegisterID* property, RegisterID* base)
+RegisterID* BytecodeGenerator::emitInByVal(RegisterID* dst, RegisterID* property, RegisterID* base)
 {
     UnlinkedArrayProfile arrayProfile = newArrayProfile();
-    emitOpcode(op_in);
+    emitOpcode(op_in_by_val);
     instructions().append(dst->index());
     instructions().append(base->index());
     instructions().append(property->index());
@@ -2678,6 +2678,15 @@ RegisterID* BytecodeGenerator::emitIn(RegisterID* dst, RegisterID* property, Reg
     return dst;
 }
 
+RegisterID* BytecodeGenerator::emitInById(RegisterID* dst, RegisterID* base, const Identifier& property)
+{
+    emitOpcode(op_in_by_id);
+    instructions().append(dst->index());
+    instructions().append(base->index());
+    instructions().append(addConstant(property));
+    return dst;
+}
+
 RegisterID* BytecodeGenerator::emitTryGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
 {
     ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties are not supported with tryGetById.");
index b7255ac..97828ca 100644 (file)
@@ -694,7 +694,8 @@ namespace JSC {
         RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype);
         RegisterID* emitInstanceOfCustom(RegisterID* dst, RegisterID* value, RegisterID* constructor, RegisterID* hasInstanceValue);
         RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
-        RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base);
+        RegisterID* emitInByVal(RegisterID* dst, RegisterID* property, RegisterID* base);
+        RegisterID* emitInById(RegisterID* dst, RegisterID* base, const Identifier& property);
 
         RegisterID* emitTryGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
         RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
index 07a9c90..a5fa525 100644 (file)
@@ -2280,10 +2280,16 @@ RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterI
 
 RegisterID* InNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
+    if (isNonIndexStringElement(*m_expr1)) {
+        RefPtr<RegisterID> base = generator.emitNode(m_expr2);
+        generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+        return generator.emitInById(generator.finalDestination(dst, base.get()), base.get(), static_cast<StringNode*>(m_expr1)->value());
+    }
+
     RefPtr<RegisterID> key = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator));
     RefPtr<RegisterID> base = generator.emitNode(m_expr2);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    return generator.emitIn(generator.finalDestination(dst, key.get()), key.get(), base.get());
+    return generator.emitInByVal(generator.finalDestination(dst, key.get()), key.get(), base.get());
 }
 
 
index 1cdbb0b..c4c92dd 100644 (file)
@@ -3259,10 +3259,30 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         clobberWorld();
         break;
         
-    case In: {
+    case InById: {
         // FIXME: We can determine when the property definitely exists based on abstract
         // value information.
         clobberWorld();
+        filter(node->child1(), SpecObject);
+        setNonCellTypeForNode(node, SpecBoolean);
+        break;
+    }
+
+    case InByVal: {
+        AbstractValue& property = forNode(node->child2());
+        if (JSValue constant = property.value()) {
+            if (constant.isString()) {
+                JSString* string = asString(constant);
+                const StringImpl* impl = string->tryGetValueImpl();
+                if (impl && impl->isAtomic())
+                    m_state.setFoundConstants(true);
+            }
+        }
+
+        // FIXME: We can determine when the property definitely exists based on abstract
+        // value information.
+        clobberWorld();
+        filter(node->child1(), SpecObject);
         setNonCellTypeForNode(node, SpecBoolean);
         break;
     }
index 77a3c61..fa097f3 100644 (file)
@@ -6392,11 +6392,20 @@ void ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_to_object);
         }
 
-        case op_in: {
-            ArrayMode arrayMode = getArrayMode(currentInstruction[OPCODE_LENGTH(op_in) - 1].u.arrayProfile);
+        case op_in_by_val: {
+            ArrayMode arrayMode = getArrayMode(currentInstruction[OPCODE_LENGTH(op_in_by_val) - 1].u.arrayProfile);
             set(VirtualRegister(currentInstruction[1].u.operand),
-                addToGraph(In, OpInfo(arrayMode.asWord()), get(VirtualRegister(currentInstruction[2].u.operand)), get(VirtualRegister(currentInstruction[3].u.operand))));
-            NEXT_OPCODE(op_in);
+                addToGraph(InByVal, OpInfo(arrayMode.asWord()), get(VirtualRegister(currentInstruction[2].u.operand)), get(VirtualRegister(currentInstruction[3].u.operand))));
+            NEXT_OPCODE(op_in_by_val);
+        }
+
+        case op_in_by_id: {
+            Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
+            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
+            set(VirtualRegister(currentInstruction[1].u.operand),
+                addToGraph(InById, OpInfo(identifierNumber), base));
+            NEXT_OPCODE(op_in_by_id);
+            break;
         }
 
         case op_get_enumerable_length: {
index 5cee65b..dadc92d 100644 (file)
@@ -236,7 +236,8 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_to_object:
     case op_switch_imm:
     case op_switch_char:
-    case op_in:
+    case op_in_by_val:
+    case op_in_by_id:
     case op_get_scope:
     case op_get_from_scope:
     case op_get_enumerable_length:
index 628f8a9..3ea02a8 100644 (file)
@@ -623,7 +623,8 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case ConstructVarargs:
     case ConstructForwardVarargs:
     case ToPrimitive:
-    case In:
+    case InByVal:
+    case InById:
     case HasOwnProperty:
     case ValueAdd:
     case SetFunctionName:
index 6d211ae..757c9b4 100644 (file)
@@ -651,6 +651,23 @@ private:
                 break;
             }
 
+            case InByVal: {
+                AbstractValue& property = m_state.forNode(node->child2());
+                if (JSValue constant = property.value()) {
+                    if (constant.isString()) {
+                        JSString* string = asString(constant);
+                        const StringImpl* impl = string->tryGetValueImpl();
+                        if (impl && impl->isAtomic()) {
+                            unsigned identifierNumber = m_graph.identifiers().ensure(const_cast<UniquedStringImpl*>(static_cast<const UniquedStringImpl*>(impl)));
+                            node->convertToInById(identifierNumber);
+                            changed = true;
+                            break;
+                        }
+                    }
+                }
+                break;
+            }
+
             case ToPrimitive: {
                 if (m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol | SpecBigInt))
                     break;
index fcd1b72..fdf2e77 100644 (file)
@@ -193,7 +193,8 @@ bool doesGC(Graph& graph, Node* node)
     case CallStringConstructor:
     case NumberToStringWithRadix:
     case NumberToStringWithValidRadixConstant:
-    case In:
+    case InByVal:
+    case InById:
     case HasOwnProperty:
     case Jump:
     case Branch:
index f4e9161..ecbb3d3 100644 (file)
@@ -1476,7 +1476,12 @@ private:
             fixEdge<CellUse>(node->child2());
             break;
 
-        case In: {
+        case InById: {
+            fixEdge<CellUse>(node->child1());
+            break;
+        }
+
+        case InByVal: {
             if (node->child2()->shouldSpeculateInt32()) {
                 convertToHasIndexedProperty(node);
                 break;
index 5e5a7a8..5fd50b8 100644 (file)
@@ -265,26 +265,9 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
     finalizeInlineCaches(m_getByIds, linkBuffer);
     finalizeInlineCaches(m_getByIdsWithThis, linkBuffer);
     finalizeInlineCaches(m_putByIds, linkBuffer);
+    finalizeInlineCaches(m_inByIds, linkBuffer);
     finalizeInlineCaches(m_instanceOfs, linkBuffer);
 
-    for (unsigned i = 0; i < m_ins.size(); ++i) {
-        StructureStubInfo& info = *m_ins[i].m_stubInfo;
-
-        CodeLocationLabel<JITStubRoutinePtrTag> start = linkBuffer.locationOf<JITStubRoutinePtrTag>(m_ins[i].m_jump);
-        info.patch.start = start;
-
-        ptrdiff_t inlineSize = MacroAssembler::differenceBetweenCodePtr(
-            start, linkBuffer.locationOf<JSInternalPtrTag>(m_ins[i].m_done));
-        RELEASE_ASSERT(inlineSize >= 0);
-        info.patch.inlineSize = inlineSize;
-
-        info.patch.deltaFromStartToSlowPathCallLocation = MacroAssembler::differenceBetweenCodePtr(
-            start, linkBuffer.locationOf<JSInternalPtrTag>(m_ins[i].m_slowPathGenerator->call()));
-
-        info.patch.deltaFromStartToSlowPathStart = MacroAssembler::differenceBetweenCodePtr(
-            start, linkBuffer.locationOf<JSInternalPtrTag>(m_ins[i].m_slowPathGenerator->label()));
-    }
-    
     auto linkCallThunk = FunctionPtr<NoPtrTag>(vm()->getCTIStub(linkCallThunkGenerator).retaggedCode<NoPtrTag>());
     for (auto& record : m_jsCalls) {
         CallLinkInfo& info = *record.info;
index 050eb7c..c17b032 100644 (file)
@@ -76,23 +76,6 @@ struct CallLinkRecord {
     FunctionPtr<OperationPtrTag> m_function;
 };
 
-struct InRecord {
-    InRecord(
-        MacroAssembler::PatchableJump jump, MacroAssembler::Label done,
-        SlowPathGenerator* slowPathGenerator, StructureStubInfo* stubInfo)
-        : m_jump(jump)
-        , m_done(done)
-        , m_slowPathGenerator(slowPathGenerator)
-        , m_stubInfo(stubInfo)
-    {
-    }
-    
-    MacroAssembler::PatchableJump m_jump;
-    MacroAssembler::Label m_done;
-    SlowPathGenerator* m_slowPathGenerator;
-    StructureStubInfo* m_stubInfo;
-};
-
 // === JITCompiler ===
 //
 // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
@@ -209,11 +192,11 @@ public:
         m_instanceOfs.append(InlineCacheWrapper<JITInstanceOfGenerator>(gen, slowPath));
     }
 
-    void addIn(const InRecord& record)
+    void addInById(const JITInByIdGenerator& gen, SlowPathGenerator* slowPath)
     {
-        m_ins.append(record);
+        m_inByIds.append(InlineCacheWrapper<JITInByIdGenerator>(gen, slowPath));
     }
-    
+
     void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo* info)
     {
         m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, info));
@@ -359,8 +342,8 @@ private:
     Vector<InlineCacheWrapper<JITGetByIdGenerator>, 4> m_getByIds;
     Vector<InlineCacheWrapper<JITGetByIdWithThisGenerator>, 4> m_getByIdsWithThis;
     Vector<InlineCacheWrapper<JITPutByIdGenerator>, 4> m_putByIds;
+    Vector<InlineCacheWrapper<JITInByIdGenerator>, 4> m_inByIds;
     Vector<InlineCacheWrapper<JITInstanceOfGenerator>, 4> m_instanceOfs;
-    Vector<InRecord, 4> m_ins;
     Vector<JSCallRecord, 4> m_jsCalls;
     Vector<JSDirectCallRecord, 4> m_jsDirectCalls;
     Vector<JSDirectTailCallRecord, 4> m_jsDirectTailCalls;
index 5cad0aa..6236309 100644 (file)
@@ -752,6 +752,15 @@ public:
         setOp(SetRegExpObjectLastIndex);
         m_opInfo = false;
     }
+
+    void convertToInById(unsigned identifierNumber)
+    {
+        ASSERT(m_op == InByVal);
+        setOpAndDefaultFlags(InById);
+        children.setChild2(Edge());
+        m_opInfo = identifierNumber;
+        m_opInfo2 = OpInfoWrapper();
+    }
     
     JSValue asJSValue()
     {
@@ -1019,6 +1028,7 @@ public:
         case PutSetterById:
         case PutGetterSetterById:
         case DeleteById:
+        case InById:
         case GetDynamicVar:
         case PutDynamicVar:
         case ResolveScopeForHoistingFuncDeclInEval:
@@ -1987,7 +1997,7 @@ public:
         case GetIndexedPropertyStorage:
         case GetArrayLength:
         case GetVectorLength:
-        case In:
+        case InByVal:
         case PutByValDirect:
         case PutByVal:
         case PutByValAlias:
index 90e4ef3..531711b 100644 (file)
@@ -370,7 +370,8 @@ namespace JSC { namespace DFG {
     macro(NumberToStringWithValidRadixConstant, NodeResultJS) \
     macro(NewStringObject, NodeResultJS) \
     macro(MakeRope, NodeResultJS) \
-    macro(In, NodeResultBoolean | NodeMustGenerate) \
+    macro(InByVal, NodeResultBoolean | NodeMustGenerate) \
+    macro(InById, NodeResultBoolean | NodeMustGenerate) \
     macro(ProfileType, NodeMustGenerate) \
     macro(ProfileControlFlow, NodeMustGenerate) \
     macro(SetFunctionName, NodeMustGenerate) \
index 0d0e717..9c661f9 100644 (file)
@@ -981,7 +981,8 @@ private:
             setPrediction(SpecObjectOther);
             break;
 
-        case In:
+        case InByVal:
+        case InById:
             setPrediction(SpecBoolean);
             break;
 
index 26f6c4c..d6d026c 100644 (file)
@@ -332,7 +332,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case CallStringConstructor:
     case NewStringObject:
     case MakeRope:
-    case In:
+    case InByVal:
+    case InById:
     case HasOwnProperty:
     case PushWithScope:
     case CreateActivation:
index 975e5ac..1d56d46 100644 (file)
@@ -1056,67 +1056,52 @@ void SpeculativeJIT::compileGetByIdFlush(Node* node, AccessType accessType)
     }
 }
 
-void SpeculativeJIT::compileIn(Node* node)
+void SpeculativeJIT::compileInById(Node* node)
 {
     SpeculateCellOperand base(this, node->child1());
+    JSValueRegsTemporary result(this, Reuse, base, PayloadWord);
+
     GPRReg baseGPR = base.gpr();
-    
-    if (JSString* string = node->child2()->dynamicCastConstant<JSString*>(*m_jit.vm())) {
-        if (string->tryGetValueImpl() && string->tryGetValueImpl()->isAtomic()) {
-            StructureStubInfo* stubInfo = m_jit.codeBlock()->addStubInfo(AccessType::In);
-            
-            GPRTemporary result(this);
-            GPRReg resultGPR = result.gpr();
+    JSValueRegs resultRegs = result.regs();
 
-            use(node->child2());
-            
-            MacroAssembler::PatchableJump jump = m_jit.patchableJump();
-            MacroAssembler::Label done = m_jit.label();
-            
-            // Since this block is executed only when the result of string->tryGetValueImpl() is atomic,
-            // we can cast it to const AtomicStringImpl* safely.
-            auto slowPath = slowPathCall(
-                jump.m_jump, this, operationInOptimize,
-                JSValueRegs::payloadOnly(resultGPR), stubInfo, baseGPR,
-                static_cast<const AtomicStringImpl*>(string->tryGetValueImpl()));
-            
-            stubInfo->callSiteIndex = m_jit.addCallSite(node->origin.semantic);
-            stubInfo->codeOrigin = node->origin.semantic;
-            stubInfo->patch.baseGPR = static_cast<int8_t>(baseGPR);
-            stubInfo->patch.valueGPR = static_cast<int8_t>(resultGPR);
-            stubInfo->patch.thisGPR = static_cast<int8_t>(InvalidGPRReg);
-#if USE(JSVALUE32_64)
-            stubInfo->patch.valueTagGPR = static_cast<int8_t>(InvalidGPRReg);
-            stubInfo->patch.baseTagGPR = static_cast<int8_t>(InvalidGPRReg);
-            stubInfo->patch.thisTagGPR = static_cast<int8_t>(InvalidGPRReg);
-#endif
-            stubInfo->patch.usedRegisters = usedRegisters();
+    base.use();
 
-            m_jit.addIn(InRecord(jump, done, slowPath.get(), stubInfo));
-            addSlowPathGenerator(WTFMove(slowPath));
+    CodeOrigin codeOrigin = node->origin.semantic;
+    CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
+    RegisterSet usedRegisters = this->usedRegisters();
+    JITInByIdGenerator gen(
+        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, identifierUID(node->identifierNumber()),
+        JSValueRegs::payloadOnly(baseGPR), resultRegs);
+    gen.generateFastPath(m_jit);
 
-            base.use();
+    auto slowPath = slowPathCall(
+        gen.slowPathJump(), this, operationInByIdOptimize,
+        NeedToSpill, ExceptionCheckRequirement::CheckNeeded,
+        resultRegs, gen.stubInfo(), CCallHelpers::CellValue(baseGPR), identifierUID(node->identifierNumber()));
 
-            blessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
-            return;
-        }
-    }
+    m_jit.addInById(gen, slowPath.get());
+    addSlowPathGenerator(WTFMove(slowPath));
 
+    blessedBooleanResult(resultRegs.payloadGPR(), node, UseChildrenCalledExplicitly);
+}
+
+void SpeculativeJIT::compileInByVal(Node* node)
+{
+    SpeculateCellOperand base(this, node->child1());
     JSValueOperand key(this, node->child2());
+
+    GPRReg baseGPR = base.gpr();
     JSValueRegs regs = key.jsValueRegs();
-        
-    GPRFlushedCallResult result(this);
-    GPRReg resultGPR = result.gpr();
-        
+
     base.use();
     key.use();
-        
+
     flushRegisters();
-    callOperation(
-        operationGenericIn, extractResult(JSValueRegs::payloadOnly(resultGPR)),
-        baseGPR, regs);
+    JSValueRegsFlushedCallResult result(this);
+    JSValueRegs resultRegs = result.regs();
+    callOperation(operationInByVal, resultRegs, baseGPR, regs);
     m_jit.exceptionCheck();
-    blessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
+    blessedBooleanResult(resultRegs.payloadGPR(), node, UseChildrenCalledExplicitly);
 }
 
 void SpeculativeJIT::compileDeleteById(Node* node)
index 77a63b1..05a08ea 100644 (file)
@@ -735,7 +735,8 @@ public:
     void compilePushWithScope(Node*);
     void compileGetById(Node*, AccessType);
     void compileGetByIdFlush(Node*, AccessType);
-    void compileIn(Node*);
+    void compileInById(Node*);
+    void compileInByVal(Node*);
     
     void nonSpeculativeNonPeepholeCompareNullOrUndefined(Edge operand);
     void nonSpeculativePeepholeBranchNullOrUndefined(Edge operand, Node* branchNode);
index a303c3f..272c57a 100644 (file)
@@ -3756,8 +3756,12 @@ void SpeculativeJIT::compile(Node* node)
         compileSetFunctionName(node);
         break;
 
-    case In:
-        compileIn(node);
+    case InById:
+        compileInById(node);
+        break;
+
+    case InByVal:
+        compileInByVal(node);
         break;
 
     case HasOwnProperty: {
index 06a46ba..50f2645 100644 (file)
@@ -4306,8 +4306,12 @@ void SpeculativeJIT::compile(Node* node)
         compileSetFunctionName(node);
         break;
 
-    case In:
-        compileIn(node);
+    case InById:
+        compileInById(node);
+        break;
+
+    case InByVal:
+        compileInByVal(node);
         break;
 
     case HasOwnProperty: {
index 9cdd119..f1513bb 100644 (file)
@@ -205,7 +205,8 @@ inline CapabilityLevel canCompile(Node* node)
     case Throw:
     case ThrowStaticError:
     case Unreachable:
-    case In:
+    case InByVal:
+    case InById:
     case HasOwnProperty:
     case IsCellWithType:
     case MapHash:
index 3247d2a..911d62a 100644 (file)
@@ -708,8 +708,11 @@ private:
         case GetByIdDirectFlush:
             compileGetById(AccessType::GetDirect);
             break;
-        case In:
-            compileIn();
+        case InById:
+            compileInById();
+            break;
+        case InByVal:
+            compileInByVal();
             break;
         case HasOwnProperty:
             compileHasOwnProperty();
@@ -9713,87 +9716,70 @@ private:
         setJSValue(m_out.phi(Int64, results));
     }
     
-    void compileIn()
+    void compileInByVal()
     {
-        DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == CellUse, m_node->child1().useKind());
+        setJSValue(vmCall(Int64, m_out.operation(operationInByVal), m_callFrame, lowCell(m_node->child1()), lowJSValue(m_node->child2())));
+    }
 
+    void compileInById()
+    {
         Node* node = m_node;
-        Edge base = node->child1();
-        LValue cell = lowCell(base);
-        if (JSString* string = node->child2()->dynamicCastConstant<JSString*>(vm())) {
-            if (string->tryGetValueImpl() && string->tryGetValueImpl()->isAtomic()) {
-                UniquedStringImpl* str = bitwise_cast<UniquedStringImpl*>(string->tryGetValueImpl());
-                PatchpointValue* patchpoint = m_out.patchpoint(Int64);
-                patchpoint->appendSomeRegister(cell);
-                patchpoint->append(m_tagMask, ValueRep::lateReg(GPRInfo::tagMaskRegister));
-                patchpoint->append(m_tagTypeNumber, ValueRep::lateReg(GPRInfo::tagTypeNumberRegister));
-                patchpoint->clobber(RegisterSet::macroScratchRegisters());
-
-                RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint);
-
-                State* state = &m_ftlState;
-                patchpoint->setGenerator(
-                    [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+        UniquedStringImpl* uid = m_graph.identifiers()[node->identifierNumber()];
+        LValue base = lowCell(m_node->child1());
+
+        PatchpointValue* patchpoint = m_out.patchpoint(Int64);
+        patchpoint->appendSomeRegister(base);
+        patchpoint->append(m_tagMask, ValueRep::lateReg(GPRInfo::tagMaskRegister));
+        patchpoint->append(m_tagTypeNumber, ValueRep::lateReg(GPRInfo::tagTypeNumberRegister));
+
+        patchpoint->clobber(RegisterSet::macroScratchRegisters());
+
+        RefPtr<PatchpointExceptionHandle> exceptionHandle =
+            preparePatchpointForExceptions(patchpoint);
+
+        State* state = &m_ftlState;
+        patchpoint->setGenerator(
+            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                AllowMacroScratchRegisterUsage allowScratch(jit);
+
+                CallSiteIndex callSiteIndex =
+                    state->jitCode->common.addUniqueCallSiteIndex(node->origin.semantic);
+
+                // This is the direct exit target for operation calls.
+                Box<CCallHelpers::JumpList> exceptions =
+                    exceptionHandle->scheduleExitCreation(params)->jumps(jit);
+
+                auto generator = Box<JITInByIdGenerator>::create(
+                    jit.codeBlock(), node->origin.semantic, callSiteIndex,
+                    params.unavailableRegisters(), uid, JSValueRegs(params[1].gpr()),
+                    JSValueRegs(params[0].gpr()));
+
+                generator->generateFastPath(jit);
+                CCallHelpers::Label done = jit.label();
+
+                params.addLatePath(
+                    [=] (CCallHelpers& jit) {
                         AllowMacroScratchRegisterUsage allowScratch(jit);
 
-                        // This is the direct exit target for operation calls. We don't need a JS exceptionHandle because we don't
-                        // cache Proxy objects.
-                        Box<CCallHelpers::JumpList> exceptions = exceptionHandle->scheduleExitCreation(params)->jumps(jit);
-
-                        GPRReg baseGPR = params[1].gpr();
-                        GPRReg resultGPR = params[0].gpr();
-
-                        StructureStubInfo* stubInfo =
-                            jit.codeBlock()->addStubInfo(AccessType::In);
-                        stubInfo->callSiteIndex =
-                            state->jitCode->common.addCodeOrigin(node->origin.semantic);
-                        stubInfo->codeOrigin = node->origin.semantic;
-                        stubInfo->patch.baseGPR = static_cast<int8_t>(baseGPR);
-                        stubInfo->patch.valueGPR = static_cast<int8_t>(resultGPR);
-                        stubInfo->patch.thisGPR = static_cast<int8_t>(InvalidGPRReg);
-                        stubInfo->patch.usedRegisters = params.unavailableRegisters();
-
-                        CCallHelpers::PatchableJump jump = jit.patchableJump();
-                        CCallHelpers::Label done = jit.label();
-
-                        params.addLatePath(
-                            [=] (CCallHelpers& jit) {
-                                AllowMacroScratchRegisterUsage allowScratch(jit);
-
-                                jump.m_jump.link(&jit);
-                                CCallHelpers::Label slowPathBegin = jit.label();
-                                CCallHelpers::Call slowPathCall = callOperation(
-                                    *state, params.unavailableRegisters(), jit,
-                                    node->origin.semantic, exceptions.get(), operationInOptimize,
-                                    resultGPR, CCallHelpers::TrustedImmPtr(stubInfo), baseGPR,
-                                    CCallHelpers::TrustedImmPtr(str)).call();
-                                jit.jump().linkTo(done, &jit);
-
-                                jit.addLinkTask(
-                                    [=] (LinkBuffer& linkBuffer) {
-                                        CodeLocationLabel<JITStubRoutinePtrTag> start = linkBuffer.locationOf<JITStubRoutinePtrTag>(jump);
-                                        stubInfo->patch.start = start;
-                                        ptrdiff_t inlineSize = MacroAssembler::differenceBetweenCodePtr(
-                                            start, linkBuffer.locationOf<NoPtrTag>(done));
-                                        RELEASE_ASSERT(inlineSize >= 0);
-                                        stubInfo->patch.inlineSize = inlineSize;
-
-                                        stubInfo->patch.deltaFromStartToSlowPathCallLocation = MacroAssembler::differenceBetweenCodePtr(
-                                            start, linkBuffer.locationOf<NoPtrTag>(slowPathCall));
-
-                                        stubInfo->patch.deltaFromStartToSlowPathStart = MacroAssembler::differenceBetweenCodePtr(
-                                            start, linkBuffer.locationOf<NoPtrTag>(slowPathBegin));
-
-                                    });
+                        generator->slowPathJump().link(&jit);
+                        CCallHelpers::Label slowPathBegin = jit.label();
+                        CCallHelpers::Call slowPathCall = callOperation(
+                            *state, params.unavailableRegisters(), jit, node->origin.semantic,
+                            exceptions.get(), operationInByIdOptimize, params[0].gpr(),
+                            CCallHelpers::TrustedImmPtr(generator->stubInfo()), params[1].gpr(),
+                            CCallHelpers::TrustedImmPtr(uid)).call();
+                        jit.jump().linkTo(done, &jit);
+
+                        generator->reportSlowPathCall(slowPathBegin, slowPathCall);
+
+                        jit.addLinkTask(
+                            [=] (LinkBuffer& linkBuffer) {
+                                generator->finalize(linkBuffer, linkBuffer);
                             });
                     });
+            });
 
-                setJSValue(patchpoint);
-                return;
-            }
-        } 
-
-        setJSValue(vmCall(Int64, m_out.operation(operationGenericIn), m_callFrame, cell, lowJSValue(m_node->child2())));
+        setJSValue(patchpoint);
     }
 
     void compileHasOwnProperty()
index 5625199..aa6712f 100644 (file)
@@ -1336,6 +1336,14 @@ public:
 #endif
     }
 
+    void boxBoolean(bool value, JSValueRegs boxedRegs)
+    {
+        boxBooleanPayload(value, boxedRegs.payloadGPR());
+#if USE(JSVALUE32_64)
+        move(TrustedImm32(JSValue::BooleanTag), boxedRegs.tagGPR());
+#endif
+    }
+
     void boxInt32(GPRReg intGPR, JSValueRegs boxedRegs, TagRegistersMode mode = HaveTagRegisters)
     {
 #if USE(JSVALUE64)
index c1c2d4e..684e813 100644 (file)
@@ -50,9 +50,10 @@ namespace JSC {
     macro(OperationGetByIdBuildList) \
     macro(OperationGetByIdOptimize) \
     macro(OperationGetByIdWithThisOptimize) \
-    macro(OperationInOptimize) \
-    macro(OperationIn) \
     macro(OperationGenericIn) \
+    macro(OperationInById) \
+    macro(OperationInByIdGeneric) \
+    macro(OperationInByIdOptimize) \
     macro(OperationPutByIdStrict) \
     macro(OperationPutByIdNonStrict) \
     macro(OperationPutByIdDirectStrict) \
@@ -67,7 +68,8 @@ namespace JSC {
     macro(OperationPutByIdDirectNonStrictBuildList) \
     macro(PutByIdAddAccessCase) \
     macro(PutByIdReplaceWithJump) \
-    macro(PutByIdSelfPatch)
+    macro(PutByIdSelfPatch) \
+    macro(InByIdSelfPatch)
 
 class ICEvent {
 public:
index 199d81a..d9db062 100644 (file)
@@ -78,11 +78,6 @@ JIT::JIT(VM* vm, CodeBlock* codeBlock, unsigned loopOSREntryBytecodeOffset)
     , m_interpreter(vm->interpreter)
     , m_labels(codeBlock ? codeBlock->numberOfInstructions() : 0)
     , m_bytecodeOffset(std::numeric_limits<unsigned>::max())
-    , m_getByIdIndex(UINT_MAX)
-    , m_getByIdWithThisIndex(UINT_MAX)
-    , m_putByIdIndex(UINT_MAX)
-    , m_byValInstructionIndex(UINT_MAX)
-    , m_callLinkInfoIndex(UINT_MAX)
     , m_pcToCodeOriginMapBuilder(*vm)
     , m_canBeOptimized(false)
     , m_shouldEmitProfiling(false)
@@ -277,7 +272,7 @@ void JIT::privateCompileMainPass()
         unsigned bytecodeOffset = m_bytecodeOffset;
 
         switch (opcodeID) {
-        DEFINE_SLOW_OP(in)
+        DEFINE_SLOW_OP(in_by_val)
         DEFINE_SLOW_OP(less)
         DEFINE_SLOW_OP(lesseq)
         DEFINE_SLOW_OP(greater)
@@ -341,6 +336,7 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_below)
         DEFINE_OP(op_beloweq)
         DEFINE_OP(op_try_get_by_id)
+        DEFINE_OP(op_in_by_id)
         case op_get_array_length:
         case op_get_by_id_proto_load:
         case op_get_by_id_unset:
@@ -478,6 +474,7 @@ void JIT::privateCompileSlowCases()
     m_getByIdIndex = 0;
     m_getByIdWithThisIndex = 0;
     m_putByIdIndex = 0;
+    m_inByIdIndex = 0;
     m_instanceOfIndex = 0;
     m_byValInstructionIndex = 0;
     m_callLinkInfoIndex = 0;
@@ -521,6 +518,7 @@ void JIT::privateCompileSlowCases()
         DEFINE_SLOWCASE_OP(op_construct)
         DEFINE_SLOWCASE_OP(op_eq)
         DEFINE_SLOWCASE_OP(op_try_get_by_id)
+        DEFINE_SLOWCASE_OP(op_in_by_id)
         case op_get_array_length:
         case op_get_by_id_proto_load:
         case op_get_by_id_unset:
@@ -600,6 +598,7 @@ void JIT::privateCompileSlowCases()
     RELEASE_ASSERT(m_getByIdIndex == m_getByIds.size());
     RELEASE_ASSERT(m_getByIdWithThisIndex == m_getByIdsWithThis.size());
     RELEASE_ASSERT(m_putByIdIndex == m_putByIds.size());
+    RELEASE_ASSERT(m_inByIdIndex == m_inByIds.size());
     RELEASE_ASSERT(m_instanceOfIndex == m_instanceOfs.size());
     RELEASE_ASSERT(m_callLinkInfoIndex == m_callCompilationInfo.size());
     RELEASE_ASSERT(numberOfValueProfiles == m_codeBlock->numberOfValueProfiles());
@@ -842,6 +841,7 @@ CompilationResult JIT::link()
     finalizeInlineCaches(m_getByIds, patchBuffer);
     finalizeInlineCaches(m_getByIdsWithThis, patchBuffer);
     finalizeInlineCaches(m_putByIds, patchBuffer);
+    finalizeInlineCaches(m_inByIds, patchBuffer);
     finalizeInlineCaches(m_instanceOfs, patchBuffer);
 
     if (m_byValCompilationInfo.size()) {
index 156f1b5..b96aa22 100644 (file)
@@ -500,6 +500,7 @@ namespace JSC {
         void emit_op_get_arguments_length(Instruction*);
         void emit_op_get_by_val(Instruction*);
         void emit_op_get_argument_by_val(Instruction*);
+        void emit_op_in_by_id(Instruction*);
         void emit_op_init_lazy_reg(Instruction*);
         void emit_op_overrides_has_instance(Instruction*);
         void emit_op_instanceof(Instruction*);
@@ -611,6 +612,7 @@ namespace JSC {
         void emitSlow_op_get_arguments_length(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_get_argument_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_in_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_instanceof_custom(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_jless(Instruction*, Vector<SlowCaseEntry>::iterator&);
@@ -865,6 +867,7 @@ namespace JSC {
         Vector<JITGetByIdGenerator> m_getByIds;
         Vector<JITGetByIdWithThisGenerator> m_getByIdsWithThis;
         Vector<JITPutByIdGenerator> m_putByIds;
+        Vector<JITInByIdGenerator> m_inByIds;
         Vector<JITInstanceOfGenerator> m_instanceOfs;
         Vector<ByValCompilationInfo> m_byValCompilationInfo;
         Vector<CallCompilationInfo> m_callCompilationInfo;
@@ -878,12 +881,13 @@ namespace JSC {
         JumpList m_exceptionChecksWithCallFrameRollback;
         Label m_exceptionHandler;
 
-        unsigned m_getByIdIndex;
-        unsigned m_getByIdWithThisIndex;
-        unsigned m_putByIdIndex;
-        unsigned m_instanceOfIndex;
-        unsigned m_byValInstructionIndex;
-        unsigned m_callLinkInfoIndex;
+        unsigned m_getByIdIndex { UINT_MAX };
+        unsigned m_getByIdWithThisIndex { UINT_MAX };
+        unsigned m_putByIdIndex { UINT_MAX };
+        unsigned m_inByIdIndex { UINT_MAX };
+        unsigned m_instanceOfIndex { UINT_MAX };
+        unsigned m_byValInstructionIndex { UINT_MAX };
+        unsigned m_callLinkInfoIndex { UINT_MAX };
         
         Label m_arityCheck;
         std::unique_ptr<LinkBuffer> m_linkBuffer;
index 8f17e9e..2f96977 100644 (file)
@@ -166,6 +166,21 @@ V_JITOperation_ESsiJJI JITPutByIdGenerator::slowPathFunction()
     return operationPutByIdNonStrictOptimize;
 }
 
+JITInByIdGenerator::JITInByIdGenerator(
+    CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet& usedRegisters,
+    UniquedStringImpl* propertyName, JSValueRegs base, JSValueRegs value)
+    : JITByIdGenerator(codeBlock, codeOrigin, callSite, AccessType::In, usedRegisters, base, value)
+{
+    // FIXME: We are not supporting fast path for "length" property.
+    UNUSED_PARAM(propertyName);
+    RELEASE_ASSERT(base.payloadGPR() != value.tagGPR());
+}
+
+void JITInByIdGenerator::generateFastPath(MacroAssembler& jit)
+{
+    generateFastCommon(jit, InlineAccess::sizeForPropertyAccess());
+}
+
 JITInstanceOfGenerator::JITInstanceOfGenerator(
     CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSiteIndex,
     const RegisterSet& usedRegisters, GPRReg result, GPRReg value, GPRReg prototype,
index 07a08c8..b747b86 100644 (file)
@@ -143,6 +143,17 @@ private:
     PutKind m_putKind;
 };
 
+class JITInByIdGenerator : public JITByIdGenerator {
+public:
+    JITInByIdGenerator() { }
+
+    JITInByIdGenerator(
+        CodeBlock*, CodeOrigin, CallSiteIndex, const RegisterSet& usedRegisters, UniquedStringImpl* propertyName,
+        JSValueRegs base, JSValueRegs value);
+
+    void generateFastPath(MacroAssembler&);
+};
+
 class JITInstanceOfGenerator : public JITInlineCacheGenerator {
 public:
     JITInstanceOfGenerator() { }
index bf1677e..fa456fa 100644 (file)
@@ -377,64 +377,91 @@ EncodedJSValue JIT_OPERATION operationGetByIdWithThisOptimize(ExecState* exec, S
     }));
 }
 
-EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key)
+EncodedJSValue JIT_OPERATION operationInById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
 {
     SuperSamplerScope superSamplerScope(false);
-    
-    VM* vm = &exec->vm();
-    NativeCallFrameTracer tracer(vm, exec);
-    auto scope = DECLARE_THROW_SCOPE(*vm);
 
-    if (!base->isObject()) {
-        throwException(exec, scope, createInvalidInParameterError(exec, base));
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    stubInfo->tookSlowPath = true;
+
+    Identifier ident = Identifier::fromUid(&vm, uid);
+
+    JSValue baseValue = JSValue::decode(base);
+    if (!baseValue.isObject()) {
+        throwException(exec, scope, createInvalidInParameterError(exec, baseValue));
         return JSValue::encode(jsUndefined());
     }
-    
-    AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
+    JSObject* baseObject = asObject(baseValue);
 
-    Identifier ident = Identifier::fromUid(vm, key);
-    LOG_IC((ICEvent::OperationInOptimize, base->classInfo(*vm), ident));
-    PropertySlot slot(base, PropertySlot::InternalMethodType::HasProperty);
-    bool result = asObject(base)->getPropertySlot(exec, ident, slot);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    
-    RELEASE_ASSERT(accessType == stubInfo->accessType);
-    
-    if (stubInfo->considerCaching(exec->codeBlock(), asObject(base)->structure()))
-        repatchIn(exec, base, ident, result, slot, *stubInfo);
-    
-    return JSValue::encode(jsBoolean(result));
+    LOG_IC((ICEvent::OperationInById, baseObject->classInfo(vm), ident));
+
+    scope.release();
+    PropertySlot slot(baseObject, PropertySlot::InternalMethodType::HasProperty);
+    return JSValue::encode(jsBoolean(baseObject->getPropertySlot(exec, ident, slot)));
 }
 
-EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key)
+EncodedJSValue JIT_OPERATION operationInByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid)
 {
     SuperSamplerScope superSamplerScope(false);
-    
-    VM* vm = &exec->vm();
-    NativeCallFrameTracer tracer(vm, exec);
-    auto scope = DECLARE_THROW_SCOPE(*vm);
 
-    stubInfo->tookSlowPath = true;
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
 
-    if (!base->isObject()) {
-        throwException(exec, scope, createInvalidInParameterError(exec, base));
+    Identifier ident = Identifier::fromUid(&vm, uid);
+
+    JSValue baseValue = JSValue::decode(base);
+    if (!baseValue.isObject()) {
+        throwException(exec, scope, createInvalidInParameterError(exec, baseValue));
         return JSValue::encode(jsUndefined());
     }
+    JSObject* baseObject = asObject(baseValue);
+
+    LOG_IC((ICEvent::OperationInByIdGeneric, baseObject->classInfo(vm), ident));
+
+    scope.release();
+    PropertySlot slot(baseObject, PropertySlot::InternalMethodType::HasProperty);
+    return JSValue::encode(jsBoolean(baseObject->getPropertySlot(exec, ident, slot)));
+}
+
+EncodedJSValue JIT_OPERATION operationInByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
+{
+    SuperSamplerScope superSamplerScope(false);
+
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    Identifier ident = Identifier::fromUid(&vm, uid);
+
+    JSValue baseValue = JSValue::decode(base);
+    if (!baseValue.isObject()) {
+        throwException(exec, scope, createInvalidInParameterError(exec, baseValue));
+        return JSValue::encode(jsUndefined());
+    }
+    JSObject* baseObject = asObject(baseValue);
+
+    LOG_IC((ICEvent::OperationInByIdOptimize, baseObject->classInfo(vm), ident));
 
-    Identifier ident = Identifier::fromUid(vm, key);
-    LOG_IC((ICEvent::OperationIn, base->classInfo(*vm), ident));
     scope.release();
-    return JSValue::encode(jsBoolean(asObject(base)->hasProperty(exec, ident)));
+    PropertySlot slot(baseObject, PropertySlot::InternalMethodType::HasProperty);
+    bool found = baseObject->getPropertySlot(exec, ident, slot);
+    if (stubInfo->considerCaching(exec->codeBlock(), baseObject->structure(vm)))
+        repatchInByID(exec, baseObject, ident, found, slot, *stubInfo);
+    return JSValue::encode(jsBoolean(found));
 }
 
-EncodedJSValue JIT_OPERATION operationGenericIn(ExecState* exec, JSCell* base, EncodedJSValue key)
+EncodedJSValue JIT_OPERATION operationInByVal(ExecState* exec, JSCell* base, EncodedJSValue key)
 {
     SuperSamplerScope superSamplerScope(false);
     
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    return JSValue::encode(jsBoolean(CommonSlowPaths::opIn(exec, base, JSValue::decode(key))));
+    return JSValue::encode(jsBoolean(CommonSlowPaths::opInByVal(exec, base, JSValue::decode(key))));
 }
 
 void JIT_OPERATION operationPutByIdStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
index 7a32669..6071e5d 100644 (file)
@@ -371,9 +371,12 @@ EncodedJSValue JIT_OPERATION operationGetByIdWithThisOptimize(ExecState*, Struct
 EncodedJSValue JIT_OPERATION operationGetByIdDirect(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByIdDirectGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByIdDirectOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationInById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationInByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationInByIdOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationInOptimize(ExecState*, StructureStubInfo*, JSCell*, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationIn(ExecState*, StructureStubInfo*, JSCell*, UniquedStringImpl*) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationGenericIn(ExecState*, JSCell*, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationInByVal(ExecState*, JSCell*, EncodedJSValue) WTF_INTERNAL;
 void JIT_OPERATION operationPutByIdStrict(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL;
 void JIT_OPERATION operationPutByIdNonStrict(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL;
 void JIT_OPERATION operationPutByIdDirectStrict(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL;
index 7e5d107..e636f71 100644 (file)
@@ -751,6 +751,42 @@ void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCase
     gen.reportSlowPathCall(coldPathBegin, call);
 }
 
+void JIT::emit_op_in_by_id(Instruction* currentInstruction)
+{
+    int resultVReg = currentInstruction[1].u.operand;
+    int baseVReg = currentInstruction[2].u.operand;
+    const Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
+
+    emitGetVirtualRegister(baseVReg, regT0);
+
+    emitJumpSlowCaseIfNotJSCell(regT0, baseVReg);
+
+    JITInByIdGenerator gen(
+        m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(m_bytecodeOffset), RegisterSet::stubUnavailableRegisters(),
+        ident->impl(), JSValueRegs(regT0), JSValueRegs(regT0));
+    gen.generateFastPath(*this);
+    addSlowCase(gen.slowPathJump());
+    m_inByIds.append(gen);
+
+    emitPutVirtualRegister(resultVReg);
+}
+
+void JIT::emitSlow_op_in_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    int resultVReg = currentInstruction[1].u.operand;
+    const Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
+
+    JITInByIdGenerator& gen = m_inByIds[m_inByIdIndex++];
+
+    Label coldPathBegin = label();
+
+    Call call = callOperation(operationInByIdOptimize, resultVReg, gen.stubInfo(), regT0, ident->impl());
+
+    gen.reportSlowPathCall(coldPathBegin, call);
+}
+
 void JIT::emitVarInjectionCheck(bool needsVarInjectionChecks)
 {
     if (!needsVarInjectionChecks)
index db2a472..a70a155 100644 (file)
@@ -771,6 +771,41 @@ void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCase
     gen.reportSlowPathCall(coldPathBegin, call);
 }
 
+void JIT::emit_op_in_by_id(Instruction* currentInstruction)
+{
+    int dst = currentInstruction[1].u.operand;
+    int base = currentInstruction[2].u.operand;
+    const Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
+
+    emitLoad(base, regT1, regT0);
+    emitJumpSlowCaseIfNotJSCell(base, regT1);
+
+    JITInByIdGenerator gen(
+        m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(currentInstruction), RegisterSet::stubUnavailableRegisters(),
+        ident->impl(), JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0));
+    gen.generateFastPath(*this);
+    addSlowCase(gen.slowPathJump());
+    m_inByIds.append(gen);
+
+    emitStore(dst, regT1, regT0);
+}
+
+void JIT::emitSlow_op_in_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    int resultVReg = currentInstruction[1].u.operand;
+    const Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
+
+    JITInByIdGenerator& gen = m_inByIds[m_inByIdIndex++];
+
+    Label coldPathBegin = label();
+
+    Call call = callOperation(operationInByIdOptimize, resultVReg, gen.stubInfo(), JSValueRegs(regT1, regT0), ident->impl());
+
+    gen.reportSlowPathCall(coldPathBegin, call);
+}
+
 void JIT::emitVarInjectionCheck(bool needsVarInjectionChecks)
 {
     if (!needsVarInjectionChecks)
index 14373bb..85ec0b2 100644 (file)
@@ -605,8 +605,8 @@ void repatchPutByID(ExecState* exec, JSValue baseValue, Structure* structure, co
     }
 }
 
-static InlineCacheAction tryCacheIn(
-    ExecState* exec, JSCell* base, const Identifier& ident,
+static InlineCacheAction tryCacheInByID(
+    ExecState* exec, JSObject* base, const Identifier& ident,
     bool wasFound, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
     VM& vm = exec->vm();
@@ -631,6 +631,26 @@ static InlineCacheAction tryCacheIn(
         std::unique_ptr<PolyProtoAccessChain> prototypeAccessChain;
         ObjectPropertyConditionSet conditionSet;
         if (wasFound) {
+            InlineCacheAction action = actionForCell(vm, base);
+            if (action != AttemptToCache)
+                return action;
+
+            // Optimize self access.
+            if (stubInfo.cacheType == CacheType::Unset
+                && slot.isCacheableValue()
+                && slot.slotBase() == base
+                && !slot.watchpointSet()
+                && !structure->needImpurePropertyWatchpoint()) {
+                bool generatedCodeInline = InlineAccess::generateSelfInAccess(stubInfo, structure);
+                if (generatedCodeInline) {
+                    LOG_IC((ICEvent::InByIdSelfPatch, structure->classInfo(), ident));
+                    structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset());
+                    ftlThunkAwareRepatchCall(codeBlock, stubInfo.slowPathCallLocation(), operationInByIdOptimize);
+                    stubInfo.initInByIdSelf(codeBlock, structure, slot.cachedOffset());
+                    return RetryCacheLater;
+                }
+            }
+
             if (slot.slotBase() != base) {
                 bool usesPolyProto;
                 prototypeAccessChain = PolyProtoAccessChain::create(exec->lexicalGlobalObject(), base, slot, usesPolyProto);
@@ -664,7 +684,7 @@ static InlineCacheAction tryCacheIn(
         LOG_IC((ICEvent::InAddAccessCase, structure->classInfo(), ident));
 
         std::unique_ptr<AccessCase> newCase = AccessCase::create(
-            vm, codeBlock, wasFound ? AccessCase::InHit : AccessCase::InMiss, invalidOffset, structure, conditionSet, WTFMove(prototypeAccessChain));
+            vm, codeBlock, wasFound ? AccessCase::InHit : AccessCase::InMiss, wasFound ? slot.cachedOffset() : invalidOffset, structure, conditionSet, WTFMove(prototypeAccessChain));
 
         result = stubInfo.addAccessCase(locker, codeBlock, ident, WTFMove(newCase));
 
@@ -672,10 +692,7 @@ static InlineCacheAction tryCacheIn(
             LOG_IC((ICEvent::InReplaceWithJump, structure->classInfo(), ident));
             
             RELEASE_ASSERT(result.code());
-
-            MacroAssembler::repatchJump(
-                stubInfo.patchableJump(),
-                CodeLocationLabel<JITStubRoutinePtrTag>(result.code()));
+            InlineAccess::rewireStubAsJump(stubInfo, CodeLocationLabel<JITStubRoutinePtrTag>(result.code()));
         }
     }
 
@@ -684,13 +701,14 @@ static InlineCacheAction tryCacheIn(
     return result.shouldGiveUpNow() ? GiveUpOnCache : RetryCacheLater;
 }
 
-void repatchIn(
-    ExecState* exec, JSCell* base, const Identifier& ident, bool wasFound,
-    const PropertySlot& slot, StructureStubInfo& stubInfo)
+void repatchInByID(ExecState* exec, JSObject* baseObject, const Identifier& propertyName, bool wasFound, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
     SuperSamplerScope superSamplerScope(false);
-    if (tryCacheIn(exec, base, ident, wasFound, slot, stubInfo) == GiveUpOnCache)
-        ftlThunkAwareRepatchCall(exec->codeBlock(), stubInfo.slowPathCallLocation(), operationIn);
+
+    if (tryCacheInByID(exec, baseObject, propertyName, wasFound, slot, stubInfo) == GiveUpOnCache) {
+        CodeBlock* codeBlock = exec->codeBlock();
+        ftlThunkAwareRepatchCall(codeBlock, stubInfo.slowPathCallLocation(), operationInById);
+    }
 }
 
 static InlineCacheAction tryCacheInstanceOf(
@@ -1236,9 +1254,10 @@ static void resetPatchableJump(StructureStubInfo& stubInfo)
     MacroAssembler::repatchJump(stubInfo.patchableJump(), stubInfo.slowPathStartLocation());
 }
 
-void resetIn(StructureStubInfo& stubInfo)
+void resetInByID(CodeBlock* codeBlock, StructureStubInfo& stubInfo)
 {
-    resetPatchableJump(stubInfo);
+    ftlThunkAwareRepatchCall(codeBlock, stubInfo.slowPathCallLocation(), operationInByIdOptimize);
+    InlineAccess::rewireStubAsJump(stubInfo, stubInfo.slowPathStartLocation());
 }
 
 void resetInstanceOf(StructureStubInfo& stubInfo)
index aa32c26..0f366dd 100644 (file)
@@ -44,7 +44,7 @@ void buildGetByIDList(ExecState*, JSValue, const Identifier&, const PropertySlot
 void buildGetByIDProtoList(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&);
 void repatchPutByID(ExecState*, JSValue, Structure*, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
 void buildPutByIdList(ExecState*, JSValue, Structure*, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
-void repatchIn(ExecState*, JSCell*, const Identifier&, bool wasFound, const PropertySlot&, StructureStubInfo&);
+void repatchInByID(ExecState*, JSObject*, const Identifier&, bool wasFound, const PropertySlot&, StructureStubInfo&);
 void repatchInstanceOf(ExecState*, JSValue value, JSValue prototype, StructureStubInfo&, bool wasFound);
 void linkFor(ExecState*, CallLinkInfo&, CodeBlock*, JSObject* callee, MacroAssemblerCodePtr<JSEntryPtrTag>);
 void linkDirectFor(ExecState*, CallLinkInfo&, CodeBlock*, MacroAssemblerCodePtr<JSEntryPtrTag>);
@@ -54,7 +54,7 @@ void linkVirtualFor(ExecState*, CallLinkInfo&);
 void linkPolymorphicCall(ExecState*, CallLinkInfo&, CallVariant);
 void resetGetByID(CodeBlock*, StructureStubInfo&, GetByIDKind);
 void resetPutByID(CodeBlock*, StructureStubInfo&);
-void resetIn(StructureStubInfo&);
+void resetInByID(CodeBlock*, StructureStubInfo&);
 void resetInstanceOf(StructureStubInfo&);
 void ftlThunkAwareRepatchCall(CodeBlock*, CodeLocationCall<JSInternalPtrTag>, FunctionPtr<CFunctionPtrTag> newCalleeFunction);
 
index 2bc9feb..7648705 100644 (file)
@@ -1507,10 +1507,16 @@ _llint_op_is_function:
     dispatch(constexpr op_is_function_length)
 
 
-_llint_op_in:
+_llint_op_in_by_id:
     traceExecution()
-    callSlowPath(_slow_path_in)
-    dispatch(constexpr op_in_length)
+    callSlowPath(_slow_path_in_by_id)
+    dispatch(constexpr op_in_by_id_length)
+
+
+_llint_op_in_by_val:
+    traceExecution()
+    callSlowPath(_slow_path_in_by_val)
+    dispatch(constexpr op_in_by_val_length)
 
 
 _llint_op_try_get_by_id:
index 626989d..3eea54d 100644 (file)
@@ -1552,6 +1552,7 @@ _llint_op_put_by_id:
     callSlowPath(_llint_slow_path_put_by_id)
     dispatch(constexpr op_put_by_id_length)
 
+
 macro finishGetByVal(result, scratch)
     loadisFromInstruction(1, scratch)
     storeq result, [cfr, scratch, 8]
index e6f03b6..5d77db1 100644 (file)
@@ -623,7 +623,7 @@ namespace JSC {
     }
 
     inline InNode::InNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
-        : ThrowableBinaryOpNode(location, expr1, expr2, op_in, rightHasAssignments)
+        : ThrowableBinaryOpNode(location, expr1, expr2, op_in_by_val, rightHasAssignments)
     {
     }
 
index 84dd3d2..253db5e 100644 (file)
@@ -648,10 +648,21 @@ SLOW_PATH_DECL(slow_path_is_function)
     RETURN(jsBoolean(jsIsFunctionType(OP_C(2).jsValue())));
 }
 
-SLOW_PATH_DECL(slow_path_in)
+SLOW_PATH_DECL(slow_path_in_by_val)
 {
     BEGIN();
-    RETURN(jsBoolean(CommonSlowPaths::opIn(exec, OP_C(2).jsValue(), OP_C(3).jsValue(), pc[4].u.arrayProfile)));
+    RETURN(jsBoolean(CommonSlowPaths::opInByVal(exec, OP_C(2).jsValue(), OP_C(3).jsValue(), pc[4].u.arrayProfile)));
+}
+
+SLOW_PATH_DECL(slow_path_in_by_id)
+{
+    BEGIN();
+
+    JSValue baseValue = OP_C(2).jsValue();
+    if (!baseValue.isObject())
+        THROW(createInvalidInParameterError(exec, baseValue));
+
+    RETURN(jsBoolean(asObject(baseValue)->hasProperty(exec, exec->codeBlock()->identifier(pc[3].u.operand))));
 }
 
 SLOW_PATH_DECL(slow_path_del_by_val)
index c285135..406cda3 100644 (file)
@@ -85,7 +85,7 @@ ALWAYS_INLINE int arityCheckFor(ExecState* exec, VM& vm, CodeSpecializationKind
     return padding;
 }
 
-inline bool opIn(ExecState* exec, JSValue baseVal, JSValue propName, ArrayProfile* arrayProfile = nullptr)
+inline bool opInByVal(ExecState* exec, JSValue baseVal, JSValue propName, ArrayProfile* arrayProfile = nullptr)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -308,7 +308,8 @@ SLOW_PATH_HIDDEN_DECL(slow_path_typeof);
 SLOW_PATH_HIDDEN_DECL(slow_path_is_object);
 SLOW_PATH_HIDDEN_DECL(slow_path_is_object_or_null);
 SLOW_PATH_HIDDEN_DECL(slow_path_is_function);
-SLOW_PATH_HIDDEN_DECL(slow_path_in);
+SLOW_PATH_HIDDEN_DECL(slow_path_in_by_id);
+SLOW_PATH_HIDDEN_DECL(slow_path_in_by_val);
 SLOW_PATH_HIDDEN_DECL(slow_path_del_by_val);
 SLOW_PATH_HIDDEN_DECL(slow_path_strcat);
 SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive);