[JSC] JSC should have consistent InById IC
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 May 2018 20:21:30 +0000 (20:21 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 May 2018 20:21:30 +0000 (20:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185682

Reviewed by Filip Pizlo.

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:

Current our op_in IC is adhoc: It is only emitted in DFG and FTL layers,
when we found that DFG::In's parameter is constant string. We should
align this IC to the other ById ICs to clean up and remove adhoc code
in DFG and FTL.

This patch cleans up our "In" IC by aligning it to the other ById ICs.
We split op_in bytecode to op_in_by_id and op_in_by_val. op_in_by_val
is the same to the original op_in. For op_in_by_id, we use JITInByIdGenerator
to emit InById IC code. In addition, our JITInByIdGenerator and op_in_by_id
has a inline access cache for own property case, which is the same to
JITGetByIdGenerator.

And we split DFG::In to DFG::InById and DFG::InByVal. InByVal is the same
to the original In DFG node. DFG AI attempts to lower InByVal to InById
if AI figured out that the property name is a constant string. And in
InById node, we use JITInByIdGenerator code.

This patch cleans up DFG and FTL's adhoc In IC code.

In a subsequent patch, we should introduce InByIdStatus to optimize
InById in DFG and FTL. We would like to have a new InByIdStatus instead of
reusing GetByIdStatus since GetByIdStatus becomes too complicated, and
AccessCase::Types are different from them (AccessCase::InHit / InMiss).

* bytecode/AccessCase.cpp:
(JSC::AccessCase::fromStructureStubInfo):
(JSC::AccessCase::generateWithGuard):
* 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/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@231998 268f45cc-cd09-0410-ab3c-d52691b4dbfc

56 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/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 b6ad046..72f9954 100644 (file)
@@ -1,3 +1,36 @@
+2018-05-19  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] JSC should have consistent InById IC
+        https://bugs.webkit.org/show_bug.cgi?id=185682
+
+        Reviewed by Filip Pizlo.
+
+        * 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-18  Keith Miller  <keith_miller@apple.com>
 
         op_in should mark if it sees out of bounds accesses
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 88cdd95..02fb647 100644 (file)
@@ -1,3 +1,148 @@
+2018-05-19  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] JSC should have consistent InById IC
+        https://bugs.webkit.org/show_bug.cgi?id=185682
+
+        Reviewed by Filip Pizlo.
+
+        Current our op_in IC is adhoc: It is only emitted in DFG and FTL layers,
+        when we found that DFG::In's parameter is constant string. We should
+        align this IC to the other ById ICs to clean up and remove adhoc code
+        in DFG and FTL.
+
+        This patch cleans up our "In" IC by aligning it to the other ById ICs.
+        We split op_in bytecode to op_in_by_id and op_in_by_val. op_in_by_val
+        is the same to the original op_in. For op_in_by_id, we use JITInByIdGenerator
+        to emit InById IC code. In addition, our JITInByIdGenerator and op_in_by_id
+        has a inline access cache for own property case, which is the same to
+        JITGetByIdGenerator.
+
+        And we split DFG::In to DFG::InById and DFG::InByVal. InByVal is the same
+        to the original In DFG node. DFG AI attempts to lower InByVal to InById
+        if AI figured out that the property name is a constant string. And in
+        InById node, we use JITInByIdGenerator code.
+
+        This patch cleans up DFG and FTL's adhoc In IC code.
+
+        In a subsequent patch, we should introduce InByIdStatus to optimize
+        InById in DFG and FTL. We would like to have a new InByIdStatus instead of
+        reusing GetByIdStatus since GetByIdStatus becomes too complicated, and
+        AccessCase::Types are different from them (AccessCase::InHit / InMiss).
+
+        * bytecode/AccessCase.cpp:
+        (JSC::AccessCase::fromStructureStubInfo):
+        (JSC::AccessCase::generateWithGuard):
+        * 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/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-18  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r231982.
index e3239a1..3e772bc 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)
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..f351f82 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.boxBooleanPayload(true, value.payloadGPR());
+
+    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 d5819aa..04218db 100644 (file)
@@ -81,6 +81,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) {
@@ -90,6 +99,7 @@ void StructureStubInfo::deref()
     case CacheType::Unset:
     case CacheType::GetByIdSelf:
     case CacheType::PutByIdReplace:
+    case CacheType::InByIdSelf:
     case CacheType::ArrayLength:
         return;
     }
@@ -106,6 +116,7 @@ void StructureStubInfo::aboutToDie()
     case CacheType::Unset:
     case CacheType::GetByIdSelf:
     case CacheType::PutByIdReplace:
+    case CacheType::InByIdSelf:
     case CacheType::ArrayLength:
         return;
     }
@@ -236,7 +247,7 @@ void StructureStubInfo::reset(CodeBlock* codeBlock)
         resetPutByID(codeBlock, *this);
         break;
     case AccessType::In:
-        resetIn(*this);
+        resetInByID(codeBlock, *this);
         break;
     case AccessType::InstanceOf:
         resetInstanceOf(*this);
@@ -259,6 +270,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;
@@ -282,6 +294,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 14fed94..efe619b 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>);
 
@@ -174,7 +176,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;
@@ -195,7 +197,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 9bd8a53..9da5f41 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 3874fcc..1077649 100644 (file)
@@ -6363,11 +6363,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 ad62364..552edef 100644 (file)
@@ -619,7 +619,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 7374185..b7edc06 100644 (file)
@@ -616,6 +616,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 974d971..416210a 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 0101d37..9a1dc13 100644 (file)
@@ -1469,7 +1469,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 4d97cd3..f6e10eb 100644 (file)
@@ -743,6 +743,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()
     {
@@ -1010,6 +1019,7 @@ public:
         case PutSetterById:
         case PutGetterSetterById:
         case DeleteById:
+        case InById:
         case GetDynamicVar:
         case PutDynamicVar:
         case ResolveScopeForHoistingFuncDeclInEval:
@@ -1967,7 +1977,7 @@ public:
         case GetIndexedPropertyStorage:
         case GetArrayLength:
         case GetVectorLength:
-        case In:
+        case InByVal:
         case PutByValDirect:
         case PutByVal:
         case PutByValAlias:
index feec25e..4fba90d 100644 (file)
@@ -369,7 +369,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 4bcb02c..228643b 100644 (file)
@@ -980,7 +980,8 @@ private:
             setPrediction(SpecObjectOther);
             break;
 
-        case In:
+        case InByVal:
+        case InById:
             setPrediction(SpecBoolean);
             break;
 
index f183ae9..82eed6a 100644 (file)
@@ -332,7 +332,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case CallStringConstructor:
     case NewStringObject:
     case MakeRope:
-    case In:
+    case InByVal:
+    case InById:
     case HasOwnProperty:
     case PushWithScope:
     case CreateActivation:
index 3f934e3..fe8be37 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 0b7912d..46174c9 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 9f131d9..3efb7b7 100644 (file)
@@ -3751,8 +3751,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 a2caa00..8d38697 100644 (file)
@@ -4301,8 +4301,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 06863d0..6b95134 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 12c9338..e6decfa 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();
@@ -9669,87 +9672,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 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..76d72e2 100644 (file)
@@ -377,64 +377,88 @@ 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));
+
+    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);
 
-    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)));
+    LOG_IC((ICEvent::OperationInByIdGeneric, baseObject->classInfo(vm), ident));
+
+    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));
+
+    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..6041bc4 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_getByIdIndex++];
+
+    Label coldPathBegin = label();
+
+    Call call = callOperationWithProfile(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);