⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 280760 in webkit


Ignore:
Timestamp:
Aug 7, 2021, 2:38:59 PM (5 years ago)
Author:
keith_miller@apple.com
Message:

for-in should only emit one loop in bytecode
​https://bugs.webkit.org/show_bug.cgi?id=227989

Reviewed by Yusuke Suzuki.

JSTests:

  • microbenchmarks/for-in-double-array-with-own-named.js: Added.

(test):

  • microbenchmarks/for-in-double-array.js: Added.

(test):

  • microbenchmarks/for-in-getters.js: Added.

(test):

  • microbenchmarks/for-in-int32-array-with-own-named.js: Added.

(test):

  • microbenchmarks/for-in-int32-array.js: Added.

(test):

  • microbenchmarks/for-in-int32-object-with-own-named-and-getters.js: Added.

(test):

  • microbenchmarks/for-in-int32-object-with-own-named.js: Added.

(test):

  • microbenchmarks/for-in-object-with-own-named.js: Added.

(sum):
(opaqueSet):

  • microbenchmarks/for-in-string-array.js: Added.

(test):

  • microbenchmarks/for-of-iterate-array-map-set.js: Added.

(sum):
(let.generator):

  • stress/for-in-array-mode.js:

(test):

  • stress/for-in-base-reassigned-later.js:
  • stress/for-in-delete-during-iteration.js:
  • stress/for-in-primitive-index-on-prototype.js: Added.

(test):

  • stress/for-in-tests.js:
  • stress/has-own-property-structure-for-in-loop-correctness.js:

(test5):

Source/JavaScriptCore:

This patch redesigns how we implement for-in loops. Before this patch we would emit three copies of the for-in loop body. One for the indexed properties, one for the named-own properties, and one for generic properties (anything else). This had a couple of problems. Firstly, it meant bytecode size grew exponentially to number of nested for-in loops. This in turn meant DFG/FTL compilation took much longer.

Going off our experience with fast for-of, this patch turns for-in loops specializations into
a "fused" opcode that internally switches on the enumeration mode it currently sees. For example, if we are enumerating an own-named property, the new enumerator_get_by_val bytecode will check the enumerator cell's cached structure matches the base's then load the property offset directly.

There are four new opcodes this patch adds, which replace the various operations we had for the specialized loops previously. The new opcodes are EnumeratorGetByVal, EnumeratorInByVal, EnumeratorHasOwnProperty, and EnumeratorNext. The first three correspond to GetByVal, InByVal, and HasOwnProperty respectively. The EnumeratorNext opcode has three results in bytecode, the next enumeration value's mode, the index of the property name, and the property name string itself. When enumeration is done EnumeratorNext returns JS null as the property name string. Since the DFG doesn't support tuples yet this opcode is spilt into four new nodes. The first computes the updated index and mode for the next enumeration key, which is encoded into a single JS number. Then there are two nodes that extract the mode and index. Finally, the last new node produces the property name string or null based on the extracted mode and index.

Since, in most benchmarks, any given enumeration opcode tends to profile exactly one enumeration mode. This patch focuses primarily on reimplementing all the optimizations we have for any one specific mode. This means there are still potential optimizations for the multi-mode flavors of each new opcode.

The main optimizations implemented for each new opcode are:

EnumeratorNext:
1) IndexedMode loops are loaded and checked for presence inline (DFG/FTL).
2) NamedMode is computed inline as long as the cached structure on the enumerator cell matches the base (Baseline+). This can only differ if there's a transition.
3) property names are extracted from the cached buffer inline (Baseline+).

EnumeratorGetByVal:
EnumeratorInByVal:
EnumeratorHasOwnProperty:
1) IndexedMode has all the optimizations of a normal XByVal on indexed properties (DFG/FTL).
2) NamedMode will extract the value directly from the inline/out-of-line offset if the structure matches the enumerator's (Baseline+).

There are also a few interesting changes worth mentioning here:
1) If a for-in loop would produce an empty enumerator we now always
return the VMs empty enumerator. This has two benefits, most importantly, it distingishes between an unprofiled for-in loop and empty enumeration, which prevents OSR exit loops. Also, it means that the various Enumerator opcodes no longer need to handle undefined/null when toObjecting the base value.

2) The enumerator now contains a bit set of all the modes it will produce. This removes a few extra branches when speculating on the modes we will see in EnumeratorNext.

3) In the DFG, enumerator GetByVal relies on compileGetByVal to set the result it also passes a prefix callback which emits code after the various cases set up their operands but before code is emitting to help satisfy the branch over register allocation validation. Also, the array mode branch in compileGetByVal passes the data format that it would prefer, which for normal GetByVal is returned. For EnumeratorGetByVal, that preference is completely ignored and it always returns DataFormatJS.

  • assembler/MacroAssemblerARM64.h:

(JSC::MacroAssemblerARM64::or8):

  • assembler/MacroAssemblerX86Common.h:

(JSC::MacroAssemblerX86Common::or8):

  • assembler/MacroAssemblerX86_64.h:

(JSC::MacroAssemblerX86_64::rshift64):
(JSC::MacroAssemblerX86_64::or8): Deleted.

  • builtins/BuiltinNames.h:
  • bytecode/BytecodeList.rb:
  • bytecode/BytecodeUseDef.cpp:

(JSC::computeUsesForBytecodeIndexImpl):
(JSC::computeDefsForBytecodeIndexImpl):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::finishCreation):

  • bytecode/LinkTimeConstant.h:
  • bytecode/Opcode.h:
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::recordHasOwnPropertyInForInLoop):
(JSC::BytecodeGenerator::emitInByVal):
(JSC::BytecodeGenerator::emitGetByVal):
(JSC::BytecodeGenerator::emitEnumeratorNext):
(JSC::BytecodeGenerator::emitEnumeratorHasOwnProperty):
(JSC::BytecodeGenerator::pushForInScope):
(JSC::BytecodeGenerator::popForInScope):
(JSC::rewriteOp):
(JSC::ForInContext::finalize):
(JSC::BytecodeGenerator::findForInContext):
(JSC::BytecodeGenerator::recordHasOwnStructurePropertyInForInLoop): Deleted.
(JSC::BytecodeGenerator::emitGetEnumerableLength): Deleted.
(JSC::BytecodeGenerator::emitHasEnumerableIndexedProperty): Deleted.
(JSC::BytecodeGenerator::emitHasEnumerableStructureProperty): Deleted.
(JSC::BytecodeGenerator::emitHasEnumerableProperty): Deleted.
(JSC::BytecodeGenerator::emitHasOwnStructureProperty): Deleted.
(JSC::BytecodeGenerator::emitEnumeratorStructurePropertyName): Deleted.
(JSC::BytecodeGenerator::emitEnumeratorGenericPropertyName): Deleted.
(JSC::BytecodeGenerator::emitToIndexString): Deleted.
(JSC::BytecodeGenerator::pushIndexedForInScope): Deleted.
(JSC::BytecodeGenerator::popIndexedForInScope): Deleted.
(JSC::BytecodeGenerator::pushStructureForInScope): Deleted.
(JSC::BytecodeGenerator::popStructureForInScope): Deleted.
(JSC::StructureForInContext::finalize): Deleted.
(JSC::IndexedForInContext::finalize): Deleted.
(JSC::BytecodeGenerator::findStructureForInContext): Deleted.

  • bytecompiler/BytecodeGenerator.h:

(JSC::ForInContext::isValid const):
(JSC::ForInContext::invalidate):
(JSC::ForInContext::local const):
(JSC::ForInContext::propertyName const):
(JSC::ForInContext::propertyOffset const):
(JSC::ForInContext::enumerator const):
(JSC::ForInContext::mode const):
(JSC::ForInContext::ForInContext):
(JSC::ForInContext::bodyBytecodeStartOffset const):
(JSC::ForInContext::type const): Deleted.
(JSC::ForInContext::isIndexedForInContext const): Deleted.
(JSC::ForInContext::isStructureForInContext const): Deleted.
(JSC::ForInContext::asIndexedForInContext): Deleted.
(JSC::ForInContext::asStructureForInContext): Deleted.
(JSC::StructureForInContext::StructureForInContext): Deleted.
(JSC::StructureForInContext::index const): Deleted.
(JSC::StructureForInContext::property const): Deleted.
(JSC::StructureForInContext::enumerator const): Deleted.
(JSC::StructureForInContext::baseVariable const): Deleted.
(JSC::StructureForInContext::addGetInst): Deleted.
(JSC::StructureForInContext::addInInst): Deleted.
(JSC::StructureForInContext::addHasOwnPropertyJump): Deleted.
(JSC::IndexedForInContext::IndexedForInContext): Deleted.
(JSC::IndexedForInContext::index const): Deleted.
(JSC::IndexedForInContext::addGetInst): Deleted.

  • bytecompiler/NodesCodegen.cpp:

(JSC::HasOwnPropertyFunctionCallDotNode::emitBytecode):
(JSC::ForInNode::emitBytecode):

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGArrayMode.h:

(JSC::DFG::ArrayMode::isSaneChain const):

  • dfg/DFGBackwardsPropagationPhase.cpp:

(JSC::DFG::BackwardsPropagationPhase::propagate):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCFAPhase.cpp:

(JSC::DFG::CFAPhase::injectOSR):

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::setJSArraySaneChainIfPossible):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):

  • dfg/DFGIntegerRangeOptimizationPhase.cpp:
  • dfg/DFGMayExit.cpp:
  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasStorageChild const):
(JSC::DFG::Node::storageChildIndex):
(JSC::DFG::Node::hasArrayMode):
(JSC::DFG::Node::hasEnumeratorMetadata const):
(JSC::DFG::Node::enumeratorMetadata):

  • dfg/DFGNodeType.h:
  • dfg/DFGOpInfo.h:

(JSC::DFG::OpInfo::OpInfo):

  • dfg/DFGOperations.cpp:

(JSC::DFG::JSC_DEFINE_JIT_OPERATION):

  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSSALoweringPhase.cpp:

(JSC::DFG::SSALoweringPhase::handleNode):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::JSValueRegsTemporary::JSValueRegsTemporary):
(JSC::DFG::SpeculativeJIT::compileGetByValOnString):
(JSC::DFG::SpeculativeJIT::setIntTypedArrayLoadResult):
(JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray):
(JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray):
(JSC::DFG::SpeculativeJIT::compileGetByValForObjectWithString):
(JSC::DFG::SpeculativeJIT::compileGetByValForObjectWithSymbol):
(JSC::DFG::SpeculativeJIT::compileGetByValOnDirectArguments):
(JSC::DFG::SpeculativeJIT::compileGetByValOnScopedArguments):
(JSC::DFG::SpeculativeJIT::compileEnumeratorNextUpdateIndexAndMode):
(JSC::DFG::SpeculativeJIT::compileEnumeratorNextExtractIndex):
(JSC::DFG::SpeculativeJIT::compileEnumeratorNextExtractMode):
(JSC::DFG::SpeculativeJIT::compileEnumeratorNextUpdatePropertyName):
(JSC::DFG::SpeculativeJIT::compileEnumeratorGetByVal):
(JSC::DFG::SpeculativeJIT::compileEnumeratorHasProperty):
(JSC::DFG::SpeculativeJIT::compileEnumeratorInByVal):
(JSC::DFG::SpeculativeJIT::compileEnumeratorHasOwnProperty):
(JSC::DFG::SpeculativeJIT::compileHasIndexedProperty):
(JSC::DFG::SpeculativeJIT::compileGetEnumerableLength): Deleted.
(JSC::DFG::SpeculativeJIT::compileHasEnumerableProperty): Deleted.
(JSC::DFG::SpeculativeJIT::compileToIndexString): Deleted.
(JSC::DFG::SpeculativeJIT::compileHasEnumerableStructureProperty): Deleted.
(JSC::DFG::SpeculativeJIT::compileHasOwnStructurePropertyImpl): Deleted.
(JSC::DFG::SpeculativeJIT::compileHasOwnStructureProperty): Deleted.
(JSC::DFG::SpeculativeJIT::compileInStructureProperty): Deleted.
(JSC::DFG::SpeculativeJIT::compileGetEnumeratorPname): Deleted.
(JSC::DFG::SpeculativeJIT::compileGetDirectPname): Deleted.

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::allocate):
(JSC::DFG::JSValueOperand::regs):
(JSC::DFG::JSValueOperand::gpr):
(JSC::DFG::StorageOperand::StorageOperand):
(JSC::DFG::StorageOperand::~StorageOperand):
(JSC::DFG::StorageOperand::emplace):
(JSC::DFG::JSValueRegsTemporary::operator bool):
(JSC::DFG::JSValueRegsTemporary::JSValueRegsTemporary):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compileGetByVal):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compileGetByVal):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGTypeCheckHoistingPhase.cpp:

(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):

  • ftl/FTLAbstractHeapRepository.h:
  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByValImpl):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
(JSC::FTL::DFG::LowerDFGToB3::compileStringCharAtImpl):
(JSC::FTL::DFG::LowerDFGToB3::compileStringCharAt):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):

  • ftl/FTLOutput.h:

(JSC::FTL::Output::phi):

  • generator/DSL.rb:
  • interpreter/Register.h:
  • interpreter/RegisterInlines.h:

(JSC::Register::operator=):

  • jit/AssemblyHelpers.h:
  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):

  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::privateCompileHasIndexedProperty):
(JSC::JIT::emit_op_has_structure_propertyImpl): Deleted.
(JSC::JIT::emit_op_has_enumerable_structure_property): Deleted.
(JSC::JIT::emit_op_has_own_structure_property): Deleted.
(JSC::JIT::emit_op_in_structure_property): Deleted.
(JSC::JIT::emit_op_has_enumerable_indexed_property): Deleted.
(JSC::JIT::emitSlow_op_has_enumerable_indexed_property): Deleted.
(JSC::JIT::emit_op_get_direct_pname): Deleted.
(JSC::JIT::emit_op_enumerator_structure_pname): Deleted.
(JSC::JIT::emit_op_enumerator_generic_pname): Deleted.

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::privateCompileHasIndexedProperty):
(JSC::JIT::emit_op_has_structure_propertyImpl): Deleted.
(JSC::JIT::emit_op_has_enumerable_structure_property): Deleted.
(JSC::JIT::emit_op_has_own_structure_property): Deleted.
(JSC::JIT::emit_op_in_structure_property): Deleted.
(JSC::JIT::emit_op_has_enumerable_indexed_property): Deleted.
(JSC::JIT::emitSlow_op_has_enumerable_indexed_property): Deleted.
(JSC::JIT::emit_op_get_direct_pname): Deleted.
(JSC::JIT::emit_op_enumerator_structure_pname): Deleted.
(JSC::JIT::emit_op_enumerator_generic_pname): Deleted.

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::generateGetByValSlowCase):
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_enumerator_next):
(JSC::JIT::emit_op_enumerator_get_by_val):
(JSC::JIT::emitSlow_op_enumerator_get_by_val):
(JSC::JIT::emit_enumerator_has_propertyImpl):
(JSC::JIT::emit_op_enumerator_in_by_val):
(JSC::JIT::emit_op_enumerator_has_own_property):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_enumerator_next):
(JSC::JIT::emit_op_enumerator_get_by_val):
(JSC::JIT::emitSlow_op_enumerator_get_by_val):
(JSC::JIT::emit_op_enumerator_in_by_val):
(JSC::JIT::emit_op_enumerator_has_own_property):

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/CommonSlowPaths.cpp:

(JSC::JSC_DEFINE_COMMON_SLOW_PATH):

  • runtime/CommonSlowPaths.h:
  • runtime/FileBasedFuzzerAgent.cpp:

(JSC::FileBasedFuzzerAgent::getPredictionInternal):

  • runtime/FileBasedFuzzerAgentBase.cpp:

(JSC::FileBasedFuzzerAgentBase::opcodeAliasForLookupKey):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/JSPropertyNameEnumerator.cpp:

(JSC::JSPropertyNameEnumerator::JSPropertyNameEnumerator):
(JSC::JSPropertyNameEnumerator::computeNext):

  • runtime/JSPropertyNameEnumerator.h:

(JSC::propertyNameEnumerator):

  • runtime/PredictionFileCreatingFuzzerAgent.cpp:

(JSC::PredictionFileCreatingFuzzerAgent::getPredictionInternal):

Location:
trunk
Files:
11 added
68 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r280716 r280760  
     12021-08-07  Keith Miller  <keith_miller@apple.com>
     2
     3        for-in should only emit one loop in bytecode
     4        https://bugs.webkit.org/show_bug.cgi?id=227989
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        * microbenchmarks/for-in-double-array-with-own-named.js: Added.
     9        (test):
     10        * microbenchmarks/for-in-double-array.js: Added.
     11        (test):
     12        * microbenchmarks/for-in-getters.js: Added.
     13        (test):
     14        * microbenchmarks/for-in-int32-array-with-own-named.js: Added.
     15        (test):
     16        * microbenchmarks/for-in-int32-array.js: Added.
     17        (test):
     18        * microbenchmarks/for-in-int32-object-with-own-named-and-getters.js: Added.
     19        (test):
     20        * microbenchmarks/for-in-int32-object-with-own-named.js: Added.
     21        (test):
     22        * microbenchmarks/for-in-object-with-own-named.js: Added.
     23        (sum):
     24        (opaqueSet):
     25        * microbenchmarks/for-in-string-array.js: Added.
     26        (test):
     27        * microbenchmarks/for-of-iterate-array-map-set.js: Added.
     28        (sum):
     29        (let.generator):
     30        * stress/for-in-array-mode.js:
     31        (test):
     32        * stress/for-in-base-reassigned-later.js:
     33        * stress/for-in-delete-during-iteration.js:
     34        * stress/for-in-primitive-index-on-prototype.js: Added.
     35        (test):
     36        * stress/for-in-tests.js:
     37        * stress/has-own-property-structure-for-in-loop-correctness.js:
     38        (test5):
     39
    1402021-08-05  Mikhail R. Gadelha  <mikhail@igalia.com>
    241
  • trunk/JSTests/stress/for-in-array-mode.js

    r182444 r280760  
    2727"(arr) {" + "\n" +
    2828"    var sum = 0;" + "\n" +
    29 "    for (var i in arr)" + "\n" +
     29"    for (var i in arr) {" + "\n" +
    3030"        sum += arr[i];" + "\n" +
     31"    } " +
    3132"    return sum;" + "\n" +
    3233"}";
    … …  
    7677        if ((actual != expected) && (actual != previousResult)) {
    7778            print("FAIL: " + name + ": expected: " + expected + ", actual: " + actual + ", starting @ loop iteration " + i);
     79            $vm.breakpoint();
    7880            previousResult = actual;
    7981            failed = true;
  • trunk/JSTests/stress/for-in-base-reassigned-later.js

    r172794 r280760  
    1515    var result = foo({0:0, 1:1, a:2, b:3});
    1616    if (result != 7)
    17         throw "Error: bad result: " + result;
     17        throw new Error("bad result: " + result);
    1818}
  • trunk/JSTests/stress/for-in-delete-during-iteration.js

    r181891 r280760  
    1313    noInline(foo);
    1414    for (var i = 0; i < 10000; ++i) {
    15         if (foo() !== "1235")
    16             throw new Error("bad result");
     15        var result = foo();
     16        if (result !== "1235")
     17            throw new Error("bad result got: " + result);
    1718    }
    1819    foo(null);
    … …  
    3738    noInline(foo);
    3839    for (var i = 0; i < 10000; ++i) {
    39         if (foo() !== "xz")
    40             throw new Error("bad result");
     40        var result = foo();
     41        if (result !== "xz")
     42            throw new Error("bad result: " + result);
    4143    }
    4244})();
  • trunk/JSTests/stress/for-in-tests.js

    r271269 r280760  
    106106    }
    107107})();
     108
    108109(function() {
    109110    var foo = function(a, b) {
  • trunk/JSTests/stress/has-own-property-structure-for-in-loop-correctness.js

    r262233 r280760  
    133133
    134134    for (let i = 0; i < 1000; ++i) {
    135         assert(count(o) === 0);
     135        var c = count(o);
     136        if (c)
     137            print(c);
     138        assert(c === 0);
    136139    }
    137140}
  • trunk/Source/JavaScriptCore/ChangeLog

    r280745 r280760  
     12021-08-07  Keith Miller  <keith_miller@apple.com>
     2
     3        for-in should only emit one loop in bytecode
     4        https://bugs.webkit.org/show_bug.cgi?id=227989
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        This patch redesigns how we implement for-in loops. Before this patch we would emit three copies of the for-in loop body. One for the indexed properties, one for the named-own properties, and one for generic properties (anything else). This had a couple of problems. Firstly, it meant bytecode size grew exponentially to number of nested for-in loops. This in turn meant DFG/FTL compilation took much longer.
     9
     10        Going off our experience with fast for-of, this patch turns for-in loops specializations into
     11        a "fused" opcode that internally switches on the enumeration mode it currently sees. For example, if we are enumerating an own-named property, the new enumerator_get_by_val bytecode will check the enumerator cell's cached structure matches the base's then load the property offset directly.
     12
     13        There are four new opcodes this patch adds, which replace the various operations we had for the specialized loops previously. The new opcodes are EnumeratorGetByVal, EnumeratorInByVal, EnumeratorHasOwnProperty, and EnumeratorNext. The first three correspond to GetByVal, InByVal, and HasOwnProperty respectively. The EnumeratorNext opcode has three results in bytecode, the next enumeration value's mode, the index of the property name, and the property name string itself. When enumeration is done EnumeratorNext returns JS null as the property name string. Since the DFG doesn't support tuples yet this opcode is spilt into four new nodes. The first computes the updated index and mode for the next enumeration key, which is encoded into a single JS number. Then there are two nodes that extract the mode and index. Finally, the last new node produces the property name string or null based on the extracted mode and index.
     14
     15        Since, in most benchmarks, any given enumeration opcode tends to profile exactly one enumeration mode. This patch focuses primarily on reimplementing all the optimizations we have for any one specific mode. This means there are still potential optimizations for the multi-mode flavors of each new opcode.
     16
     17        The main optimizations implemented for each new opcode are:
     18
     19        EnumeratorNext:
     20        1) IndexedMode loops are loaded and checked for presence inline (DFG/FTL).
     21        2) NamedMode is computed inline as long as the cached structure on the enumerator cell matches the base (Baseline+). This can only differ if there's a transition.
     22        3) property names are extracted from the cached buffer inline (Baseline+).
     23
     24        EnumeratorGetByVal:
     25        EnumeratorInByVal:
     26        EnumeratorHasOwnProperty:
     27        1) IndexedMode has all the optimizations of a normal XByVal on indexed properties (DFG/FTL).
     28        2) NamedMode will extract the value directly from the inline/out-of-line offset if the structure matches the enumerator's (Baseline+).
     29
     30        There are also a few interesting changes worth mentioning here:
     31        1) If a for-in loop would produce an empty enumerator we now always
     32        return the VMs empty enumerator. This has two benefits, most importantly, it distingishes between an unprofiled for-in loop and empty enumeration, which prevents OSR exit loops. Also, it means that the various Enumerator opcodes no longer need to handle undefined/null when `toObject`ing the base value.
     33
     34        2) The enumerator now contains a bit set of all the modes it will produce. This removes a few extra branches when speculating on the modes we will see in EnumeratorNext.
     35
     36        3) In the DFG, enumerator GetByVal relies on compileGetByVal to set the result it also passes a prefix callback which emits code after the various cases set up their operands but before code is emitting to help satisfy the branch over register allocation validation. Also, the array mode branch in compileGetByVal passes the data format that it would prefer, which for normal GetByVal is returned. For EnumeratorGetByVal, that preference is completely ignored and it always returns DataFormatJS.
     37
     38        * assembler/MacroAssemblerARM64.h:
     39        (JSC::MacroAssemblerARM64::or8):
     40        * assembler/MacroAssemblerX86Common.h:
     41        (JSC::MacroAssemblerX86Common::or8):
     42        * assembler/MacroAssemblerX86_64.h:
     43        (JSC::MacroAssemblerX86_64::rshift64):
     44        (JSC::MacroAssemblerX86_64::or8): Deleted.
     45        * builtins/BuiltinNames.h:
     46        * bytecode/BytecodeList.rb:
     47        * bytecode/BytecodeUseDef.cpp:
     48        (JSC::computeUsesForBytecodeIndexImpl):
     49        (JSC::computeDefsForBytecodeIndexImpl):
     50        * bytecode/CodeBlock.cpp:
     51        (JSC::CodeBlock::finishCreation):
     52        * bytecode/LinkTimeConstant.h:
     53        * bytecode/Opcode.h:
     54        * bytecompiler/BytecodeGenerator.cpp:
     55        (JSC::BytecodeGenerator::recordHasOwnPropertyInForInLoop):
     56        (JSC::BytecodeGenerator::emitInByVal):
     57        (JSC::BytecodeGenerator::emitGetByVal):
     58        (JSC::BytecodeGenerator::emitEnumeratorNext):
     59        (JSC::BytecodeGenerator::emitEnumeratorHasOwnProperty):
     60        (JSC::BytecodeGenerator::pushForInScope):
     61        (JSC::BytecodeGenerator::popForInScope):
     62        (JSC::rewriteOp):
     63        (JSC::ForInContext::finalize):
     64        (JSC::BytecodeGenerator::findForInContext):
     65        (JSC::BytecodeGenerator::recordHasOwnStructurePropertyInForInLoop): Deleted.
     66        (JSC::BytecodeGenerator::emitGetEnumerableLength): Deleted.
     67        (JSC::BytecodeGenerator::emitHasEnumerableIndexedProperty): Deleted.
     68        (JSC::BytecodeGenerator::emitHasEnumerableStructureProperty): Deleted.
     69        (JSC::BytecodeGenerator::emitHasEnumerableProperty): Deleted.
     70        (JSC::BytecodeGenerator::emitHasOwnStructureProperty): Deleted.
     71        (JSC::BytecodeGenerator::emitEnumeratorStructurePropertyName): Deleted.
     72        (JSC::BytecodeGenerator::emitEnumeratorGenericPropertyName): Deleted.
     73        (JSC::BytecodeGenerator::emitToIndexString): Deleted.
     74        (JSC::BytecodeGenerator::pushIndexedForInScope): Deleted.
     75        (JSC::BytecodeGenerator::popIndexedForInScope): Deleted.
     76        (JSC::BytecodeGenerator::pushStructureForInScope): Deleted.
     77        (JSC::BytecodeGenerator::popStructureForInScope): Deleted.
     78        (JSC::StructureForInContext::finalize): Deleted.
     79        (JSC::IndexedForInContext::finalize): Deleted.
     80        (JSC::BytecodeGenerator::findStructureForInContext): Deleted.
     81        * bytecompiler/BytecodeGenerator.h:
     82        (JSC::ForInContext::isValid const):
     83        (JSC::ForInContext::invalidate):
     84        (JSC::ForInContext::local const):
     85        (JSC::ForInContext::propertyName const):
     86        (JSC::ForInContext::propertyOffset const):
     87        (JSC::ForInContext::enumerator const):
     88        (JSC::ForInContext::mode const):
     89        (JSC::ForInContext::ForInContext):
     90        (JSC::ForInContext::bodyBytecodeStartOffset const):
     91        (JSC::ForInContext::type const): Deleted.
     92        (JSC::ForInContext::isIndexedForInContext const): Deleted.
     93        (JSC::ForInContext::isStructureForInContext const): Deleted.
     94        (JSC::ForInContext::asIndexedForInContext): Deleted.
     95        (JSC::ForInContext::asStructureForInContext): Deleted.
     96        (JSC::StructureForInContext::StructureForInContext): Deleted.
     97        (JSC::StructureForInContext::index const): Deleted.
     98        (JSC::StructureForInContext::property const): Deleted.
     99        (JSC::StructureForInContext::enumerator const): Deleted.
     100        (JSC::StructureForInContext::baseVariable const): Deleted.
     101        (JSC::StructureForInContext::addGetInst): Deleted.
     102        (JSC::StructureForInContext::addInInst): Deleted.
     103        (JSC::StructureForInContext::addHasOwnPropertyJump): Deleted.
     104        (JSC::IndexedForInContext::IndexedForInContext): Deleted.
     105        (JSC::IndexedForInContext::index const): Deleted.
     106        (JSC::IndexedForInContext::addGetInst): Deleted.
     107        * bytecompiler/NodesCodegen.cpp:
     108        (JSC::HasOwnPropertyFunctionCallDotNode::emitBytecode):
     109        (JSC::ForInNode::emitBytecode):
     110        * dfg/DFGAbstractInterpreterInlines.h:
     111        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     112        * dfg/DFGArrayMode.h:
     113        (JSC::DFG::ArrayMode::isSaneChain const):
     114        * dfg/DFGBackwardsPropagationPhase.cpp:
     115        (JSC::DFG::BackwardsPropagationPhase::propagate):
     116        * dfg/DFGByteCodeParser.cpp:
     117        (JSC::DFG::ByteCodeParser::parseBlock):
     118        * dfg/DFGCFAPhase.cpp:
     119        (JSC::DFG::CFAPhase::injectOSR):
     120        * dfg/DFGCapabilities.cpp:
     121        (JSC::DFG::capabilityLevel):
     122        * dfg/DFGClobberize.h:
     123        (JSC::DFG::clobberize):
     124        * dfg/DFGDoesGC.cpp:
     125        (JSC::DFG::doesGC):
     126        * dfg/DFGFixupPhase.cpp:
     127        (JSC::DFG::FixupPhase::fixupNode):
     128        (JSC::DFG::FixupPhase::setJSArraySaneChainIfPossible):
     129        * dfg/DFGGraph.cpp:
     130        (JSC::DFG::Graph::dump):
     131        * dfg/DFGIntegerRangeOptimizationPhase.cpp:
     132        * dfg/DFGMayExit.cpp:
     133        * dfg/DFGNode.h:
     134        (JSC::DFG::Node::hasHeapPrediction):
     135        (JSC::DFG::Node::hasStorageChild const):
     136        (JSC::DFG::Node::storageChildIndex):
     137        (JSC::DFG::Node::hasArrayMode):
     138        (JSC::DFG::Node::hasEnumeratorMetadata const):
     139        (JSC::DFG::Node::enumeratorMetadata):
     140        * dfg/DFGNodeType.h:
     141        * dfg/DFGOpInfo.h:
     142        (JSC::DFG::OpInfo::OpInfo):
     143        * dfg/DFGOperations.cpp:
     144        (JSC::DFG::JSC_DEFINE_JIT_OPERATION):
     145        * dfg/DFGOperations.h:
     146        * dfg/DFGPredictionPropagationPhase.cpp:
     147        * dfg/DFGSSALoweringPhase.cpp:
     148        (JSC::DFG::SSALoweringPhase::handleNode):
     149        * dfg/DFGSafeToExecute.h:
     150        (JSC::DFG::safeToExecute):
     151        * dfg/DFGSpeculativeJIT.cpp:
     152        (JSC::DFG::JSValueRegsTemporary::JSValueRegsTemporary):
     153        (JSC::DFG::SpeculativeJIT::compileGetByValOnString):
     154        (JSC::DFG::SpeculativeJIT::setIntTypedArrayLoadResult):
     155        (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray):
     156        (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray):
     157        (JSC::DFG::SpeculativeJIT::compileGetByValForObjectWithString):
     158        (JSC::DFG::SpeculativeJIT::compileGetByValForObjectWithSymbol):
     159        (JSC::DFG::SpeculativeJIT::compileGetByValOnDirectArguments):
     160        (JSC::DFG::SpeculativeJIT::compileGetByValOnScopedArguments):
     161        (JSC::DFG::SpeculativeJIT::compileEnumeratorNextUpdateIndexAndMode):
     162        (JSC::DFG::SpeculativeJIT::compileEnumeratorNextExtractIndex):
     163        (JSC::DFG::SpeculativeJIT::compileEnumeratorNextExtractMode):
     164        (JSC::DFG::SpeculativeJIT::compileEnumeratorNextUpdatePropertyName):
     165        (JSC::DFG::SpeculativeJIT::compileEnumeratorGetByVal):
     166        (JSC::DFG::SpeculativeJIT::compileEnumeratorHasProperty):
     167        (JSC::DFG::SpeculativeJIT::compileEnumeratorInByVal):
     168        (JSC::DFG::SpeculativeJIT::compileEnumeratorHasOwnProperty):
     169        (JSC::DFG::SpeculativeJIT::compileHasIndexedProperty):
     170        (JSC::DFG::SpeculativeJIT::compileGetEnumerableLength): Deleted.
     171        (JSC::DFG::SpeculativeJIT::compileHasEnumerableProperty): Deleted.
     172        (JSC::DFG::SpeculativeJIT::compileToIndexString): Deleted.
     173        (JSC::DFG::SpeculativeJIT::compileHasEnumerableStructureProperty): Deleted.
     174        (JSC::DFG::SpeculativeJIT::compileHasOwnStructurePropertyImpl): Deleted.
     175        (JSC::DFG::SpeculativeJIT::compileHasOwnStructureProperty): Deleted.
     176        (JSC::DFG::SpeculativeJIT::compileInStructureProperty): Deleted.
     177        (JSC::DFG::SpeculativeJIT::compileGetEnumeratorPname): Deleted.
     178        (JSC::DFG::SpeculativeJIT::compileGetDirectPname): Deleted.
     179        * dfg/DFGSpeculativeJIT.h:
     180        (JSC::DFG::SpeculativeJIT::allocate):
     181        (JSC::DFG::JSValueOperand::regs):
     182        (JSC::DFG::JSValueOperand::gpr):
     183        (JSC::DFG::StorageOperand::StorageOperand):
     184        (JSC::DFG::StorageOperand::~StorageOperand):
     185        (JSC::DFG::StorageOperand::emplace):
     186        (JSC::DFG::JSValueRegsTemporary::operator bool):
     187        (JSC::DFG::JSValueRegsTemporary::JSValueRegsTemporary):
     188        * dfg/DFGSpeculativeJIT32_64.cpp:
     189        (JSC::DFG::SpeculativeJIT::compileGetByVal):
     190        (JSC::DFG::SpeculativeJIT::compile):
     191        * dfg/DFGSpeculativeJIT64.cpp:
     192        (JSC::DFG::SpeculativeJIT::compileGetByVal):
     193        (JSC::DFG::SpeculativeJIT::compile):
     194        * dfg/DFGTypeCheckHoistingPhase.cpp:
     195        (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
     196        (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
     197        * ftl/FTLAbstractHeapRepository.h:
     198        * ftl/FTLCapabilities.cpp:
     199        (JSC::FTL::canCompile):
     200        * ftl/FTLLowerDFGToB3.cpp:
     201        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     202        (JSC::FTL::DFG::LowerDFGToB3::compileGetByValImpl):
     203        (JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
     204        (JSC::FTL::DFG::LowerDFGToB3::compileStringCharAtImpl):
     205        (JSC::FTL::DFG::LowerDFGToB3::compileStringCharAt):
     206        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
     207        * ftl/FTLOutput.h:
     208        (JSC::FTL::Output::phi):
     209        * generator/DSL.rb:
     210        * interpreter/Register.h:
     211        * interpreter/RegisterInlines.h:
     212        (JSC::Register::operator=):
     213        * jit/AssemblyHelpers.h:
     214        * jit/JIT.cpp:
     215        (JSC::JIT::privateCompileMainPass):
     216        (JSC::JIT::privateCompileSlowCases):
     217        * jit/JIT.h:
     218        * jit/JITOpcodes.cpp:
     219        (JSC::JIT::privateCompileHasIndexedProperty):
     220        (JSC::JIT::emit_op_has_structure_propertyImpl): Deleted.
     221        (JSC::JIT::emit_op_has_enumerable_structure_property): Deleted.
     222        (JSC::JIT::emit_op_has_own_structure_property): Deleted.
     223        (JSC::JIT::emit_op_in_structure_property): Deleted.
     224        (JSC::JIT::emit_op_has_enumerable_indexed_property): Deleted.
     225        (JSC::JIT::emitSlow_op_has_enumerable_indexed_property): Deleted.
     226        (JSC::JIT::emit_op_get_direct_pname): Deleted.
     227        (JSC::JIT::emit_op_enumerator_structure_pname): Deleted.
     228        (JSC::JIT::emit_op_enumerator_generic_pname): Deleted.
     229        * jit/JITOpcodes32_64.cpp:
     230        (JSC::JIT::privateCompileHasIndexedProperty):
     231        (JSC::JIT::emit_op_has_structure_propertyImpl): Deleted.
     232        (JSC::JIT::emit_op_has_enumerable_structure_property): Deleted.
     233        (JSC::JIT::emit_op_has_own_structure_property): Deleted.
     234        (JSC::JIT::emit_op_in_structure_property): Deleted.
     235        (JSC::JIT::emit_op_has_enumerable_indexed_property): Deleted.
     236        (JSC::JIT::emitSlow_op_has_enumerable_indexed_property): Deleted.
     237        (JSC::JIT::emit_op_get_direct_pname): Deleted.
     238        (JSC::JIT::emit_op_enumerator_structure_pname): Deleted.
     239        (JSC::JIT::emit_op_enumerator_generic_pname): Deleted.
     240        * jit/JITPropertyAccess.cpp:
     241        (JSC::JIT::generateGetByValSlowCase):
     242        (JSC::JIT::emitSlow_op_get_by_val):
     243        (JSC::JIT::emit_op_enumerator_next):
     244        (JSC::JIT::emit_op_enumerator_get_by_val):
     245        (JSC::JIT::emitSlow_op_enumerator_get_by_val):
     246        (JSC::JIT::emit_enumerator_has_propertyImpl):
     247        (JSC::JIT::emit_op_enumerator_in_by_val):
     248        (JSC::JIT::emit_op_enumerator_has_own_property):
     249        * jit/JITPropertyAccess32_64.cpp:
     250        (JSC::JIT::emit_op_enumerator_next):
     251        (JSC::JIT::emit_op_enumerator_get_by_val):
     252        (JSC::JIT::emitSlow_op_enumerator_get_by_val):
     253        (JSC::JIT::emit_op_enumerator_in_by_val):
     254        (JSC::JIT::emit_op_enumerator_has_own_property):
     255        * llint/LowLevelInterpreter.asm:
     256        * llint/LowLevelInterpreter64.asm:
     257        * runtime/CommonSlowPaths.cpp:
     258        (JSC::JSC_DEFINE_COMMON_SLOW_PATH):
     259        * runtime/CommonSlowPaths.h:
     260        * runtime/FileBasedFuzzerAgent.cpp:
     261        (JSC::FileBasedFuzzerAgent::getPredictionInternal):
     262        * runtime/FileBasedFuzzerAgentBase.cpp:
     263        (JSC::FileBasedFuzzerAgentBase::opcodeAliasForLookupKey):
     264        * runtime/JSGlobalObject.cpp:
     265        (JSC::JSGlobalObject::init):
     266        * runtime/JSPropertyNameEnumerator.cpp:
     267        (JSC::JSPropertyNameEnumerator::JSPropertyNameEnumerator):
     268        (JSC::JSPropertyNameEnumerator::computeNext):
     269        * runtime/JSPropertyNameEnumerator.h:
     270        (JSC::propertyNameEnumerator):
     271        * runtime/PredictionFileCreatingFuzzerAgent.cpp:
     272        (JSC::PredictionFileCreatingFuzzerAgent::getPredictionInternal):
     273
    12742021-08-06  Yusuke Suzuki  <ysuzuki@apple.com>
    2275
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h

    r280583 r280760  
    10701070    }
    10711071
     1072    void or8(RegisterID src, AbsoluteAddress address)
     1073    {
     1074        load8(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
     1075        or32(src, dataTempRegister, dataTempRegister);
     1076        store8(dataTempRegister, address.m_ptr);
     1077    }
     1078
    10721079    void or8(TrustedImm32 imm, AbsoluteAddress address)
    10731080    {
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r280578 r280760  
    626626    }
    627627
     628    void or8(RegisterID src, AbsoluteAddress address)
     629    {
     630        move(TrustedImmPtr(address.m_ptr), scratchRegister());
     631        or8(src, Address(scratchRegister()));
     632    }
     633
    628634    void or32(Address src, RegisterID dest)
    629635    {
    … …  
    664670    {
    665671        m_assembler.orb_im(static_cast<int8_t>(imm.m_value), address.offset, address.base, address.index, address.scale);
     672    }
     673
     674    void or8(TrustedImm32 imm, AbsoluteAddress address)
     675    {
     676        move(TrustedImmPtr(address.m_ptr), scratchRegister());
     677        or8(imm, Address(scratchRegister()));
    666678    }
    667679
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h

    r279889 r280760  
    9898    }
    9999
    100     void or8(TrustedImm32 imm, AbsoluteAddress address)
    101     {
    102         move(TrustedImmPtr(address.m_ptr), scratchRegister());
    103         or8(imm, Address(scratchRegister()));
    104     }
    105 
    106100    void sub32(TrustedImm32 imm, AbsoluteAddress address)
    107101    {
    … …  
    586580            swap(src, X86Registers::ecx);
    587581        }
     582    }
     583
     584    void rshift64(RegisterID src, TrustedImm32 imm, RegisterID dest)
     585    {
     586        move(src, dest);
     587        rshift64(imm, dest);
    588588    }
    589589
  • trunk/Source/JavaScriptCore/builtins/BuiltinNames.h

    r275439 r280760  
    182182    macro(createPrivateSymbol) \
    183183    macro(entries) \
    184     macro(outOfLineReactionCounts)
     184    macro(outOfLineReactionCounts) \
     185    macro(emptyPropertyNameEnumerator)
    185186
    186187
  • trunk/Source/JavaScriptCore/bytecode/BytecodeList.rb

    r277926 r280760  
    3030    :ECMAMode,
    3131    :ErrorTypeWithExtension,
     32    :EnumeratorMetadata,
    3233    :GetByIdMode,
    3334    :GetByIdModeMetadata,
    … …  
    11551156    }
    11561157
    1157 op :get_enumerable_length,
    1158     args: {
    1159         dst: VirtualRegister,
    1160         base: VirtualRegister,
    1161     }
    1162 
    1163 op :has_enumerable_indexed_property,
    1164     args: {
    1165         dst: VirtualRegister,
    1166         base: VirtualRegister,
    1167         property: VirtualRegister,
     1158op :get_property_enumerator,
     1159    args: {
     1160        dst: VirtualRegister,
     1161        base: VirtualRegister,
     1162    }
     1163
     1164op :enumerator_next,
     1165    args: {
     1166        # out
     1167        propertyName: VirtualRegister,
     1168        # in/out
     1169        mode: VirtualRegister, # Will always be a JS UInt32 representing a JSForInMode.
     1170        index: VirtualRegister, # Gets reset to zero every time mode changes.
     1171        # in
     1172        base: VirtualRegister,
     1173        enumerator: VirtualRegister,
    11681174    },
    11691175    metadata: {
    11701176        arrayProfile: ArrayProfile,
    1171     }
    1172 
    1173 op :has_enumerable_structure_property,
    1174     args: {
    1175         dst: VirtualRegister,
    1176         base: VirtualRegister,
    1177         property: VirtualRegister,
    1178         enumerator: VirtualRegister,
    1179     }
    1180 
    1181 op :has_own_structure_property,
    1182     args: {
    1183         dst: VirtualRegister,
    1184         base: VirtualRegister,
    1185         property: VirtualRegister,
    1186         enumerator: VirtualRegister,
    1187     }
    1188 
    1189 op :in_structure_property,
    1190     args: {
    1191         dst: VirtualRegister,
    1192         base: VirtualRegister,
    1193         property: VirtualRegister,
    1194         enumerator: VirtualRegister,
    1195     }
    1196 
    1197 op :has_enumerable_property,
    1198     args: {
    1199         dst: VirtualRegister,
    1200         base: VirtualRegister,
    1201         property: VirtualRegister,
    1202     }
    1203 
    1204 op :get_direct_pname,
    1205     args: {
    1206         dst: VirtualRegister,
    1207         base: VirtualRegister,
    1208         property: VirtualRegister,
     1177        enumeratorMetadata: EnumeratorMetadata,
     1178    }
     1179
     1180op :enumerator_get_by_val,
     1181    args: {
     1182        dst: VirtualRegister,
     1183        base: VirtualRegister,
     1184        mode: VirtualRegister,
     1185        propertyName: VirtualRegister,
    12091186        index: VirtualRegister,
    12101187        enumerator: VirtualRegister,
    … …  
    12121189    metadata: {
    12131190        profile: ValueProfile,
    1214     }
    1215 
    1216 op :get_property_enumerator,
    1217     args: {
    1218         dst: VirtualRegister,
    1219         base: VirtualRegister,
    1220     }
    1221 
    1222 op :enumerator_structure_pname,
    1223     args: {
    1224         dst: VirtualRegister,
     1191        arrayProfile: ArrayProfile,
     1192        enumeratorMetadata: EnumeratorMetadata,
     1193    }
     1194
     1195op :enumerator_in_by_val,
     1196    args: {
     1197        dst: VirtualRegister,
     1198        base: VirtualRegister,
     1199        mode: VirtualRegister,
     1200        propertyName: VirtualRegister,
     1201        index: VirtualRegister,
    12251202        enumerator: VirtualRegister,
     1203    },
     1204    metadata: {
     1205        arrayProfile: ArrayProfile,
     1206        enumeratorMetadata: EnumeratorMetadata,
     1207    }
     1208
     1209op :enumerator_has_own_property,
     1210    args: {
     1211        dst: VirtualRegister,
     1212        base: VirtualRegister,
     1213        mode: VirtualRegister,
     1214        propertyName: VirtualRegister,
    12261215        index: VirtualRegister,
    1227     }
    1228 
    1229 op :enumerator_generic_pname,
    1230     args: {
    1231         dst: VirtualRegister,
    12321216        enumerator: VirtualRegister,
    1233         index: VirtualRegister,
    1234     }
    1235 
    1236 op :to_index_string,
    1237     args: {
    1238         dst: VirtualRegister,
    1239         index: VirtualRegister,
     1217    },
     1218    metadata: {
     1219        arrayProfile: ArrayProfile,
     1220        enumeratorMetadata: EnumeratorMetadata,
    12401221    }
    12411222
  • trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp

    r277926 r280760  
    164164    USES(OpSpread, argument)
    165165    USES(OpGetPropertyEnumerator, base)
    166     USES(OpGetEnumerableLength, base)
    167166    USES(OpNewFuncExp, scope)
    168167    USES(OpNewGeneratorFuncExp, scope)
    169168    USES(OpNewAsyncFuncExp, scope)
    170     USES(OpToIndexString, index)
    171169    USES(OpCreateLexicalEnvironment, scope, symbolTable, initialValue)
    172170    USES(OpCreateGeneratorFrameEnvironment, scope, symbolTable, initialValue)
    … …  
    222220    USES(OpNewArrayBuffer, immutableButterfly)
    223221
    224     USES(OpHasEnumerableIndexedProperty, base, property)
    225     USES(OpHasEnumerableStructureProperty, base, property, enumerator)
    226     USES(OpHasEnumerableProperty, base, property)
    227     USES(OpEnumeratorStructurePname, enumerator, index)
    228     USES(OpEnumeratorGenericPname, enumerator, index)
    229222    USES(OpGetByVal, base, property)
    230223    USES(OpGetPrivateName, base, property)
    … …  
    266259    USES(OpGetByValWithThis, base, thisValue, property)
    267260    USES(OpInstanceofCustom, value, constructor, hasInstanceValue)
    268     USES(OpHasOwnStructureProperty, base, property, enumerator)
    269     USES(OpInStructureProperty, base, property, enumerator)
    270261
    271262    case op_call_varargs: {
    … …  
    285276    }
    286277
    287     USES(OpGetDirectPname, base, property, index, enumerator)
    288 
    289278    USES(OpSwitchString, scrutinee)
    290279    USES(OpSwitchChar, scrutinee)
    … …  
    295284
    296285    USES(OpYield, argument)
     286
     287    USES(OpEnumeratorNext, mode, index, base, enumerator)
     288    USES(OpEnumeratorGetByVal, base, mode, propertyName, index, enumerator)
     289    USES(OpEnumeratorInByVal, base, mode, propertyName, index, enumerator)
     290    USES(OpEnumeratorHasOwnProperty, base, mode, propertyName, index, enumerator)
    297291
    298292    case op_iterator_open: {
    … …  
    425419    // These all have a single destination for the first argument.
    426420    DEFS(OpArgumentCount, dst)
    427     DEFS(OpToIndexString, dst)
    428     DEFS(OpGetEnumerableLength, dst)
    429     DEFS(OpHasEnumerableIndexedProperty, dst)
    430     DEFS(OpHasEnumerableStructureProperty, dst)
    431     DEFS(OpHasEnumerableProperty, dst)
    432     DEFS(OpHasOwnStructureProperty, dst)
    433     DEFS(OpInStructureProperty, dst)
    434     DEFS(OpGetDirectPname, dst)
    435421    DEFS(OpGetPropertyEnumerator, dst)
    436     DEFS(OpEnumeratorStructurePname, dst)
    437     DEFS(OpEnumeratorGenericPname, dst)
    438422    DEFS(OpGetParentScope, dst)
    439423    DEFS(OpPushWithScope, dst)
    … …  
    568552    DEFS(OpCatch, exception, thrownValue)
    569553
     554    DEFS(OpEnumeratorNext, propertyName, mode, index)
     555    DEFS(OpEnumeratorGetByVal, dst)
     556    DEFS(OpEnumeratorInByVal, dst)
     557    DEFS(OpEnumeratorHasOwnProperty, dst)
     558
    570559    case op_iterator_open: {
    571560        auto bytecode = instruction->as<OpIteratorOpen>();
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r280004 r280760  
    473473        m_bytecodeCost += opcodeLengths[opcodeID];
    474474        switch (opcodeID) {
    475         LINK(OpHasEnumerableIndexedProperty)
    476 
    477475        LINK(OpCallVarargs, profile)
    478476        LINK(OpTailCallVarargs, profile)
    … …  
    482480        LINK(OpGetPrivateName, profile)
    483481
    484         LINK(OpGetDirectPname, profile)
    485482        LINK(OpGetByIdWithThis, profile)
    486483        LINK(OpTryGetById, profile)
    … …  
    503500
    504501        LINK(OpGetById, profile)
     502
     503        LINK(OpEnumeratorNext, profile)
     504        LINK(OpEnumeratorInByVal, profile)
     505        LINK(OpEnumeratorHasOwnProperty, profile)
     506        LINK(OpEnumeratorGetByVal, profile)
    505507
    506508        LINK(OpCall, profile)
  • trunk/Source/JavaScriptCore/bytecode/LinkTimeConstant.h

    r275439 r280760  
    112112    v(hasOwnPropertyFunction, nullptr) \
    113113    v(createPrivateSymbol, nullptr) \
     114    v(emptyPropertyNameEnumerator, nullptr) \
    114115
    115116
  • trunk/Source/JavaScriptCore/bytecode/Opcode.h

    r273972 r280760  
    11/*
    2  * Copyright (C) 2008, 2009, 2013, 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008-2021 Apple Inc. All rights reserved.
    33 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
    44 *
    … …  
    100100    macro(OpConstructVarargs) \
    101101    macro(OpGetByVal) \
    102     macro(OpGetDirectPname) \
     102    macro(OpEnumeratorGetByVal) \
    103103    macro(OpGetById) \
    104104    macro(OpGetByIdWithThis) \
    … …  
    128128
    129129#define FOR_EACH_OPCODE_WITH_ARRAY_PROFILE(macro) \
    130     macro(OpHasEnumerableIndexedProperty) \
    131130    macro(OpCallVarargs) \
    132131    macro(OpTailCallVarargs) \
    … …  
    137136    macro(OpPutByVal) \
    138137    macro(OpPutByValDirect) \
     138    macro(OpEnumeratorNext) \
     139    macro(OpEnumeratorGetByVal) \
     140    macro(OpEnumeratorInByVal) \
     141    macro(OpEnumeratorHasOwnProperty) \
    139142
    140143#define FOR_EACH_OPCODE_WITH_ARRAY_ALLOCATION_PROFILE(macro) \
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r279448 r280760  
    15041504}
    15051505
    1506 void BytecodeGenerator::recordHasOwnStructurePropertyInForInLoop(StructureForInContext& structureContext, unsigned branchOffset, Label& genericPath)
     1506void BytecodeGenerator::recordHasOwnPropertyInForInLoop(ForInContext& context, unsigned branchOffset, Label& genericPath)
    15071507{
    15081508    RELEASE_ASSERT(genericPath.isBound());
    15091509    RELEASE_ASSERT(!genericPath.isForward());
    1510     structureContext.addHasOwnPropertyJump(branchOffset, genericPath.location());
     1510    context.addHasOwnPropertyJump(branchOffset, genericPath.location());
    15111511}
    15121512
    … …  
    25822582            continue;
    25832583
    2584         if (!context.isStructureForInContext())
    2585             break;
    2586 
    2587         StructureForInContext& structureContext = context.asStructureForInContext();
    2588         OpInStructureProperty::emit<OpcodeSize::Wide32>(this, dst, base, property, structureContext.enumerator());
    2589         structureContext.addInInst(m_lastInstruction.offset(), property->index());
     2584        OpEnumeratorInByVal::emit<OpcodeSize::Wide32>(this, dst, base, context.mode(), property, context.propertyOffset(), context.enumerator());
     2585        context.addInInst(m_lastInstruction.offset(), property->index());
    25902586        return dst;
    25912587    }
    … …  
    27352731            continue;
    27362732
    2737         if (context.isIndexedForInContext()) {
    2738             auto& indexedContext = context.asIndexedForInContext();
    2739             kill(dst);
    2740             if (OpGetByVal::checkWithoutMetadataID<OpcodeSize::Narrow>(this, dst, base, property))
    2741                 OpGetByVal::emitWithSmallestSizeRequirement<OpcodeSize::Narrow>(this, dst, base, indexedContext.index());
    2742             else if (OpGetByVal::checkWithoutMetadataID<OpcodeSize::Wide16>(this, dst, base, property))
    2743                 OpGetByVal::emitWithSmallestSizeRequirement<OpcodeSize::Wide16>(this, dst, base, indexedContext.index());
    2744             else
    2745                 OpGetByVal::emit<OpcodeSize::Wide32>(this, dst, base, indexedContext.index());
    2746             indexedContext.addGetInst(m_lastInstruction.offset(), property->index());
    2747             return dst;
    2748         }
    2749 
    2750         // We cannot do the above optimization here since OpGetDirectPname => OpGetByVal conversion involves different metadata ID allocation.
    2751         StructureForInContext& structureContext = context.asStructureForInContext();
    2752         OpGetDirectPname::emit<OpcodeSize::Wide32>(this, kill(dst), base, property, structureContext.index(), structureContext.enumerator());
    2753 
    2754         structureContext.addGetInst(m_lastInstruction.offset(), property->index());
     2733        // FIXME: We should have a better bytecode rewriter that can resize chunks.
     2734        OpEnumeratorGetByVal::emit<OpcodeSize::Wide32>(this, kill(dst), base, context.mode(), property, context.propertyOffset(), context.enumerator());
     2735        context.addGetInst(m_lastInstruction.offset(), property->index());
    27552736        return dst;
    27562737    }
    … …  
    45534534}
    45544535
    4555 RegisterID* BytecodeGenerator::emitGetEnumerableLength(RegisterID* dst, RegisterID* base)
    4556 {
    4557     OpGetEnumerableLength::emit(this, dst, base);
    4558     return dst;
    4559 }
    4560 
    4561 RegisterID* BytecodeGenerator::emitHasEnumerableIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName)
    4562 {
    4563     OpHasEnumerableIndexedProperty::emit(this, dst, base, propertyName);
    4564     return dst;
    4565 }
    4566 
    4567 RegisterID* BytecodeGenerator::emitHasEnumerableStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator)
    4568 {
    4569     OpHasEnumerableStructureProperty::emit(this, dst, base, propertyName, enumerator);
    4570     return dst;
    4571 }
    4572 
    4573 RegisterID* BytecodeGenerator::emitHasEnumerableProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName)
    4574 {
    4575     OpHasEnumerableProperty::emit(this, dst, base, propertyName);
    4576     return dst;
    4577 }
    4578 
    4579 RegisterID* BytecodeGenerator::emitHasOwnStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator)
    4580 {
    4581     OpHasOwnStructureProperty::emit(this, dst, base, propertyName, enumerator);
     4536void BytecodeGenerator::emitEnumeratorNext(RegisterID* propertyName, RegisterID* mode, RegisterID* index, RegisterID* base, RegisterID* enumerator)
     4537{
     4538    OpEnumeratorNext::emit(this, propertyName, mode, index, base, enumerator);
     4539}
     4540
     4541RegisterID* BytecodeGenerator::emitEnumeratorHasOwnProperty(RegisterID* dst, RegisterID* base, RegisterID* mode, RegisterID* propertyName, RegisterID* index, RegisterID* enumerator)
     4542{
     4543    OpEnumeratorHasOwnProperty::emit(this, dst, base, mode, propertyName, index, enumerator);
    45824544    return dst;
    45834545}
    … …  
    45894551}
    45904552
    4591 RegisterID* BytecodeGenerator::emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index)
    4592 {
    4593     OpEnumeratorStructurePname::emit(this, dst, enumerator, index);
    4594     return dst;
    4595 }
    4596 
    4597 RegisterID* BytecodeGenerator::emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index)
    4598 {
    4599     OpEnumeratorGenericPname::emit(this, dst, enumerator, index);
    4600     return dst;
    4601 }
    4602 
    4603 RegisterID* BytecodeGenerator::emitToIndexString(RegisterID* dst, RegisterID* index)
    4604 {
    4605     OpToIndexString::emit(this, dst, index);
    4606     return dst;
    4607 }
    4608 
    46094553RegisterID* BytecodeGenerator::emitIsCellWithType(RegisterID* dst, RegisterID* src, JSType type)
    46104554{
    … …  
    46474591    OpIsEmpty::emit(this, dst, src);
    46484592    return dst;
    4649 }
    4650 
    4651 void BytecodeGenerator::pushIndexedForInScope(RegisterID* localRegister, RegisterID* indexRegister)
    4652 {
    4653     if (!localRegister)
    4654         return;
    4655     unsigned bodyBytecodeStartOffset = instructions().size();
    4656     m_forInContextStack.append(adoptRef(*new IndexedForInContext(localRegister, indexRegister, bodyBytecodeStartOffset)));
    4657 }
    4658 
    4659 void BytecodeGenerator::popIndexedForInScope(RegisterID* localRegister)
    4660 {
    4661     if (!localRegister)
    4662         return;
    4663     unsigned bodyBytecodeEndOffset = instructions().size();
    4664     m_forInContextStack.last()->asIndexedForInContext().finalize(*this, m_codeBlock.get(), bodyBytecodeEndOffset);
    4665     m_forInContextStack.removeLast();
    46664593}
    46674594
    … …  
    47694696}
    47704697
    4771 void BytecodeGenerator::pushStructureForInScope(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister, std::optional<Variable> baseVariable)
     4698void BytecodeGenerator::pushForInScope(RegisterID* localRegister, RegisterID* propertyNameRegister, RegisterID* propertyOffsetRegister, RegisterID* enumeratorRegister, RegisterID* modeRegister, std::optional<Variable> baseVariable)
    47724699{
    47734700    if (!localRegister)
    47744701        return;
    47754702    unsigned bodyBytecodeStartOffset = instructions().size();
    4776     m_forInContextStack.append(adoptRef(*new StructureForInContext(localRegister, indexRegister, propertyRegister, enumeratorRegister, baseVariable, bodyBytecodeStartOffset)));
    4777 }
    4778 
    4779 void BytecodeGenerator::popStructureForInScope(RegisterID* localRegister)
     4703    m_forInContextStack.append(adoptRef(*new ForInContext(localRegister, propertyNameRegister, propertyOffsetRegister, enumeratorRegister, modeRegister, baseVariable, bodyBytecodeStartOffset)));
     4704}
     4705
     4706void BytecodeGenerator::popForInScope(RegisterID* localRegister)
    47804707{
    47814708    if (!localRegister)
    47824709        return;
    47834710    unsigned bodyBytecodeEndOffset = instructions().size();
    4784     m_forInContextStack.last()->asStructureForInContext().finalize(*this, m_codeBlock.get(), bodyBytecodeEndOffset);
     4711    m_forInContextStack.last()->finalize(*this, m_codeBlock.get(), bodyBytecodeEndOffset);
    47854712    m_forInContextStack.removeLast();
    47864713}
    … …  
    53855312}
    53865313
     5314template <typename OldOpType, typename NewOpType, typename TupleType>
     5315ALWAYS_INLINE void rewriteOp(BytecodeGenerator& generator, TupleType& instTuple)
     5316{
     5317    unsigned instIndex = std::get<0>(instTuple);
     5318    int propertyRegIndex = std::get<1>(instTuple);
     5319    auto instruction = generator.m_writer.ref(instIndex);
     5320    auto end = instIndex + instruction->size();
     5321    ASSERT(instruction->isWide32());
     5322
     5323    generator.m_writer.seek(instIndex);
     5324
     5325    auto bytecode = instruction->as<OldOpType>();
     5326
     5327    generator.disablePeepholeOptimization();
     5328
     5329    // Change the opcode to get_by_val.
     5330    // 1. dst stays the same.
     5331    // 2. base stays the same.
     5332    // 3. property gets switched to the original property.
     5333
     5334    static_assert(sizeof(NewOpType) <= sizeof(OldOpType));
     5335    NewOpType::emit(&generator, bytecode.m_dst, bytecode.m_base, VirtualRegister(propertyRegIndex));
     5336
     5337    // 4. nop out the remaining bytes
     5338    while (generator.m_writer.position() < end)
     5339        OpNop::emit<OpcodeSize::Narrow>(&generator);
     5340}
     5341
    53875342void ForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlockGenerator* codeBlock, unsigned bodyBytecodeEndOffset)
    53885343{
    … …  
    53995354    // reassigned from its original value.
    54005355
    5401     for (unsigned offset = bodyBytecodeStartOffset(); isValid() && offset < bodyBytecodeEndOffset;) {
     5356    bool escaped = false;
     5357    for (unsigned offset = bodyBytecodeStartOffset(); !escaped && offset < bodyBytecodeEndOffset;) {
    54025358        auto instruction = generator.instructions().at(offset);
    54035359        ASSERT(!instruction->is<OpEnter>());
    … …  
    54055361            computeDefsForBytecodeIndex(codeBlock, instruction.ptr(), checkpoint, [&] (VirtualRegister operand) {
    54065362                if (local()->virtualRegister() == operand)
    5407                     invalidate();
     5363                    escaped = true;
    54085364            });
    54095365        }
    54105366        offset += instruction->size();
    54115367    }
    5412 }
    5413 
    5414 template <typename OldOpType, typename TupleType>
    5415 ALWAYS_INLINE void rewriteOp(BytecodeGenerator& generator, TupleType& instTuple)
    5416 {
    5417     unsigned instIndex = std::get<0>(instTuple);
    5418     int propertyRegIndex = std::get<1>(instTuple);
    5419     auto instruction = generator.m_writer.ref(instIndex);
    5420     auto end = instIndex + instruction->size();
    5421     ASSERT(instruction->isWide32());
    5422 
    5423     generator.m_writer.seek(instIndex);
    5424 
    5425     auto bytecode = instruction->as<OldOpType>();
    5426 
    5427     generator.disablePeepholeOptimization();
    5428 
    5429     // Change the opcode to get_by_val.
    5430     // 1. dst stays the same.
    5431     // 2. base stays the same.
    5432     // 3. property gets switched to the original property.
    5433 
    5434     if constexpr (std::is_same<OldOpType, OpGetDirectPname>::value) {
    5435         static_assert(sizeof(OpGetByVal) <= sizeof(OpGetDirectPname));
    5436         OpGetByVal::emit<OpcodeSize::Wide32>(&generator, bytecode.m_dst, bytecode.m_base, VirtualRegister(propertyRegIndex));
    5437     } else if constexpr (std::is_same<OldOpType, OpInStructureProperty>::value) {
    5438         static_assert(sizeof(OpInByVal) <= sizeof(OpInStructureProperty));
    5439         OpInByVal::emit<OpcodeSize::Wide32>(&generator, bytecode.m_dst, bytecode.m_base, VirtualRegister(propertyRegIndex));
    5440     } else
    5441         RELEASE_ASSERT_NOT_REACHED();
    5442 
    5443     // 4. nop out the remaining bytes
    5444     while (generator.m_writer.position() < end)
    5445         OpNop::emit<OpcodeSize::Narrow>(&generator);
    5446 }
    5447 
    5448 void StructureForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlockGenerator* codeBlock, unsigned bodyBytecodeEndOffset)
    5449 {
    5450     Base::finalize(generator, codeBlock, bodyBytecodeEndOffset);
    5451     if (isValid())
     5368
     5369    if (!escaped)
    54525370        return;
    54535371
    … …  
    54565374
    54575375    for (const auto& instTuple : m_getInsts)
    5458         rewriteOp<OpGetDirectPname>(generator, instTuple);
     5376        rewriteOp<OpEnumeratorGetByVal, OpGetByVal>(generator, instTuple);
    54595377
    54605378    for (const auto& instTuple : m_inInsts)
    5461         rewriteOp<OpInStructureProperty>(generator, instTuple);
     5379        rewriteOp<OpEnumeratorInByVal, OpInByVal>(generator, instTuple);
    54625380
    54635381    for (const auto& hasOwnPropertyTuple : m_hasOwnPropertyJumpInsts) {
    … …  
    54855403        generator.m_lastOpcodeID = lastOpcodeID;
    54865404        generator.m_lastInstruction = lastInstruction;
    5487     }
    5488 }
    5489 
    5490 void IndexedForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlockGenerator* codeBlock, unsigned bodyBytecodeEndOffset)
    5491 {
    5492     Base::finalize(generator, codeBlock, bodyBytecodeEndOffset);
    5493     if (isValid())
    5494         return;
    5495 
    5496     for (const auto& instPair : m_getInsts) {
    5497         unsigned instIndex = instPair.first;
    5498         int propertyRegIndex = instPair.second;
    5499         generator.m_writer.ref(instIndex)->cast<OpGetByVal>()->setProperty(VirtualRegister(propertyRegIndex), []() {
    5500             ASSERT_NOT_REACHED();
    5501             return VirtualRegister();
    5502         });
    55035405    }
    55045406}
    … …  
    55295431}
    55305432
    5531 StructureForInContext* BytecodeGenerator::findStructureForInContext(RegisterID* property)
     5433ForInContext* BytecodeGenerator::findForInContext(RegisterID* property)
    55325434{
    55335435    for (size_t i = m_forInContextStack.size(); i--; ) {
    … …  
    55365438            continue;
    55375439
    5538         if (!context.isStructureForInContext())
    5539             break;
    5540 
    5541         return &context.asStructureForInContext();
     5440        return &context;
    55425441    }
    55435442
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r279447 r280760  
    6262    class JSImmutableButterfly;
    6363    class Identifier;
    64     class IndexedForInContext;
    65     class StructureForInContext;
     64    class ForInContext;
    6665
    6766    enum ExpectedFunction {
    … …  
    257256        WTF_MAKE_NONCOPYABLE(ForInContext);
    258257    public:
    259         virtual ~ForInContext() = default;
    260 
    261         bool isValid() const { return m_isValid; }
    262         void invalidate() { m_isValid = false; }
    263 
    264         enum class Type : uint8_t {
    265             IndexedForIn,
    266             StructureForIn
    267         };
    268 
    269         Type type() const { return m_type; }
    270         bool isIndexedForInContext() const { return m_type == Type::IndexedForIn; }
    271         bool isStructureForInContext() const { return m_type == Type::StructureForIn; }
    272 
    273         IndexedForInContext& asIndexedForInContext()
    274         {
    275             ASSERT(isIndexedForInContext());
    276             return *reinterpret_cast<IndexedForInContext*>(this);
    277         }
    278 
    279         StructureForInContext& asStructureForInContext()
    280         {
    281             ASSERT(isStructureForInContext());
    282             return *reinterpret_cast<StructureForInContext*>(this);
    283         }
    284 
    285         RegisterID* local() const { return m_localRegister.get(); }
    286 
    287     protected:
    288         ForInContext(RegisterID* localRegister, Type type, unsigned bodyBytecodeStartOffset)
    289             : m_localRegister(localRegister)
    290             , m_type(type)
    291             , m_bodyBytecodeStartOffset(bodyBytecodeStartOffset)
    292         { }
    293 
    294         unsigned bodyBytecodeStartOffset() const { return m_bodyBytecodeStartOffset; }
    295 
    296         void finalize(BytecodeGenerator&, UnlinkedCodeBlockGenerator*, unsigned bodyBytecodeEndOffset);
    297 
    298     private:
    299         RefPtr<RegisterID> m_localRegister;
    300         bool m_isValid { true };
    301         Type m_type;
    302         unsigned m_bodyBytecodeStartOffset;
    303     };
    304 
    305     class StructureForInContext : public ForInContext {
    306         using Base = ForInContext;
    307     public:
    308258        using GetInst = std::tuple<unsigned, int>;
    309259        using InInst = GetInst;
    310260        using HasOwnPropertyJumpInst = std::tuple<unsigned, unsigned>;
    311261
    312         StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister, std::optional<Variable> baseVariable, unsigned bodyBytecodeStartOffset)
    313             : ForInContext(localRegister, Type::StructureForIn, bodyBytecodeStartOffset)
    314             , m_indexRegister(indexRegister)
    315             , m_propertyRegister(propertyRegister)
    316             , m_enumeratorRegister(enumeratorRegister)
     262        bool isValid() const { return m_isValid; }
     263        void invalidate() { m_isValid = false; }
     264
     265        RegisterID* local() const { return m_localRegister.get(); }
     266        RegisterID* propertyName() const { return m_propertyName.get(); }
     267        RegisterID* propertyOffset() const { return m_propertyOffset.get(); }
     268        RegisterID* enumerator() const { return m_enumerator.get(); }
     269        RegisterID* mode() const { return m_mode.get(); }
     270        const std::optional<Variable>& baseVariable() const { return m_baseVariable; }
     271
     272        void addGetInst(unsigned instIndex, int propertyRegIndex)
     273        {
     274            m_getInsts.append(GetInst { instIndex, propertyRegIndex });
     275        }
     276
     277        void addInInst(unsigned instIndex, int propertyRegIndex)
     278        {
     279            m_inInsts.append(InInst { instIndex, propertyRegIndex });
     280        }
     281
     282        void addHasOwnPropertyJump(unsigned branchInstIndex, unsigned genericPathTarget)
     283        {
     284            m_hasOwnPropertyJumpInsts.append(HasOwnPropertyJumpInst { branchInstIndex, genericPathTarget });
     285        }
     286
     287        ForInContext(RegisterID* localRegister, RegisterID* propertyName, RegisterID* propertyOffset, RegisterID* enumerator, RegisterID* mode, std::optional<Variable> baseVariable, unsigned bodyBytecodeStartOffset)
     288            : m_localRegister(localRegister)
     289            , m_propertyName(propertyName)
     290            , m_propertyOffset(propertyOffset)
     291            , m_enumerator(enumerator)
     292            , m_mode(mode)
    317293            , m_baseVariable(baseVariable)
    318         {
    319         }
    320 
    321         RegisterID* index() const { return m_indexRegister.get(); }
    322         RegisterID* property() const { return m_propertyRegister.get(); }
    323         RegisterID* enumerator() const { return m_enumeratorRegister.get(); }
    324         const std::optional<Variable>& baseVariable() const { return m_baseVariable; }
    325 
    326         void addGetInst(unsigned instIndex, int propertyRegIndex)
    327         {
    328             m_getInsts.append(GetInst { instIndex, propertyRegIndex });
    329         }
    330 
    331         void addInInst(unsigned instIndex, int propertyRegIndex)
    332         {
    333             m_inInsts.append(InInst { instIndex, propertyRegIndex });
    334         }
    335 
    336         void addHasOwnPropertyJump(unsigned branchInstIndex, unsigned genericPathTarget)
    337         {
    338             m_hasOwnPropertyJumpInsts.append(HasOwnPropertyJumpInst { branchInstIndex, genericPathTarget });
    339         }
     294            , m_bodyBytecodeStartOffset(bodyBytecodeStartOffset)
     295        { }
     296
     297        unsigned bodyBytecodeStartOffset() const { return m_bodyBytecodeStartOffset; }
    340298
    341299        void finalize(BytecodeGenerator&, UnlinkedCodeBlockGenerator*, unsigned bodyBytecodeEndOffset);
    342300
    343301    private:
    344         RefPtr<RegisterID> m_indexRegister;
    345         RefPtr<RegisterID> m_propertyRegister;
    346         RefPtr<RegisterID> m_enumeratorRegister;
     302        RefPtr<RegisterID> m_localRegister;
     303        RefPtr<RegisterID> m_propertyName;
     304        RefPtr<RegisterID> m_propertyOffset;
     305        RefPtr<RegisterID> m_enumerator;
     306        RefPtr<RegisterID> m_mode;
    347307        std::optional<Variable> m_baseVariable;
     308        bool m_isValid { true };
     309        unsigned m_bodyBytecodeStartOffset;
     310        Vector<InInst> m_inInsts;
    348311        Vector<GetInst> m_getInsts;
    349         Vector<InInst> m_inInsts;
    350312        Vector<HasOwnPropertyJumpInst> m_hasOwnPropertyJumpInsts;
    351     };
    352 
    353     class IndexedForInContext : public ForInContext {
    354         using Base = ForInContext;
    355     public:
    356         IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister, unsigned bodyBytecodeStartOffset)
    357             : ForInContext(localRegister, Type::IndexedForIn, bodyBytecodeStartOffset)
    358             , m_indexRegister(indexRegister)
    359         {
    360         }
    361 
    362         RegisterID* index() const { return m_indexRegister.get(); }
    363 
    364         void finalize(BytecodeGenerator&, UnlinkedCodeBlockGenerator*, unsigned bodyBytecodeEndOffset);
    365         void addGetInst(unsigned instIndex, int propertyIndex) { m_getInsts.append({ instIndex, propertyIndex }); }
    366 
    367     private:
    368         RefPtr<RegisterID> m_indexRegister;
    369         Vector<std::pair<unsigned, int>> m_getInsts;
    370313    };
    371314
    … …  
    400343
    401344        friend class FinallyContext;
    402         friend class IndexedForInContext;
    403         friend class StructureForInContext;
     345        friend class ForInContext;
    404346        friend class StrictModeScope;
    405347
    406         template <typename OldOpType, typename TupleType>
     348        template <typename OldOpType, typename NewOpType, typename TupleType>
    407349        friend void rewriteOp(BytecodeGenerator&, TupleType&);
    408350
    … …  
    682624        void hoistSloppyModeFunctionIfNecessary(const Identifier& functionName);
    683625
    684         StructureForInContext* findStructureForInContext(RegisterID* property);
     626        ForInContext* findForInContext(RegisterID* property);
    685627
    686628    private:
    … …  
    918860        void emitJumpIfNotFunctionApply(RegisterID* cond, Label& target);
    919861        unsigned emitWideJumpIfNotFunctionHasOwnProperty(RegisterID* cond, Label& target);
    920         void recordHasOwnStructurePropertyInForInLoop(StructureForInContext&, unsigned branchOffset, Label& genericPath);
     862        void recordHasOwnPropertyInForInLoop(ForInContext&, unsigned branchOffset, Label& genericPath);
    921863
    922864        template<typename BinOp, typename JmpOp>
    … …  
    929871        void emitCheckTraps();
    930872
    931         RegisterID* emitHasEnumerableIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName);
    932         RegisterID* emitHasEnumerableStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator);
    933         RegisterID* emitHasEnumerableProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName);
    934         RegisterID* emitHasOwnStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator);
    935873        RegisterID* emitGetPropertyEnumerator(RegisterID* dst, RegisterID* base);
    936         RegisterID* emitGetEnumerableLength(RegisterID* dst, RegisterID* base);
    937         RegisterID* emitGetStructurePropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length);
    938         RegisterID* emitGetGenericPropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length, RegisterID* structureEnumerator);
    939         RegisterID* emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index);
    940         RegisterID* emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index);
    941         RegisterID* emitToIndexString(RegisterID* dst, RegisterID* index);
     874        void emitEnumeratorNext(RegisterID* propertyName, RegisterID* mode, RegisterID* index, RegisterID* base, RegisterID* enumerator);
     875        RegisterID* emitEnumeratorHasOwnProperty(RegisterID* dst, RegisterID* base, RegisterID* mode, RegisterID* propertyName, RegisterID* index, RegisterID* enumerator);
    942876
    943877        RegisterID* emitIsCellWithType(RegisterID* dst, RegisterID* src, JSType);
    … …  
    1058992        void emitOptionalCheck(RegisterID* src);
    1059993
    1060         void pushIndexedForInScope(RegisterID* local, RegisterID* index);
    1061         void popIndexedForInScope(RegisterID* local);
    1062         void pushStructureForInScope(RegisterID* local, RegisterID* index, RegisterID* property, RegisterID* enumerator, std::optional<Variable> base);
    1063         void popStructureForInScope(RegisterID* local);
     994        void pushForInScope(RegisterID* local, RegisterID* propertyName, RegisterID* propertyOffset, RegisterID* enumerator, RegisterID* mode, std::optional<Variable> base);
     995        void popForInScope(RegisterID* local);
    1064996
    1065997        LabelScope* breakTarget(const Identifier&);
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r279447 r280760  
    21322132    ExpressionNode* argument = m_args->m_listNode->m_expr;
    21332133    RELEASE_ASSERT(argument->isResolveNode());
    2134     StructureForInContext* structureContext = nullptr;
     2134    ForInContext* context = nullptr;
    21352135    Variable argumentVariable = generator.variable(static_cast<ResolveNode*>(argument)->identifier());
    21362136    if (argumentVariable.isLocal()) {
    21372137        RegisterID* property = argumentVariable.local();
    2138         structureContext = generator.findStructureForInContext(property);
     2138        context = generator.findForInContext(property);
    21392139    }
    21402140
    21412141    auto canUseFastHasOwnProperty = [&] {
    2142         if (!structureContext)
     2142        if (!context)
    21432143            return false;
    2144         if (!structureContext->baseVariable())
     2144        if (!context->baseVariable())
    21452145            return false;
    21462146        if (m_base->isResolveNode())
    2147             return generator.variable(static_cast<ResolveNode*>(m_base)->identifier()) == structureContext->baseVariable().value();
     2147            return generator.variable(static_cast<ResolveNode*>(m_base)->identifier()) == context->baseVariable().value();
    21482148        if (m_base->isThisNode()) {
    21492149            // After generator.ensureThis (which must be invoked in |base|'s materialization), we can ensure that |this| is in local this-register.
    21502150            ASSERT(base);
    2151             return generator.variable(generator.propertyNames().builtinNames().thisPrivateName(), ThisResolutionType::Local) == structureContext->baseVariable().value();
     2151            return generator.variable(generator.propertyNames().builtinNames().thisPrivateName(), ThisResolutionType::Local) == context->baseVariable().value();
    21522152        }
    21532153        return false;
    … …  
    21612161
    21622162        unsigned branchInsnOffset = generator.emitWideJumpIfNotFunctionHasOwnProperty(function.get(), realCall.get());
    2163         generator.emitHasOwnStructureProperty(returnValue.get(), base.get(), generator.emitNode(argument), structureContext->enumerator());
     2163        generator.emitEnumeratorHasOwnProperty(returnValue.get(), base.get(), context->mode(), generator.emitNode(argument), context->propertyOffset(), context->enumerator());
    21642164        generator.emitJump(end.get());
    21652165
    … …  
    21732173        generator.emitLabel(end.get());
    21742174
    2175         generator.recordHasOwnStructurePropertyInForInLoop(*structureContext, branchInsnOffset, realCall);
     2175        generator.recordHasOwnPropertyInForInLoop(*context, branchInsnOffset, realCall);
    21762176    } else {
    21772177        CallArguments callArguments(generator, m_args);
    … …  
    41854185        generator.emitLoad(dst, jsUndefined());
    41864186
    4187     Ref<Label> end = generator.newLabel();
    4188 
    41894187    RegisterID* forLoopSymbolTable = nullptr;
    41904188    generator.pushLexicalScope(this, BytecodeGenerator::ScopeType::LetConstScope, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested, &forLoopSymbolTable);
    … …  
    41944192
    41954193    RefPtr<RegisterID> base = generator.newTemporary();
    4196     RefPtr<RegisterID> length;
    4197     RefPtr<RegisterID> enumerator;
    41984194
    41994195    generator.emitNode(base.get(), m_expr);
    42004196    RefPtr<RegisterID> local = this->tryGetBoundLocal(generator);
    4201     RefPtr<RegisterID> enumeratorIndex;
     4197
    42024198
    42034199    std::optional<Variable> baseVariable;
    … …  
    42104206    }
    42114207
    4212     // Pause at the assignment expression for each for..in iteration.
    4213     generator.emitDebugHook(m_lexpr);
    4214 
    42154208    int profilerStartOffset = m_statement->startOffset();
    42164209    int profilerEndOffset = m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0);
    42174210
    4218     enumerator = generator.emitGetPropertyEnumerator(generator.newTemporary(), base.get());
    4219 
    4220     BytecodeGenerator::PreservedTDZStack preservedTDZStack;
    4221     generator.preserveTDZStack(preservedTDZStack);
    4222 
    4223     // Indexed property loop.
    42244211    {
     4212        RefPtr<RegisterID> enumerator = generator.newTemporary();
     4213        RefPtr<RegisterID> mode = generator.emitLoad(generator.newTemporary(), jsNumber(static_cast<unsigned>(JSPropertyNameEnumerator::InitMode)));
     4214        RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(0));
     4215        RefPtr<RegisterID> propertyName = generator.newTemporary();
    42254216        Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
    4226         Ref<Label> loopStart = generator.newLabel();
    4227         Ref<Label> loopEnd = generator.newLabel();
    4228 
    4229         length = generator.emitGetEnumerableLength(generator.newTemporary(), enumerator.get());
    4230         RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0));
    4231         RefPtr<RegisterID> propertyName = generator.newTemporary();
    4232 
    4233         generator.emitLabel(loopStart.get());
     4217
     4218        enumerator = generator.emitGetPropertyEnumerator(generator.newTemporary(), base.get());
     4219        generator.moveLinkTimeConstant(propertyName.get(), LinkTimeConstant::emptyPropertyNameEnumerator);
     4220        generator.emitEqualityOp<OpStricteq>(propertyName.get(), enumerator.get(), propertyName.get());
     4221        generator.emitJumpIfTrue(propertyName.get(), scope->breakTarget());
     4222
     4223        generator.emitLabel(*scope->continueTarget());
    42344224        generator.emitLoopHint();
    4235 
    4236         RefPtr<RegisterID> result = generator.emitBinaryOp<OpLess>(generator.newTemporary(), i.get(), length.get());
    4237         generator.emitJumpIfFalse(result.get(), loopEnd.get());
    4238         generator.emitHasEnumerableIndexedProperty(result.get(), base.get(), i.get());
    4239         generator.emitJumpIfFalse(result.get(), *scope->continueTarget());
    4240 
    4241         generator.emitToIndexString(propertyName.get(), i.get());
     4225        generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
     4226        generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration.
     4227
     4228        // FIXME: We should have a way to see if anyone is actually using the propertyName for something other than a get_by_val. If not, we could eliminate the toString in this opcode.
     4229        generator.emitEnumeratorNext(propertyName.get(), mode.get(), index.get(), base.get(), enumerator.get());
     4230
     4231        // Note, choosing undefined or null helps please DFG's Abstract Interpreter as it doesn't distinguish null and undefined as types (via SpecOther).
     4232        generator.emitJumpIfTrue(generator.emitIsUndefinedOrNull(generator.newTemporary(), propertyName.get()), scope->breakTarget());
     4233
    42424234        this->emitLoopHeader(generator, propertyName.get());
    42434235
    42444236        generator.emitProfileControlFlow(profilerStartOffset);
    42454237
    4246         generator.pushIndexedForInScope(local.get(), i.get());
     4238        generator.pushForInScope(local.get(), propertyName.get(), index.get(), enumerator.get(), mode.get(), baseVariable);
    42474239        generator.emitNode(dst, m_statement);
    4248         generator.popIndexedForInScope(local.get());
     4240        generator.popForInScope(local.get());
    42494241
    42504242        generator.emitProfileControlFlow(profilerEndOffset);
    4251 
    4252         generator.emitLabel(*scope->continueTarget());
    4253         generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
    4254         generator.emitInc(i.get());
    4255         generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration.
    4256         generator.emitJump(loopStart.get());
     4243        generator.emitJump(*scope->continueTarget());
    42574244
    42584245        generator.emitLabel(scope->breakTarget());
    4259         generator.emitJump(end.get());
    4260         generator.emitLabel(loopEnd.get());
    4261     }
    4262     generator.restoreTDZStack(preservedTDZStack);
    4263 
    4264     // Structure property loop.
    4265     {
    4266         Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
    4267         Ref<Label> loopStart = generator.newLabel();
    4268         Ref<Label> loopEnd = generator.newLabel();
    4269 
    4270         enumeratorIndex = generator.emitLoad(generator.newTemporary(), jsNumber(0));
    4271         RefPtr<RegisterID> propertyName = generator.newTemporary();
    4272         generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
    4273 
    4274         generator.emitLabel(loopStart.get());
    4275         generator.emitLoopHint();
    4276 
    4277         RefPtr<RegisterID> result = generator.emitIsNull(generator.newTemporary(), propertyName.get());
    4278         generator.emitJumpIfTrue(result.get(), loopEnd.get());
    4279         generator.emitHasEnumerableStructureProperty(result.get(), base.get(), propertyName.get(), enumerator.get());
    4280         generator.emitJumpIfFalse(result.get(), *scope->continueTarget());
    4281 
    4282         this->emitLoopHeader(generator, propertyName.get());
    4283 
    4284         generator.emitProfileControlFlow(profilerStartOffset);
    4285 
    4286         generator.pushStructureForInScope(local.get(), enumeratorIndex.get(), propertyName.get(), enumerator.get(), baseVariable);
    4287         generator.emitNode(dst, m_statement);
    4288         generator.popStructureForInScope(local.get());
    4289 
    4290         generator.emitProfileControlFlow(profilerEndOffset);
    4291 
    4292         generator.emitLabel(*scope->continueTarget());
    4293         generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
    4294         generator.emitInc(enumeratorIndex.get());
    4295         generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
    4296         generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration.
    4297         generator.emitJump(loopStart.get());
    4298        
    4299         generator.emitLabel(scope->breakTarget());
    4300         generator.emitJump(end.get());
    4301         generator.emitLabel(loopEnd.get());
    4302     }
    4303     generator.restoreTDZStack(preservedTDZStack);
    4304 
    4305     // Generic property loop.
    4306     {
    4307         Ref<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
    4308         Ref<Label> loopStart = generator.newLabel();
    4309         Ref<Label> loopEnd = generator.newLabel();
    4310 
    4311         RefPtr<RegisterID> propertyName = generator.newTemporary();
    4312 
    4313         generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
    4314 
    4315         generator.emitLabel(loopStart.get());
    4316         generator.emitLoopHint();
    4317 
    4318         RefPtr<RegisterID> result = generator.emitIsNull(generator.newTemporary(), propertyName.get());
    4319         generator.emitJumpIfTrue(result.get(), loopEnd.get());
    4320 
    4321         generator.emitHasEnumerableProperty(result.get(), base.get(), propertyName.get());
    4322         generator.emitJumpIfFalse(result.get(), *scope->continueTarget());
    4323 
    4324         this->emitLoopHeader(generator, propertyName.get());
    4325 
    4326         generator.emitProfileControlFlow(profilerStartOffset);
    4327 
    4328         generator.emitNode(dst, m_statement);
    4329 
    4330         generator.emitLabel(*scope->continueTarget());
    4331         generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
    4332         generator.emitInc(enumeratorIndex.get());
    4333         generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
    4334         generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration.
    4335         generator.emitJump(loopStart.get());
    4336 
    4337         generator.emitLabel(scope->breakTarget());
    4338         generator.emitJump(end.get());
    4339         generator.emitLabel(loopEnd.get());
    4340     }
    4341 
    4342     generator.emitLabel(end.get());
     4246    }
     4247
    43434248    generator.popLexicalScope(this);
    43444249    generator.emitProfileControlFlow(profilerEndOffset);
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r279604 r280760  
    21522152        setForNode(node, m_vm.stringStructure.get());
    21532153        break;
    2154            
     2154
     2155    case EnumeratorGetByVal: {
     2156        // FIXME: This should be able to do code motion for OwnStructureMode but we'd need to teach AI about the enumerator's cached structure for that to be profitable.
     2157        clobberWorld();
     2158        makeHeapTopForNode(node);
     2159        break;
     2160    }
     2161
    21552162    case GetByVal:
    21562163    case AtomicsAdd:
    … …  
    42454252        break;
    42464253    }
    4247            
    4248     case GetEnumerableLength: {
    4249         setNonCellTypeForNode(node, SpecInt32Only);
    4250         break;
    4251     }
    4252     case HasEnumerableProperty: {
    4253         setNonCellTypeForNode(node, SpecBoolean);
    4254         clobberWorld();
    4255         break;
    4256     }
    4257     case InStructureProperty:
    4258     case HasOwnStructureProperty:
    4259     case HasEnumerableStructureProperty: {
    4260         setNonCellTypeForNode(node, SpecBoolean);
    4261         clobberWorld();
    4262         break;
    4263     }
    4264     case HasIndexedProperty:
    4265     case HasEnumerableIndexedProperty: {
     4254
     4255    case HasIndexedProperty: {
    42664256        ArrayMode mode = node->arrayMode();
    42674257        switch (mode.type()) {
    … …  
    42824272        break;
    42834273    }
    4284     case GetDirectPname: {
    4285         clobberWorld();
    4286         makeHeapTopForNode(node);
    4287         break;
    4288     }
     4274
    42894275    case GetPropertyEnumerator: {
    42904276        setTypeForNode(node, SpecCell);
    … …  
    42924278        break;
    42934279    }
    4294     case GetEnumeratorStructurePname: {
     4280
     4281    case EnumeratorNextUpdateIndexAndMode: {
     4282        ArrayMode arrayMode = node->arrayMode();
     4283        if (arrayMode.isSaneChain())
     4284            ASSERT(node->enumeratorMetadata() == JSPropertyNameEnumerator::IndexedMode);
     4285        else if (node->enumeratorMetadata() != JSPropertyNameEnumerator::OwnStructureMode || m_graph.varArgChild(node, 0).useKind() != CellUse)
     4286            clobberWorld();
     4287
     4288        setNonCellTypeForNode(node, SpecBytecodeNumber);
     4289        break;
     4290    }
     4291
     4292    case EnumeratorNextExtractMode: {
     4293        if (node->child1()->enumeratorMetadata() == JSPropertyNameEnumerator::IndexedMode) {
     4294            setConstant(node, jsNumber(static_cast<uint8_t>(JSPropertyNameEnumerator::IndexedMode)));
     4295            break;
     4296        }
     4297
     4298        if (node->child1()->enumeratorMetadata() == JSPropertyNameEnumerator::OwnStructureMode && m_graph.varArgChild(node->child1().node(), 0).useKind() == CellUse) {
     4299            setConstant(node, jsNumber(static_cast<uint8_t>(JSPropertyNameEnumerator::OwnStructureMode)));
     4300            break;
     4301        }
     4302
     4303        FALLTHROUGH;
     4304    }
     4305    case EnumeratorNextExtractIndex: {
     4306        setNonCellTypeForNode(node, SpecInt32Only);
     4307        break;
     4308    }
     4309
     4310    case EnumeratorNextUpdatePropertyName: {
    42954311        setTypeForNode(node, SpecString | SpecOther);
    42964312        break;
    42974313    }
    4298     case GetEnumeratorGenericPname: {
    4299         setTypeForNode(node, SpecString | SpecOther);
    4300         break;
    4301     }
    4302     case ToIndexString: {
    4303         setTypeForNode(node, SpecString);
     4314
     4315    case EnumeratorInByVal:
     4316    case EnumeratorHasOwnProperty: {
     4317        // FIXME: We can determine when the property definitely exists based on abstract
     4318        // value information.
     4319        clobberWorld();
     4320        setNonCellTypeForNode(node, SpecBoolean);
    43044321        break;
    43054322    }
  • trunk/Source/JavaScriptCore/dfg/DFGArrayMode.h

    r272170 r280760  
    288288    {
    289289        return speculation() == Array::OutOfBoundsSaneChain;
     290    }
     291
     292    bool isSaneChain() const
     293    {
     294        return isInBoundsSaneChain() || isOutOfBoundsSaneChain();
    290295    }
    291296
  • trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp

    r261895 r280760  
    391391            break;
    392392        }
    393            
     393
     394        case EnumeratorGetByVal:
    394395        case GetByVal: {
    395396            m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue);
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r279690 r280760  
    83888388        }
    83898389
    8390         case op_get_enumerable_length: {
    8391             auto bytecode = currentInstruction->as<OpGetEnumerableLength>();
    8392             set(bytecode.m_dst, addToGraph(GetEnumerableLength, get(bytecode.m_base)));
    8393             NEXT_OPCODE(op_get_enumerable_length);
    8394         }
    8395 
    8396         case op_has_enumerable_structure_property: {
    8397             auto bytecode = currentInstruction->as<OpHasEnumerableStructureProperty>();
    8398             set(bytecode.m_dst, addToGraph(HasEnumerableStructureProperty,
    8399                 get(bytecode.m_base),
    8400                 get(bytecode.m_property),
    8401                 get(bytecode.m_enumerator)));
    8402             NEXT_OPCODE(op_has_enumerable_structure_property);
    8403         }
    8404 
    8405         case op_has_enumerable_property: {
    8406             auto bytecode = currentInstruction->as<OpHasEnumerableProperty>();
    8407             set(bytecode.m_dst, addToGraph(HasEnumerableProperty, get(bytecode.m_base), get(bytecode.m_property)));
    8408             NEXT_OPCODE(op_has_enumerable_property);
    8409         }
    8410 
    8411         case op_has_own_structure_property: {
    8412             auto bytecode = currentInstruction->as<OpHasOwnStructureProperty>();
    8413             set(bytecode.m_dst, addToGraph(HasOwnStructureProperty,
    8414                 get(bytecode.m_base),
    8415                 get(bytecode.m_property),
    8416                 get(bytecode.m_enumerator)));
    8417             NEXT_OPCODE(op_has_own_structure_property);
    8418         }
    8419 
    8420         case op_in_structure_property: {
    8421             auto bytecode = currentInstruction->as<OpInStructureProperty>();
    8422             set(bytecode.m_dst, addToGraph(InStructureProperty,
    8423                 get(bytecode.m_base),
    8424                 get(bytecode.m_property),
    8425                 get(bytecode.m_enumerator)));
    8426             NEXT_OPCODE(op_in_structure_property);
    8427         }
    8428 
    8429         case op_has_enumerable_indexed_property: {
    8430             auto bytecode = currentInstruction->as<OpHasEnumerableIndexedProperty>();
    8431             Node* base = get(bytecode.m_base);
    8432             ArrayMode arrayMode = getArrayMode(bytecode.metadata(codeBlock).m_arrayProfile, Array::Read);
    8433             Node* property = get(bytecode.m_property);
    8434             addVarArgChild(base);
    8435             addVarArgChild(property);
    8436             addVarArgChild(nullptr);
    8437             Node* hasIterableProperty = addToGraph(Node::VarArg, HasEnumerableIndexedProperty, OpInfo(arrayMode.asWord()));
    8438             m_exitOK = false; // HasIndexedProperty must be treated as if it clobbers exit state, since FixupPhase may make it generic.
    8439             set(bytecode.m_dst, hasIterableProperty);
    8440             NEXT_OPCODE(op_has_enumerable_indexed_property);
    8441         }
    8442 
    8443         case op_get_direct_pname: {
    8444             auto bytecode = currentInstruction->as<OpGetDirectPname>();
    8445             SpeculatedType prediction = getPredictionWithoutOSRExit();
    8446            
    8447             Node* base = get(bytecode.m_base);
    8448             Node* property = get(bytecode.m_property);
    8449             Node* index = get(bytecode.m_index);
    8450             Node* enumerator = get(bytecode.m_enumerator);
    8451 
    8452             addVarArgChild(base);
    8453             addVarArgChild(property);
    8454             addVarArgChild(index);
    8455             addVarArgChild(enumerator);
    8456             set(bytecode.m_dst, addToGraph(Node::VarArg, GetDirectPname, OpInfo(0), OpInfo(prediction)));
    8457 
    8458             NEXT_OPCODE(op_get_direct_pname);
    8459         }
    8460 
    84618390        case op_get_property_enumerator: {
    84628391            auto bytecode = currentInstruction->as<OpGetPropertyEnumerator>();
    … …  
    84658394        }
    84668395
    8467         case op_enumerator_structure_pname: {
    8468             auto bytecode = currentInstruction->as<OpEnumeratorStructurePname>();
    8469             set(bytecode.m_dst, addToGraph(GetEnumeratorStructurePname,
    8470                 get(bytecode.m_enumerator),
    8471                 get(bytecode.m_index)));
    8472             NEXT_OPCODE(op_enumerator_structure_pname);
    8473         }
    8474 
    8475         case op_enumerator_generic_pname: {
    8476             auto bytecode = currentInstruction->as<OpEnumeratorGenericPname>();
    8477             set(bytecode.m_dst, addToGraph(GetEnumeratorGenericPname,
    8478                 get(bytecode.m_enumerator),
    8479                 get(bytecode.m_index)));
    8480             NEXT_OPCODE(op_enumerator_generic_pname);
    8481         }
    8482            
    8483         case op_to_index_string: {
    8484             auto bytecode = currentInstruction->as<OpToIndexString>();
    8485             set(bytecode.m_dst, addToGraph(ToIndexString, get(bytecode.m_index)));
    8486             NEXT_OPCODE(op_to_index_string);
     8396        case op_enumerator_next: {
     8397            auto bytecode = currentInstruction->as<OpEnumeratorNext>();
     8398            auto& metadata = bytecode.metadata(codeBlock);
     8399            ArrayMode arrayMode = getArrayMode(metadata.m_arrayProfile, Array::Read);
     8400            Node* base = get(bytecode.m_base);
     8401            Node* index = get(bytecode.m_index);
     8402            Node* enumerator = get(bytecode.m_enumerator);
     8403            Node* mode = get(bytecode.m_mode);
     8404
     8405            auto seenModes = OptionSet<JSPropertyNameEnumerator::Mode>::fromRaw(metadata.m_enumeratorMetadata);
     8406
     8407            if (!seenModes)
     8408                addToGraph(ForceOSRExit);
     8409
     8410            addVarArgChild(base);
     8411            addVarArgChild(index);
     8412            addVarArgChild(mode);
     8413            addVarArgChild(enumerator);
     8414            addVarArgChild(nullptr); // storage for IndexedMode only.
     8415            Node* updatedIndexAndMode = addToGraph(Node::VarArg, EnumeratorNextUpdateIndexAndMode, OpInfo(arrayMode.asWord()), OpInfo(seenModes));
     8416
     8417            Node* updatedMode = addToGraph(EnumeratorNextExtractMode, updatedIndexAndMode);
     8418            set(bytecode.m_mode, updatedMode);
     8419
     8420            Node* updatedIndex = addToGraph(EnumeratorNextExtractIndex, updatedIndexAndMode);
     8421            set(bytecode.m_index, updatedIndex);
     8422
     8423            set(bytecode.m_propertyName, addToGraph(EnumeratorNextUpdatePropertyName, OpInfo(), OpInfo(seenModes), updatedIndex, updatedMode, enumerator));
     8424
     8425            NEXT_OPCODE(op_enumerator_next);
     8426        }
     8427
     8428        case op_enumerator_get_by_val: {
     8429            auto bytecode = currentInstruction->as<OpEnumeratorGetByVal>();
     8430            auto& metadata = bytecode.metadata(codeBlock);
     8431            ArrayMode arrayMode = getArrayMode(metadata.m_arrayProfile, Array::Read);
     8432            SpeculatedType speculation = getPredictionWithoutOSRExit();
     8433
     8434            Node* base = get(bytecode.m_base);
     8435            Node* propertyName = get(bytecode.m_propertyName);
     8436            Node* index = get(bytecode.m_index);
     8437            Node* mode = get(bytecode.m_mode);
     8438            Node* enumerator = get(bytecode.m_enumerator);
     8439
     8440            auto seenModes = OptionSet<JSPropertyNameEnumerator::Mode>::fromRaw(metadata.m_enumeratorMetadata);
     8441            if (!seenModes)
     8442                addToGraph(ForceOSRExit);
     8443
     8444            if (seenModes == JSPropertyNameEnumerator::IndexedMode) {
     8445                Node* badMode = addToGraph(ArithBitAnd, mode, jsConstant(jsNumber(JSPropertyNameEnumerator::GenericMode | JSPropertyNameEnumerator::OwnStructureMode)));
     8446
     8447                // We know the ArithBitAnd cannot have effects so it's ok to exit here.
     8448                m_exitOK = true;
     8449                addToGraph(ExitOK);
     8450
     8451                addToGraph(CheckIsConstant, OpInfo(m_graph.freezeStrong(jsNumber(0))), badMode);
     8452
     8453                addVarArgChild(base);
     8454                addVarArgChild(index); // Use index so we'll use the normal indexed optimizations.
     8455                addVarArgChild(nullptr); // For property storage to match GetByVal.
     8456                set(bytecode.m_dst, addToGraph(Node::VarArg, GetByVal, OpInfo(arrayMode.asWord()), OpInfo(speculation)));
     8457
     8458                addToGraph(Phantom, propertyName);
     8459                addToGraph(Phantom, enumerator);
     8460                NEXT_OPCODE(op_enumerator_get_by_val);
     8461            }
     8462
     8463            // FIXME: Checking for a BadConstantValue causes us to always use the Generic variant if we switched from IndexedMode -> IndexedMode + OwnStructureMode even though that might be fine.
     8464            if (!seenModes.containsAny({ JSPropertyNameEnumerator::GenericMode, JSPropertyNameEnumerator::HasSeenOwnStructureModeStructureMismatch })
     8465                && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantValue)) {
     8466                Node* modeTest = addToGraph(SameValue, mode, jsConstant(jsNumber(static_cast<uint8_t>(JSPropertyNameEnumerator::GenericMode))));
     8467                addToGraph(CheckIsConstant, OpInfo(m_graph.freezeStrong(jsBoolean(false))), modeTest);
     8468
     8469                addVarArgChild(base);
     8470                addVarArgChild(index); // Use index so we'll use the normal indexed optimizations.
     8471                addVarArgChild(nullptr); // For property storage to match GetByVal.
     8472                addVarArgChild(index);
     8473                addVarArgChild(mode);
     8474                addVarArgChild(enumerator);
     8475                set(bytecode.m_dst, addToGraph(Node::VarArg, EnumeratorGetByVal, OpInfo(arrayMode.asWord()), OpInfo(speculation)));
     8476
     8477                addToGraph(Phantom, propertyName);
     8478                NEXT_OPCODE(op_enumerator_get_by_val);
     8479            }
     8480
     8481            addVarArgChild(base);
     8482            addVarArgChild(propertyName);
     8483            addVarArgChild(nullptr); // For property storage to match GetByVal.
     8484            addVarArgChild(index);
     8485            addVarArgChild(mode);
     8486            addVarArgChild(enumerator);
     8487            set(bytecode.m_dst, addToGraph(Node::VarArg, EnumeratorGetByVal, OpInfo(arrayMode.asWord()), OpInfo(speculation)));
     8488
     8489            NEXT_OPCODE(op_enumerator_get_by_val);
     8490        }
     8491
     8492        case op_enumerator_in_by_val: {
     8493            auto bytecode = currentInstruction->as<OpEnumeratorInByVal>();
     8494            auto& metadata = bytecode.metadata(codeBlock);
     8495            ArrayMode arrayMode = getArrayMode(metadata.m_arrayProfile, Array::Read);
     8496
     8497            addVarArgChild(get(bytecode.m_base));
     8498            addVarArgChild(get(bytecode.m_propertyName));
     8499            addVarArgChild(get(bytecode.m_index));
     8500            addVarArgChild(get(bytecode.m_mode));
     8501            addVarArgChild(get(bytecode.m_enumerator));
     8502            set(bytecode.m_dst, addToGraph(Node::VarArg, EnumeratorInByVal, OpInfo(arrayMode.asWord()), OpInfo(metadata.m_enumeratorMetadata)));
     8503
     8504            NEXT_OPCODE(op_enumerator_in_by_val);
     8505        }
     8506
     8507        case op_enumerator_has_own_property: {
     8508            auto bytecode = currentInstruction->as<OpEnumeratorHasOwnProperty>();
     8509            auto& metadata = bytecode.metadata(codeBlock);
     8510            ArrayMode arrayMode = getArrayMode(metadata.m_arrayProfile, Array::Read);
     8511
     8512            addVarArgChild(get(bytecode.m_base));
     8513            addVarArgChild(get(bytecode.m_propertyName));
     8514            addVarArgChild(get(bytecode.m_index));
     8515            addVarArgChild(get(bytecode.m_mode));
     8516            addVarArgChild(get(bytecode.m_enumerator));
     8517            set(bytecode.m_dst, addToGraph(Node::VarArg, EnumeratorHasOwnProperty, OpInfo(arrayMode.asWord()), OpInfo(metadata.m_enumeratorMetadata)));
     8518
     8519            NEXT_OPCODE(op_enumerator_has_own_property);
    84878520        }
    84888521
  • trunk/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp

    r278253 r280760  
    165165       
    166166        // This merges snapshot of stack values while CFA phase want to have proven types and values. This is somewhat tricky.
    167         // But this is OK as long as DFG OSR entry validates the inputs with *proven* AbstracValue values. And it turns out that this
     167        // But this is OK as long as DFG OSR entry validates the inputs with *proven* AbstractValue values. And it turns out that this
    168168        // type widening is critical to navier-stokes. Without it, navier-stokes has more strict constraint on OSR entry and
    169169        // fails OSR entry repeatedly.
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp

    r277926 r280760  
    255255    case op_get_scope:
    256256    case op_get_from_scope:
    257     case op_get_enumerable_length:
    258     case op_has_enumerable_indexed_property:
    259     case op_has_enumerable_structure_property:
    260     case op_has_enumerable_property:
    261     case op_has_own_structure_property:
    262     case op_in_structure_property:
    263     case op_get_direct_pname:
    264257    case op_get_property_enumerator:
    265     case op_enumerator_structure_pname:
    266     case op_enumerator_generic_pname:
    267     case op_to_index_string:
    268258    case op_new_func:
    269259    case op_new_func_exp:
    … …  
    300290    case op_check_private_brand:
    301291    case op_switch_string:
     292    case op_enumerator_next:
     293    case op_enumerator_get_by_val:
     294    case op_enumerator_in_by_val:
     295    case op_enumerator_has_own_property:
    302296        return CanCompileAndInline;
    303297
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r279604 r280760  
    148148        case CheckArrayOrEmpty:
    149149            break;
     150        case EnumeratorNextUpdateIndexAndMode:
     151        case EnumeratorGetByVal:
     152        case EnumeratorInByVal:
     153        case EnumeratorHasOwnProperty:
    150154        case GetIndexedPropertyStorage:
    151155        case GetArrayLength:
    … …  
    165169        case ArrayIndexOf:
    166170        case HasIndexedProperty:
    167         case HasEnumerableIndexedProperty:
    168171        case AtomicsAdd:
    169172        case AtomicsAnd:
    … …  
    338341        return;
    339342
    340     case GetEnumerableLength: {
    341         read(Heap);
    342         write(SideState);
    343         return;
    344     }
    345 
    346     case ToIndexString:
    347     case GetEnumeratorStructurePname:
    348     case GetEnumeratorGenericPname: {
     343    case EnumeratorNextUpdatePropertyName: {
     344        def(PureValue(node, node->enumeratorMetadata().toRaw()));
     345        return;
     346    }
     347
     348    case EnumeratorNextExtractMode:
     349    case EnumeratorNextExtractIndex: {
    349350        def(PureValue(node));
    350351        return;
    351352    }
    352353
    353     case HasIndexedProperty:
    354     case HasEnumerableIndexedProperty: {
     354    case EnumeratorNextUpdateIndexAndMode: {
     355        read(JSObject_butterfly);
     356        if (node->enumeratorMetadata() == JSPropertyNameEnumerator::OwnStructureMode && graph.varArgChild(node, 0).useKind() == CellUse) {
     357            read(NamedProperties);
     358            read(JSCell_structureID);
     359            return;
     360        }
     361
     362        if (node->enumeratorMetadata() != JSPropertyNameEnumerator::IndexedMode) {
     363            clobberTop();
     364            return;
     365        }
     366
     367        ArrayMode mode = node->arrayMode();
     368        switch (mode.type()) {
     369        case Array::ForceExit: {
     370            write(SideState);
     371            return;
     372        }
     373        case Array::Int32: {
     374            if (mode.isSaneChain()) {
     375                read(Butterfly_publicLength);
     376                read(IndexedInt32Properties);
     377                def(HeapLocation(HasIndexedPropertyLoc, IndexedInt32Properties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
     378                return;
     379            }
     380            break;
     381        }
     382
     383        case Array::Double: {
     384            if (mode.isSaneChain()) {
     385                read(Butterfly_publicLength);
     386                read(IndexedDoubleProperties);
     387                def(HeapLocation(HasIndexedPropertyLoc, IndexedDoubleProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
     388                return;
     389            }
     390            break;
     391        }
     392
     393        case Array::Contiguous: {
     394            if (mode.isSaneChain()) {
     395                read(Butterfly_publicLength);
     396                read(IndexedContiguousProperties);
     397                def(HeapLocation(HasIndexedPropertyLoc, IndexedContiguousProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
     398                return;
     399            }
     400            break;
     401        }
     402
     403        case Array::ArrayStorage: {
     404            if (mode.isInBounds()) {
     405                read(Butterfly_vectorLength);
     406                read(IndexedArrayStorageProperties);
     407                return;
     408            }
     409            break;
     410        }
     411
     412        default:
     413            break;
     414        }
     415
     416        clobberTop();
     417        return;
     418    }
     419
     420    case HasIndexedProperty: {
    355421        read(JSObject_butterfly);
    356422        ArrayMode mode = node->arrayMode();
    … …  
    706772    case ToPropertyKey:
    707773    case InByVal:
     774    case EnumeratorInByVal:
     775    case EnumeratorHasOwnProperty:
    708776    case InById:
    709777    case HasPrivateName:
    … …  
    717785    case ResolveScope:
    718786    case ToObject:
    719     case HasEnumerableStructureProperty:
    720     case HasEnumerableProperty:
    721     case HasOwnStructureProperty:
    722     case InStructureProperty:
    723787    case GetPropertyEnumerator:
    724     case GetDirectPname:
    725788    case InstanceOfCustom:
    726789    case ToNumber:
    … …  
    905968        for (unsigned i = data->limit; i--;)
    906969            write(AbstractHeap(Stack, data->start + static_cast<int>(i)));
     970        return;
     971    }
     972
     973    case EnumeratorGetByVal: {
     974        clobberTop();
    907975        return;
    908976    }
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r279604 r280760  
    206206    case GetByOffset:
    207207    case GetGetterSetterByOffset:
    208     case GetEnumerableLength:
    209208    case FiatInt52:
    210209    case BooleanToNumber:
    … …  
    298297    case GetByIdWithThis:
    299298    case GetByValWithThis:
    300     case GetDirectPname:
    301299    case GetDynamicVar:
    302300    case GetMapBucket:
    303301    case HasIndexedProperty:
    304     case HasEnumerableIndexedProperty:
    305     case HasEnumerableStructureProperty:
    306     case HasEnumerableProperty:
    307302    case HasOwnProperty:
    308     case HasOwnStructureProperty:
    309     case InStructureProperty:
    310303    case InById:
    311304    case InByVal:
    … …  
    393386    case ThrowStaticError:
    394387    case GetPropertyEnumerator:
    395     case GetEnumeratorStructurePname:
    396     case GetEnumeratorGenericPname:
    397     case ToIndexString:
     388    case EnumeratorInByVal:
     389    case EnumeratorHasOwnProperty:
     390    case EnumeratorNextUpdatePropertyName:
     391    case EnumeratorNextUpdateIndexAndMode:
    398392    case MaterializeNewObject:
    399393    case MaterializeNewInternalFieldObject:
    … …  
    505499    case GetIndexedPropertyStorage:
    506500    case GetByVal:
     501    case EnumeratorGetByVal:
    507502        if (node->arrayMode().type() == Array::String)
    508503            return true;
     504        return false;
     505
     506    case EnumeratorNextExtractMode:
     507    case EnumeratorNextExtractIndex:
    509508        return false;
    510509
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r279690 r280760  
    10251025        }
    10261026
     1027        case EnumeratorGetByVal: {
     1028            fixEdge<KnownInt32Use>(m_graph.varArgChild(node, 3));
     1029            fixEdge<KnownInt32Use>(m_graph.varArgChild(node, 4));
     1030            fixEdge<KnownCellUse>(m_graph.varArgChild(node, 5));
     1031            FALLTHROUGH;
     1032        }
     1033
    10271034        case GetByVal: {
    10281035            if (!node->prediction()) {
    … …  
    10631070                node->setArrayMode(ArrayMode(Array::Generic, node->arrayMode().action()));
    10641071                break;
     1072
     1073
     1074            case Array::ForceExit: {
     1075                // Don't force OSR because we have only seen OwnStructureMode.
     1076                // FIXME: WE should have a better way to do this...
     1077                if (node->op() == EnumeratorGetByVal)
     1078                    node->setArrayMode(node->arrayMode().withType(Array::Generic));
     1079                break;
     1080            }
    10651081            default:
    10661082                break;
    … …  
    10741090            case Array::Double:
    10751091            case Array::Int32: {
    1076                 std::optional<Array::Speculation> saneChainSpeculation;
    1077                 if (arrayMode.isJSArrayWithOriginalStructure()) {
    1078                     // Check if InBoundsSaneChain will work on a per-type basis. Note that:
    1079                     //
    1080                     // 1) We don't want double arrays to sometimes return undefined, since
    1081                     // that would require a change to the return type and it would pessimise
    1082                     // things a lot. So, we'd only want to do that if we actually had
    1083                     // evidence that we could read from a hole. That's pretty annoying.
    1084                     // Likely the best way to handle that case is with an equivalent of
    1085                     // InBoundsSaneChain for OutOfBounds. For now we just detect when Undefined and
    1086                     // NaN are indistinguishable according to backwards propagation, and just
    1087                     // use InBoundsSaneChain in that case. This happens to catch a lot of cases.
    1088                     //
    1089                     // 2) We don't want int32 array loads to have to do a hole check just to
    1090                     // coerce to Undefined, since that would mean twice the checks. We want to
    1091                     // be able to say we always return Int32. FIXME: Maybe this should be profiling
    1092                     // based?
    1093                     //
    1094                     // This has two implications. First, we have to do more checks than we'd
    1095                     // like. It's unfortunate that we have to do the hole check. Second,
    1096                     // some accesses that hit a hole will now need to take the full-blown
    1097                     // out-of-bounds slow path. We can fix that with:
    1098                     // https://bugs.webkit.org/show_bug.cgi?id=144668
    1099                    
    1100                     switch (arrayMode.type()) {
    1101                     case Array::Int32:
    1102                         if (is64Bit() && arrayMode.speculation() == Array::OutOfBounds && !m_graph.hasExitSite(node->origin.semantic, NegativeIndex))
    1103                             saneChainSpeculation = Array::OutOfBoundsSaneChain;
    1104                         break;
    1105                     case Array::Contiguous:
    1106                         // This is happens to be entirely natural. We already would have
    1107                         // returned any JSValue, and now we'll return Undefined. We still do
    1108                         // the check but it doesn't require taking any kind of slow path.
    1109                         if (is64Bit() && arrayMode.speculation() == Array::OutOfBounds && !m_graph.hasExitSite(node->origin.semantic, NegativeIndex))
    1110                             saneChainSpeculation = Array::OutOfBoundsSaneChain;
    1111                         else if (arrayMode.speculation() == Array::InBounds)
    1112                             saneChainSpeculation = Array::InBoundsSaneChain;
    1113                         break;
    1114                        
    1115                     case Array::Double:
    1116                         if (!(node->flags() & NodeBytecodeUsesAsOther) && arrayMode.speculation() == Array::InBounds) {
    1117                             // Holes look like NaN already, so if the user doesn't care
    1118                             // about the difference between Undefined and NaN then we can
    1119                             // do this.
    1120                             saneChainSpeculation = Array::InBoundsSaneChain;
    1121                         } else if (is64Bit() && arrayMode.speculation() == Array::OutOfBounds && !m_graph.hasExitSite(node->origin.semantic, NegativeIndex))
    1122                             saneChainSpeculation = Array::OutOfBoundsSaneChain;
    1123                         break;
    1124                        
    1125                     default:
    1126                         break;
    1127                     }
    1128                 }
    1129 
    1130                 if (saneChainSpeculation)
    1131                     setSaneChainIfPossible(node, *saneChainSpeculation);
    1132 
     1092                setJSArraySaneChainIfPossible(node);
    11331093                break;
    11341094            }
    … …  
    11791139                break;
    11801140            }
    1181            
     1141
     1142            // Don't set a non-JSValue result for EnumeratorGetByVal as the indexing mode doesn't tell us about the type of OwnStructure
     1143            // properties. This isn't an issue for IndexedMode only as BytecodeParsing will emit a normal GetByVal if we've profiled that.
     1144            if (node->op() == EnumeratorGetByVal)
     1145                break;
    11821146            switch (arrayMode.type()) {
    11831147            case Array::Double:
    … …  
    22762240        }
    22772241
    2278         case GetEnumerableLength: {
    2279             fixEdge<CellUse>(node->child1());
    2280             break;
    2281         }
    2282         case HasEnumerableProperty: {
    2283             fixEdge<CellUse>(node->child2());
    2284             break;
    2285         }
    2286         case HasEnumerableStructureProperty: {
    2287             fixEdge<StringUse>(node->child2());
    2288             fixEdge<KnownCellUse>(node->child3());
    2289             break;
    2290         }
    2291         case HasOwnStructureProperty:
    2292         case InStructureProperty: {
    2293             fixEdge<CellUse>(node->child1());
    2294             fixEdge<KnownStringUse>(node->child2());
    2295             fixEdge<KnownCellUse>(node->child3());
    2296             break;
    2297         }
    2298         case HasIndexedProperty:
    2299         case HasEnumerableIndexedProperty: {
     2242        case HasIndexedProperty: {
    23002243            node->setArrayMode(
    23012244                node->arrayMode().refine(
    … …  
    23162259            break;
    23172260        }
    2318         case GetDirectPname: {
    2319             Edge& base = m_graph.varArgChild(node, 0);
    2320             Edge& property = m_graph.varArgChild(node, 1);
    2321             Edge& index = m_graph.varArgChild(node, 2);
    2322             Edge& enumerator = m_graph.varArgChild(node, 3);
    2323             fixEdge<CellUse>(base);
    2324             fixEdge<KnownCellUse>(property);
    2325             fixEdge<Int32Use>(index);
    2326             fixEdge<KnownCellUse>(enumerator);
    2327             break;
    2328         }
     2261
    23292262        case GetPropertyEnumerator: {
    23302263            if (node->child1()->shouldSpeculateCell())
    … …  
    23322265            break;
    23332266        }
    2334         case GetEnumeratorStructurePname: {
    2335             fixEdge<KnownCellUse>(node->child1());
    2336             fixEdge<Int32Use>(node->child2());
    2337             break;
    2338         }
    2339         case GetEnumeratorGenericPname: {
    2340             fixEdge<KnownCellUse>(node->child1());
    2341             fixEdge<Int32Use>(node->child2());
    2342             break;
    2343         }
    2344         case ToIndexString: {
    2345             fixEdge<Int32Use>(node->child1());
    2346             break;
    2347         }
     2267
     2268        case EnumeratorNextUpdateIndexAndMode: {
     2269            Edge& base = m_graph.varArgChild(node, 0);
     2270            Edge& index = m_graph.varArgChild(node, 1);
     2271            Edge& storageEdge = m_graph.varArgChild(node, node->storageChildIndex());
     2272
     2273            if (node->enumeratorMetadata() == JSPropertyNameEnumerator::IndexedMode) {
     2274                node->setArrayMode(
     2275                    node->arrayMode().refine(
     2276                        m_graph, node,
     2277                        m_graph.varArgChild(node, 0)->prediction(),
     2278                        m_graph.varArgChild(node, 1)->prediction()));
     2279
     2280                fixEdge<CellUse>(base);
     2281                blessArrayOperation(base, index, storageEdge);
     2282
     2283                ArrayMode arrayMode = node->arrayMode();
     2284                if (arrayMode.benefitsFromOriginalArray())
     2285                    setSaneChainIfPossible(node, arrayMode.speculation() == Array::InBounds ? Array::InBoundsSaneChain : Array::OutOfBoundsSaneChain);
     2286            }
     2287
     2288            if (node->enumeratorMetadata() == JSPropertyNameEnumerator::OwnStructureMode && !m_graph.hasExitSite(node->origin.semantic, BadCache))
     2289                fixEdge<CellUse>(base);
     2290
     2291            fixEdge<KnownInt32Use>(index);
     2292            fixEdge<KnownInt32Use>(m_graph.varArgChild(node, 2));
     2293            fixEdge<KnownCellUse>(m_graph.varArgChild(node, 3));
     2294            break;
     2295        }
     2296
     2297        case EnumeratorNextExtractIndex:
     2298        case EnumeratorNextExtractMode: {
     2299            break;
     2300        }
     2301
     2302        case EnumeratorNextUpdatePropertyName: {
     2303            fixEdge<KnownInt32Use>(node->child1());
     2304            fixEdge<KnownInt32Use>(node->child2());
     2305            fixEdge<KnownCellUse>(node->child3());
     2306            break;
     2307        }
     2308
     2309        case EnumeratorHasOwnProperty:
     2310        case EnumeratorInByVal: {
     2311            if (m_graph.varArgChild(node, 0)->shouldSpeculateCell())
     2312                fixEdge<CellUse>(m_graph.varArgChild(node, 0));
     2313            fixEdge<KnownInt32Use>(m_graph.varArgChild(node, 2));
     2314            fixEdge<KnownInt32Use>(m_graph.varArgChild(node, 3));
     2315            fixEdge<KnownCellUse>(m_graph.varArgChild(node, 4));
     2316            break;
     2317        }
     2318
    23482319        case ProfileType: {
    23492320            // We want to insert type checks based on the instructionTypeSet of the TypeLocation, not the globalTypeSet.
    … …  
    36913662    }
    36923663
     3664    void setJSArraySaneChainIfPossible(Node* node)
     3665    {
     3666        ArrayMode arrayMode = node->arrayMode();
     3667        std::optional<Array::Speculation> saneChainSpeculation;
     3668        if (arrayMode.isJSArrayWithOriginalStructure()) {
     3669            // Check if InBoundsSaneChain will work on a per-type basis. Note that:
     3670            //
     3671            // 1) We don't want double arrays to sometimes return undefined, since
     3672            // that would require a change to the return type and it would pessimise
     3673            // things a lot. So, we'd only want to do that if we actually had
     3674            // evidence that we could read from a hole. That's pretty annoying.
     3675            // Likely the best way to handle that case is with an equivalent of
     3676            // InBoundsSaneChain for OutOfBounds. For now we just detect when Undefined and
     3677            // NaN are indistinguishable according to backwards propagation, and just
     3678            // use InBoundsSaneChain in that case. This happens to catch a lot of cases.
     3679            //
     3680            // 2) We don't want int32 array loads to have to do a hole check just to
     3681            // coerce to Undefined, since that would mean twice the checks. We want to
     3682            // be able to say we always return Int32. FIXME: Maybe this should be profiling
     3683            // based?
     3684            //
     3685            // This has two implications. First, we have to do more checks than we'd
     3686            // like. It's unfortunate that we have to do the hole check. Second,
     3687            // some accesses that hit a hole will now need to take the full-blown
     3688            // out-of-bounds slow path. We can fix that with:
     3689            // https://bugs.webkit.org/show_bug.cgi?id=144668
     3690
     3691            switch (arrayMode.type()) {
     3692            case Array::Int32:
     3693                if (is64Bit() && arrayMode.speculation() == Array::OutOfBounds && !m_graph.hasExitSite(node->origin.semantic, NegativeIndex))
     3694                    saneChainSpeculation = Array::OutOfBoundsSaneChain;
     3695                break;
     3696            case Array::Contiguous:
     3697                // This is happens to be entirely natural. We already would have
     3698                // returned any JSValue, and now we'll return Undefined. We still do
     3699                // the check but it doesn't require taking any kind of slow path.
     3700                if (is64Bit() && arrayMode.speculation() == Array::OutOfBounds && !m_graph.hasExitSite(node->origin.semantic, NegativeIndex))
     3701                    saneChainSpeculation = Array::OutOfBoundsSaneChain;
     3702                else if (arrayMode.speculation() == Array::InBounds)
     3703                    saneChainSpeculation = Array::InBoundsSaneChain;
     3704                break;
     3705
     3706            case Array::Double:
     3707                if (!(node->flags() & NodeBytecodeUsesAsOther) && arrayMode.speculation() == Array::InBounds) {
     3708                    // Holes look like NaN already, so if the user doesn't care
     3709                    // about the difference between Undefined and NaN then we can
     3710                    // do this.
     3711                    saneChainSpeculation = Array::InBoundsSaneChain;
     3712                } else if (is64Bit() && arrayMode.speculation() == Array::OutOfBounds && !m_graph.hasExitSite(node->origin.semantic, NegativeIndex))
     3713                    saneChainSpeculation = Array::OutOfBoundsSaneChain;
     3714                break;
     3715
     3716            default:
     3717                break;
     3718            }
     3719        }
     3720
     3721        if (saneChainSpeculation)
     3722            setSaneChainIfPossible(node, *saneChainSpeculation);
     3723    }
     3724
    36933725    void setSaneChainIfPossible(Node* node, Array::Speculation speculation)
    36943726    {
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r278945 r280760  
    388388    if (node->hasPutByIdStatus())
    389389        out.print(comma, *node->putByIdStatus());
     390    if (node->hasEnumeratorMetadata())
     391        out.print(comma, "enumeratorModes = ", node->enumeratorMetadata().toRaw());
    390392    if (node->isJump())
    391393        out.print(comma, "T:", *node->targetBlock());
  • trunk/Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp

    r269107 r280760  
    13451345                }
    13461346
     1347                case EnumeratorGetByVal:
    13471348                case GetByVal: {
    13481349                    if (node->arrayMode().type() != Array::Undecided)
    … …  
    13811382    {
    13821383        switch (node->op()) {
     1384        // FIXME: Teach this about EnumeratorNextExtractIndex.
    13831385        case CheckInBounds: {
    13841386            setRelationship(Relationship::safeCreate(node->child1().node(), node->child2().node(), Relationship::LessThan));
  • trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp

    r279604 r280760  
    112112    case FilterCheckPrivateBrandStatus:
    113113    case FilterSetPrivateBrandStatus:
     114    case EnumeratorNextExtractMode:
     115    case EnumeratorNextExtractIndex:
    114116        break;
    115117
     118    case EnumeratorNextUpdatePropertyName:
    116119    case StrCat:
    117120    case Call:
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r278696 r280760  
    5353#include "GetByVariant.h"
    5454#include "JSCJSValue.h"
     55#include "JSPropertyNameEnumerator.h"
    5556#include "Operands.h"
    5657#include "PrivateFieldPutKind.h"
    … …  
    17651766        case ArithCeil:
    17661767        case ArithTrunc:
    1767         case GetDirectPname:
    17681768        case GetById:
    17691769        case GetByIdFlush:
    … …  
    17731773        case GetPrototypeOf:
    17741774        case TryGetById:
     1775        case EnumeratorGetByVal:
    17751776        case GetByVal:
    17761777        case GetByValWithThis:
    … …  
    19421943    }
    19431944
     1945    bool hasStorageChild() const
     1946    {
     1947        switch (op()) {
     1948        case StringCharAt:
     1949        case StringCharCodeAt:
     1950        case StringCodePointAt:
     1951        case EnumeratorGetByVal:
     1952        case GetByVal:
     1953        case PutByValDirect:
     1954        case PutByVal:
     1955        case PutByValAlias:
     1956        case AtomicsAdd:
     1957        case AtomicsAnd:
     1958        case AtomicsCompareExchange:
     1959        case AtomicsExchange:
     1960        case AtomicsLoad:
     1961        case AtomicsOr:
     1962        case AtomicsStore:
     1963        case AtomicsSub:
     1964        case AtomicsXor:
     1965        case ArrayPush:
     1966        case ArrayPop:
     1967        case GetArrayLength:
     1968        case HasIndexedProperty:
     1969        case EnumeratorNextUpdateIndexAndMode:
     1970        case ArrayIndexOf:
     1971            return true;
     1972        default:
     1973            break;
     1974        }
     1975        return false;
     1976    }
     1977
     1978    unsigned storageChildIndex()
     1979    {
     1980        ASSERT(hasStorageChild());
     1981        switch (op()) {
     1982        case StringCharAt:
     1983        case StringCharCodeAt:
     1984        case StringCodePointAt:
     1985        case EnumeratorGetByVal:
     1986        case GetByVal:
     1987            return 2;
     1988        case PutByValDirect:
     1989        case PutByVal:
     1990        case PutByValAlias:
     1991            return 3;
     1992        case AtomicsAdd:
     1993        case AtomicsAnd:
     1994        case AtomicsCompareExchange:
     1995        case AtomicsExchange:
     1996        case AtomicsLoad:
     1997        case AtomicsOr:
     1998        case AtomicsStore:
     1999        case AtomicsSub:
     2000        case AtomicsXor:
     2001            return 2 + numExtraAtomicsArgs(op());
     2002        case ArrayPush:
     2003            return 0;
     2004
     2005        case ArrayPop:
     2006        case GetArrayLength:
     2007            return 2;
     2008
     2009        case HasIndexedProperty:
     2010            return 2;
     2011
     2012        case EnumeratorNextUpdateIndexAndMode:
     2013            return 4;
     2014
     2015        default:
     2016            // FIXME: Add ArrayIndexOf but it does non-trivial things to determine storage edge.
     2017            RELEASE_ASSERT_NOT_REACHED();
     2018        }
     2019    }
     2020
    19442021    bool hasUidOperand()
    19452022    {
    … …  
    22062283        case PutByValAlias:
    22072284        case GetByVal:
     2285        case EnumeratorNextUpdateIndexAndMode:
     2286        case EnumeratorGetByVal:
     2287        case EnumeratorInByVal:
     2288        case EnumeratorHasOwnProperty:
    22082289        case StringCharAt:
    22092290        case StringCharCodeAt:
    … …  
    22172298        case ArrayIndexOf:
    22182299        case HasIndexedProperty:
    2219         case HasEnumerableIndexedProperty:
    22202300        case AtomicsAdd:
    22212301        case AtomicsAnd:
    … …  
    31753255    }
    31763256
     3257    bool hasEnumeratorMetadata() const
     3258    {
     3259        switch (op()) {
     3260        case EnumeratorNextUpdateIndexAndMode:
     3261        case EnumeratorNextUpdatePropertyName:
     3262        case EnumeratorHasOwnProperty:
     3263        case EnumeratorInByVal:
     3264            return true;
     3265        default:
     3266            return false;
     3267        }
     3268    }
     3269
     3270    OptionSet<JSPropertyNameEnumerator::Mode> enumeratorMetadata()
     3271    {
     3272        ASSERT(hasEnumeratorMetadata());
     3273        return OptionSet<JSPropertyNameEnumerator::Mode>::fromRaw(m_opInfo2.as<unsigned>());
     3274    }
     3275
    31773276    void dumpChildren(PrintStream& out)
    31783277    {
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r279604 r280760  
    502502    macro(FencedStoreBarrier, NodeMustGenerate) \
    503503    \
    504     /* For-in enumeration opcodes */\
    505     macro(GetEnumerableLength, NodeMustGenerate | NodeResultJS) \
    506504    /* Must generate because of Proxies on the prototype chain */ \
    507505    macro(HasIndexedProperty, NodeMustGenerate | NodeResultBoolean | NodeHasVarArgs) \
    508     macro(HasEnumerableIndexedProperty, NodeMustGenerate | NodeResultBoolean | NodeHasVarArgs) \
    509     macro(HasEnumerableStructureProperty, NodeResultBoolean) \
    510     macro(HasEnumerableProperty, NodeResultBoolean) \
    511     macro(HasOwnStructureProperty, NodeResultBoolean | NodeMustGenerate) \
    512     macro(InStructureProperty, NodeMustGenerate | NodeResultBoolean) \
    513     macro(GetDirectPname, NodeMustGenerate | NodeHasVarArgs | NodeResultJS) \
     506    /* For-in enumeration opcodes */\
    514507    macro(GetPropertyEnumerator, NodeMustGenerate | NodeResultJS) \
    515     macro(GetEnumeratorStructurePname, NodeMustGenerate | NodeResultJS) \
    516     macro(GetEnumeratorGenericPname, NodeMustGenerate | NodeResultJS) \
    517     macro(ToIndexString, NodeResultJS) \
     508    macro(EnumeratorNextUpdateIndexAndMode, NodeResultJS | NodeHasVarArgs) \
     509    macro(EnumeratorNextExtractMode, NodeResultInt32) \
     510    macro(EnumeratorNextExtractIndex, NodeResultInt32) \
     511    macro(EnumeratorNextUpdatePropertyName, NodeResultJS) \
     512    macro(EnumeratorGetByVal, NodeResultJS | NodeHasVarArgs | NodeMustGenerate) \
     513    macro(EnumeratorInByVal, NodeResultBoolean | NodeHasVarArgs | NodeMustGenerate) \
     514    macro(EnumeratorHasOwnProperty, NodeResultBoolean | NodeHasVarArgs | NodeMustGenerate) \
    518515    /* Nodes for JSMap and JSSet */ \
    519516    macro(MapHash, NodeResultInt32) \
  • trunk/Source/JavaScriptCore/dfg/DFGOpInfo.h

    r267489 r280760  
    3030#include "HeapCell.h"
    3131#include "PrivateFieldPutKind.h"
     32#include <wtf/OptionSet.h>
    3233#include <wtf/StdLibExtras.h>
    3334
    … …  
    5152    explicit OpInfo(ECMAMode ecmaMode) : m_value(ecmaMode.value()) { }
    5253    explicit OpInfo(PrivateFieldPutKind putKind) : m_value(putKind.value()) { }
     54    template<typename EnumType>
     55    explicit OpInfo(OptionSet<EnumType> optionSet) : m_value(optionSet.toRaw()) { }
    5356
    5457    template <typename T>
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r280060 r280760  
    24002400}
    24012401
    2402 JSC_DEFINE_JIT_OPERATION(operationHasEnumerableProperty, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, JSCell* property))
    2403 {
    2404     VM& vm = globalObject->vm();
    2405     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
    2406     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
    2407     auto scope = DECLARE_THROW_SCOPE(vm);
    2408 
    2409     JSValue baseValue = JSValue::decode(encodedBaseValue);
    2410     if (baseValue.isUndefinedOrNull())
    2411         return JSValue::encode(jsBoolean(false));
    2412 
    2413     JSObject* base = baseValue.toObject(globalObject);
    2414     EXCEPTION_ASSERT(!scope.exception() || !base);
    2415     if (!base)
    2416         return JSValue::encode(JSValue());
    2417     auto propertyName = asString(property)->toIdentifier(globalObject);
    2418     RETURN_IF_EXCEPTION(scope, { });
    2419     RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(base->hasEnumerableProperty(globalObject, propertyName))));
    2420 }
    2421 
    2422 JSC_DEFINE_JIT_OPERATION(operationInStructureProperty, EncodedJSValue, (JSGlobalObject* globalObject, JSCell* base, JSString* property))
    2423 {
    2424     VM& vm = globalObject->vm();
    2425     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
    2426     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
    2427 
    2428     return JSValue::encode(jsBoolean(CommonSlowPaths::opInByVal(globalObject, base, property)));
    2429 }
    2430 
    2431 JSC_DEFINE_JIT_OPERATION(operationHasOwnStructureProperty, EncodedJSValue, (JSGlobalObject* globalObject, JSCell* base, JSString* property))
    2432 {
    2433     VM& vm = globalObject->vm();
    2434     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
    2435     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
    2436 
    2437     auto scope = DECLARE_THROW_SCOPE(vm);
    2438     auto propertyName = property->toIdentifier(globalObject);
    2439     RETURN_IF_EXCEPTION(scope, { });
    2440     scope.release();
    2441     return JSValue::encode(jsBoolean(objectPrototypeHasOwnProperty(globalObject, base, propertyName)));
    2442 }
    2443 
    24442402JSC_DEFINE_JIT_OPERATION(operationHasIndexedProperty, size_t, (JSGlobalObject* globalObject, JSCell* baseCell, int32_t subscript))
    24452403{
    … …  
    24982456}
    24992457
    2500 JSC_DEFINE_JIT_OPERATION(operationToIndexString, JSCell*, (JSGlobalObject* globalObject, int32_t index))
    2501 {
    2502     VM& vm = globalObject->vm();
    2503     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
    2504     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
    2505     return jsString(vm, Identifier::from(vm, index).string());
     2458JSC_DEFINE_JIT_OPERATION(operationEnumeratorNextUpdateIndexAndMode, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue baseValue, uint32_t index, int32_t modeNumber, JSPropertyNameEnumerator* enumerator))
     2459{
     2460    VM& vm = globalObject->vm();
     2461    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     2462    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
     2463    auto scope = DECLARE_THROW_SCOPE(vm);
     2464
     2465    JSPropertyNameEnumerator::Mode mode = static_cast<JSPropertyNameEnumerator::Mode>(modeNumber);
     2466    if (JSValue::decode(baseValue).isUndefinedOrNull()) {
     2467        ASSERT(mode == JSPropertyNameEnumerator::InitMode);
     2468        ASSERT(!index);
     2469        ASSERT(!enumerator->sizeOfPropertyNames());
     2470        mode = JSPropertyNameEnumerator::GenericMode;
     2471    } else {
     2472        JSObject* base = JSValue::decode(baseValue).toObject(globalObject);
     2473        RETURN_IF_EXCEPTION(scope, { });
     2474
     2475        constexpr bool shouldAllocateIndexedNameString = false;
     2476        enumerator->computeNext(globalObject, base, index, mode, shouldAllocateIndexedNameString);
     2477        RETURN_IF_EXCEPTION(scope, { });
     2478    }
     2479
     2480#if USE(JSVALUE64)
     2481    JSValue result = bitwise_cast<JSValue>(static_cast<uint64_t>(mode) << 32 | index | JSValue::DoubleEncodeOffset);
     2482#else
     2483    JSValue result = JSValue(mode, index);
     2484#endif
     2485    ASSERT(result.isDouble());
     2486    return JSValue::encode(result);
     2487}
     2488
     2489JSC_DEFINE_JIT_OPERATION(operationEnumeratorNextUpdatePropertyName, EncodedJSValue, (JSGlobalObject* globalObject, uint32_t index, int32_t modeNumber, JSPropertyNameEnumerator* enumerator))
     2490{
     2491    VM& vm = globalObject->vm();
     2492    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     2493    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
     2494
     2495    if (modeNumber == JSPropertyNameEnumerator::IndexedMode) {
     2496        if (index < enumerator->indexedLength())
     2497            return JSValue::encode(jsString(vm, Identifier::from(vm, index).string()));
     2498        return JSValue::encode(jsNull());
     2499    }
     2500
     2501    JSString* result = enumerator->propertyNameAtIndex(index);
     2502    if (!result)
     2503        return JSValue::encode(jsNull());
     2504
     2505    return JSValue::encode(result);
     2506}
     2507
     2508JSC_DEFINE_JIT_OPERATION(operationEnumeratorRecoverNameAndGetByVal, EncodedJSValue, (JSGlobalObject* globalObject, JSCell* base, uint32_t index, JSPropertyNameEnumerator* enumerator))
     2509{
     2510    VM& vm = globalObject->vm();
     2511    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     2512    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
     2513    auto scope = DECLARE_THROW_SCOPE(vm);
     2514
     2515    JSString* string = enumerator->propertyNameAtIndex(index);
     2516    PropertyName propertyName = string->toIdentifier(globalObject);
     2517    // This should only really return for TerminationException since we know string is backed by a UUID.
     2518    RETURN_IF_EXCEPTION(scope, { });
     2519    JSObject* object = base->toObject(globalObject);
     2520    RETURN_IF_EXCEPTION(scope, { });
     2521
     2522    RELEASE_AND_RETURN(scope, JSValue::encode(object->get(globalObject, propertyName)));
     2523}
     2524
     2525JSC_DEFINE_JIT_OPERATION(operationEnumeratorInByVal, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue baseValue, EncodedJSValue propertyNameValue, uint32_t index, int32_t modeNumber))
     2526{
     2527    VM& vm = globalObject->vm();
     2528    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     2529    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
     2530    auto scope = DECLARE_THROW_SCOPE(vm);
     2531
     2532    JSValue base = JSValue::decode(baseValue);
     2533    RETURN_IF_EXCEPTION(scope, { });
     2534    if (modeNumber == JSPropertyNameEnumerator::IndexedMode && base.isObject())
     2535        return JSValue::encode(jsBoolean(jsCast<JSObject*>(base)->hasProperty(globalObject, index)));
     2536
     2537    JSString* propertyName = jsSecureCast<JSString*>(vm, JSValue::decode(propertyNameValue));
     2538    RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(CommonSlowPaths::opInByVal(globalObject, base, propertyName))));
     2539}
     2540
     2541JSC_DEFINE_JIT_OPERATION(operationEnumeratorHasOwnProperty, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue baseValue, EncodedJSValue propertyNameValue, uint32_t index, int32_t modeNumber))
     2542{
     2543    VM& vm = globalObject->vm();
     2544    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     2545    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
     2546    auto scope = DECLARE_THROW_SCOPE(vm);
     2547
     2548    JSValue base = JSValue::decode(baseValue);
     2549    RETURN_IF_EXCEPTION(scope, { });
     2550    if (modeNumber == JSPropertyNameEnumerator::IndexedMode && base.isObject())
     2551        return JSValue::encode(jsBoolean(jsCast<JSObject*>(base)->hasOwnProperty(globalObject, index)));
     2552
     2553    JSString* propertyName = jsSecureCast<JSString*>(vm, JSValue::decode(propertyNameValue));
     2554    auto identifier = propertyName->toIdentifier(globalObject);
     2555    RETURN_IF_EXCEPTION(scope, { });
     2556    RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(objectPrototypeHasOwnProperty(globalObject, base, identifier))));
    25062557}
    25072558
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r279690 r280760  
    3737class JSBigInt;
    3838struct UnlinkedStringJumpTable;
     39class JSPropertyNameEnumerator;
    3940
    4041namespace DFG {
    … …  
    105106JSC_DECLARE_JIT_OPERATION(operationHasIndexedProperty, size_t, (JSGlobalObject*, JSCell*, int32_t));
    106107JSC_DECLARE_JIT_OPERATION(operationHasEnumerableIndexedProperty, size_t, (JSGlobalObject*, JSCell*, int32_t));
    107 JSC_DECLARE_JIT_OPERATION(operationHasEnumerableProperty, EncodedJSValue, (JSGlobalObject*, EncodedJSValue, JSCell*));
    108 JSC_DECLARE_JIT_OPERATION(operationHasOwnStructureProperty, EncodedJSValue, (JSGlobalObject*, JSCell*, JSString*));
    109 JSC_DECLARE_JIT_OPERATION(operationInStructureProperty, EncodedJSValue, (JSGlobalObject*, JSCell*, JSString*));
    110108JSC_DECLARE_JIT_OPERATION(operationGetPropertyEnumerator, JSCell*, (JSGlobalObject*, EncodedJSValue));
    111109JSC_DECLARE_JIT_OPERATION(operationGetPropertyEnumeratorCell, JSCell*, (JSGlobalObject*, JSCell*));
    112 JSC_DECLARE_JIT_OPERATION(operationToIndexString, JSCell*, (JSGlobalObject*, int32_t));
     110JSC_DECLARE_JIT_OPERATION(operationEnumeratorNextUpdateIndexAndMode, EncodedJSValue, (JSGlobalObject*, EncodedJSValue, uint32_t, int32_t, JSPropertyNameEnumerator*));
     111JSC_DECLARE_JIT_OPERATION(operationEnumeratorNextUpdatePropertyName, EncodedJSValue, (JSGlobalObject*, uint32_t, int32_t, JSPropertyNameEnumerator*));
     112JSC_DECLARE_JIT_OPERATION(operationEnumeratorInByVal, EncodedJSValue, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, uint32_t, int32_t));
     113JSC_DECLARE_JIT_OPERATION(operationEnumeratorHasOwnProperty, EncodedJSValue, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, uint32_t, int32_t));
     114JSC_DECLARE_JIT_OPERATION(operationEnumeratorRecoverNameAndGetByVal, EncodedJSValue, (JSGlobalObject*, JSCell*, uint32_t, JSPropertyNameEnumerator*));
     115
    113116JSC_DECLARE_JIT_OPERATION(operationNewRegexpWithLastIndex, JSCell*, (JSGlobalObject*, JSCell*, EncodedJSValue));
    114117JSC_DECLARE_JIT_OPERATION(operationNewArray, char*, (JSGlobalObject*, Structure*, void*, size_t));
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r279604 r280760  
    474474            if (!child1->prediction())
    475475                break;
    476            
     476
    477477            Edge child2 = m_graph.child(node, 1);
    478478            ArrayMode arrayMode = node->arrayMode().refine(
    … …  
    481481                child2->prediction(),
    482482                SpecNone);
    483            
     483
    484484            switch (arrayMode.type()) {
    485485            case Array::Int32:
    … …  
    863863        }
    864864
     865        case EnumeratorGetByVal:
    865866        case ArrayPop:
    866867        case ArrayPush:
    … …  
    883884        case GetPrivateNameById:
    884885        case MultiGetByOffset:
    885         case GetDirectPname:
    886886        case Call:
    887887        case DirectCall:
    … …  
    12061206            break;
    12071207
    1208         case GetEnumerableLength: {
     1208        case EnumeratorNextExtractMode:
     1209        case EnumeratorNextExtractIndex: {
    12091210            setPrediction(SpecInt32Only);
    12101211            break;
    12111212        }
     1213
     1214        case EnumeratorInByVal:
     1215        case EnumeratorHasOwnProperty:
    12121216        case InByVal:
    12131217        case InById:
    … …  
    12151219        case HasPrivateBrand:
    12161220        case HasOwnProperty:
    1217         case HasOwnStructureProperty:
    1218         case InStructureProperty:
    1219         case HasIndexedProperty:
    1220         case HasEnumerableIndexedProperty:
    1221         case HasEnumerableStructureProperty:
    1222         case HasEnumerableProperty: {
     1221        case HasIndexedProperty: {
    12231222            setPrediction(SpecBoolean);
    12241223            break;
    … …  
    12281227            break;
    12291228        }
    1230         case GetEnumeratorStructurePname: {
    1231             setPrediction(SpecCell | SpecOther);
    1232             break;
    1233         }
    1234         case GetEnumeratorGenericPname: {
    1235             setPrediction(SpecCell | SpecOther);
    1236             break;
    1237         }
    1238         case ToIndexString: {
    1239             setPrediction(SpecString);
    1240             break;
    1241         }
     1229
     1230        case EnumeratorNextUpdateIndexAndMode: {
     1231            setPrediction(SpecFullNumber);
     1232            break;
     1233        }
     1234
     1235        case EnumeratorNextUpdatePropertyName: {
     1236            setPrediction(SpecString | SpecOther);
     1237            break;
     1238        }
     1239
    12421240        case ParseInt: {
    12431241            // We expect this node to almost always produce an int32. However,
  • trunk/Source/JavaScriptCore/dfg/DFGSSALoweringPhase.cpp

    r270874 r280760  
    8383
    8484        case HasIndexedProperty:
    85         case HasEnumerableIndexedProperty:
    8685            lowerBoundsCheck(m_graph.child(m_node, 0), m_graph.child(m_node, 1), m_graph.child(m_node, 2));
    8786            break;
    8887
     88        case EnumeratorGetByVal:
    8989        case GetByVal: {
    9090            lowerBoundsCheck(m_graph.varArgChild(m_node, 0), m_graph.varArgChild(m_node, 1), m_graph.varArgChild(m_node, 2));
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r279604 r280760  
    297297    case FiatInt52:
    298298    case HasIndexedProperty:
    299     case HasEnumerableIndexedProperty:
    300     case GetEnumeratorStructurePname:
    301     case GetEnumeratorGenericPname:
    302     case ToIndexString:
    303299    case CheckStructureImmediate:
    304300    case GetMyArgumentByVal:
    … …  
    373369        return false;
    374370
     371    case EnumeratorGetByVal:
    375372    case GetByVal:
    376373    case GetIndexedPropertyStorage:
    … …  
    497494    }
    498495
     496    case EnumeratorNextUpdateIndexAndMode:
     497    // These technically don't have effects but they'll only ever follow a EnumeratorNextUpdateIndexAndMode so we might as well return false.
     498    case EnumeratorNextExtractMode:
     499    case EnumeratorNextExtractIndex:
     500    case EnumeratorNextUpdatePropertyName:
    499501    case ToThis:
    500502    case CreateThis:
    … …  
    596598    case InByVal:
    597599    case InById:
     600    case EnumeratorInByVal:
     601    case EnumeratorHasOwnProperty:
    598602    case HasPrivateName:
    599603    case HasPrivateBrand:
    … …  
    640644    case MultiPutByOffset:
    641645    case MultiDeleteByOffset:
    642     case GetEnumerableLength:
    643     case HasEnumerableStructureProperty:
    644     case HasEnumerableProperty:
    645     case HasOwnStructureProperty:
    646     case InStructureProperty:
    647     case GetDirectPname:
    648646    case GetPropertyEnumerator:
    649647    case PhantomNewObject:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r280716 r280760  
    16381638}
    16391639
     1640JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, GPRReg specificPayload)
    16401641#if USE(JSVALUE64)
    1641 template<typename T>
    1642 JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord)
    1643     : m_gpr(jit, Reuse, operand)
    1644 {
    1645 }
     1642    : m_gpr(jit, specificPayload)
    16461643#else
    1647 template<typename T>
    1648 JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord resultWord)
    1649 {
    1650     if (resultWord == PayloadWord) {
    1651         m_payloadGPR = GPRTemporary(jit, Reuse, operand);
    1652         m_tagGPR = GPRTemporary(jit);
    1653     } else {
    1654         m_payloadGPR = GPRTemporary(jit);
    1655         m_tagGPR = GPRTemporary(jit, Reuse, operand);
    1656     }
    1657 }
     1644    : m_payloadGPR(jit, specificPayload)
     1645    , m_tagGPR(jit)
    16581646#endif
     1647{
     1648}
    16591649
    16601650#if USE(JSVALUE64)
    … …  
    25982588}
    25992589
    2600 void SpeculativeJIT::compileGetByValOnString(Node* node)
     2590void SpeculativeJIT::compileGetByValOnString(Node* node, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix)
    26012591{
    26022592    SpeculateCellOperand base(this, m_graph.child(node, 0));
    … …  
    26072597    GPRReg storageReg = storage.gpr();
    26082598
    2609     GPRTemporary scratch(this);
    2610     GPRReg scratchReg = scratch.gpr();
    2611 #if USE(JSVALUE32_64)
    2612     GPRTemporary resultTag;
    2613     GPRReg resultTagReg = InvalidGPRReg;
    2614     if (node->arrayMode().isOutOfBounds()) {
    2615         GPRTemporary realResultTag(this);
    2616         resultTag.adopt(realResultTag);
    2617         resultTagReg = resultTag.gpr();
    2618     }
    2619 #endif
     2599    JSValueRegs resultRegs;
     2600    DataFormat format;
     2601    std::tie(resultRegs, format) = prefix(node->arrayMode().isOutOfBounds() ? DataFormatJS : DataFormatCell);
     2602    GPRReg scratchReg = resultRegs.payloadGPR();
    26202603
    26212604    // unsigned comparison so we can filter out negative indices and indices that are too large
    … …  
    26532636
    26542637    if (node->arrayMode().isOutOfBounds()) {
     2638        ASSERT(format == DataFormatJS);
    26552639#if USE(JSVALUE32_64)
    2656         m_jit.move(TrustedImm32(JSValue::CellTag), resultTagReg);
     2640        m_jit.move(TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
    26572641#endif
    26582642
    … …  
    26722656            m_jit.graph().registerAndWatchStructureTransition(objectPrototypeStructure);
    26732657
    2674 #if USE(JSVALUE64)
    26752658            addSlowPathGenerator(makeUnique<SaneStringGetByValSlowPathGenerator>(
    2676                 outOfBounds, this, JSValueRegs(scratchReg), TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
    2677 #else
    2678             addSlowPathGenerator(makeUnique<SaneStringGetByValSlowPathGenerator>(
    2679                 outOfBounds, this, JSValueRegs(resultTagReg, scratchReg), TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
    2680 #endif
     2659                outOfBounds, this, resultRegs, TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
    26812660        } else {
    2682 #if USE(JSVALUE64)
    26832661            addSlowPathGenerator(
    26842662                slowPathCall(
    26852663                    outOfBounds, this, operationGetByValStringInt,
    2686                     scratchReg, TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
    2687 #else
    2688             addSlowPathGenerator(
    2689                 slowPathCall(
    2690                     outOfBounds, this, operationGetByValStringInt,
    2691                     JSValueRegs(resultTagReg, scratchReg), TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
    2692 #endif
    2693         }
    2694        
    2695 #if USE(JSVALUE64)
    2696         jsValueResult(scratchReg, m_currentNode);
    2697 #else
    2698         jsValueResult(resultTagReg, scratchReg, m_currentNode);
    2699 #endif
    2700     } else
    2701         cellResult(scratchReg, m_currentNode);
     2664                    resultRegs, TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
     2665        }
     2666       
     2667        jsValueResult(resultRegs, m_currentNode);
     2668    } else {
     2669        if (format == DataFormatJS)
     2670            jsValueResult(resultRegs, m_currentNode);
     2671        else {
     2672            ASSERT(format == DataFormatCell);
     2673            cellResult(resultRegs.payloadGPR(), m_currentNode);
     2674        }
     2675    }
    27022676}
    27032677
    … …  
    33523326}
    33533327
    3354 void SpeculativeJIT::setIntTypedArrayLoadResult(Node* node, GPRReg resultReg, TypedArrayType type, bool canSpeculate)
    3355 {
    3356     if (elementSize(type) < 4 || isSigned(type)) {
     3328void SpeculativeJIT::setIntTypedArrayLoadResult(Node* node, JSValueRegs resultRegs, TypedArrayType type, bool canSpeculate, bool shouldBox)
     3329{
     3330    bool isUInt32 = elementSize(type) == 4 && !isSigned(type);
     3331    GPRReg resultReg = resultRegs.payloadGPR();
     3332
     3333    if (shouldBox) {
     3334        if (isUInt32) {
     3335            FPRTemporary fresult(this);
     3336            m_jit.convertInt32ToDouble(resultReg, fresult.fpr());
     3337            JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, resultReg, TrustedImm32(0));
     3338            m_jit.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32), fresult.fpr());
     3339            positive.link(&m_jit);
     3340            m_jit.boxDouble(fresult.fpr(), resultRegs);
     3341        } else
     3342            m_jit.boxInt32(resultRegs.payloadGPR(), resultRegs);
     3343        jsValueResult(resultRegs, node);
     3344        return;
     3345    }
     3346
     3347    if (!isUInt32) {
     3348        ASSERT(elementSize(type) < 4 || isSigned(type));
    33573349        strictInt32Result(resultReg, node);
    33583350        return;
    33593351    }
    3360    
    3361     ASSERT(elementSize(type) == 4 && !isSigned(type));
     3352
    33623353    if (node->shouldSpeculateInt32() && canSpeculate) {
    33633354        speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, resultReg, TrustedImm32(0)));
    … …  
    33833374}
    33843375
    3385 void SpeculativeJIT::compileGetByValOnIntTypedArray(Node* node, TypedArrayType type)
     3376void SpeculativeJIT::compileGetByValOnIntTypedArray(Node* node, TypedArrayType type, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix)
    33863377{
    33873378    ASSERT(isInt(type));
    … …  
    33953386    GPRReg storageReg = storage.gpr();
    33963387
    3397     GPRTemporary result(this);
    3398     GPRReg resultReg = result.gpr();
     3388    JSValueRegs resultRegs;
     3389    DataFormat format;
     3390    std::tie(resultRegs, format) = prefix(DataFormatInt32);
     3391    bool shouldBox = format == DataFormatJS;
    33993392
    34003393    emitTypedArrayBoundsCheck(node, baseReg, propertyReg);
    3401     loadFromIntTypedArray(storageReg, propertyReg, resultReg, type);
     3394    loadFromIntTypedArray(storageReg, propertyReg, resultRegs.payloadGPR(), type);
    34023395    constexpr bool canSpeculate = true;
    3403     setIntTypedArrayLoadResult(node, resultReg, type, canSpeculate);
     3396    setIntTypedArrayLoadResult(node, resultRegs, type, canSpeculate, shouldBox);
    34043397}
    34053398
    … …  
    36393632}
    36403633
    3641 void SpeculativeJIT::compileGetByValOnFloatTypedArray(Node* node, TypedArrayType type)
     3634void SpeculativeJIT::compileGetByValOnFloatTypedArray(Node* node, TypedArrayType type, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix)
    36423635{
    36433636    ASSERT(isFloat(type));
    … …  
    36503643    GPRReg propertyReg = property.gpr();
    36513644    GPRReg storageReg = storage.gpr();
     3645
     3646    JSValueRegs resultRegs;
     3647    DataFormat format;
     3648    std::tie(resultRegs, format) = prefix(DataFormatDouble);
    36523649
    36533650    FPRTemporary result(this);
    … …  
    36673664    }
    36683665   
    3669     doubleResult(resultReg, node);
     3666    if (format == DataFormatJS) {
     3667        m_jit.boxDouble(resultReg, resultRegs);
     3668        jsValueResult(resultRegs, node);
     3669    } else {
     3670        ASSERT(format == DataFormatDouble);
     3671        doubleResult(resultReg, node);
     3672    }
    36703673}
    36713674
    … …  
    37063709}
    37073710
    3708 void SpeculativeJIT::compileGetByValForObjectWithString(Node* node)
     3711void SpeculativeJIT::compileGetByValForObjectWithString(Node* node, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix)
    37093712{
    37103713    SpeculateCellOperand arg1(this, m_graph.varArgChild(node, 0));
    … …  
    37143717    GPRReg arg2GPR = arg2.gpr();
    37153718
     3719    JSValueRegs resultRegs;
     3720    std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     3721
    37163722    speculateObject(m_graph.varArgChild(node, 0), arg1GPR);
    37173723    speculateString(m_graph.varArgChild(node, 1), arg2GPR);
    37183724
    37193725    flushRegisters();
    3720     JSValueRegsFlushedCallResult result(this);
    3721     JSValueRegs resultRegs = result.regs();
    37223726    callOperation(operationGetByValObjectString, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR);
    37233727    m_jit.exceptionCheck();
    … …  
    37263730}
    37273731
    3728 void SpeculativeJIT::compileGetByValForObjectWithSymbol(Node* node)
     3732void SpeculativeJIT::compileGetByValForObjectWithSymbol(Node* node, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix)
    37293733{
    37303734    SpeculateCellOperand arg1(this, m_graph.varArgChild(node, 0));
    … …  
    37343738    GPRReg arg2GPR = arg2.gpr();
    37353739
     3740    JSValueRegs resultRegs;
     3741    std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     3742
    37363743    speculateObject(m_graph.varArgChild(node, 0), arg1GPR);
    37373744    speculateSymbol(m_graph.varArgChild(node, 1), arg2GPR);
    37383745
    37393746    flushRegisters();
    3740     JSValueRegsFlushedCallResult result(this);
    3741     JSValueRegs resultRegs = result.regs();
    37423747    callOperation(operationGetByValObjectSymbol, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR);
    37433748    m_jit.exceptionCheck();
    … …  
    80418046}
    80428047
    8043 void SpeculativeJIT::compileGetByValOnDirectArguments(Node* node)
     8048void SpeculativeJIT::compileGetByValOnDirectArguments(Node* node, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix)
    80448049{
    80458050    SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
    80468051    SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    8047     JSValueRegsTemporary result(this);
    8048     GPRTemporary scratch(this);
    80498052   
    80508053    GPRReg baseReg = base.gpr();
    80518054    GPRReg propertyReg = property.gpr();
    8052     JSValueRegs resultRegs = result.regs();
    8053     GPRReg scratchReg = scratch.gpr();
     8055
     8056    JSValueRegs resultRegs;
     8057    std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     8058    GPRReg scratchReg = resultRegs.payloadGPR();
    80548059   
    80558060    if (!m_compileOkay)
    … …  
    80828087}
    80838088
    8084 void SpeculativeJIT::compileGetByValOnScopedArguments(Node* node)
     8089void SpeculativeJIT::compileGetByValOnScopedArguments(Node* node, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix)
    80858090{
    80868091    SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
    80878092    SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    8088     JSValueRegsTemporary result(this);
    80898093    GPRTemporary scratch(this);
    80908094    GPRTemporary scratch2(this);
    … …  
    80928096    GPRReg baseReg = base.gpr();
    80938097    GPRReg propertyReg = property.gpr();
    8094     JSValueRegs resultRegs = result.regs();
    80958098    GPRReg scratchReg = scratch.gpr();
    80968099    GPRReg scratch2Reg = scratch2.gpr();
    … …  
    80988101    if (!m_compileOkay)
    80998102        return;
     8103
     8104    JSValueRegs resultRegs;
     8105    std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
    81008106   
    81018107    m_jit.loadPtr(
    … …  
    1344513451}
    1344613452
    13447 void SpeculativeJIT::compileGetEnumerableLength(Node* node)
    13448 {
    13449     SpeculateCellOperand enumerator(this, node->child1());
    13450     GPRTemporary result(this, Reuse, enumerator);
     13453void SpeculativeJIT::compileEnumeratorNextUpdateIndexAndMode(Node* node)
     13454{
     13455    Edge baseEdge = m_graph.varArgChild(node, 0);
     13456    SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
     13457    SpeculateStrictInt32Operand mode(this, m_graph.varArgChild(node, 2));
     13458    SpeculateCellOperand enumerator(this, m_graph.varArgChild(node, 3));
     13459
     13460    GPRReg indexGPR = index.gpr();
     13461    GPRReg modeGPR = mode.gpr();
    1345113462    GPRReg enumeratorGPR = enumerator.gpr();
    13452     GPRReg resultGPR = result.gpr();
    13453 
    13454     m_jit.load32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::indexedLengthOffset()), resultGPR);
    13455     strictInt32Result(resultGPR, node);
    13456 }
    13457 
    13458 void SpeculativeJIT::compileHasEnumerableProperty(Node* node)
    13459 {
    13460     JSValueOperand base(this, node->child1());
    13461     SpeculateCellOperand property(this, node->child2());
    13462 
    13463     JSValueRegs baseRegs = base.jsValueRegs();
    13464     GPRReg propertyGPR = property.gpr();
     13463
     13464    if (node->enumeratorMetadata() == JSPropertyNameEnumerator::IndexedMode) {
     13465        JSValueRegsTemporary result(this);
     13466        GPRTemporary scratch(this, Reuse, index);
     13467        JSValueRegs resultRegs = result.regs();
     13468
     13469        speculationCheck(BadCache, JSValueSource(), node, m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()), TrustedImm32(0)));
     13470
     13471        MacroAssembler::Label incrementLoop;
     13472        MacroAssembler::Jump done;
     13473        compileHasIndexedProperty(node, operationHasEnumerableIndexedProperty, scopedLambda<std::tuple<GPRReg, GPRReg>()>([&] {
     13474
     13475            m_jit.move(indexGPR, scratch.gpr());
     13476            MacroAssembler::Jump initMode = m_jit.branchTest32(MacroAssembler::Zero, modeGPR);
     13477
     13478            incrementLoop = m_jit.label();
     13479            m_jit.add32(TrustedImm32(1), scratch.gpr());
     13480
     13481            initMode.link(&m_jit);
     13482            done = m_jit.branch32(MacroAssembler::AboveOrEqual, scratch.gpr(), MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::indexedLengthOffset()));
     13483            return std::make_pair(scratch.gpr(), resultRegs.payloadGPR());
     13484        }));
     13485        m_jit.branchTest32(MacroAssembler::Zero, resultRegs.payloadGPR()).linkTo(incrementLoop, &m_jit);
     13486
     13487        done.link(&m_jit);
     13488
     13489#if USE(JSVALUE64)
     13490        m_jit.move(TrustedImm64(JSValue::DoubleEncodeOffset | static_cast<uint64_t>(JSPropertyNameEnumerator::IndexedMode) << 32), resultRegs.payloadGPR());
     13491        m_jit.or64(scratch.gpr(), resultRegs.payloadGPR());
     13492#else
     13493        m_jit.move(TrustedImm32(JSPropertyNameEnumerator::IndexedMode), resultRegs.tagGPR());
     13494#endif
     13495
     13496        jsValueResult(resultRegs, node);
     13497        return;
     13498    }
     13499
     13500    if (node->enumeratorMetadata() == JSPropertyNameEnumerator::OwnStructureMode && baseEdge.useKind() == CellUse) {
     13501        SpeculateCellOperand base(this, baseEdge);
     13502        JSValueRegsTemporary result(this);
     13503        GPRReg baseGPR = base.gpr();
     13504        JSValueRegs resultRegs = result.regs();
     13505
     13506        // Has the same structure as the enumerator.
     13507        m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), resultRegs.payloadGPR());
     13508        speculationCheck(BadCache, JSValueSource(), node, m_jit.branch32(MacroAssembler::NotEqual, resultRegs.payloadGPR(), MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset())));
     13509
     13510        m_jit.load32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::modeSetOffset()), resultRegs.payloadGPR());
     13511        speculationCheck(BadCache, JSValueSource(), node, m_jit.branch32(MacroAssembler::NotEqual, TrustedImm32(JSPropertyNameEnumerator::OwnStructureMode), resultRegs.payloadGPR()));
     13512
     13513        m_jit.move(indexGPR, resultRegs.payloadGPR());
     13514        MacroAssembler::Jump initMode = m_jit.branchTest32(MacroAssembler::Zero, modeGPR);
     13515
     13516        m_jit.add32(MacroAssembler::TrustedImm32(1), resultRegs.payloadGPR());
     13517
     13518        initMode.link(&m_jit);
     13519#if USE(JSVALUE64)
     13520        m_jit.or64(TrustedImm64(JSValue::DoubleEncodeOffset | static_cast<uint64_t>(JSPropertyNameEnumerator::OwnStructureMode) << 32), resultRegs.payloadGPR());
     13521#else
     13522        m_jit.move(TrustedImm32(JSPropertyNameEnumerator::OwnStructureMode), resultRegs.tagGPR());
     13523#endif
     13524
     13525        jsValueResult(resultRegs, node);
     13526        return;
     13527    }
     13528
     13529    JSValueOperand base(this, baseEdge);
     13530    JSValueRegs baseRegs = base.regs();
    1346513531
    1346613532    flushRegisters();
    1346713533    JSValueRegsFlushedCallResult result(this);
    1346813534    JSValueRegs resultRegs = result.regs();
    13469     callOperation(operationHasEnumerableProperty, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, propertyGPR);
     13535    callOperation(operationEnumeratorNextUpdateIndexAndMode, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, indexGPR, modeGPR, enumeratorGPR);
    1347013536    m_jit.exceptionCheck();
    13471     blessedBooleanResult(resultRegs.payloadGPR(), node);
    13472 }
    13473 
    13474 void SpeculativeJIT::compileToIndexString(Node* node)
    13475 {
    13476     SpeculateInt32Operand index(this, node->child1());
    13477     GPRReg indexGPR = index.gpr();
    13478 
    13479     flushRegisters();
    13480     GPRFlushedCallResult result(this);
     13537    jsValueResult(resultRegs, node);
     13538}
     13539
     13540void SpeculativeJIT::compileEnumeratorNextExtractIndex(Node* node)
     13541{
     13542    JSValueOperand updatedPair(this, node->child1());
     13543    JSValueRegs pairRegs = updatedPair.jsValueRegs();
     13544    GPRReg payloadGPR = pairRegs.payloadGPR();
     13545
     13546    GPRTemporary result(this);
    1348113547    GPRReg resultGPR = result.gpr();
    13482     callOperation(operationToIndexString, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), indexGPR);
    13483     m_jit.exceptionCheck();
    13484     cellResult(resultGPR, node);
     13548
     13549    m_jit.and32(TrustedImm32(std::numeric_limits<uint32_t>::max()), payloadGPR, resultGPR);
     13550
     13551    strictInt32Result(resultGPR, node);
     13552}
     13553
     13554void SpeculativeJIT::compileEnumeratorNextExtractMode(Node* node)
     13555{
     13556    JSValueOperand updatedPair(this, node->child1());
     13557    JSValueRegs pairRegs = updatedPair.jsValueRegs();
     13558    GPRReg pairGPR = is64Bit() ? pairRegs.payloadGPR() : pairRegs.tagGPR();
     13559
     13560    GPRTemporary result(this);
     13561    GPRReg resultGPR = result.gpr();
     13562
     13563#if CPU(ARM64) && USE(JSVALUE64)
     13564    m_jit.extractUnsignedBitfield64(pairGPR, TrustedImm32(32), TrustedImm32(WTF::fastLog2(static_cast<unsigned>(JSPropertyNameEnumerator::enumerationModeMask + 1))), resultGPR);
     13565#else
     13566#if USE(JSVALUE64)
     13567    m_jit.rshift64(pairGPR, TrustedImm32(32), resultGPR);
     13568#else
     13569    m_jit.move(pairGPR, resultGPR);
     13570#endif
     13571    m_jit.and32(TrustedImm32(JSPropertyNameEnumerator::enumerationModeMask), resultGPR);
     13572#endif
     13573
     13574    strictInt32Result(resultGPR, node);
     13575}
     13576
     13577void SpeculativeJIT::compileEnumeratorNextUpdatePropertyName(Node* node)
     13578{
     13579    SpeculateStrictInt32Operand indexOperand(this, node->child1());
     13580    SpeculateStrictInt32Operand modeOperand(this, node->child2());
     13581    SpeculateCellOperand enumeratorOperand(this, node->child3());
     13582    JSValueRegsTemporary resultTemp(this);
     13583
     13584    GPRReg index = indexOperand.gpr();
     13585    GPRReg mode = modeOperand.gpr();
     13586    GPRReg enumerator = enumeratorOperand.gpr();
     13587    JSValueRegs resultRegs = resultTemp.regs();
     13588
     13589    OptionSet seenModes = node->enumeratorMetadata();
     13590
     13591    MacroAssembler::JumpList doneCases;
     13592    MacroAssembler::Jump operationCall;
     13593
     13594    bool needsOperation = seenModes.contains(JSPropertyNameEnumerator::IndexedMode);
     13595
     13596    // Make sure we flush on all code paths if we could call the operation.
     13597    if (needsOperation)
     13598        flushRegisters();
     13599
     13600    if (seenModes.containsAny({ JSPropertyNameEnumerator::OwnStructureMode, JSPropertyNameEnumerator::GenericMode })) {
     13601
     13602        if (needsOperation)
     13603            operationCall = m_jit.branchTest32(MacroAssembler::NonZero, mode, TrustedImm32(JSPropertyNameEnumerator::IndexedMode));
     13604
     13605        auto outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, index, MacroAssembler::Address(enumerator, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
     13606
     13607        m_jit.loadPtr(MacroAssembler::Address(enumerator, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), resultRegs.payloadGPR());
     13608        m_jit.loadPtr(MacroAssembler::BaseIndex(resultRegs.payloadGPR(), index, MacroAssembler::ScalePtr), resultRegs.payloadGPR());
     13609#if USE(JSVALUE32_64)
     13610        m_jit.move(TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
     13611#endif
     13612        doneCases.append(m_jit.jump());
     13613
     13614        outOfBounds.link(&m_jit);
     13615        m_jit.moveTrustedValue(jsNull(), resultRegs);
     13616    }
     13617
     13618    if (needsOperation) {
     13619        if (operationCall.isSet()) {
     13620            doneCases.append(m_jit.jump());
     13621            operationCall.link(&m_jit);
     13622        }
     13623        callOperation(operationEnumeratorNextUpdatePropertyName, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), index, mode, enumerator);
     13624        m_jit.exceptionCheck();
     13625    }
     13626
     13627    doneCases.link(&m_jit);
     13628    jsValueResult(resultRegs, node);
     13629}
     13630
     13631void SpeculativeJIT::compileEnumeratorGetByVal(Node* node)
     13632{
     13633    Edge baseEdge = m_graph.varArgChild(node, 0);
     13634    auto generate = [&] (GPRReg baseCellGPR) {
     13635        MacroAssembler::JumpList doneCases;
     13636        JSValueRegsTemporary result;
     13637        JSValueRegs resultRegs;
     13638        GPRReg indexGPR;
     13639        GPRReg enumeratorGPR;
     13640        MacroAssembler::Jump badStructureSlowPath;
     13641
     13642        compileGetByVal(node, scopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat)>([&] (DataFormat) {
     13643            Edge storageEdge = m_graph.varArgChild(node, 2);
     13644            StorageOperand storage;
     13645            if (storageEdge)
     13646                storage.emplace(this, storageEdge);
     13647            SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 3));
     13648            SpeculateStrictInt32Operand mode(this, m_graph.varArgChild(node, 4));
     13649            SpeculateCellOperand enumerator(this, m_graph.varArgChild(node, 5));
     13650
     13651            GPRReg modeGPR = mode.gpr();
     13652            indexGPR = index.gpr();
     13653            enumeratorGPR = enumerator.gpr();
     13654
     13655            result = JSValueRegsTemporary(this);
     13656            resultRegs = result.regs();
     13657            GPRReg scratchGPR = resultRegs.payloadGPR();
     13658
     13659            bool haveStorage = !!storageEdge;
     13660            GPRTemporary storageTemporary;
     13661            GPRReg storageGPR;
     13662            if (!haveStorage) {
     13663                storageTemporary = GPRTemporary(this, Reuse, enumerator);
     13664                storageGPR = storageTemporary.gpr();
     13665            } else
     13666                storageGPR = storage.gpr();
     13667
     13668            MacroAssembler::JumpList notFastNamedCases;
     13669
     13670            // FIXME: We shouldn't generate this code if we know base is not an object.
     13671            notFastNamedCases.append(m_jit.branchTest32(MacroAssembler::NonZero, modeGPR, TrustedImm32(JSPropertyNameEnumerator::IndexedMode | JSPropertyNameEnumerator::GenericMode)));
     13672            {
     13673                if (!m_state.forNode(baseEdge).isType(SpecCell))
     13674                    notFastNamedCases.append(m_jit.branchIfNotCell(baseCellGPR));
     13675
     13676                // Check the structure
     13677                // FIXME: If we know there's only one structure for base we can just embed it here.
     13678                m_jit.load32(MacroAssembler::Address(baseCellGPR, JSCell::structureIDOffset()), scratchGPR);
     13679
     13680                auto badStructure = m_jit.branch32(
     13681                    MacroAssembler::NotEqual,
     13682                    scratchGPR,
     13683                    MacroAssembler::Address(
     13684                        enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset()));
     13685
     13686                // FIXME: Maybe we should have a better way to represent Indexed+Named?
     13687                if (m_graph.varArgChild(node, 1).node() == m_graph.varArgChild(node, 3).node())
     13688                    badStructureSlowPath = badStructure;
     13689                else
     13690                    notFastNamedCases.append(badStructure);
     13691
     13692                // Compute the offset
     13693                // If index is less than the enumerator's cached inline storage, then it's an inline access
     13694                MacroAssembler::Jump outOfLineAccess = m_jit.branch32(MacroAssembler::AboveOrEqual,
     13695                    indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
     13696
     13697                m_jit.loadValue(MacroAssembler::BaseIndex(baseCellGPR, indexGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage()), resultRegs);
     13698
     13699                doneCases.append(m_jit.jump());
     13700
     13701                // Otherwise it's out of line
     13702                outOfLineAccess.link(&m_jit);
     13703                m_jit.move(indexGPR, scratchGPR);
     13704                m_jit.sub32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), scratchGPR);
     13705                m_jit.neg32(scratchGPR);
     13706                m_jit.signExtend32ToPtr(scratchGPR, scratchGPR);
     13707                if (!haveStorage)
     13708                    m_jit.loadPtr(MacroAssembler::Address(baseCellGPR, JSObject::butterflyOffset()), storageGPR);
     13709                int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
     13710                m_jit.loadValue(MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, offsetOfFirstProperty), resultRegs);
     13711                doneCases.append(m_jit.jump());
     13712            }
     13713
     13714            notFastNamedCases.link(&m_jit);
     13715            return std::make_pair(resultRegs, DataFormatJS);
     13716        }));
     13717
     13718        // We rely on compileGetByVal to call jsValueResult for us.
     13719        // FIXME: This is kinda hacky...
     13720        ASSERT(generationInfo(node).jsValueRegs() == resultRegs && generationInfo(node).registerFormat() == DataFormatJS);
     13721
     13722        if (badStructureSlowPath.isSet())
     13723            addSlowPathGenerator(slowPathCall(badStructureSlowPath, this, operationEnumeratorRecoverNameAndGetByVal, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseCellGPR, indexGPR, enumeratorGPR));
     13724
     13725        doneCases.link(&m_jit);
     13726    };
     13727
     13728    if (isCell(baseEdge.useKind())) {
     13729        // Use manual operand speculation since Fixup may have picked a UseKind more restrictive than CellUse.
     13730        speculate(node, baseEdge);
     13731        SpeculateCellOperand baseOperand(this, baseEdge, ManualOperandSpeculation);
     13732        generate(baseOperand.gpr());
     13733    } else {
     13734        JSValueOperand baseOperand(this, baseEdge);
     13735        generate(baseOperand.gpr());
     13736    }
     13737}
     13738
     13739template<typename SlowPathFunctionType>
     13740void SpeculativeJIT::compileEnumeratorHasProperty(Node* node, SlowPathFunctionType slowPathFunction)
     13741{
     13742    Edge baseEdge = m_graph.varArgChild(node, 0);
     13743    auto generate = [&] (auto base, GPRReg baseCellGPR) {
     13744        JSValueOperand propertyName(this, m_graph.varArgChild(node, 1));
     13745        SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 2));
     13746        SpeculateStrictInt32Operand mode(this, m_graph.varArgChild(node, 3));
     13747        SpeculateCellOperand enumerator(this, m_graph.varArgChild(node, 4));
     13748
     13749        JSValueRegs propertyNameRegs = propertyName.regs();
     13750        GPRReg indexGPR = index.gpr();
     13751        GPRReg modeGPR = mode.gpr();
     13752        GPRReg enumeratorGPR = enumerator.gpr();
     13753
     13754        JSValueRegsTemporary result(this);
     13755        JSValueRegs resultRegs = result.regs();
     13756
     13757        MacroAssembler::JumpList operationCases;
     13758
     13759        if (m_state.forNode(baseEdge).m_type & ~SpecCell)
     13760            operationCases.append(m_jit.branchIfNotCell(base));
     13761
     13762        // FIXME: We shouldn't generate this code if we know base is not a cell.
     13763        operationCases.append(m_jit.branchTest32(MacroAssembler::Zero, modeGPR, TrustedImm32(JSPropertyNameEnumerator::OwnStructureMode)));
     13764
     13765        m_jit.load32(MacroAssembler::Address(baseCellGPR, JSCell::structureIDOffset()), resultRegs.payloadGPR());
     13766        operationCases.append(m_jit.branch32(MacroAssembler::NotEqual, resultRegs.payloadGPR(), MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset())));
     13767
     13768        moveTrueTo(resultRegs.payloadGPR());
     13769        MacroAssembler::Jump done = m_jit.jump();
     13770
     13771        operationCases.link(&m_jit);
     13772
     13773        flushRegisters();
     13774#if USE(JSVALUE32_64)
     13775        m_jit.move(TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
     13776        auto baseRegs = JSValueRegs(baseCellGPR, resultRegs.tagGPR());
     13777#else
     13778        auto baseRegs = base;
     13779#endif
     13780        callOperation(slowPathFunction, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, propertyNameRegs, indexGPR, modeGPR);
     13781        m_jit.exceptionCheck();
     13782
     13783        done.link(&m_jit);
     13784
     13785        blessedBooleanResult(resultRegs.payloadGPR(), node);
     13786    };
     13787
     13788    if (isCell(baseEdge.useKind())) {
     13789        SpeculateCellOperand base(this, baseEdge);
     13790        generate(base.gpr(), base.gpr());
     13791    } else {
     13792        JSValueOperand base(this, baseEdge);
     13793        generate(base.regs(), base.regs().payloadGPR());
     13794    }
     13795}
     13796
     13797void SpeculativeJIT::compileEnumeratorInByVal(Node* node)
     13798{
     13799    compileEnumeratorHasProperty(node, operationEnumeratorInByVal);
     13800}
     13801
     13802void SpeculativeJIT::compileEnumeratorHasOwnProperty(Node* node)
     13803{
     13804    compileEnumeratorHasProperty(node, operationEnumeratorHasOwnProperty);
    1348513805}
    1348613806
    … …  
    1362513945}
    1362613946
    13627 void SpeculativeJIT::compileHasEnumerableStructureProperty(Node* node)
    13628 {
    13629     JSValueOperand base(this, node->child1());
    13630     SpeculateCellOperand property(this, node->child2());
    13631     SpeculateCellOperand enumerator(this, node->child3());
    13632     JSValueRegsTemporary result(this);
    13633 
    13634     JSValueRegs baseRegs = base.jsValueRegs();
    13635     GPRReg propertyGPR = property.gpr();
    13636     JSValueRegs resultRegs = result.regs();
    13637 
    13638     CCallHelpers::JumpList wrongStructure;
    13639 
    13640     wrongStructure.append(m_jit.branchIfNotCell(baseRegs));
    13641 
    13642     m_jit.load32(MacroAssembler::Address(baseRegs.payloadGPR(), JSCell::structureIDOffset()), resultRegs.payloadGPR());
    13643     wrongStructure.append(m_jit.branch32(MacroAssembler::NotEqual,
    13644         resultRegs.payloadGPR(),
    13645         MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset())));
    13646 
    13647     moveTrueTo(resultRegs.payloadGPR());
    13648 
    13649     addSlowPathGenerator(slowPathCall(wrongStructure, this, operationHasEnumerableProperty, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, propertyGPR));
    13650     blessedBooleanResult(resultRegs.payloadGPR(), node);
    13651 }
    13652 
    13653 template <typename Function>
    13654 void SpeculativeJIT::compileHasOwnStructurePropertyImpl(Node* node, Function slowPath)
    13655 {
    13656     SpeculateCellOperand base(this, node->child1());
    13657     SpeculateCellOperand property(this, node->child2());
    13658     SpeculateCellOperand enumerator(this, node->child3());
    13659     JSValueRegsTemporary result(this);
    13660 
    13661     GPRReg baseGPR = base.gpr();
    13662     GPRReg propertyGPR = property.gpr();
    13663     JSValueRegs resultRegs = result.regs();
    13664 
    13665     CCallHelpers::JumpList wrongStructure;
    13666 
    13667     m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), resultRegs.payloadGPR());
    13668     wrongStructure.append(m_jit.branch32(MacroAssembler::NotEqual,
    13669         resultRegs.payloadGPR(),
    13670         MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset())));
    13671 
    13672     moveTrueTo(resultRegs.payloadGPR());
    13673 
    13674     addSlowPathGenerator(slowPathCall(wrongStructure, this, slowPath, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyGPR));
    13675     blessedBooleanResult(resultRegs.payloadGPR(), node);
    13676 }
    13677 
    13678 void SpeculativeJIT::compileHasOwnStructureProperty(Node* node)
    13679 {
    13680     compileHasOwnStructurePropertyImpl(node, operationHasOwnStructureProperty);
    13681 }
    13682 
    13683 void SpeculativeJIT::compileInStructureProperty(Node* node)
    13684 {
    13685     compileHasOwnStructurePropertyImpl(node, operationInStructureProperty);
    13686 }
    13687 
    1368813947void SpeculativeJIT::compileGetPropertyEnumerator(Node* node)
    1368913948{
    … …  
    1371013969    m_jit.exceptionCheck();
    1371113970    cellResult(resultGPR, node);
    13712 }
    13713 
    13714 void SpeculativeJIT::compileGetEnumeratorPname(Node* node)
    13715 {
    13716     ASSERT(node->op() == GetEnumeratorStructurePname || node->op() == GetEnumeratorGenericPname);
    13717     SpeculateCellOperand enumerator(this, node->child1());
    13718     SpeculateStrictInt32Operand index(this, node->child2());
    13719     GPRTemporary scratch(this);
    13720     JSValueRegsTemporary result(this);
    13721 
    13722     GPRReg enumeratorGPR = enumerator.gpr();
    13723     GPRReg indexGPR = index.gpr();
    13724     GPRReg scratchGPR = scratch.gpr();
    13725     JSValueRegs resultRegs = result.regs();
    13726 
    13727     MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, indexGPR,
    13728         MacroAssembler::Address(enumeratorGPR, (node->op() == GetEnumeratorStructurePname)
    13729             ? JSPropertyNameEnumerator::endStructurePropertyIndexOffset()
    13730             : JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
    13731 
    13732     m_jit.moveValue(jsNull(), resultRegs);
    13733 
    13734     MacroAssembler::Jump done = m_jit.jump();
    13735     inBounds.link(&m_jit);
    13736 
    13737     m_jit.loadPtr(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), scratchGPR);
    13738     m_jit.loadPtr(MacroAssembler::BaseIndex(scratchGPR, indexGPR, MacroAssembler::ScalePtr), resultRegs.payloadGPR());
    13739 #if USE(JSVALUE32_64)
    13740     m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
    13741 #endif
    13742 
    13743     done.link(&m_jit);
    13744     jsValueResult(resultRegs, node);
    1374513971}
    1374613972
    … …  
    1493715163}
    1493815164
    14939 void SpeculativeJIT::compileHasIndexedProperty(Node* node, S_JITOperation_GCZ slowPathOperation)
     15165void SpeculativeJIT::compileHasIndexedProperty(Node* node, S_JITOperation_GCZ slowPathOperation, const ScopedLambda<std::tuple<GPRReg, GPRReg>()>& prefix)
    1494015166{
    1494115167    SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
    14942     SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
    14943     GPRTemporary result(this);
    1494415168
    1494515169    GPRReg baseGPR = base.gpr();
    14946     GPRReg indexGPR = index.gpr();
    14947     GPRReg resultGPR = result.gpr();
     15170    GPRReg indexGPR = InvalidGPRReg;
     15171    GPRReg resultGPR = InvalidGPRReg;
    1494815172
    1494915173    MacroAssembler::JumpList slowCases;
    … …  
    1495215176    case Array::Int32:
    1495315177    case Array::Contiguous: {
    14954         ASSERT(!!m_graph.varArgChild(node, 2));
    14955         StorageOperand storage(this, m_graph.varArgChild(node, 2));
     15178        ASSERT(!!m_graph.varArgChild(node, node->storageChildIndex()));
     15179        StorageOperand storage(this, m_graph.varArgChild(node, node->storageChildIndex()));
    1495615180        GPRTemporary scratch(this);
    1495715181
    1495815182        GPRReg storageGPR = storage.gpr();
    1495915183        GPRReg scratchGPR = scratch.gpr();
     15184
     15185        std::tie(indexGPR, resultGPR) = prefix();
    1496015186
    1496115187        MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
    … …  
    1498615212    }
    1498715213    case Array::Double: {
    14988         ASSERT(!!m_graph.varArgChild(node, 2));
    14989         StorageOperand storage(this, m_graph.varArgChild(node, 2));
     15214        ASSERT(!!m_graph.varArgChild(node, node->storageChildIndex()));
     15215        StorageOperand storage(this, m_graph.varArgChild(node, node->storageChildIndex()));
    1499015216        FPRTemporary scratch(this);
    1499115217        FPRReg scratchFPR = scratch.fpr();
    1499215218        GPRReg storageGPR = storage.gpr();
     15219
     15220        std::tie(indexGPR, resultGPR) = prefix();
    1499315221
    1499415222        MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
    … …  
    1501515243    }
    1501615244    case Array::ArrayStorage: {
    15017         ASSERT(!!m_graph.varArgChild(node, 2));
    15018         StorageOperand storage(this, m_graph.varArgChild(node, 2));
     15245        ASSERT(!!m_graph.varArgChild(node, node->storageChildIndex()));
     15246        StorageOperand storage(this, m_graph.varArgChild(node, node->storageChildIndex()));
    1501915247        GPRTemporary scratch(this);
    1502015248
    1502115249        GPRReg storageGPR = storage.gpr();
    1502215250        GPRReg scratchGPR = scratch.gpr();
     15251
     15252        std::tie(indexGPR, resultGPR) = prefix();
    1502315253
    1502415254        MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
    … …  
    1505015280        // FIXME: Optimize TypedArrays in HasIndexedProperty IC
    1505115281        // https://bugs.webkit.org/show_bug.cgi?id=221183
     15282        std::tie(indexGPR, resultGPR) = prefix();
    1505215283        slowCases.append(m_jit.jump());
    1505315284        break;
    … …  
    1505615287
    1505715288    addSlowPathGenerator(slowPathCall(slowCases, this, slowPathOperation, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, indexGPR));
    15058 
    15059     unblessedBooleanResult(resultGPR, node);
    15060 }
    15061 
    15062 void SpeculativeJIT::compileGetDirectPname(Node* node)
    15063 {
    15064     Edge& baseEdge = m_jit.graph().varArgChild(node, 0);
    15065     Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
    15066     Edge& indexEdge = m_jit.graph().varArgChild(node, 2);
    15067 
    15068     SpeculateCellOperand base(this, baseEdge);
    15069     SpeculateCellOperand property(this, propertyEdge);
    15070     GPRReg baseGPR = base.gpr();
    15071     GPRReg propertyGPR = property.gpr();
    15072 
    15073     Edge& enumeratorEdge = m_jit.graph().varArgChild(node, 3);
    15074     SpeculateStrictInt32Operand index(this, indexEdge);
    15075     SpeculateCellOperand enumerator(this, enumeratorEdge);
    15076     GPRTemporary scratch(this);
    15077     JSValueRegsTemporary result(this);
    15078 
    15079     GPRReg indexGPR = index.gpr();
    15080     GPRReg enumeratorGPR = enumerator.gpr();
    15081     GPRReg scratchGPR = scratch.gpr();
    15082     JSValueRegs resultRegs = result.regs();
    15083 
    15084     MacroAssembler::JumpList slowPath;
    15085 
    15086     // Check the structure
    15087     m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), scratchGPR);
    15088     slowPath.append(
    15089         m_jit.branch32(
    15090             MacroAssembler::NotEqual,
    15091             scratchGPR,
    15092             MacroAssembler::Address(
    15093                 enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset())));
    15094 
    15095     // Compute the offset
    15096     // If index is less than the enumerator's cached inline storage, then it's an inline access
    15097     MacroAssembler::Jump outOfLineAccess = m_jit.branch32(MacroAssembler::AboveOrEqual,
    15098         indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
    15099 
    15100     m_jit.loadValue(MacroAssembler::BaseIndex(baseGPR, indexGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage()), resultRegs);
    15101 
    15102     MacroAssembler::Jump done = m_jit.jump();
    15103 
    15104     // Otherwise it's out of line
    15105     outOfLineAccess.link(&m_jit);
    15106     m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), resultRegs.payloadGPR());
    15107     m_jit.move(indexGPR, scratchGPR);
    15108     m_jit.sub32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), scratchGPR);
    15109     m_jit.neg32(scratchGPR);
    15110     m_jit.signExtend32ToPtr(scratchGPR, scratchGPR);
    15111     int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
    15112     m_jit.loadValue(MacroAssembler::BaseIndex(resultRegs.payloadGPR(), scratchGPR, MacroAssembler::TimesEight, offsetOfFirstProperty), resultRegs);
    15113 
    15114     done.link(&m_jit);
    15115 
    15116     addSlowPathGenerator(slowPathCall(slowPath, this, operationGetByValCell, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, CCallHelpers::CellValue(propertyGPR)));
    15117 
    15118     jsValueResult(resultRegs, node);
    1511915289}
    1512015290
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r279604 r280760  
    4848
    4949class GPRTemporary;
     50class JSValueRegsTemporary;
    5051class JSValueOperand;
    5152class SlowPathGenerator;
    … …  
    247248    GPRReg allocate(GPRReg specific)
    248249    {
     250        if (specific == InvalidGPRReg)
     251            allocate();
    249252#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
    250253        m_jit.addRegisterAllocationAtOffset(m_jit.debugOffset());
    … …  
    13461349    }
    13471350   
     1351    // We use a scopedLambda to placate register allocation validation.
     1352    void compileGetByVal(Node*, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix);
     1353
    13481354    void compileGetCharCodeAt(Node*);
    1349     void compileGetByValOnString(Node*);
     1355    void compileGetByValOnString(Node*, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix);
    13501356    void compileFromCharCode(Node*);
    13511357
    1352     void compileGetByValOnDirectArguments(Node*);
    1353     void compileGetByValOnScopedArguments(Node*);
     1358    void compileGetByValOnDirectArguments(Node*, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix);
     1359    void compileGetByValOnScopedArguments(Node*, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix);
    13541360
    13551361    void compileGetPrivateName(Node*);
    … …  
    14251431    void emitTypedArrayBoundsCheck(Node*, GPRReg baseGPR, GPRReg indexGPR);
    14261432    void compileGetTypedArrayByteOffset(Node*);
    1427     void compileGetByValOnIntTypedArray(Node*, TypedArrayType);
     1433    void compileGetByValOnIntTypedArray(Node*, TypedArrayType, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix);
    14281434    void compilePutByValForIntTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType);
    1429     void compileGetByValOnFloatTypedArray(Node*, TypedArrayType);
     1435    void compileGetByValOnFloatTypedArray(Node*, TypedArrayType, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix);
    14301436    void compilePutByValForFloatTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType);
    1431     void compileGetByValForObjectWithString(Node*);
    1432     void compileGetByValForObjectWithSymbol(Node*);
     1437    void compileGetByValForObjectWithString(Node*, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix);
     1438    void compileGetByValForObjectWithSymbol(Node*, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix);
    14331439    void compilePutByValForCellWithString(Node*, Edge& child1, Edge& child2, Edge& child3);
    14341440    void compilePutByValForCellWithSymbol(Node*, Edge& child1, Edge& child2, Edge& child3);
    … …  
    14591465        Edge valueUse);
    14601466    void loadFromIntTypedArray(GPRReg storageReg, GPRReg propertyReg, GPRReg resultReg, TypedArrayType);
    1461     void setIntTypedArrayLoadResult(Node*, GPRReg resultReg, TypedArrayType, bool canSpeculate);
     1467    void setIntTypedArrayLoadResult(Node*, JSValueRegs resultRegs, TypedArrayType, bool canSpeculate, bool shouldBox);
    14621468    template <typename ClassType> void compileNewFunctionCommon(GPRReg, RegisteredStructure, GPRReg, GPRReg, GPRReg, MacroAssembler::JumpList&, size_t, FunctionExecutable*);
    14631469    void compileNewFunction(Node*);
    … …  
    15251531    void compileThrow(Node*);
    15261532    void compileThrowStaticError(Node*);
    1527     void compileGetEnumerableLength(Node*);
    1528     void compileHasEnumerableStructureProperty(Node*);
    1529     void compileHasEnumerableProperty(Node*);
    1530     void compileToIndexString(Node*);
     1533
     1534    void compileEnumeratorNextUpdateIndexAndMode(Node*);
     1535    void compileEnumeratorNextExtractMode(Node*);
     1536    void compileEnumeratorNextExtractIndex(Node*);
     1537    void compileEnumeratorNextUpdatePropertyName(Node*);
     1538    void compileEnumeratorGetByVal(Node*);
     1539    template<typename SlowPathFunctionType>
     1540    void compileEnumeratorHasProperty(Node*, SlowPathFunctionType);
     1541    void compileEnumeratorInByVal(Node*);
     1542    void compileEnumeratorHasOwnProperty(Node*);
     1543
    15311544    void compilePutByIdFlush(Node*);
    15321545    void compilePutById(Node*);
    15331546    void compilePutByIdDirect(Node*);
    15341547    void compilePutByIdWithThis(Node*);
    1535     template <typename Function>
    1536     void compileHasOwnStructurePropertyImpl(Node*, Function);
    1537     void compileHasOwnStructureProperty(Node*);
    1538     void compileInStructureProperty(Node*);
    1539     void compileGetDirectPname(Node*);
    15401548    void compileGetPropertyEnumerator(Node*);
    1541     void compileGetEnumeratorPname(Node*);
    15421549    void compileGetExecutable(Node*);
    15431550    void compileGetGetter(Node*);
    … …  
    15691576    void compileLogShadowChickenPrologue(Node*);
    15701577    void compileLogShadowChickenTail(Node*);
    1571     void compileHasIndexedProperty(Node*, S_JITOperation_GCZ);
     1578    void compileHasIndexedProperty(Node*, S_JITOperation_GCZ, const ScopedLambda<std::tuple<GPRReg, GPRReg>()>& prefix);
    15721579    void compileExtractCatchLocal(Node*);
    15731580    void compileClearCatchLocals(Node*);
    … …  
    19271934    }
    19281935
     1936    JSValueRegs regs() { return jsValueRegs(); }
     1937
    19291938#if USE(JSVALUE64)
    19301939    GPRReg gpr()
    … …  
    19661975    }
    19671976
    1968     GPRReg gpr(WhichValueWord which)
     1977    GPRReg gpr(WhichValueWord which = PayloadWord)
    19691978    {
    19701979        return jsValueRegs().gpr(which);
    … …  
    20042013    WTF_MAKE_FAST_ALLOCATED;
    20052014public:
     2015    StorageOperand() = default;
     2016
    20062017    explicit StorageOperand(SpeculativeJIT* jit, Edge edge)
    20072018        : m_jit(jit)
    … …  
    20092020        , m_gprOrInvalid(InvalidGPRReg)
    20102021    {
     2022        emplace(jit, edge);
     2023    }
     2024   
     2025    ~StorageOperand()
     2026    {
     2027        if (m_gprOrInvalid != InvalidGPRReg)
     2028            m_jit->unlock(m_gprOrInvalid);
     2029    }
     2030   
     2031    Edge edge() const
     2032    {
     2033        return m_edge;
     2034    }
     2035   
     2036    Node* node() const
     2037    {
     2038        return edge().node();
     2039    }
     2040   
     2041    GPRReg gpr()
     2042    {
     2043        if (m_gprOrInvalid == InvalidGPRReg)
     2044            m_gprOrInvalid = m_jit->fillStorage(edge());
     2045        return m_gprOrInvalid;
     2046    }
     2047
     2048    void emplace(SpeculativeJIT* jit, Edge edge)
     2049    {
     2050        m_jit = jit;
     2051        m_edge = edge;
     2052        ASSERT(m_gprOrInvalid == InvalidGPRReg);
    20112053        ASSERT(m_jit);
    20122054        ASSERT(edge.useKind() == UntypedUse || edge.useKind() == KnownCellUse);
    … …  
    20152057    }
    20162058   
    2017     ~StorageOperand()
    2018     {
    2019         ASSERT(m_gprOrInvalid != InvalidGPRReg);
    2020         m_jit->unlock(m_gprOrInvalid);
    2021     }
    2022    
    2023     Edge edge() const
    2024     {
    2025         return m_edge;
    2026     }
    2027    
    2028     Node* node() const
    2029     {
    2030         return edge().node();
    2031     }
    2032    
    2033     GPRReg gpr()
    2034     {
    2035         if (m_gprOrInvalid == InvalidGPRReg)
    2036             m_gprOrInvalid = m_jit->fillStorage(edge());
    2037         return m_gprOrInvalid;
    2038     }
    2039    
    20402059    void use()
    20412060    {
    … …  
    20442063   
    20452064private:
    2046     SpeculativeJIT* m_jit;
     2065    SpeculativeJIT* m_jit { nullptr };
    20472066    Edge m_edge;
    2048     GPRReg m_gprOrInvalid;
     2067    GPRReg m_gprOrInvalid { InvalidGPRReg };
    20492068};
    20502069
    … …  
    21352154    JSValueRegsTemporary();
    21362155    JSValueRegsTemporary(SpeculativeJIT*);
     2156    JSValueRegsTemporary(SpeculativeJIT*, GPRReg specificPayload);
     2157#if USE(JSVALUE32_64)
     2158    JSValueRegsTemporary(SpeculativeJIT*, GPRReg specificPayload, GPRReg specificTag);
     2159#endif
    21372160    template<typename T>
    21382161    JSValueRegsTemporary(SpeculativeJIT*, ReuseTag, T& operand, WhichValueWord resultRegWord = PayloadWord);
    … …  
    21402163    ~JSValueRegsTemporary();
    21412164   
     2165    explicit operator bool() { return !!regs(); }
     2166
     2167    JSValueRegsTemporary& operator=(JSValueRegsTemporary&&) = default;
     2168
    21422169    JSValueRegs regs();
    21432170
    … …  
    21502177#endif
    21512178};
     2179
     2180#if USE(JSVALUE64)
     2181template<typename T>
     2182JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord)
     2183    : m_gpr(jit, Reuse, operand)
     2184{
     2185}
     2186#else
     2187template<typename T>
     2188JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord resultWord)
     2189{
     2190    if (resultWord == PayloadWord) {
     2191        m_payloadGPR = GPRTemporary(jit, Reuse, operand);
     2192        m_tagGPR = GPRTemporary(jit);
     2193    } else {
     2194        m_payloadGPR = GPRTemporary(jit);
     2195        m_tagGPR = GPRTemporary(jit, Reuse, operand);
     2196    }
     2197}
     2198#endif
    21522199
    21532200class FPRTemporary {
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r279604 r280760  
    18131813}
    18141814
     1815void SpeculativeJIT::compileGetByVal(Node* node, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix)
     1816{
     1817    switch (node->arrayMode().type()) {
     1818    case Array::SelectUsingPredictions:
     1819    case Array::ForceExit:
     1820        RELEASE_ASSERT_NOT_REACHED();
     1821#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
     1822        terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
     1823#endif
     1824        break;
     1825    case Array::Undecided: {
     1826        SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
     1827
     1828        GPRReg indexGPR = index.gpr();
     1829
     1830        JSValueRegs resultRegs;
     1831        std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     1832
     1833        speculationCheck(OutOfBounds, JSValueRegs(), node,
     1834            m_jit.branch32(MacroAssembler::LessThan, indexGPR, MacroAssembler::TrustedImm32(0)));
     1835
     1836        m_jit.move(MacroAssembler::TrustedImm32(JSValue::UndefinedTag), resultRegs.tagGPR());
     1837        m_jit.move(MacroAssembler::TrustedImm32(0), resultRegs.payloadGPR());
     1838        jsValueResult(resultRegs, node);
     1839        break;
     1840    }
     1841    case Array::Generic: {
     1842        if (m_graph.m_slowGetByVal.contains(node)) {
     1843            if (m_graph.varArgChild(node, 0).useKind() == ObjectUse) {
     1844                if (m_graph.varArgChild(node, 1).useKind() == StringUse) {
     1845                    compileGetByValForObjectWithString(node, prefix);
     1846                    break;
     1847                }
     1848
     1849                if (m_graph.varArgChild(node, 1).useKind() == SymbolUse) {
     1850                    compileGetByValForObjectWithSymbol(node, prefix);
     1851                    break;
     1852                }
     1853            }
     1854
     1855            SpeculateCellOperand base(this, m_graph.varArgChild(node, 0)); // Save a register, speculate cell. We'll probably be right.
     1856            JSValueOperand property(this, m_graph.varArgChild(node, 1));
     1857            GPRReg baseGPR = base.gpr();
     1858            JSValueRegs propertyRegs = property.jsValueRegs();
     1859
     1860            JSValueRegs resultRegs;
     1861            std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     1862
     1863            flushRegisters();
     1864            callOperation(operationGetByValCell, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyRegs);
     1865            m_jit.exceptionCheck();
     1866
     1867            jsValueResult(resultRegs, node);
     1868            break;
     1869        }
     1870
     1871        speculate(node, m_graph.varArgChild(node, 0));
     1872        speculate(node, m_graph.varArgChild(node, 1));
     1873
     1874        JSValueOperand base(this, m_graph.varArgChild(node, 0), ManualOperandSpeculation);
     1875        JSValueOperand property(this, m_graph.varArgChild(node, 1), ManualOperandSpeculation);
     1876
     1877        JSValueRegs baseRegs = base.jsValueRegs();
     1878        JSValueRegs propertyRegs = property.jsValueRegs();
     1879
     1880        JSValueRegs resultRegs;
     1881        std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     1882
     1883        CodeOrigin codeOrigin = node->origin.semantic;
     1884        CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
     1885        RegisterSet usedRegisters = this->usedRegisters();
     1886
     1887        JITCompiler::JumpList slowCases;
     1888        if (!m_state.forNode(m_graph.varArgChild(node, 0)).isType(SpecCell))
     1889            slowCases.append(m_jit.branchIfNotCell(baseRegs.tagGPR()));
     1890
     1891        JITGetByValGenerator gen(
     1892            m_jit.codeBlock(), JITType::DFGJIT, codeOrigin, callSite, AccessType::GetByVal, usedRegisters,
     1893            baseRegs, propertyRegs, resultRegs, InvalidGPRReg);
     1894
     1895        if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecString))
     1896            gen.stubInfo()->propertyIsString = true;
     1897        else if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecInt32Only))
     1898            gen.stubInfo()->propertyIsInt32 = true;
     1899        else if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecSymbol))
     1900            gen.stubInfo()->propertyIsSymbol = true;
     1901
     1902        gen.generateFastPath(m_jit);
     1903
     1904        slowCases.append(gen.slowPathJump());
     1905
     1906        std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
     1907            slowCases, this, operationGetByValOptimize,
     1908            resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), nullptr, baseRegs, propertyRegs);
     1909
     1910        m_jit.addGetByVal(gen, slowPath.get());
     1911        addSlowPathGenerator(WTFMove(slowPath));
     1912
     1913        jsValueResult(resultRegs, node);
     1914        break;
     1915    }
     1916    case Array::Int32:
     1917    case Array::Contiguous: {
     1918        if (node->arrayMode().isInBounds()) {
     1919            SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     1920            StorageOperand storage(this, m_graph.varArgChild(node, 2));
     1921
     1922            GPRReg propertyReg = property.gpr();
     1923            GPRReg storageReg = storage.gpr();
     1924
     1925            if (!m_compileOkay)
     1926                return;
     1927
     1928            JSValueRegs resultRegs;
     1929            DataFormat format;
     1930            std::tie(resultRegs, format) = prefix(node->arrayMode().type() == Array::Int32 ? DataFormatInt32 : DataFormatJS);
     1931
     1932            speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
     1933
     1934            if (format == DataFormatInt32) {
     1935                ASSERT(!node->arrayMode().isInBoundsSaneChain());
     1936
     1937                speculationCheck(
     1938                    OutOfBounds, JSValueRegs(), 0,
     1939                    m_jit.branch32(
     1940                        MacroAssembler::Equal,
     1941                        MacroAssembler::BaseIndex(
     1942                            storageReg, propertyReg, MacroAssembler::TimesEight, TagOffset),
     1943                        TrustedImm32(JSValue::EmptyValueTag)));
     1944                m_jit.load32(
     1945                    MacroAssembler::BaseIndex(
     1946                        storageReg, propertyReg, MacroAssembler::TimesEight, PayloadOffset),
     1947                    resultRegs.payloadGPR());
     1948                strictInt32Result(resultRegs.payloadGPR(), node);
     1949                break;
     1950            }
     1951
     1952            ASSERT(format == DataFormatJS);
     1953            m_jit.load32(
     1954                MacroAssembler::BaseIndex(
     1955                    storageReg, propertyReg, MacroAssembler::TimesEight, TagOffset),
     1956                resultRegs.tagGPR());
     1957            m_jit.load32(
     1958                MacroAssembler::BaseIndex(
     1959                    storageReg, propertyReg, MacroAssembler::TimesEight, PayloadOffset),
     1960                resultRegs.payloadGPR());
     1961            if (node->arrayMode().isInBoundsSaneChain()) {
     1962                JITCompiler::Jump notHole = m_jit.branchIfNotEmpty(resultRegs.tagGPR());
     1963                m_jit.move(TrustedImm32(JSValue::UndefinedTag), resultRegs.tagGPR());
     1964                m_jit.move(TrustedImm32(0), resultRegs.payloadGPR());
     1965                notHole.link(&m_jit);
     1966            } else {
     1967                speculationCheck(
     1968                    LoadFromHole, JSValueRegs(), nullptr,
     1969                    m_jit.branchIfEmpty(resultRegs.tagGPR()));
     1970            }
     1971            jsValueResult(resultRegs, node);
     1972            break;
     1973        }
     1974
     1975        SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
     1976        SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     1977        StorageOperand storage(this, m_graph.varArgChild(node, 2));
     1978
     1979        GPRReg baseReg = base.gpr();
     1980        GPRReg propertyReg = property.gpr();
     1981        GPRReg storageReg = storage.gpr();
     1982
     1983        if (!m_compileOkay)
     1984            return;
     1985
     1986        JSValueRegs resultRegs;
     1987        std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     1988
     1989        MacroAssembler::JumpList slowCases;
     1990
     1991        slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
     1992
     1993        m_jit.loadValue(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultRegs);
     1994        slowCases.append(m_jit.branchIfEmpty(resultRegs.tagGPR()));
     1995
     1996        addSlowPathGenerator(
     1997            slowPathCall(
     1998                slowCases, this, operationGetByValObjectInt,
     1999                resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
     2000
     2001        jsValueResult(resultRegs, node);
     2002        break;
     2003    }
     2004    case Array::Double: {
     2005        if (node->arrayMode().isInBounds()) {
     2006            SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2007            StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2008
     2009            GPRReg propertyReg = property.gpr();
     2010            GPRReg storageReg = storage.gpr();
     2011
     2012            if (!m_compileOkay)
     2013                return;
     2014
     2015            FPRTemporary result(this);
     2016
     2017            JSValueRegs resultRegs;
     2018            DataFormat format;
     2019            std::tie(resultRegs, format) = prefix(DataFormatDouble);
     2020
     2021            speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
     2022
     2023            m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
     2024            if (!node->arrayMode().isInBoundsSaneChain())
     2025                speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchIfNaN(result.fpr()));
     2026            if (format == DataFormatJS) {
     2027                boxDouble(result.fpr(), resultRegs);
     2028                jsValueResult(resultRegs, node);
     2029            } else {
     2030                ASSERT(format == DataFormatDouble && !resultRegs);
     2031                doubleResult(result.fpr(), node);
     2032            }
     2033            break;
     2034        }
     2035
     2036        SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
     2037        SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2038        StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2039
     2040        GPRReg baseReg = base.gpr();
     2041        GPRReg propertyReg = property.gpr();
     2042        GPRReg storageReg = storage.gpr();
     2043
     2044        if (!m_compileOkay)
     2045            return;
     2046
     2047        FPRTemporary temp(this);
     2048        FPRReg tempReg = temp.fpr();
     2049
     2050        JSValueRegs resultRegs;
     2051        std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     2052
     2053        MacroAssembler::JumpList slowCases;
     2054
     2055        slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
     2056
     2057        m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
     2058        slowCases.append(m_jit.branchIfNaN(tempReg));
     2059        boxDouble(tempReg, resultRegs);
     2060
     2061        addSlowPathGenerator(
     2062            slowPathCall(
     2063                slowCases, this, operationGetByValObjectInt,
     2064                resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
     2065
     2066        jsValueResult(resultRegs, node);
     2067        break;
     2068    }
     2069    case Array::ArrayStorage:
     2070    case Array::SlowPutArrayStorage: {
     2071        if (node->arrayMode().isInBounds()) {
     2072            SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2073            StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2074            GPRReg propertyReg = property.gpr();
     2075            GPRReg storageReg = storage.gpr();
     2076
     2077            if (!m_compileOkay)
     2078                return;
     2079
     2080            JSValueRegs resultRegs;
     2081            std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     2082
     2083            speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
     2084
     2085            m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultRegs.tagGPR());
     2086            speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchIfEmpty(resultRegs.tagGPR()));
     2087            m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultRegs.payloadGPR());
     2088
     2089            jsValueResult(resultRegs, node);
     2090            break;
     2091        }
     2092
     2093        SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
     2094        SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2095        StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2096        GPRReg propertyReg = property.gpr();
     2097        GPRReg storageReg = storage.gpr();
     2098        GPRReg baseReg = base.gpr();
     2099
     2100        if (!m_compileOkay)
     2101            return;
     2102
     2103        JSValueRegs resultRegs;
     2104        std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     2105
     2106        JITCompiler::Jump outOfBounds = m_jit.branch32(
     2107            MacroAssembler::AboveOrEqual, propertyReg,
     2108            MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
     2109
     2110        m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultRegs.tagGPR());
     2111        JITCompiler::Jump hole = m_jit.branchIfEmpty(resultRegs.tagGPR());
     2112        m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultRegs.payloadGPR());
     2113
     2114        JITCompiler::JumpList slowCases;
     2115        slowCases.append(outOfBounds);
     2116        slowCases.append(hole);
     2117        addSlowPathGenerator(
     2118            slowPathCall(
     2119                slowCases, this, operationGetByValObjectInt,
     2120                resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)),
     2121                baseReg, propertyReg));
     2122
     2123        jsValueResult(resultRegs, node);
     2124        break;
     2125    }
     2126    case Array::String:
     2127        compileGetByValOnString(node, prefix);
     2128        break;
     2129    case Array::DirectArguments:
     2130        compileGetByValOnDirectArguments(node, prefix);
     2131        break;
     2132    case Array::ScopedArguments:
     2133        compileGetByValOnScopedArguments(node, prefix);
     2134        break;
     2135    default: {
     2136        TypedArrayType type = node->arrayMode().typedArrayType();
     2137        if (isInt(type))
     2138            compileGetByValOnIntTypedArray(node, type, prefix);
     2139        else
     2140            compileGetByValOnFloatTypedArray(node, type, prefix);
     2141    } }
     2142}
     2143
    18152144void SpeculativeJIT::compile(Node* node)
    18162145{
    … …  
    22342563    case StringCharAt: {
    22352564        // Relies on StringCharAt node having same basic layout as GetByVal
    2236         compileGetByValOnString(node);
     2565        JSValueRegsTemporary result;
     2566        compileGetByValOnString(node, scopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>([&] (DataFormat preferredFormat) {
     2567            result = JSValueRegsTemporary(this);
     2568            ASSERT(preferredFormat & DataFormatJS);
     2569            return std::make_pair(result.regs(), preferredFormat);
     2570        }));
    22372571        break;
    22382572    }
    … …  
    22662600
    22672601    case GetByVal: {
    2268         switch (node->arrayMode().type()) {
    2269         case Array::SelectUsingPredictions:
    2270         case Array::ForceExit:
    2271             RELEASE_ASSERT_NOT_REACHED();
    2272 #if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
    2273             terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
    2274 #endif
    2275             break;
    2276         case Array::Undecided: {
    2277             SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
    2278             GPRTemporary resultTag(this, Reuse, index);
    2279             GPRTemporary resultPayload(this);
    2280 
    2281             GPRReg indexGPR = index.gpr();
    2282             GPRReg resultTagGPR = resultTag.gpr();
    2283             GPRReg resultPayloadGPR = resultPayload.gpr();
    2284 
    2285             speculationCheck(OutOfBounds, JSValueRegs(), node,
    2286                 m_jit.branch32(MacroAssembler::LessThan, indexGPR, MacroAssembler::TrustedImm32(0)));
    2287 
    2288             use(m_graph.varArgChild(node, 0));
    2289             index.use();
    2290 
    2291             m_jit.move(MacroAssembler::TrustedImm32(JSValue::UndefinedTag), resultTagGPR);
    2292             m_jit.move(MacroAssembler::TrustedImm32(0), resultPayloadGPR);
    2293             jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
    2294             break;
    2295         }
    2296         case Array::Generic: {
    2297             if (m_graph.m_slowGetByVal.contains(node)) {
    2298                 if (m_graph.varArgChild(node, 0).useKind() == ObjectUse) {
    2299                     if (m_graph.varArgChild(node, 1).useKind() == StringUse) {
    2300                         compileGetByValForObjectWithString(node);
    2301                         break;
    2302                     }
    2303 
    2304                     if (m_graph.varArgChild(node, 1).useKind() == SymbolUse) {
    2305                         compileGetByValForObjectWithSymbol(node);
    2306                         break;
    2307                     }
    2308                 }
    2309 
    2310                 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0)); // Save a register, speculate cell. We'll probably be right.
    2311                 JSValueOperand property(this, m_graph.varArgChild(node, 1));
    2312                 GPRReg baseGPR = base.gpr();
    2313                 JSValueRegs propertyRegs = property.jsValueRegs();
    2314                
    2315                 flushRegisters();
    2316                 JSValueRegsFlushedCallResult result(this);
    2317                 JSValueRegs resultRegs = result.regs();
    2318                 callOperation(operationGetByValCell, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyRegs);
    2319                 m_jit.exceptionCheck();
    2320                
    2321                 jsValueResult(resultRegs, node);
     2602        JSValueRegsTemporary jsValueResult;
     2603        GPRTemporary oneRegResult;
     2604        compileGetByVal(node, scopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>([&] (DataFormat preferredFormat) {
     2605            JSValueRegs resultRegs;
     2606            switch (preferredFormat) {
     2607            case DataFormatDouble:
     2608                break;
     2609            case DataFormatInt32:
     2610            case DataFormatCell:
     2611                oneRegResult = GPRTemporary(this);
     2612                resultRegs = JSValueRegs::payloadOnly(oneRegResult.gpr());
     2613                break;
     2614            default: {
     2615                ASSERT(preferredFormat == DataFormatJS);
     2616                jsValueResult = JSValueRegsTemporary(this);
     2617                resultRegs = jsValueResult.regs();
    23222618                break;
    23232619            }
    2324 
    2325             speculate(node, m_graph.varArgChild(node, 0));
    2326             speculate(node, m_graph.varArgChild(node, 1));
    2327 
    2328             JSValueOperand base(this, m_graph.varArgChild(node, 0), ManualOperandSpeculation);
    2329             JSValueOperand property(this, m_graph.varArgChild(node, 1), ManualOperandSpeculation);
    2330             GPRTemporary resultTag(this, Reuse, property, TagWord);
    2331             GPRTemporary resultPayload(this, Reuse, property, PayloadWord);
    2332 
    2333             JSValueRegs baseRegs = base.jsValueRegs();
    2334             JSValueRegs propertyRegs = property.jsValueRegs();
    2335             JSValueRegs resultRegs(resultTag.gpr(), resultPayload.gpr());
    2336 
    2337             CodeOrigin codeOrigin = node->origin.semantic;
    2338             CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
    2339             RegisterSet usedRegisters = this->usedRegisters();
    2340 
    2341             JITCompiler::JumpList slowCases;
    2342             if (!m_state.forNode(m_graph.varArgChild(node, 0)).isType(SpecCell))
    2343                 slowCases.append(m_jit.branchIfNotCell(baseRegs.tagGPR()));
    2344 
    2345             JITGetByValGenerator gen(
    2346                 m_jit.codeBlock(), JITType::DFGJIT, codeOrigin, callSite, AccessType::GetByVal, usedRegisters,
    2347                 baseRegs, propertyRegs, resultRegs, InvalidGPRReg);
    2348 
    2349             if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecString))
    2350                 gen.stubInfo()->propertyIsString = true;
    2351             else if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecInt32Only))
    2352                 gen.stubInfo()->propertyIsInt32 = true;
    2353             else if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecSymbol))
    2354                 gen.stubInfo()->propertyIsSymbol = true;
    2355 
    2356             gen.generateFastPath(m_jit);
    2357            
    2358             slowCases.append(gen.slowPathJump());
    2359 
    2360             std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
    2361                 slowCases, this, operationGetByValOptimize,
    2362                 resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), nullptr, baseRegs, propertyRegs);
    2363            
    2364             m_jit.addGetByVal(gen, slowPath.get());
    2365             addSlowPathGenerator(WTFMove(slowPath));
    2366 
    2367             jsValueResult(resultRegs, node);
    2368             break;
    2369         }
    2370         case Array::Int32:
    2371         case Array::Contiguous: {
    2372             if (node->arrayMode().isInBounds()) {
    2373                 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2374                 StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2375            
    2376                 GPRReg propertyReg = property.gpr();
    2377                 GPRReg storageReg = storage.gpr();
    2378            
    2379                 if (!m_compileOkay)
    2380                     return;
    2381            
    2382                 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
    2383            
    2384                 GPRTemporary resultPayload(this);
    2385                 if (node->arrayMode().type() == Array::Int32) {
    2386                     ASSERT(!node->arrayMode().isInBoundsSaneChain());
    2387                    
    2388                     speculationCheck(
    2389                         OutOfBounds, JSValueRegs(), 0,
    2390                         m_jit.branch32(
    2391                             MacroAssembler::Equal,
    2392                             MacroAssembler::BaseIndex(
    2393                                 storageReg, propertyReg, MacroAssembler::TimesEight, TagOffset),
    2394                             TrustedImm32(JSValue::EmptyValueTag)));
    2395                     m_jit.load32(
    2396                         MacroAssembler::BaseIndex(
    2397                             storageReg, propertyReg, MacroAssembler::TimesEight, PayloadOffset),
    2398                         resultPayload.gpr());
    2399                     strictInt32Result(resultPayload.gpr(), node);
    2400                     break;
    2401                 }
    2402                
    2403                 GPRTemporary resultTag(this);
    2404                 m_jit.load32(
    2405                     MacroAssembler::BaseIndex(
    2406                         storageReg, propertyReg, MacroAssembler::TimesEight, TagOffset),
    2407                     resultTag.gpr());
    2408                 m_jit.load32(
    2409                     MacroAssembler::BaseIndex(
    2410                         storageReg, propertyReg, MacroAssembler::TimesEight, PayloadOffset),
    2411                     resultPayload.gpr());
    2412                 if (node->arrayMode().isInBoundsSaneChain()) {
    2413                     JITCompiler::Jump notHole = m_jit.branchIfNotEmpty(resultTag.gpr());
    2414                     m_jit.move(TrustedImm32(JSValue::UndefinedTag), resultTag.gpr());
    2415                     m_jit.move(TrustedImm32(0), resultPayload.gpr());
    2416                     notHole.link(&m_jit);
    2417                 } else {
    2418                     speculationCheck(
    2419                         LoadFromHole, JSValueRegs(), 0,
    2420                         m_jit.branchIfEmpty(resultTag.gpr()));
    2421                 }
    2422                 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
    2423                 break;
    2424             }
    2425 
    2426             SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
    2427             SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2428             StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2429            
    2430             GPRReg baseReg = base.gpr();
    2431             GPRReg propertyReg = property.gpr();
    2432             GPRReg storageReg = storage.gpr();
    2433            
    2434             if (!m_compileOkay)
    2435                 return;
    2436            
    2437             GPRTemporary resultTag(this);
    2438             GPRTemporary resultPayload(this);
    2439             GPRReg resultTagReg = resultTag.gpr();
    2440             GPRReg resultPayloadReg = resultPayload.gpr();
    2441            
    2442             MacroAssembler::JumpList slowCases;
    2443 
    2444             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
    2445            
    2446             m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
    2447             m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadReg);
    2448             slowCases.append(m_jit.branchIfEmpty(resultTagReg));
    2449            
    2450             addSlowPathGenerator(
    2451                 slowPathCall(
    2452                     slowCases, this, operationGetByValObjectInt,
    2453                     JSValueRegs(resultTagReg, resultPayloadReg), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
    2454            
    2455             jsValueResult(resultTagReg, resultPayloadReg, node);
    2456             break;
    2457         }
    2458         case Array::Double: {
    2459             if (node->arrayMode().isInBounds()) {
    2460                 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2461                 StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2462            
    2463                 GPRReg propertyReg = property.gpr();
    2464                 GPRReg storageReg = storage.gpr();
    2465            
    2466                 if (!m_compileOkay)
    2467                     return;
    2468            
    2469                 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
    2470            
    2471                 FPRTemporary result(this);
    2472                 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
    2473                 if (!node->arrayMode().isInBoundsSaneChain())
    2474                     speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchIfNaN(result.fpr()));
    2475                 doubleResult(result.fpr(), node);
    2476                 break;
    2477             }
    2478 
    2479             SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
    2480             SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2481             StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2482            
    2483             GPRReg baseReg = base.gpr();
    2484             GPRReg propertyReg = property.gpr();
    2485             GPRReg storageReg = storage.gpr();
    2486            
    2487             if (!m_compileOkay)
    2488                 return;
    2489            
    2490             GPRTemporary resultTag(this);
    2491             GPRTemporary resultPayload(this);
    2492             FPRTemporary temp(this);
    2493             GPRReg resultTagReg = resultTag.gpr();
    2494             GPRReg resultPayloadReg = resultPayload.gpr();
    2495             FPRReg tempReg = temp.fpr();
    2496            
    2497             MacroAssembler::JumpList slowCases;
    2498            
    2499             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
    2500            
    2501             m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
    2502             slowCases.append(m_jit.branchIfNaN(tempReg));
    2503             boxDouble(tempReg, resultTagReg, resultPayloadReg);
    2504 
    2505             addSlowPathGenerator(
    2506                 slowPathCall(
    2507                     slowCases, this, operationGetByValObjectInt,
    2508                     JSValueRegs(resultTagReg, resultPayloadReg), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
    2509            
    2510             jsValueResult(resultTagReg, resultPayloadReg, node);
    2511             break;
    2512         }
    2513         case Array::ArrayStorage:
    2514         case Array::SlowPutArrayStorage: {
    2515             if (node->arrayMode().isInBounds()) {
    2516                 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2517                 StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2518                 GPRReg propertyReg = property.gpr();
    2519                 GPRReg storageReg = storage.gpr();
    2520        
    2521                 if (!m_compileOkay)
    2522                     return;
    2523 
    2524                 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
    2525 
    2526                 GPRTemporary resultTag(this);
    2527                 GPRTemporary resultPayload(this);
    2528 
    2529                 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
    2530                 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchIfEmpty(resultTag.gpr()));
    2531                 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
    2532            
    2533                 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
    2534                 break;
    2535             }
    2536 
    2537             SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
    2538             SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2539             StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2540             GPRReg propertyReg = property.gpr();
    2541             GPRReg storageReg = storage.gpr();
    2542             GPRReg baseReg = base.gpr();
    2543 
    2544             if (!m_compileOkay)
    2545                 return;
    2546 
    2547             GPRTemporary resultTag(this);
    2548             GPRTemporary resultPayload(this);
    2549             GPRReg resultTagReg = resultTag.gpr();
    2550             GPRReg resultPayloadReg = resultPayload.gpr();
    2551 
    2552             JITCompiler::Jump outOfBounds = m_jit.branch32(
    2553                 MacroAssembler::AboveOrEqual, propertyReg,
    2554                 MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
    2555 
    2556             m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
    2557             JITCompiler::Jump hole = m_jit.branchIfEmpty(resultTag.gpr());
    2558             m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadReg);
    2559            
    2560             JITCompiler::JumpList slowCases;
    2561             slowCases.append(outOfBounds);
    2562             slowCases.append(hole);
    2563             addSlowPathGenerator(
    2564                 slowPathCall(
    2565                     slowCases, this, operationGetByValObjectInt,
    2566                     JSValueRegs(resultTagReg, resultPayloadReg), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)),
    2567                     baseReg, propertyReg));
    2568 
    2569             jsValueResult(resultTagReg, resultPayloadReg, node);
    2570             break;
    2571         }
    2572         case Array::String:
    2573             compileGetByValOnString(node);
    2574             break;
    2575         case Array::DirectArguments:
    2576             compileGetByValOnDirectArguments(node);
    2577             break;
    2578         case Array::ScopedArguments:
    2579             compileGetByValOnScopedArguments(node);
    2580             break;
    2581         default: {
    2582             TypedArrayType type = node->arrayMode().typedArrayType();
    2583             if (isInt(type))
    2584                 compileGetByValOnIntTypedArray(node, type);
    2585             else
    2586                 compileGetByValOnFloatTypedArray(node, type);
    2587         } }
     2620            };
     2621            return std::make_pair(resultRegs, preferredFormat);
     2622        }));
    25882623        break;
    25892624    }
    … …  
    41134148    }
    41144149
    4115     case GetEnumerableLength: {
    4116         compileGetEnumerableLength(node);
    4117         break;
    4118     }
    4119     case HasEnumerableStructureProperty: {
    4120         compileHasEnumerableStructureProperty(node);
    4121         break;
    4122     }
    4123     case HasEnumerableProperty: {
    4124         compileHasEnumerableProperty(node);
    4125         break;
    4126     }
    4127     case HasOwnStructureProperty: {
    4128         compileHasOwnStructureProperty(node);
    4129         break;
    4130     }
    4131     case InStructureProperty: {
    4132         compileInStructureProperty(node);
    4133         break;
    4134     }
    41354150    case HasIndexedProperty: {
    4136         compileHasIndexedProperty(node, operationHasIndexedProperty);
    4137         break;
    4138     }
    4139     case HasEnumerableIndexedProperty: {
    4140         compileHasIndexedProperty(node, operationHasEnumerableIndexedProperty);
    4141         break;
    4142     }
    4143     case GetDirectPname: {
    4144         compileGetDirectPname(node);
    4145         break;
    4146     }
     4151        SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
     4152        GPRTemporary result(this, Reuse, index);
     4153
     4154        compileHasIndexedProperty(node, operationHasIndexedProperty, scopedLambda<std::tuple<GPRReg, GPRReg>()>([&] { return std::make_pair(index.gpr(), result.gpr()); }));
     4155        unblessedBooleanResult(result.gpr(), node);
     4156        break;
     4157    }
     4158
    41474159    case GetPropertyEnumerator: {
    41484160        compileGetPropertyEnumerator(node);
    41494161        break;
    41504162    }
    4151     case GetEnumeratorStructurePname:
    4152     case GetEnumeratorGenericPname: {
    4153         compileGetEnumeratorPname(node);
    4154         break;
    4155     }
    4156     case ToIndexString: {
    4157         compileToIndexString(node);
    4158         break;
    4159     }
     4163
     4164    case EnumeratorNextUpdateIndexAndMode: {
     4165        compileEnumeratorNextUpdateIndexAndMode(node);
     4166        break;
     4167    }
     4168
     4169    case EnumeratorNextExtractMode: {
     4170        compileEnumeratorNextExtractMode(node);
     4171        break;
     4172    }
     4173
     4174    case EnumeratorNextExtractIndex: {
     4175        compileEnumeratorNextExtractIndex(node);
     4176        break;
     4177    }
     4178
     4179    case EnumeratorNextUpdatePropertyName: {
     4180        compileEnumeratorNextUpdatePropertyName(node);
     4181        break;
     4182    }
     4183
     4184    case EnumeratorGetByVal: {
     4185        compileEnumeratorGetByVal(node);
     4186        break;
     4187    }
     4188
     4189    case EnumeratorInByVal: {
     4190        compileEnumeratorInByVal(node);
     4191        break;
     4192    }
     4193
     4194    case EnumeratorHasOwnProperty: {
     4195        compileEnumeratorHasOwnProperty(node);
     4196        break;
     4197    }
     4198
    41604199    case ProfileType: {
    41614200        compileProfileType(node);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r279903 r280760  
    22472247}
    22482248
     2249void SpeculativeJIT::compileGetByVal(Node* node, const ScopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>& prefix)
     2250{
     2251    switch (node->arrayMode().type()) {
     2252    case Array::AnyTypedArray:
     2253    case Array::ForceExit:
     2254    case Array::SelectUsingArguments:
     2255    case Array::SelectUsingPredictions:
     2256    case Array::Unprofiled:
     2257        DFG_CRASH(m_jit.graph(), node, "Bad array mode type");
     2258        break;
     2259    case Array::Undecided: {
     2260        SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
     2261        GPRReg indexGPR = index.gpr();
     2262
     2263        JSValueRegs resultRegs;
     2264        std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     2265
     2266        speculationCheck(OutOfBounds, JSValueRegs(), node,
     2267            m_jit.branch32(MacroAssembler::LessThan, indexGPR, MacroAssembler::TrustedImm32(0)));
     2268
     2269        m_jit.move(MacroAssembler::TrustedImm64(JSValue::ValueUndefined), resultRegs.gpr());
     2270
     2271        jsValueResult(resultRegs, node);
     2272        break;
     2273    }
     2274    case Array::BigInt64Array:
     2275    case Array::BigUint64Array:
     2276    case Array::Generic: {
     2277        if (m_graph.m_slowGetByVal.contains(node)) {
     2278            if (m_graph.varArgChild(node, 0).useKind() == ObjectUse) {
     2279                if (m_graph.varArgChild(node, 1).useKind() == StringUse) {
     2280                    compileGetByValForObjectWithString(node, prefix);
     2281                    return;
     2282                }
     2283
     2284                if (m_graph.varArgChild(node, 1).useKind() == SymbolUse) {
     2285                    compileGetByValForObjectWithSymbol(node, prefix);
     2286                    return;
     2287                }
     2288            }
     2289
     2290            JSValueOperand base(this, m_graph.varArgChild(node, 0));
     2291            JSValueOperand property(this, m_graph.varArgChild(node, 1));
     2292            GPRReg baseGPR = base.gpr();
     2293            GPRReg propertyGPR = property.gpr();
     2294
     2295            JSValueRegs resultRegs;
     2296            std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     2297
     2298            flushRegisters();
     2299            callOperation(operationGetByVal, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyGPR);
     2300            m_jit.exceptionCheck();
     2301
     2302            jsValueResult(resultRegs, node);
     2303            return;
     2304        }
     2305
     2306        JSValueOperand base(this, m_graph.varArgChild(node, 0), ManualOperandSpeculation);
     2307        JSValueOperand property(this, m_graph.varArgChild(node, 1), ManualOperandSpeculation);
     2308        GPRReg baseGPR = base.gpr();
     2309        GPRReg propertyGPR = property.gpr();
     2310
     2311        GPRTemporary stubInfo;
     2312        GPRReg stubInfoGPR = InvalidGPRReg;
     2313        if (JITCode::useDataIC(JITType::DFGJIT)) {
     2314            stubInfo = GPRTemporary(this);
     2315            stubInfoGPR = stubInfo.gpr();
     2316        }
     2317
     2318        speculate(node, m_graph.varArgChild(node, 0));
     2319        speculate(node, m_graph.varArgChild(node, 1));
     2320
     2321        JSValueRegs resultRegs;
     2322        std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     2323        GPRReg resultGPR = resultRegs.gpr();
     2324
     2325        CodeOrigin codeOrigin = node->origin.semantic;
     2326        CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
     2327        RegisterSet usedRegisters = this->usedRegisters();
     2328
     2329        JITCompiler::JumpList slowCases;
     2330        if (!m_state.forNode(m_graph.varArgChild(node, 0)).isType(SpecCell))
     2331            slowCases.append(m_jit.branchIfNotCell(baseGPR));
     2332
     2333        JITGetByValGenerator gen(
     2334            m_jit.codeBlock(), JITType::DFGJIT, codeOrigin, callSite, AccessType::GetByVal, usedRegisters,
     2335            JSValueRegs(baseGPR), JSValueRegs(propertyGPR), JSValueRegs(resultGPR), stubInfoGPR);
     2336
     2337        if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecString))
     2338            gen.stubInfo()->propertyIsString = true;
     2339        else if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecInt32Only))
     2340            gen.stubInfo()->propertyIsInt32 = true;
     2341        else if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecSymbol))
     2342            gen.stubInfo()->propertyIsSymbol = true;
     2343
     2344        gen.generateFastPath(m_jit);
     2345
     2346        if (!JITCode::useDataIC(JITType::DFGJIT))
     2347            slowCases.append(gen.slowPathJump());
     2348
     2349        std::unique_ptr<SlowPathGenerator> slowPath;
     2350        if (JITCode::useDataIC(JITType::DFGJIT)) {
     2351            slowPath = slowPathICCall(
     2352                slowCases, this, gen.stubInfo(), stubInfoGPR, CCallHelpers::Address(stubInfoGPR, StructureStubInfo::offsetOfSlowOperation()), operationGetByValOptimize,
     2353                resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), stubInfoGPR, nullptr, baseGPR, propertyGPR);
     2354        } else {
     2355            slowPath = slowPathCall(
     2356                slowCases, this, operationGetByValOptimize,
     2357                resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), nullptr, baseGPR, propertyGPR);
     2358        }
     2359
     2360        m_jit.addGetByVal(gen, slowPath.get());
     2361        addSlowPathGenerator(WTFMove(slowPath));
     2362
     2363        jsValueResult(resultGPR, node);
     2364        break;
     2365    }
     2366    case Array::Int32:
     2367    case Array::Contiguous: {
     2368        if (node->arrayMode().isInBounds()) {
     2369            SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2370            StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2371
     2372            GPRReg propertyReg = property.gpr();
     2373            GPRReg storageReg = storage.gpr();
     2374
     2375            if (!m_compileOkay)
     2376                return;
     2377
     2378            JSValueRegs resultRegs;
     2379            DataFormat format;
     2380            std::tie(resultRegs, format) = prefix(node->arrayMode().type() == Array::Int32 ? DataFormatJSInt32 : DataFormatJS);
     2381            GPRReg result = resultRegs.gpr();
     2382
     2383            speculationCheck(OutOfBounds, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
     2384
     2385            m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result);
     2386            if (node->arrayMode().isInBoundsSaneChain()) {
     2387                ASSERT(node->arrayMode().type() == Array::Contiguous);
     2388                JITCompiler::Jump notHole = m_jit.branchIfNotEmpty(result);
     2389                m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), result);
     2390                notHole.link(&m_jit);
     2391            } else {
     2392                speculationCheck(
     2393                    LoadFromHole, JSValueRegs(), nullptr,
     2394                    m_jit.branchIfEmpty(result));
     2395            }
     2396            jsValueResult(result, node, format);
     2397            break;
     2398        }
     2399
     2400        SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
     2401        SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2402        StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2403
     2404        GPRReg baseReg = base.gpr();
     2405        GPRReg propertyReg = property.gpr();
     2406        GPRReg storageReg = storage.gpr();
     2407
     2408        if (!m_compileOkay)
     2409            return;
     2410
     2411        JSValueRegs resultRegs;
     2412        std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     2413        GPRReg resultReg = resultRegs.gpr();
     2414
     2415        MacroAssembler::JumpList slowCases;
     2416
     2417        slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
     2418
     2419        m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
     2420
     2421        if (node->arrayMode().isOutOfBoundsSaneChain()) {
     2422            auto done = m_jit.branchIfNotEmpty(resultReg);
     2423            slowCases.link(&m_jit);
     2424            speculationCheck(NegativeIndex, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, propertyReg, CCallHelpers::TrustedImm32(0)));
     2425            m_jit.move(CCallHelpers::TrustedImm64(JSValue::encode(jsUndefined())), resultReg);
     2426            done.link(&m_jit);
     2427        } else {
     2428            slowCases.append(m_jit.branchIfEmpty(resultReg));
     2429            addSlowPathGenerator(
     2430                slowPathCall(
     2431                    slowCases, this, operationGetByValObjectInt,
     2432                    resultReg, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
     2433        }
     2434
     2435
     2436        jsValueResult(resultReg, node);
     2437        break;
     2438    }
     2439
     2440    case Array::Double: {
     2441        if (node->arrayMode().isInBounds()) {
     2442            SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2443            StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2444
     2445            GPRReg propertyReg = property.gpr();
     2446            GPRReg storageReg = storage.gpr();
     2447
     2448            if (!m_compileOkay)
     2449                return;
     2450
     2451            FPRTemporary result(this);
     2452            FPRReg resultReg = result.fpr();
     2453
     2454            JSValueRegs resultRegs;
     2455            DataFormat format;
     2456            std::tie(resultRegs, format) = prefix(DataFormatDouble);
     2457
     2458            speculationCheck(OutOfBounds, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
     2459
     2460            m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
     2461            if (!node->arrayMode().isInBoundsSaneChain())
     2462                speculationCheck(LoadFromHole, JSValueRegs(), nullptr, m_jit.branchIfNaN(resultReg));
     2463            if (format == DataFormatJS) {
     2464                boxDouble(resultReg, resultRegs);
     2465                jsValueResult(resultRegs, node);
     2466            } else {
     2467                ASSERT(format == DataFormatDouble && !resultRegs);
     2468                doubleResult(resultReg, node);
     2469            }
     2470            break;
     2471        }
     2472
     2473        bool resultIsUnboxed = node->arrayMode().isOutOfBoundsSaneChain() && !(node->flags() & NodeBytecodeUsesAsOther);
     2474
     2475        SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
     2476        SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2477        StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2478
     2479        GPRReg baseReg = base.gpr();
     2480        GPRReg propertyReg = property.gpr();
     2481        GPRReg storageReg = storage.gpr();
     2482
     2483        if (!m_compileOkay)
     2484            return;
     2485
     2486        FPRTemporary temp(this);
     2487        FPRReg tempReg = temp.fpr();
     2488
     2489        JSValueRegs resultRegs;
     2490        DataFormat format;
     2491        std::tie(resultRegs, format) = prefix(resultIsUnboxed ? DataFormatDouble : DataFormatJS);
     2492
     2493        MacroAssembler::JumpList slowCases;
     2494
     2495        slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
     2496
     2497        m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
     2498        if (node->arrayMode().isOutOfBoundsSaneChain()) {
     2499            if (format == DataFormatDouble) {
     2500                auto done = m_jit.jump();
     2501                slowCases.link(&m_jit);
     2502                speculationCheck(NegativeIndex, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, propertyReg, CCallHelpers::TrustedImm32(0)));
     2503                static const double NaN = PNaN;
     2504                m_jit.loadDouble(TrustedImmPtr(&NaN), tempReg);
     2505                done.link(&m_jit);
     2506                ASSERT(!resultRegs);
     2507                doubleResult(tempReg, node);
     2508            } else {
     2509                slowCases.append(m_jit.branchIfNaN(tempReg));
     2510                boxDouble(tempReg, resultRegs.gpr());
     2511                auto done = m_jit.jump();
     2512                slowCases.link(&m_jit);
     2513                speculationCheck(NegativeIndex, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, propertyReg, CCallHelpers::TrustedImm32(0)));
     2514                m_jit.move(CCallHelpers::TrustedImm64(JSValue::encode(jsUndefined())), resultRegs.gpr());
     2515                done.link(&m_jit);
     2516                jsValueResult(resultRegs.gpr(), node);
     2517            }
     2518        } else {
     2519            slowCases.append(m_jit.branchIfNaN(tempReg));
     2520            boxDouble(tempReg, resultRegs.gpr());
     2521            addSlowPathGenerator(
     2522                slowPathCall(
     2523                    slowCases, this, operationGetByValObjectInt,
     2524                    resultRegs.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
     2525            jsValueResult(resultRegs.gpr(), node);
     2526        }
     2527
     2528        break;
     2529    }
     2530
     2531    case Array::ArrayStorage:
     2532    case Array::SlowPutArrayStorage: {
     2533        if (node->arrayMode().isInBounds()) {
     2534            SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2535            StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2536
     2537            GPRReg propertyReg = property.gpr();
     2538            GPRReg storageReg = storage.gpr();
     2539
     2540            if (!m_compileOkay)
     2541                return;
     2542
     2543            JSValueRegs resultRegs;
     2544            std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     2545            GPRReg resultGPR = resultRegs.gpr();
     2546
     2547            speculationCheck(OutOfBounds, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
     2548
     2549
     2550            m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), resultGPR);
     2551            speculationCheck(LoadFromHole, JSValueRegs(), nullptr, m_jit.branchIfEmpty(resultGPR));
     2552
     2553            jsValueResult(resultGPR, node);
     2554            break;
     2555        }
     2556
     2557        SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
     2558        SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
     2559        StorageOperand storage(this, m_graph.varArgChild(node, 2));
     2560
     2561        GPRReg baseReg = base.gpr();
     2562        GPRReg propertyReg = property.gpr();
     2563        GPRReg storageReg = storage.gpr();
     2564
     2565        if (!m_compileOkay)
     2566            return;
     2567
     2568        JSValueRegs resultRegs;
     2569        std::tie(resultRegs, std::ignore) = prefix(DataFormatJS);
     2570        GPRReg resultReg = resultRegs.gpr();
     2571
     2572        MacroAssembler::JumpList slowCases;
     2573
     2574        slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
     2575
     2576        m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), resultReg);
     2577        slowCases.append(m_jit.branchIfEmpty(resultReg));
     2578
     2579        addSlowPathGenerator(
     2580            slowPathCall(
     2581                slowCases, this, operationGetByValObjectInt,
     2582                resultReg, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
     2583
     2584        jsValueResult(resultReg, node);
     2585        break;
     2586    }
     2587    case Array::String:
     2588        compileGetByValOnString(node, prefix);
     2589        break;
     2590    case Array::DirectArguments:
     2591        compileGetByValOnDirectArguments(node, prefix);
     2592        break;
     2593    case Array::ScopedArguments:
     2594        compileGetByValOnScopedArguments(node, prefix);
     2595        break;
     2596    case Array::Int8Array:
     2597    case Array::Int16Array:
     2598    case Array::Int32Array:
     2599    case Array::Uint8Array:
     2600    case Array::Uint8ClampedArray:
     2601    case Array::Uint16Array:
     2602    case Array::Uint32Array:
     2603    case Array::Float32Array:
     2604    case Array::Float64Array: {
     2605        TypedArrayType type = node->arrayMode().typedArrayType();
     2606        if (isInt(type))
     2607            compileGetByValOnIntTypedArray(node, type, prefix);
     2608        else
     2609            compileGetByValOnFloatTypedArray(node, type, prefix);
     2610    } }
     2611}
     2612
    22492613void SpeculativeJIT::compile(Node* node)
    22502614{
    … …  
    27143078    case StringCharAt: {
    27153079        // Relies on StringCharAt node having same basic layout as GetByVal
    2716         compileGetByValOnString(node);
     3080        JSValueRegsTemporary result;
     3081        compileGetByValOnString(node, scopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>([&] (DataFormat preferredFormat) {
     3082            result = JSValueRegsTemporary(this);
     3083            ASSERT(preferredFormat == DataFormatJS || preferredFormat == DataFormatCell);
     3084            return std::make_pair(result.regs(), preferredFormat);
     3085        }));
    27173086        break;
    27183087    }
    … …  
    27473116
    27483117    case GetByVal: {
    2749         switch (node->arrayMode().type()) {
    2750         case Array::AnyTypedArray:
    2751         case Array::ForceExit:
    2752         case Array::SelectUsingArguments:
    2753         case Array::SelectUsingPredictions:
    2754         case Array::Unprofiled:
    2755             DFG_CRASH(m_jit.graph(), node, "Bad array mode type");
    2756             break;
    2757         case Array::Undecided: {
    2758             SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
    2759             GPRTemporary result(this, Reuse, index);
    2760             GPRReg indexGPR = index.gpr();
    2761             GPRReg resultGPR = result.gpr();
    2762 
    2763             speculationCheck(OutOfBounds, JSValueRegs(), node,
    2764                 m_jit.branch32(MacroAssembler::LessThan, indexGPR, MacroAssembler::TrustedImm32(0)));
    2765 
    2766             use(m_graph.varArgChild(node, 0));
    2767             index.use();
    2768 
    2769             m_jit.move(MacroAssembler::TrustedImm64(JSValue::ValueUndefined), resultGPR);
    2770             jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
    2771             break;
    2772         }
    2773         case Array::BigInt64Array:
    2774         case Array::BigUint64Array:
    2775         case Array::Generic: {
    2776             if (m_graph.m_slowGetByVal.contains(node)) {
    2777                 if (m_graph.varArgChild(node, 0).useKind() == ObjectUse) {
    2778                     if (m_graph.varArgChild(node, 1).useKind() == StringUse) {
    2779                         compileGetByValForObjectWithString(node);
    2780                         break;
    2781                     }
    2782 
    2783                     if (m_graph.varArgChild(node, 1).useKind() == SymbolUse) {
    2784                         compileGetByValForObjectWithSymbol(node);
    2785                         break;
    2786                     }
    2787                 }
    2788 
    2789                 JSValueOperand base(this, m_graph.varArgChild(node, 0));
    2790                 JSValueOperand property(this, m_graph.varArgChild(node, 1));
    2791                 GPRReg baseGPR = base.gpr();
    2792                 GPRReg propertyGPR = property.gpr();
    2793                
    2794                 flushRegisters();
    2795                 GPRFlushedCallResult result(this);
    2796                 callOperation(operationGetByVal, result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyGPR);
    2797                 m_jit.exceptionCheck();
    2798                
    2799                 jsValueResult(result.gpr(), node);
     3118        JSValueRegsTemporary result;
     3119        compileGetByVal(node, scopedLambda<std::tuple<JSValueRegs, DataFormat>(DataFormat preferredFormat)>([&] (DataFormat preferredFormat) {
     3120            JSValueRegs resultRegs;
     3121            switch (preferredFormat) {
     3122            case DataFormatDouble:
     3123                break;
     3124            default: {
     3125                result = JSValueRegsTemporary(this);
     3126                resultRegs = result.regs();
    28003127                break;
    28013128            }
    2802 
    2803             std::optional<GPRTemporary> stubInfo;
    2804             JSValueOperand base(this, m_graph.varArgChild(node, 0), ManualOperandSpeculation);
    2805             JSValueOperand property(this, m_graph.varArgChild(node, 1), ManualOperandSpeculation);
    2806             GPRTemporary result(this, Reuse, property);
    2807 
    2808             GPRReg stubInfoGPR = InvalidGPRReg;
    2809             if (JITCode::useDataIC(JITType::DFGJIT)) {
    2810                 stubInfo.emplace(this);
    2811                 stubInfoGPR = stubInfo->gpr();
    2812             }
    2813             GPRReg baseGPR = base.gpr();
    2814             GPRReg propertyGPR = property.gpr();
    2815             GPRReg resultGPR = result.gpr();
    2816 
    2817             speculate(node, m_graph.varArgChild(node, 0));
    2818             speculate(node, m_graph.varArgChild(node, 1));
    2819 
    2820             CodeOrigin codeOrigin = node->origin.semantic;
    2821             CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
    2822             RegisterSet usedRegisters = this->usedRegisters();
    2823 
    2824             JITCompiler::JumpList slowCases;
    2825             if (!m_state.forNode(m_graph.varArgChild(node, 0)).isType(SpecCell))
    2826                 slowCases.append(m_jit.branchIfNotCell(baseGPR));
    2827 
    2828             JITGetByValGenerator gen(
    2829                 m_jit.codeBlock(), JITType::DFGJIT, codeOrigin, callSite, AccessType::GetByVal, usedRegisters,
    2830                 JSValueRegs(baseGPR), JSValueRegs(propertyGPR), JSValueRegs(resultGPR), stubInfoGPR);
    2831 
    2832             if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecString))
    2833                 gen.stubInfo()->propertyIsString = true;
    2834             else if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecInt32Only))
    2835                 gen.stubInfo()->propertyIsInt32 = true;
    2836             else if (m_state.forNode(m_graph.varArgChild(node, 1)).isType(SpecSymbol))
    2837                 gen.stubInfo()->propertyIsSymbol = true;
    2838 
    2839             gen.generateFastPath(m_jit);
    2840            
    2841             if (!JITCode::useDataIC(JITType::DFGJIT))
    2842                 slowCases.append(gen.slowPathJump());
    2843 
    2844             std::unique_ptr<SlowPathGenerator> slowPath;
    2845             if (JITCode::useDataIC(JITType::DFGJIT)) {
    2846                 slowPath = slowPathICCall(
    2847                     slowCases, this, gen.stubInfo(), stubInfoGPR, CCallHelpers::Address(stubInfoGPR, StructureStubInfo::offsetOfSlowOperation()), operationGetByValOptimize,
    2848                     resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), stubInfoGPR, nullptr, baseGPR, propertyGPR);
    2849             } else {
    2850                 slowPath = slowPathCall(
    2851                     slowCases, this, operationGetByValOptimize,
    2852                     resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), nullptr, baseGPR, propertyGPR);
    2853             }
    2854            
    2855             m_jit.addGetByVal(gen, slowPath.get());
    2856             addSlowPathGenerator(WTFMove(slowPath));
    2857 
    2858             jsValueResult(resultGPR, node);
    2859             break;
    2860         }
    2861         case Array::Int32:
    2862         case Array::Contiguous: {
    2863             if (node->arrayMode().isInBounds()) {
    2864                 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2865                 StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2866 
    2867                 GPRReg propertyReg = property.gpr();
    2868                 GPRReg storageReg = storage.gpr();
    2869 
    2870                 if (!m_compileOkay)
    2871                     return;
    2872                
    2873                 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
    2874                
    2875                 GPRTemporary result(this);
    2876 
    2877                 m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.gpr());
    2878                 if (node->arrayMode().isInBoundsSaneChain()) {
    2879                     ASSERT(node->arrayMode().type() == Array::Contiguous);
    2880                     JITCompiler::Jump notHole = m_jit.branchIfNotEmpty(result.gpr());
    2881                     m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), result.gpr());
    2882                     notHole.link(&m_jit);
    2883                 } else {
    2884                     speculationCheck(
    2885                         LoadFromHole, JSValueRegs(), nullptr,
    2886                         m_jit.branchIfEmpty(result.gpr()));
    2887                 }
    2888                 jsValueResult(result.gpr(), node, node->arrayMode().type() == Array::Int32 ? DataFormatJSInt32 : DataFormatJS);
    2889                 break;
    2890             }
    2891            
    2892             SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
    2893             SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2894             StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2895            
    2896             GPRReg baseReg = base.gpr();
    2897             GPRReg propertyReg = property.gpr();
    2898             GPRReg storageReg = storage.gpr();
    2899            
    2900             if (!m_compileOkay)
    2901                 return;
    2902            
    2903             GPRTemporary result(this);
    2904             GPRReg resultReg = result.gpr();
    2905            
    2906             MacroAssembler::JumpList slowCases;
    2907            
    2908             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
    2909 
    2910             m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
    2911 
    2912             if (node->arrayMode().isOutOfBoundsSaneChain()) {
    2913                 auto done = m_jit.branchIfNotEmpty(resultReg);
    2914                 slowCases.link(&m_jit);
    2915                 speculationCheck(NegativeIndex, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, propertyReg, CCallHelpers::TrustedImm32(0)));
    2916                 m_jit.move(CCallHelpers::TrustedImm64(JSValue::encode(jsUndefined())), resultReg);
    2917                 done.link(&m_jit);
    2918             } else {
    2919                 slowCases.append(m_jit.branchIfEmpty(resultReg));
    2920                 addSlowPathGenerator(
    2921                     slowPathCall(
    2922                         slowCases, this, operationGetByValObjectInt,
    2923                         result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
    2924             }
    2925            
    2926            
    2927             jsValueResult(resultReg, node);
    2928             break;
    2929         }
    2930 
    2931         case Array::Double: {
    2932             if (node->arrayMode().isInBounds()) {
    2933                 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2934                 StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2935 
    2936                 GPRReg propertyReg = property.gpr();
    2937                 GPRReg storageReg = storage.gpr();
    2938 
    2939                 if (!m_compileOkay)
    2940                     return;
    2941 
    2942                 FPRTemporary result(this);
    2943                 FPRReg resultReg = result.fpr();
    2944 
    2945                 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
    2946 
    2947                 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
    2948                 if (!node->arrayMode().isInBoundsSaneChain())
    2949                     speculationCheck(LoadFromHole, JSValueRegs(), nullptr, m_jit.branchIfNaN(resultReg));
    2950                 doubleResult(resultReg, node);
    2951                 break;
    2952             }
    2953 
    2954             bool resultIsUnboxed = node->arrayMode().isOutOfBoundsSaneChain() && !(node->flags() & NodeBytecodeUsesAsOther);
    2955 
    2956             SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
    2957             SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    2958             StorageOperand storage(this, m_graph.varArgChild(node, 2));
    2959            
    2960             GPRReg baseReg = base.gpr();
    2961             GPRReg propertyReg = property.gpr();
    2962             GPRReg storageReg = storage.gpr();
    2963            
    2964             if (!m_compileOkay)
    2965                 return;
    2966            
    2967             std::optional<GPRTemporary> result;
    2968             std::optional<GPRReg> resultReg;
    2969             if (!resultIsUnboxed) {
    2970                 result.emplace(this);
    2971                 resultReg = result->gpr();
    2972             }
    2973             FPRTemporary temp(this);
    2974             FPRReg tempReg = temp.fpr();
    2975            
    2976             MacroAssembler::JumpList slowCases;
    2977            
    2978             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
    2979 
    2980             m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
    2981             if (node->arrayMode().isOutOfBoundsSaneChain()) {
    2982                 if (resultIsUnboxed) {
    2983                     auto done = m_jit.jump();
    2984                     slowCases.link(&m_jit);
    2985                     speculationCheck(NegativeIndex, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, propertyReg, CCallHelpers::TrustedImm32(0)));
    2986                     static const double NaN = PNaN;
    2987                     m_jit.loadDouble(TrustedImmPtr(&NaN), tempReg);
    2988                     done.link(&m_jit);
    2989                     doubleResult(tempReg, node);
    2990                 } else {
    2991                     slowCases.append(m_jit.branchIfNaN(tempReg));
    2992                     boxDouble(tempReg, *resultReg);
    2993                     auto done = m_jit.jump();
    2994                     slowCases.link(&m_jit);
    2995                     speculationCheck(NegativeIndex, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, propertyReg, CCallHelpers::TrustedImm32(0)));
    2996                     m_jit.move(CCallHelpers::TrustedImm64(JSValue::encode(jsUndefined())), *resultReg);
    2997                     done.link(&m_jit);
    2998                     jsValueResult(*resultReg, node);
    2999                 }
    3000             } else {
    3001                 slowCases.append(m_jit.branchIfNaN(tempReg));
    3002                 boxDouble(tempReg, *resultReg);
    3003                 addSlowPathGenerator(
    3004                     slowPathCall(
    3005                         slowCases, this, operationGetByValObjectInt,
    3006                         *resultReg, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
    3007                 jsValueResult(*resultReg, node);
    3008             }
    3009 
    3010             break;
    3011         }
    3012 
    3013         case Array::ArrayStorage:
    3014         case Array::SlowPutArrayStorage: {
    3015             if (node->arrayMode().isInBounds()) {
    3016                 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    3017                 StorageOperand storage(this, m_graph.varArgChild(node, 2));
    3018            
    3019                 GPRReg propertyReg = property.gpr();
    3020                 GPRReg storageReg = storage.gpr();
    3021            
    3022                 if (!m_compileOkay)
    3023                     return;
    3024            
    3025                 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
    3026            
    3027                 GPRTemporary result(this);
    3028                 m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), result.gpr());
    3029                 speculationCheck(LoadFromHole, JSValueRegs(), nullptr, m_jit.branchIfEmpty(result.gpr()));
    3030            
    3031                 jsValueResult(result.gpr(), node);
    3032                 break;
    3033             }
    3034 
    3035             SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
    3036             SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
    3037             StorageOperand storage(this, m_graph.varArgChild(node, 2));
    3038            
    3039             GPRReg baseReg = base.gpr();
    3040             GPRReg propertyReg = property.gpr();
    3041             GPRReg storageReg = storage.gpr();
    3042            
    3043             if (!m_compileOkay)
    3044                 return;
    3045            
    3046             GPRTemporary result(this);
    3047             GPRReg resultReg = result.gpr();
    3048            
    3049             MacroAssembler::JumpList slowCases;
    3050            
    3051             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
    3052    
    3053             m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), resultReg);
    3054             slowCases.append(m_jit.branchIfEmpty(resultReg));
    3055    
    3056             addSlowPathGenerator(
    3057                 slowPathCall(
    3058                     slowCases, this, operationGetByValObjectInt,
    3059                     result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
    3060            
    3061             jsValueResult(resultReg, node);
    3062             break;
    3063         }
    3064         case Array::String:
    3065             compileGetByValOnString(node);
    3066             break;
    3067         case Array::DirectArguments:
    3068             compileGetByValOnDirectArguments(node);
    3069             break;
    3070         case Array::ScopedArguments:
    3071             compileGetByValOnScopedArguments(node);
    3072             break;
    3073         case Array::Int8Array:
    3074         case Array::Int16Array:
    3075         case Array::Int32Array:
    3076         case Array::Uint8Array:
    3077         case Array::Uint8ClampedArray:
    3078         case Array::Uint16Array:
    3079         case Array::Uint32Array:
    3080         case Array::Float32Array:
    3081         case Array::Float64Array: {
    3082             TypedArrayType type = node->arrayMode().typedArrayType();
    3083             if (isInt(type))
    3084                 compileGetByValOnIntTypedArray(node, type);
    3085             else
    3086                 compileGetByValOnFloatTypedArray(node, type);
    3087         } }
     3129            };
     3130            return std::make_pair(resultRegs, preferredFormat);
     3131        }));
    30883132        break;
    30893133    }
    … …  
    35823626        }
    35833627        constexpr bool canSpeculate = false;
    3584         setIntTypedArrayLoadResult(node, resultGPR, type, canSpeculate);
     3628        constexpr bool shouldBox = false;
     3629        setIntTypedArrayLoadResult(node, JSValueRegs(resultGPR), type, canSpeculate, shouldBox);
    35853630        break;
    35863631    }
    … …  
    52705315        break;
    52715316    }
    5272        
    5273     case GetEnumerableLength: {
    5274         compileGetEnumerableLength(node);
    5275         break;
    5276     }
    5277     case HasEnumerableStructureProperty: {
    5278         compileHasEnumerableStructureProperty(node);
    5279         break;
    5280     }
    5281     case HasEnumerableProperty: {
    5282         compileHasEnumerableProperty(node);
    5283         break;
    5284     }
    5285     case HasOwnStructureProperty: {
    5286         compileHasOwnStructureProperty(node);
    5287         break;
    5288     }
    5289     case InStructureProperty: {
    5290         compileInStructureProperty(node);
    5291         break;
    5292     }
     5317
    52935318    case HasIndexedProperty: {
    5294         compileHasIndexedProperty(node, operationHasIndexedProperty);
    5295         break;
    5296     }
    5297     case HasEnumerableIndexedProperty: {
    5298         compileHasIndexedProperty(node, operationHasEnumerableIndexedProperty);
    5299         break;
    5300     }
    5301     case GetDirectPname: {
    5302         compileGetDirectPname(node);
    5303         break;
    5304     }
     5319        SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
     5320        GPRTemporary result(this, Reuse, index);
     5321
     5322        compileHasIndexedProperty(node, operationHasIndexedProperty, scopedLambda<std::tuple<GPRReg, GPRReg>()>([&] { return std::make_pair(index.gpr(), result.gpr()); }));
     5323        unblessedBooleanResult(result.gpr(), node);
     5324        break;
     5325    }
     5326
    53055327    case GetPropertyEnumerator: {
    53065328        compileGetPropertyEnumerator(node);
    53075329        break;
    53085330    }
    5309     case GetEnumeratorStructurePname:
    5310     case GetEnumeratorGenericPname: {
    5311         compileGetEnumeratorPname(node);
    5312         break;
    5313     }
    5314     case ToIndexString: {
    5315         compileToIndexString(node);
    5316         break;
    5317     }
     5331
     5332    case EnumeratorNextUpdateIndexAndMode: {
     5333        compileEnumeratorNextUpdateIndexAndMode(node);
     5334        break;
     5335    }
     5336
     5337    case EnumeratorNextExtractMode: {
     5338        compileEnumeratorNextExtractMode(node);
     5339        break;
     5340    }
     5341
     5342    case EnumeratorNextExtractIndex: {
     5343        compileEnumeratorNextExtractIndex(node);
     5344        break;
     5345    }
     5346
     5347    case EnumeratorNextUpdatePropertyName: {
     5348        compileEnumeratorNextUpdatePropertyName(node);
     5349        break;
     5350    }
     5351
     5352    case EnumeratorGetByVal: {
     5353        compileEnumeratorGetByVal(node);
     5354        break;
     5355    }
     5356
     5357    case EnumeratorInByVal: {
     5358        compileEnumeratorInByVal(node);
     5359        break;
     5360    }
     5361
     5362    case EnumeratorHasOwnProperty: {
     5363        compileEnumeratorHasOwnProperty(node);
     5364        break;
     5365    }
     5366
    53185367    case ProfileType: {
    53195368        compileProfileType(node);
  • trunk/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp

    r278253 r280760  
    274274                case NukeStructureAndSetButterfly:
    275275                case GetButterfly:
     276                case EnumeratorGetByVal:
    276277                case GetByVal:
    277278                case PutByValDirect:
    … …  
    353354                case ReallocatePropertyStorage:
    354355                case GetButterfly:
     356                case EnumeratorGetByVal:
    355357                case GetByVal:
    356358                case PutByValDirect:
  • trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h

    r278462 r280760  
    115115    macro(JSPropertyNameEnumerator_endStructurePropertyIndex, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()) \
    116116    macro(JSPropertyNameEnumerator_indexLength, JSPropertyNameEnumerator::indexedLengthOffset()) \
     117    macro(JSPropertyNameEnumerator_modeSet, JSPropertyNameEnumerator::modeSetOffset()) \
    117118    macro(JSRopeString_flags, JSRopeString::offsetOfFlags()) \
    118119    macro(JSRopeString_length, JSRopeString::offsetOfLength()) \
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r279604 r280760  
    287287    case BooleanToNumber:
    288288    case HasIndexedProperty:
    289     case HasEnumerableIndexedProperty:
    290     case HasEnumerableStructureProperty:
    291     case HasEnumerableProperty:
    292     case HasOwnStructureProperty:
    293     case InStructureProperty:
    294     case GetDirectPname:
    295     case GetEnumerableLength:
    296289    case GetIndexedPropertyStorage:
    297290    case GetPropertyEnumerator:
    298     case GetEnumeratorStructurePname:
    299     case GetEnumeratorGenericPname:
    300     case ToIndexString:
     291    case EnumeratorNextUpdateIndexAndMode:
     292    case EnumeratorNextExtractMode:
     293    case EnumeratorNextExtractIndex:
     294    case EnumeratorNextUpdatePropertyName:
     295    case EnumeratorGetByVal:
     296    case EnumeratorInByVal:
     297    case EnumeratorHasOwnProperty:
    301298    case BottomValue:
    302299    case PhantomNewObject:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r280198 r280760  
    15241524            break;
    15251525        case HasIndexedProperty:
    1526             compileHasIndexedProperty(operationHasIndexedProperty);
    1527             break;
    1528         case HasEnumerableIndexedProperty:
    1529             compileHasIndexedProperty(operationHasEnumerableIndexedProperty);
    1530             break;
    1531         case HasEnumerableStructureProperty:
    1532             compileHasEnumerableStructureProperty();
    1533             break;
    1534         case HasEnumerableProperty:
    1535             compileHasEnumerableProperty();
    1536             break;
    1537         case HasOwnStructureProperty:
    1538             compileHasOwnStructureProperty();
    1539             break;
    1540         case InStructureProperty:
    1541             compileInStructureProperty();
    1542             break;
    1543         case GetDirectPname:
    1544             compileGetDirectPname();
    1545             break;
    1546         case GetEnumerableLength:
    1547             compileGetEnumerableLength();
     1526            compileHasIndexedProperty();
    15481527            break;
    15491528        case GetPropertyEnumerator:
    15501529            compileGetPropertyEnumerator();
    15511530            break;
    1552         case GetEnumeratorStructurePname:
    1553             compileGetEnumeratorStructurePname();
    1554             break;
    1555         case GetEnumeratorGenericPname:
    1556             compileGetEnumeratorGenericPname();
    1557             break;
    1558         case ToIndexString:
    1559             compileToIndexString();
     1531        case EnumeratorNextUpdateIndexAndMode:
     1532            compileEnumeratorNextUpdateIndexAndMode();
     1533            break;
     1534        case EnumeratorNextExtractIndex:
     1535            compileEnumeratorNextExtractIndex();
     1536            break;
     1537        case EnumeratorNextExtractMode:
     1538            compileEnumeratorNextExtractMode();
     1539            break;
     1540        case EnumeratorNextUpdatePropertyName:
     1541            compileEnumeratorNextUpdatePropertyName();
     1542            break;
     1543        case EnumeratorGetByVal:
     1544            compileEnumeratorGetByVal();
     1545            break;
     1546        case EnumeratorInByVal:
     1547            compileEnumeratorInByVal();
     1548            break;
     1549        case EnumeratorHasOwnProperty:
     1550            compileEnumeratorHasOwnProperty();
    15601551            break;
    15611552        case CheckStructureImmediate:
    … …  
    50215012    }
    50225013   
    5023     void compileGetByVal()
     5014    LValue compileGetByValImpl()
    50245015    {
    50255016        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
    … …  
    50485039                if (m_node->arrayMode().type() == Array::Contiguous)
    50495040                    ensureStillAliveHere(base);
    5050                 setJSValue(result);
    5051                 return;
     5041                return result;
    50525042            }
    50535043
    … …  
    50815071            if (m_node->arrayMode().type() == Array::Contiguous)
    50825072                ensureStillAliveHere(base);
    5083             setJSValue(m_out.phi(Int64, fastResult, slowResult));
    5084             return;
     5073            return m_out.phi(Int64, fastResult, slowResult);
    50855074        }
    50865075           
    … …  
    51015090                        m_out.doubleNotEqualOrUnordered(result, result));
    51025091                }
    5103                 setDouble(result);
    5104                 break;
     5092
     5093                return result;
    51055094            }
    51065095
    … …  
    51425131            m_out.appendTo(continuation, lastNext);
    51435132            if (resultIsUnboxed)
    5144                 setDouble(m_out.phi(Double, fastResult, slowResult));
    5145             else
    5146                 setJSValue(m_out.phi(Int64, fastResult, slowResult));
    5147             return;
     5133                return m_out.phi(Double, fastResult, slowResult);
     5134
     5135            return m_out.phi(Int64, fastResult, slowResult);
    51485136        }
    51495137
    … …  
    51525140
    51535141            speculate(OutOfBounds, noValue(), m_node, m_out.lessThan(index, m_out.int32Zero));
    5154             setJSValue(m_out.constInt64(JSValue::ValueUndefined));
    5155             return;
     5142            return m_out.constInt64(JSValue::ValueUndefined);
    51565143        }
    51575144           
    … …  
    51705157                TypedPointer address = m_out.baseIndex(
    51715158                    m_heaps.DirectArguments_storage, base, m_out.zeroExtPtr(index));
    5172                 setJSValue(m_out.load64(address));
    5173                 return;
     5159                return m_out.load64(address);
    51745160            }
    51755161
    … …  
    51935179
    51945180            m_out.appendTo(continuation, lastNext);
    5195             setJSValue(m_out.phi(Int64, fastResult, slowResult));
    5196             return;
     5181            return m_out.phi(Int64, fastResult, slowResult);
    51975182        }
    51985183           
    … …  
    52475232           
    52485233            m_out.appendTo(continuation, lastNext);
    5249             setJSValue(m_out.phi(Int64, namedResult, overflowResult));
    5250             return;
     5234            return m_out.phi(Int64, namedResult, overflowResult);
    52515235        }
    52525236           
    … …  
    52575241                if (m_graph.varArgChild(m_node, 0).useKind() == ObjectUse) {
    52585242                    if (m_graph.varArgChild(m_node, 1).useKind() == StringUse) {
    5259                         setJSValue(vmCall(
     5243                        return vmCall(
    52605244                            Int64, operationGetByValObjectString, weakPointer(globalObject),
    5261                             lowObject(m_graph.varArgChild(m_node, 0)), lowString(m_graph.varArgChild(m_node, 1))));
    5262                         return;
     5245                            lowObject(m_graph.varArgChild(m_node, 0)), lowString(m_graph.varArgChild(m_node, 1)));
    52635246                    }
    52645247
    52655248                    if (m_graph.varArgChild(m_node, 1).useKind() == SymbolUse) {
    5266                         setJSValue(vmCall(
     5249                        return vmCall(
    52675250                            Int64, operationGetByValObjectSymbol, weakPointer(globalObject),
    5268                             lowObject(m_graph.varArgChild(m_node, 0)), lowSymbol(m_graph.varArgChild(m_node, 1))));
    5269                         return;
     5251                            lowObject(m_graph.varArgChild(m_node, 0)), lowSymbol(m_graph.varArgChild(m_node, 1)));
    52705252                    }
    52715253                }
    52725254
    5273                 setJSValue(vmCall(
     5255                return vmCall(
    52745256                    Int64, operationGetByVal, weakPointer(globalObject),
    5275                     lowJSValue(m_graph.varArgChild(m_node, 0)), lowJSValue(m_graph.varArgChild(m_node, 1))));
    5276                 return;
     5257                    lowJSValue(m_graph.varArgChild(m_node, 0)), lowJSValue(m_graph.varArgChild(m_node, 1)));
    52775258            }
    52785259
    … …  
    53745355            });
    53755356
    5376             setJSValue(patchpoint);
    5377             return;
     5357            return patchpoint;
    53785358        }
    53795359
    … …  
    53915371                // We have to keep base alive to keep content in storage alive.
    53925372                ensureStillAliveHere(base);
    5393                 setJSValue(result);
    5394                 return;
     5373                return result;
    53955374            }
    53965375
    … …  
    54185397            // We have to keep base alive to keep content in storage alive.
    54195398            ensureStillAliveHere(base);
    5420             setJSValue(m_out.phi(Int64, fastResult, slowResult));
    5421             return;
     5399            return m_out.phi(Int64, fastResult, slowResult);
    54225400        }
    54235401           
    54245402        case Array::String: {
    5425             compileStringCharAt();
    5426             return;
     5403            return compileStringCharAtImpl();
    54275404        }
    54285405           
    … …  
    54495426                    // We have to keep base alive since that keeps storage alive.
    54505427                    ensureStillAliveHere(base);
    5451                     constexpr bool canSpeculate = true;
    5452                     setIntTypedArrayLoadResult(result, type, canSpeculate);
    5453                     return;
     5428                    return result;
    54545429                }
    54555430           
    … …  
    54705445                // We have to keep base alive since that keeps storage alive.
    54715446                ensureStillAliveHere(base);
    5472                 setDouble(result);
    5473                 return;
     5447                return result;
    54745448            }
    54755449        }
    … …  
    54815455        case Array::Unprofiled:
    54825456            DFG_CRASH(m_graph, m_node, "Bad array type");
     5457            return nullptr;
     5458        }
     5459    }
     5460
     5461    void compileGetByVal()
     5462    {
     5463        LValue result = compileGetByValImpl();
     5464        TypedArrayType type = m_node->arrayMode().typedArrayType();
     5465        if (isInt(type)) {
     5466            constexpr bool canSpeculate = true;
     5467            setIntTypedArrayLoadResult(result, type, canSpeculate);
    54835468            return;
    54845469        }
     5470
     5471        if (result->type() == Double)
     5472            setDouble(result);
     5473        else
     5474            setJSValue(result);
    54855475    }
    54865476   
    … …  
    85728562    }
    85738563   
    8574     void compileStringCharAt()
     8564    LValue compileStringCharAtImpl()
    85758565    {
    85768566        LValue base = lowString(m_graph.child(m_node, 0));
    … …  
    86808670        // We have to keep base alive since that keeps storage alive.
    86818671        ensureStillAliveHere(base);
    8682         setJSValue(m_out.phi(Int64, results));
     8672        return m_out.phi(Int64, results);
     8673    }
     8674
     8675    void compileStringCharAt()
     8676    {
     8677        setJSValue(compileStringCharAtImpl());
    86838678    }
    86848679   
    … …  
    1290712902    }
    1290812903   
    12909     void compileHasIndexedProperty(S_JITOperation_GCZ slowPathOperation)
     12904    LValue compileHasIndexedPropertyImpl(LValue index, S_JITOperation_GCZ slowPathOperation)
    1291012905    {
    1291112906        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
    1291212907        LValue base = lowCell(m_graph.varArgChild(m_node, 0));
    12913         LValue index = lowInt32(m_graph.varArgChild(m_node, 1));
    1291412908        ArrayMode mode = m_node->arrayMode();
    1291512909
    … …  
    1291712911        case Array::Int32:
    1291812912        case Array::Contiguous: {
    12919             LValue storage = lowStorage(m_graph.varArgChild(m_node, 2));
     12913            LValue storage = lowStorage(m_graph.varArgChild(m_node, m_node->storageChildIndex()));
    1292012914
    1292112915            IndexedAbstractHeap& heap = mode.type() == Array::Int32 ?
    … …  
    1295212946
    1295312947            m_out.appendTo(continuation, lastNext);
    12954             setBoolean(m_out.phi(Int32, checkHoleResult, slowResult));
    12955             return;
     12948            return m_out.phi(Int32, checkHoleResult, slowResult);
    1295612949        }
    1295712950        case Array::Double: {
    12958             LValue storage = lowStorage(m_graph.varArgChild(m_node, 2));
     12951            LValue storage = lowStorage(m_graph.varArgChild(m_node, m_node->storageChildIndex()));
    1295912952           
    1296012953            IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
    … …  
    1299012983           
    1299112984            m_out.appendTo(continuation, lastNext);
    12992             setBoolean(m_out.phi(Int32, checkHoleResult, slowResult));
    12993             return;
     12985            return m_out.phi(Int32, checkHoleResult, slowResult);
    1299412986        }
    1299512987
    1299612988        case Array::ArrayStorage: {
    12997             LValue storage = lowStorage(m_graph.varArgChild(m_node, 2));
     12989            LValue storage = lowStorage(m_graph.varArgChild(m_node, m_node->storageChildIndex()));
    1299812990
    1299912991            LBasicBlock slowCase = m_out.newBlock();
    … …  
    1302713019
    1302813020            m_out.appendTo(continuation, lastNext);
    13029             setBoolean(m_out.phi(Int32, checkHoleResult, slowResult));
    13030             break;
     13021            return m_out.phi(Int32, checkHoleResult, slowResult);
    1303113022        }
    1303213023
    1303313024        default: {
    13034             setBoolean(m_out.notZero64(vmCall(Int64, slowPathOperation, weakPointer(globalObject), base, index)));
    13035             break;
    13036         }
    13037         }
    13038     }
    13039 
    13040     void compileHasEnumerableProperty()
    13041     {
    13042         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
    13043         LValue base = lowJSValue(m_node->child1());
    13044         LValue property = lowCell(m_node->child2());
    13045         setJSValue(vmCall(Int64, operationHasEnumerableProperty, weakPointer(globalObject), base, property));
    13046     }
    13047 
    13048     template <typename SlowPathCall>
    13049     void compileHasStructurePropertyImpl(LValue base, SlowPathCall slowPathCall)
    13050     {
    13051         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
    13052         LValue property = lowString(m_node->child2());
    13053         LValue enumerator = lowCell(m_node->child3());
    13054 
    13055         LBasicBlock isCellCase = m_out.newBlock();
    13056         LBasicBlock correctStructure = m_out.newBlock();
    13057         LBasicBlock slowPath = m_out.newBlock();
    13058         LBasicBlock continuation = m_out.newBlock();
    13059 
    13060         m_out.branch(isCell(base, provenType(m_node->child1())),
    13061             usually(isCellCase), rarely(slowPath));
    13062 
    13063         LBasicBlock lastNext = m_out.appendTo(isCellCase, correctStructure);
    13064 
    13065         m_out.branch(m_out.notEqual(
    13066             m_out.load32(base, m_heaps.JSCell_structureID),
    13067             m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
    13068             rarely(slowPath), usually(correctStructure));
    13069 
    13070         m_out.appendTo(correctStructure, slowPath);
    13071         ValueFromBlock correctStructureResult = m_out.anchor(m_out.booleanTrue);
    13072         m_out.jump(continuation);
    13073 
    13074         m_out.appendTo(slowPath, continuation);
    13075         ValueFromBlock slowPathResult = m_out.anchor(
    13076             m_out.equal(
    13077                 m_out.constInt64(JSValue::encode(jsBoolean(true))),
    13078                 vmCall(Int64, slowPathCall, weakPointer(globalObject), base, property)));
    13079         m_out.jump(continuation);
    13080 
    13081         m_out.appendTo(continuation, lastNext);
    13082         setBoolean(m_out.phi(Int32, correctStructureResult, slowPathResult));
    13083     }
    13084 
    13085     void compileHasEnumerableStructureProperty()
    13086     {
    13087         compileHasStructurePropertyImpl(lowJSValue(m_node->child1()), operationHasEnumerableProperty);
    13088     }
    13089 
    13090     void compileHasOwnStructureProperty()
    13091     {
    13092         compileHasStructurePropertyImpl(lowCell(m_node->child1()), operationHasOwnStructureProperty);
    13093     }
    13094 
    13095     void compileInStructureProperty()
    13096     {
    13097         compileHasStructurePropertyImpl(lowCell(m_node->child1()), operationInStructureProperty);
    13098     }
    13099 
    13100     void compileGetDirectPname()
    13101     {
    13102         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
    13103         LValue base = lowCell(m_graph.varArgChild(m_node, 0));
    13104         LValue property = lowCell(m_graph.varArgChild(m_node, 1));
    13105         LValue index = lowInt32(m_graph.varArgChild(m_node, 2));
    13106         LValue enumerator = lowCell(m_graph.varArgChild(m_node, 3));
    13107 
    13108         LBasicBlock checkOffset = m_out.newBlock();
    13109         LBasicBlock inlineLoad = m_out.newBlock();
    13110         LBasicBlock outOfLineLoad = m_out.newBlock();
    13111         LBasicBlock slowCase = m_out.newBlock();
    13112         LBasicBlock continuation = m_out.newBlock();
    13113 
    13114         m_out.branch(m_out.notEqual(
    13115             m_out.load32(base, m_heaps.JSCell_structureID),
    13116             m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
    13117             rarely(slowCase), usually(checkOffset));
    13118 
    13119         LBasicBlock lastNext = m_out.appendTo(checkOffset, inlineLoad);
    13120         m_out.branch(m_out.aboveOrEqual(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity)),
    13121             unsure(outOfLineLoad), unsure(inlineLoad));
    13122 
    13123         m_out.appendTo(inlineLoad, outOfLineLoad);
    13124         ValueFromBlock inlineResult = m_out.anchor(
    13125             m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(),
    13126                 base, m_out.zeroExt(index, Int64), ScaleEight, JSObject::offsetOfInlineStorage())));
    13127         m_out.jump(continuation);
    13128 
    13129         m_out.appendTo(outOfLineLoad, slowCase);
    13130         LValue storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly);
    13131         LValue realIndex = m_out.signExt32To64(
    13132             m_out.neg(m_out.sub(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity))));
    13133         int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
    13134         ValueFromBlock outOfLineResult = m_out.anchor(
    13135             m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), storage, realIndex, ScaleEight, offsetOfFirstProperty)));
    13136         m_out.jump(continuation);
    13137 
    13138         m_out.appendTo(slowCase, continuation);
    13139         ValueFromBlock slowCaseResult = m_out.anchor(
    13140             vmCall(Int64, operationGetByVal, weakPointer(globalObject), base, property));
    13141         m_out.jump(continuation);
    13142 
    13143         m_out.appendTo(continuation, lastNext);
    13144         setJSValue(m_out.phi(Int64, inlineResult, outOfLineResult, slowCaseResult));
    13145     }
    13146 
    13147     void compileGetEnumerableLength()
    13148     {
    13149         LValue enumerator = lowCell(m_node->child1());
    13150         setInt32(m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_indexLength));
     13025            return m_out.notZero64(vmCall(Int64, slowPathOperation, weakPointer(globalObject), base, index));
     13026        }
     13027        }
     13028    }
     13029
     13030    void compileHasIndexedProperty()
     13031    {
     13032        LValue index = lowInt32(m_graph.varArgChild(m_node, 1));
     13033        setBoolean(compileHasIndexedPropertyImpl(index, operationHasIndexedProperty));
    1315113034    }
    1315213035
    … …  
    1316013043    }
    1316113044
    13162     void compileGetEnumeratorStructurePname()
    13163     {
    13164         LValue enumerator = lowCell(m_node->child1());
    13165         LValue index = lowInt32(m_node->child2());
    13166 
    13167         LBasicBlock inBounds = m_out.newBlock();
    13168         LBasicBlock outOfBounds = m_out.newBlock();
    13169         LBasicBlock continuation = m_out.newBlock();
    13170 
    13171         m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endStructurePropertyIndex)),
    13172             usually(inBounds), rarely(outOfBounds));
    13173 
    13174         LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds);
    13175         LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector);
    13176         ValueFromBlock inBoundsResult = m_out.anchor(
    13177             m_out.loadPtr(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, storage, m_out.zeroExtPtr(index))));
    13178         m_out.jump(continuation);
    13179 
    13180         m_out.appendTo(outOfBounds, continuation);
    13181         ValueFromBlock outOfBoundsResult = m_out.anchor(m_out.constInt64(JSValue::ValueNull));
    13182         m_out.jump(continuation);
    13183        
    13184         m_out.appendTo(continuation, lastNext);
    13185         setJSValue(m_out.phi(Int64, inBoundsResult, outOfBoundsResult));
    13186     }
    13187 
    13188     void compileGetEnumeratorGenericPname()
    13189     {
    13190         LValue enumerator = lowCell(m_node->child1());
    13191         LValue index = lowInt32(m_node->child2());
    13192 
    13193         LBasicBlock inBounds = m_out.newBlock();
    13194         LBasicBlock outOfBounds = m_out.newBlock();
    13195         LBasicBlock continuation = m_out.newBlock();
    13196 
    13197         m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endGenericPropertyIndex)),
    13198             usually(inBounds), rarely(outOfBounds));
    13199 
    13200         LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds);
    13201         LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector);
    13202         ValueFromBlock inBoundsResult = m_out.anchor(
    13203             m_out.loadPtr(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, storage, m_out.zeroExtPtr(index))));
    13204         m_out.jump(continuation);
    13205 
    13206         m_out.appendTo(outOfBounds, continuation);
    13207         ValueFromBlock outOfBoundsResult = m_out.anchor(m_out.constInt64(JSValue::ValueNull));
    13208         m_out.jump(continuation);
    13209        
    13210         m_out.appendTo(continuation, lastNext);
    13211         setJSValue(m_out.phi(Int64, inBoundsResult, outOfBoundsResult));
    13212     }
    13213    
    13214     void compileToIndexString()
     13045    void compileEnumeratorNextUpdateIndexAndMode()
     13046    {
     13047        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
     13048        LValue index = lowInt32(m_graph.varArgChild(m_node, 1));
     13049        LValue mode = lowInt32(m_graph.varArgChild(m_node, 2));
     13050        LValue enumerator = lowCell(m_graph.varArgChild(m_node, 3));
     13051
     13052        if (m_node->enumeratorMetadata() == JSPropertyNameEnumerator::IndexedMode) {
     13053            speculate(BadCache, noValue(), m_node, m_out.notZero32(m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endGenericPropertyIndex)));
     13054
     13055            LBasicBlock increment = m_out.newBlock();
     13056            LBasicBlock checkHasProperty = m_out.newBlock();
     13057            LBasicBlock continuation = m_out.newBlock();
     13058
     13059            ValueFromBlock initialIndex = m_out.anchor(index);
     13060            ValueFromBlock initialIndexForHasProperty = m_out.anchor(index);
     13061            m_out.branch(m_out.isZero32(mode), unsure(checkHasProperty), unsure(increment));
     13062
     13063            m_out.appendTo(increment);
     13064            LValue indexPhi = m_out.phi(Int32, initialIndex);
     13065            LValue incrementedIndex = m_out.add(indexPhi, m_out.int32One);
     13066            ValueFromBlock incrementedIndexResult = m_out.anchor(incrementedIndex);
     13067            ValueFromBlock finalIncrementedIndex = m_out.anchor(incrementedIndex);
     13068            m_out.branch(m_out.lessThan(incrementedIndex, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_indexLength)), unsure(checkHasProperty), unsure(continuation));
     13069
     13070            m_out.appendTo(checkHasProperty);
     13071            LValue propertyIndex = m_out.phi(Int32, initialIndexForHasProperty, incrementedIndexResult);
     13072            m_out.addIncomingToPhi(indexPhi, m_out.anchor(propertyIndex));
     13073            ValueFromBlock finalPropertyIndex = m_out.anchor(propertyIndex);
     13074            LValue hasProperty = compileHasIndexedPropertyImpl(propertyIndex, operationHasEnumerableIndexedProperty);
     13075            m_out.branch(hasProperty, unsure(continuation), unsure(increment));
     13076
     13077            m_out.appendTo(continuation);
     13078            LValue finalIndex = m_out.phi(Int32, finalIncrementedIndex, finalPropertyIndex);
     13079            setJSValue(m_out.bitOr(m_out.zeroExt(finalIndex, Int64), m_out.constInt64(JSValue::NumberTag | static_cast<uint64_t>(JSPropertyNameEnumerator::IndexedMode) << 32)));
     13080            return;
     13081        }
     13082
     13083        Edge& baseEdge = m_graph.varArgChild(m_node, 0);
     13084        if (m_node->enumeratorMetadata() == JSPropertyNameEnumerator::OwnStructureMode && baseEdge.useKind() == CellUse) {
     13085            LValue base = lowCell(baseEdge);
     13086            speculate(BadCache, noValue(), m_node, m_out.notEqual(m_out.load32(base, m_heaps.JSCell_structureID), m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)));
     13087
     13088            speculate(BadCache, noValue(), m_node, m_out.notEqual(m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_modeSet), m_out.constInt32(JSPropertyNameEnumerator::OwnStructureMode)));
     13089
     13090            LBasicBlock increment = m_out.newBlock();
     13091            LBasicBlock continuation = m_out.newBlock();
     13092
     13093            ValueFromBlock initialIndex = m_out.anchor(index);
     13094            m_out.branch(m_out.isZero32(mode), unsure(continuation), unsure(increment));
     13095
     13096            m_out.appendTo(increment);
     13097            ValueFromBlock incrementedIndex = m_out.anchor(m_out.add(index, m_out.int32One));
     13098            m_out.jump(continuation);
     13099
     13100            m_out.appendTo(continuation);
     13101            index = m_out.phi(Int32, initialIndex, incrementedIndex);
     13102            setJSValue(m_out.bitOr(m_out.zeroExt(index, Int64), m_out.constInt64(JSValue::DoubleEncodeOffset | static_cast<uint64_t>(JSPropertyNameEnumerator::OwnStructureMode) << 32)));
     13103            return;
     13104        }
     13105
     13106        LValue base = lowJSValue(baseEdge);
     13107        setJSValue(vmCall(Int64, operationEnumeratorNextUpdateIndexAndMode, weakPointer(globalObject), base, index, mode, enumerator));
     13108    }
     13109
     13110    void compileEnumeratorNextExtractIndex()
     13111    {
     13112        LValue boxedPair = lowJSValue(m_node->child1());
     13113
     13114        setInt32(m_out.castToInt32(boxedPair));
     13115    }
     13116
     13117    void compileEnumeratorNextExtractMode()
     13118    {
     13119        LValue boxedPair = lowJSValue(m_node->child1());
     13120
     13121        LValue highBits = m_out.castToInt32(m_out.lShr(boxedPair, m_out.constInt32(32)));
     13122        setInt32(m_out.bitAnd(highBits, m_out.constInt32(JSPropertyNameEnumerator::enumerationModeMask)));
     13123    }
     13124
     13125    // FIXME: We should probably have a method of value recovery for this node since it's "effect" free but always live in bytecode.
     13126    void compileEnumeratorNextUpdatePropertyName()
    1321513127    {
    1321613128        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
    1321713129        LValue index = lowInt32(m_node->child1());
    13218         setJSValue(vmCall(Int64, operationToIndexString, weakPointer(globalObject), index));
     13130        LValue mode = lowInt32(m_node->child2());
     13131        LValue enumerator = lowCell(m_node->child3());
     13132
     13133        LBasicBlock operationBlock = nullptr;
     13134        LBasicBlock continuation = nullptr;
     13135
     13136        Vector<ValueFromBlock, 3> results;
     13137        OptionSet seenModes = m_node->enumeratorMetadata();
     13138
     13139        if (seenModes.containsAny({ JSPropertyNameEnumerator::OwnStructureMode, JSPropertyNameEnumerator::GenericMode })) {
     13140            LBasicBlock checkIndex = nullptr;
     13141            LBasicBlock outOfBoundsBlock = m_out.newBlock();
     13142            LBasicBlock loadPropertyNameBlock = m_out.newBlock();
     13143            continuation = m_out.newBlock();
     13144
     13145            if (seenModes.contains(JSPropertyNameEnumerator::IndexedMode)) {
     13146                checkIndex = m_out.newBlock();
     13147                operationBlock = m_out.newBlock();
     13148                m_out.branch(m_out.testIsZero32(mode, m_out.constInt32(JSPropertyNameEnumerator::IndexedMode)), unsure(checkIndex), unsure(operationBlock));
     13149            }
     13150
     13151            {
     13152                if (checkIndex)
     13153                    m_out.appendTo(checkIndex);
     13154                LValue outOfBounds = m_out.aboveOrEqual(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endGenericPropertyIndex));
     13155                m_out.branch(outOfBounds, unsure(outOfBoundsBlock), unsure(loadPropertyNameBlock));
     13156            }
     13157
     13158            {
     13159                m_out.appendTo(outOfBoundsBlock);
     13160                results.append(m_out.anchor(m_out.constInt64(JSValue::encode(jsNull()))));
     13161                m_out.jump(continuation);
     13162            }
     13163
     13164            {
     13165                m_out.appendTo(loadPropertyNameBlock);
     13166                LValue namesVector = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector);
     13167                results.append(m_out.anchor(m_out.zeroExtPtr(m_out.loadPtr(m_out.baseIndex(m_heaps.WriteBarrierBuffer_bufferContents.atAnyIndex(), namesVector, m_out.zeroExt(index, Int64), ScalePtr)))));
     13168                m_out.jump(continuation);
     13169            }
     13170        }
     13171
     13172        if (seenModes.contains(JSPropertyNameEnumerator::IndexedMode)) {
     13173            if (operationBlock)
     13174                m_out.appendTo(operationBlock);
     13175            results.append(m_out.anchor(vmCall(Int64, operationEnumeratorNextUpdatePropertyName, weakPointer(globalObject), index, mode, enumerator)));
     13176            if (continuation)
     13177                m_out.jump(continuation);
     13178        }
     13179
     13180        if (continuation)
     13181            m_out.appendTo(continuation);
     13182
     13183        ASSERT(results.size());
     13184        LValue result = m_out.phi(Int64, results);
     13185        setJSValue(result);
     13186    }
     13187
     13188    void compileEnumeratorGetByVal()
     13189    {
     13190        Edge baseEdge = m_graph.varArgChild(m_node, 0);
     13191        Edge propertyNameEdge = m_graph.varArgChild(m_node, 1);
     13192        Edge storageEdge = m_graph.varArgChild(m_node, 2);
     13193        Edge indexEdge = m_graph.varArgChild(m_node, 3);
     13194
     13195        LValue base = DFG::isCell(baseEdge.useKind()) ? lowCell(baseEdge, ManualOperandSpeculation) : lowJSValue(baseEdge);
     13196
     13197        LValue storage = storageEdge ? lowStorage(storageEdge) : nullptr;
     13198        // We have to materialize the propertyName here in case it requires boxing since the IC path won't dominate subsequent uses in subsequent nodes.
     13199        // If it's an Int32 and we use it as such this boxing will be DCE'd by b3 later anyway.
     13200        lowJSValue(propertyNameEdge, ManualOperandSpeculation);
     13201
     13202
     13203        LValue index = lowInt32(indexEdge);
     13204        LValue mode = lowInt32(m_graph.varArgChild(m_node, 4));
     13205        LValue enumerator = lowCell(m_graph.varArgChild(m_node, 5));
     13206
     13207        LBasicBlock checkIsCellBlock = m_out.newBlock();
     13208        LBasicBlock checkStructureBlock = m_out.newBlock();
     13209        LBasicBlock checkInlineOrOutOfLineBlock = m_out.newBlock();
     13210        LBasicBlock inlineLoadBlock = m_out.newBlock();
     13211        LBasicBlock outOfLineLoadBlock = m_out.newBlock();
     13212        LBasicBlock genericICBlock = m_out.newBlock();
     13213        LBasicBlock continuation = m_out.newBlock();
     13214
     13215        Vector<ValueFromBlock, 4> results;
     13216
     13217        LValue isNotNamed = m_out.testNonZero32(mode, m_out.constInt32(JSPropertyNameEnumerator::IndexedMode | JSPropertyNameEnumerator::GenericMode));
     13218        m_out.branch(isNotNamed, unsure(genericICBlock), unsure(checkIsCellBlock));
     13219
     13220        m_out.appendTo(checkIsCellBlock);
     13221        m_out.branch(isCell(base, provenType(baseEdge)), usually(checkStructureBlock), rarely(genericICBlock));
     13222
     13223        m_out.appendTo(checkStructureBlock);
     13224        LValue structureID;
     13225        auto structure = m_state.forNode(baseEdge.node()).m_structure.onlyStructure();
     13226        if (structure)
     13227            structureID = m_out.constInt32(structure->id());
     13228        else
     13229            structureID = m_out.load32(base, m_heaps.JSCell_structureID);
     13230
     13231        LValue hasEnumeratorStructure = m_out.equal(structureID, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID));
     13232
     13233        if (indexEdge.node() == propertyNameEdge.node()) {
     13234            JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
     13235            LBasicBlock badStructureSlowPath = m_out.newBlock();
     13236            m_out.branch(hasEnumeratorStructure, usually(checkInlineOrOutOfLineBlock), rarely(genericICBlock));
     13237
     13238            m_out.appendTo(badStructureSlowPath);
     13239            results.append(m_out.anchor(vmCall(Int64, operationEnumeratorRecoverNameAndGetByVal, weakPointer(globalObject), base, index, enumerator)));
     13240        } else
     13241            m_out.branch(hasEnumeratorStructure, usually(checkInlineOrOutOfLineBlock), rarely(genericICBlock));
     13242
     13243        m_out.appendTo(checkInlineOrOutOfLineBlock);
     13244        LValue inlineCapacity = nullptr;
     13245        bool hasNoOutOfLineProperties = false;
     13246        if (structure) {
     13247            hasNoOutOfLineProperties = !structure->outOfLineCapacity();
     13248            inlineCapacity = m_out.constInt32(structure->inlineCapacity());
     13249        }
     13250        if (!inlineCapacity)
     13251            inlineCapacity = m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity);
     13252        LValue isInline = hasNoOutOfLineProperties ? m_out.int32One : m_out.below(index, inlineCapacity);
     13253        m_out.branch(isInline, unsure(inlineLoadBlock), unsure(outOfLineLoadBlock));
     13254
     13255        m_out.appendTo(inlineLoadBlock);
     13256        results.append(m_out.anchor(
     13257            m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(),
     13258                base, m_out.zeroExt(index, Int64), ScaleEight, JSObject::offsetOfInlineStorage()))));
     13259        m_out.jump(continuation);
     13260
     13261        m_out.appendTo(outOfLineLoadBlock);
     13262        if (!storage)
     13263            storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly);
     13264
     13265        LValue realIndex = m_out.signExt32To64(
     13266            m_out.neg(m_out.sub(index, inlineCapacity)));
     13267        int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
     13268        results.append(m_out.anchor(
     13269            m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), storage, realIndex, ScaleEight, offsetOfFirstProperty))));
     13270        m_out.jump(continuation);
     13271
     13272        m_out.appendTo(genericICBlock);
     13273        LValue genericResult = compileGetByValImpl();
     13274        TypedArrayType type = m_node->arrayMode().typedArrayType();
     13275        if (isInt(type)) {
     13276            if (elementSize(type) < 4 || isSigned(type))
     13277                genericResult = boxInt32(genericResult);
     13278            else
     13279                genericResult = strictInt52ToJSValue(genericResult);
     13280        } else if (genericResult->type() == Double)
     13281            genericResult = boxDouble(genericResult);
     13282
     13283        results.append(m_out.anchor(genericResult));
     13284        m_out.jump(continuation);
     13285
     13286        m_out.appendTo(continuation);
     13287        ASSERT(results.size());
     13288        LValue result = m_out.phi(Int64, results);
     13289        setJSValue(result);
     13290    }
     13291
     13292    template<typename SlowPathFunctionType>
     13293    void compileEnumeratorHasProperty(SlowPathFunctionType slowPathFunction)
     13294    {
     13295        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
     13296        Edge baseEdge = m_graph.varArgChild(m_node, 0);
     13297        LValue base = baseEdge.useKind() == CellUse ? lowCell(baseEdge) : lowJSValue(baseEdge);
     13298        LValue propertyName = lowJSValue(m_graph.varArgChild(m_node, 1));
     13299        LValue index = lowInt32(m_graph.varArgChild(m_node, 2));
     13300        LValue mode = lowInt32(m_graph.varArgChild(m_node, 3));
     13301        LValue enumerator = lowCell(m_graph.varArgChild(m_node, 4));
     13302
     13303        LBasicBlock isNamedBlock = m_out.newBlock();
     13304        LBasicBlock isCellBlock = m_out.newBlock();
     13305        LBasicBlock matchesStructureBlock = m_out.newBlock();
     13306        LBasicBlock operationBlock = m_out.newBlock();
     13307        LBasicBlock continuation = m_out.newBlock();
     13308
     13309        m_out.branch(m_out.testNonZero32(mode, m_out.constInt32(JSPropertyNameEnumerator::OwnStructureMode)), unsure(isNamedBlock), unsure(operationBlock));
     13310        m_out.appendTo(isNamedBlock);
     13311
     13312        m_out.branch(isCell(base, provenType(baseEdge)), unsure(isCellBlock), unsure(operationBlock));
     13313
     13314        m_out.appendTo(isCellBlock);
     13315        LValue structureID = m_out.load32(base, m_heaps.JSCell_structureID);
     13316        m_out.branch(m_out.equal(structureID, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
     13317            usually(matchesStructureBlock), rarely(operationBlock));
     13318
     13319        m_out.appendTo(matchesStructureBlock);
     13320        ValueFromBlock namedResult = m_out.anchor(m_out.booleanTrue);
     13321        m_out.jump(continuation);
     13322
     13323        m_out.appendTo(operationBlock);
     13324        ValueFromBlock operationResult = m_out.anchor(unboxBoolean(vmCall(Int64, slowPathFunction, weakPointer(globalObject), base, propertyName, index, mode)));
     13325        m_out.jump(continuation);
     13326
     13327        m_out.appendTo(continuation);
     13328        setBoolean(m_out.phi(Int32, namedResult, operationResult));
     13329    }
     13330
     13331    void compileEnumeratorInByVal()
     13332    {
     13333        compileEnumeratorHasProperty(operationEnumeratorInByVal);
     13334    }
     13335
     13336    void compileEnumeratorHasOwnProperty()
     13337    {
     13338        compileEnumeratorHasProperty(operationEnumeratorHasOwnProperty);
    1321913339    }
    1322013340   
    … …  
    1734517465            return;
    1734617466        }
    17347        
     17467
    1734817468        if (m_node->shouldSpeculateInt32() && canSpeculate) {
    1734917469            speculate(
    … …  
    2029720417    }
    2029820418
     20419    // This only works for ints right now.
     20420    PatchpointValue* dataLogForDebugging(const char* prefix, LValue value)
     20421    {
     20422        PatchpointValue* result = m_out.patchpoint(Void);
     20423        result->effects.writesLocalState = true;
     20424        result->append(value, ValueRep::reg(GPRInfo::regT0));
     20425        Type valueType = value->type();
     20426        result->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams&) {
     20427            AllowMacroScratchRegisterUsage allowScratch(jit);
     20428
     20429            jit.probeDebug([=] (Probe::Context& context) {
     20430                if (valueType == Int32)
     20431                    dataLogLn(prefix, context.gpr<int32_t>(GPRInfo::regT0));
     20432                else
     20433                    dataLogLn(prefix, context.gpr<JSValue>(GPRInfo::regT0));
     20434            });
     20435        });
     20436
     20437        return result;
     20438    }
     20439
    2029920440    AvailabilityMap& availabilityMap() { return m_availabilityCalculator.m_availability; }
    2030020441   
  • trunk/Source/JavaScriptCore/ftl/FTLOutput.h

    r280198 r280760  
    11/*
    2  * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
    … …  
    146146    template<typename... Params>
    147147    void addIncomingToPhi(LValue phi, ValueFromBlock, Params... theRest);
     148    template<typename... Params>
     149    void addIncomingToPhiIfSet(LValue phi, Params... theRest);
    148150   
    149151    LValue opaque(LValue);
    … …  
    481483inline LValue Output::phi(LType type, const VectorType& vector)
    482484{
     485    ASSERT(vector.size());
    483486    LValue phiNode = phi(type);
    484487    for (const ValueFromBlock& valueFromBlock : vector)
  • trunk/Source/JavaScriptCore/generator/DSL.rb

    r267489 r280760  
    139139#include "Instruction.h"
    140140#include "IterationModeMetadata.h"
     141#include "JSPropertyNameEnumerator.h"
    141142#include "Opcode.h"
    142143#include "PrivateFieldPutKind.h"
  • trunk/Source/JavaScriptCore/interpreter/Register.h

    r270855 r280760  
    5454        ALWAYS_INLINE Register& operator=(CodeBlock*);
    5555        ALWAYS_INLINE Register& operator=(JSScope*);
    56         ALWAYS_INLINE Register& operator=(JSObject*);
     56        ALWAYS_INLINE Register& operator=(JSCell*);
    5757        ALWAYS_INLINE Register& operator=(EncodedJSValue);
    5858
  • trunk/Source/JavaScriptCore/interpreter/RegisterInlines.h

    r251886 r280760  
    6464}
    6565
    66 ALWAYS_INLINE Register& Register::operator=(JSObject* object)
     66ALWAYS_INLINE Register& Register::operator=(JSCell* object)
    6767{
    6868    u.value = JSValue::encode(JSValue(object));
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h

    r279256 r280760  
    189189#endif
    190190    }
    191    
     191
    192192    void loadValue(Address address, JSValueRegs regs)
    193193    {
    … …  
    890890            Below, Address(cellGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(ObjectType));
    891891    }
    892    
     892
    893893    // Note that first and last are inclusive.
    894894    Jump branchIfType(GPRReg cellGPR, JSTypeRange range)
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r279105 r280760  
    309309        DEFINE_SLOW_OP(new_array_buffer)
    310310        DEFINE_SLOW_OP(spread)
    311         DEFINE_SLOW_OP(get_enumerable_length)
    312         DEFINE_SLOW_OP(has_enumerable_property)
    313311        DEFINE_SLOW_OP(get_property_enumerator)
    314         DEFINE_SLOW_OP(to_index_string)
    315312        DEFINE_SLOW_OP(create_direct_arguments)
    316313        DEFINE_SLOW_OP(create_scoped_arguments)
    … …  
    366363        DEFINE_OP(op_get_by_id_direct)
    367364        DEFINE_OP(op_get_by_val)
     365        DEFINE_OP(op_enumerator_next)
     366        DEFINE_OP(op_enumerator_get_by_val)
     367        DEFINE_OP(op_enumerator_in_by_val)
     368        DEFINE_OP(op_enumerator_has_own_property)
    368369        DEFINE_OP(op_get_private_name)
    369370        DEFINE_OP(op_set_private_brand)
    … …  
    474475        DEFINE_OP(op_put_to_arguments)
    475476
    476         DEFINE_OP(op_has_enumerable_indexed_property)
    477         DEFINE_OP(op_has_enumerable_structure_property)
    478         DEFINE_OP(op_has_own_structure_property)
    479         DEFINE_OP(op_in_structure_property)
    480         DEFINE_OP(op_get_direct_pname)
    481         DEFINE_OP(op_enumerator_structure_pname)
    482         DEFINE_OP(op_enumerator_generic_pname)
    483            
    484477        DEFINE_OP(op_log_shadow_chicken_prologue)
    485478        DEFINE_OP(op_log_shadow_chicken_tail)
    … …  
    579572        DEFINE_SLOWCASE_OP(op_get_by_id_direct)
    580573        DEFINE_SLOWCASE_OP(op_get_by_val)
     574        DEFINE_SLOWCASE_OP(op_enumerator_get_by_val)
    581575        DEFINE_SLOWCASE_OP(op_get_private_name)
    582576        DEFINE_SLOWCASE_OP(op_set_private_brand)
    … …  
    610604        DEFINE_SLOWCASE_OP(op_del_by_id)
    611605        DEFINE_SLOWCASE_OP(op_sub)
    612         DEFINE_SLOWCASE_OP(op_has_enumerable_indexed_property)
    613606#if !ENABLE(EXTRA_CTI_THUNKS)
    614607        DEFINE_SLOWCASE_OP(op_get_from_scope)
    … …  
    643636        DEFINE_SLOWCASE_SLOW_OP(stricteq)
    644637        DEFINE_SLOWCASE_SLOW_OP(nstricteq)
    645         DEFINE_SLOWCASE_SLOW_OP(get_direct_pname)
    646638        DEFINE_SLOWCASE_SLOW_OP(get_prototype_of)
    647         DEFINE_SLOWCASE_SLOW_OP(has_enumerable_structure_property)
    648         DEFINE_SLOWCASE_SLOW_OP(has_own_structure_property)
    649         DEFINE_SLOWCASE_SLOW_OP(in_structure_property)
    650639#if !ENABLE(EXTRA_CTI_THUNKS)
    651640        DEFINE_SLOWCASE_SLOW_OP(resolve_scope)
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r279105 r280760  
    454454        void emitGetVirtualRegister(VirtualRegister src, JSValueRegs dst);
    455455        void emitPutVirtualRegister(VirtualRegister dst, JSValueRegs src);
     456        void emitStore(VirtualRegister, const JSValue constant, RegisterID base = callFrameRegister);
    456457
    457458        int32_t getOperandConstantInt(VirtualRegister src);
    … …  
    470471
    471472        void emitStore(VirtualRegister, RegisterID tag, RegisterID payload, RegisterID base = callFrameRegister);
    472         void emitStore(VirtualRegister, const JSValue constant, RegisterID base = callFrameRegister);
    473473        void emitStoreInt32(VirtualRegister, RegisterID payload, bool indexIsInt32 = false);
    474474        void emitStoreInt32(VirtualRegister, TrustedImm32 payload, bool indexIsInt32 = false);
    … …  
    671671        void emit_op_unsigned(const Instruction*);
    672672        void emit_op_urshift(const Instruction*);
    673         template <typename OpCodeType>
    674         void emit_op_has_structure_propertyImpl(const Instruction*);
    675         void emit_op_has_enumerable_indexed_property(const Instruction*);
    676         void emit_op_has_enumerable_structure_property(const Instruction*);
    677         void emit_op_has_own_structure_property(const Instruction*);
    678         void emit_op_in_structure_property(const Instruction*);
    679         void emit_op_get_direct_pname(const Instruction*);
    680         void emit_op_enumerator_structure_pname(const Instruction*);
    681         void emit_op_enumerator_generic_pname(const Instruction*);
    682673        void emit_op_get_internal_field(const Instruction*);
    683674        void emit_op_put_internal_field(const Instruction*);
    … …  
    685676        void emit_op_log_shadow_chicken_tail(const Instruction*);
    686677        void emit_op_to_property_key(const Instruction*);
     678
     679        template<typename OpcodeType>
     680        void generateGetByValSlowCase(const OpcodeType&, Vector<SlowCaseEntry>::iterator&);
     681
     682        void emit_op_enumerator_next(const Instruction*);
     683        void emit_op_enumerator_get_by_val(const Instruction*);
     684        void emitSlow_op_enumerator_get_by_val(const Instruction*, Vector<SlowCaseEntry>::iterator&);
     685
     686        template<typename OpcodeType, typename SlowPathFunctionType>
     687        void emit_enumerator_has_propertyImpl(const Instruction*, const OpcodeType&, SlowPathFunctionType);
     688        void emit_op_enumerator_in_by_val(const Instruction*);
     689        void emit_op_enumerator_has_own_property(const Instruction*);
    687690
    688691        void emitSlow_op_add(const Instruction*, Vector<SlowCaseEntry>::iterator&);
    … …  
    736739        void emitSlow_op_put_private_name(const Instruction*, Vector<SlowCaseEntry>::iterator&);
    737740        void emitSlow_op_sub(const Instruction*, Vector<SlowCaseEntry>::iterator&);
    738         void emitSlow_op_has_enumerable_indexed_property(const Instruction*, Vector<SlowCaseEntry>::iterator&);
    739741
    740742        void emit_op_resolve_scope(const Instruction*);
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r279216 r280760  
    16931693#if USE(JSVALUE64)
    16941694
    1695 template <typename OpCodeType>
    1696 void JIT::emit_op_has_structure_propertyImpl(const Instruction* currentInstruction)
    1697 {
    1698     auto bytecode = currentInstruction->as<OpCodeType>();
    1699     VirtualRegister dst = bytecode.m_dst;
    1700     VirtualRegister base = bytecode.m_base;
    1701     VirtualRegister enumerator = bytecode.m_enumerator;
    1702 
    1703     emitGetVirtualRegister(base, regT0);
    1704     emitGetVirtualRegister(enumerator, regT1);
    1705     emitJumpSlowCaseIfNotJSCell(regT0, base);
    1706 
    1707     load32(Address(regT0, JSCell::structureIDOffset()), regT0);
    1708     addSlowCase(branch32(NotEqual, regT0, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset())));
    1709    
    1710     move(TrustedImm64(JSValue::encode(jsBoolean(true))), regT0);
    1711     emitPutVirtualRegister(dst);
    1712 }
    1713 
    1714 void JIT::emit_op_has_enumerable_structure_property(const Instruction* currentInstruction)
    1715 {
    1716     emit_op_has_structure_propertyImpl<OpHasEnumerableStructureProperty>(currentInstruction);
    1717 }
    1718 
    1719 void JIT::emit_op_has_own_structure_property(const Instruction* currentInstruction)
    1720 {
    1721     emit_op_has_structure_propertyImpl<OpHasOwnStructureProperty>(currentInstruction);
    1722 }
    1723 
    1724 void JIT::emit_op_in_structure_property(const Instruction* currentInstruction)
    1725 {
    1726     emit_op_has_structure_propertyImpl<OpInStructureProperty>(currentInstruction);
    1727 }
    1728 
    17291695void JIT::privateCompileHasIndexedProperty(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
    17301696{
    17311697    const Instruction* currentInstruction = m_codeBlock->instructions().at(byValInfo->bytecodeIndex).ptr();
    1732    
     1698
    17331699    PatchableJump badType;
    1734    
     1700
    17351701    // FIXME: Add support for other types like TypedArrays and Arguments.
    17361702    // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034.
    … …  
    17401706
    17411707    LinkBuffer patchBuffer(*this, m_codeBlock, LinkBuffer::Profile::InlineCache);
    1742    
     1708
    17431709    patchBuffer.link(badType, byValInfo->slowPathTarget);
    17441710    patchBuffer.link(slowCases, byValInfo->slowPathTarget);
    … …  
    17491715        m_codeBlock, patchBuffer, JITStubRoutinePtrTag,
    17501716        "Baseline has_indexed_property stub for %s, return point %p", toCString(*m_codeBlock).data(), returnAddress.untaggedValue());
    1751    
     1717
    17521718    if (JITCode::useDataIC(JITType::BaselineJIT)) {
    17531719        byValInfo->m_badTypeJumpTarget = CodeLocationLabel<JITStubRoutinePtrTag>(byValInfo->stubRoutine->code().code());
    … …  
    17571723        MacroAssembler::repatchCall(CodeLocationCall<ReturnAddressPtrTag>(MacroAssemblerCodePtr<ReturnAddressPtrTag>(returnAddress)), FunctionPtr<OperationPtrTag>(operationHasIndexedPropertyGeneric));
    17581724    }
    1759 }
    1760 
    1761 void JIT::emit_op_has_enumerable_indexed_property(const Instruction* currentInstruction)
    1762 {
    1763     auto bytecode = currentInstruction->as<OpHasEnumerableIndexedProperty>();
    1764     auto& metadata = bytecode.metadata(m_codeBlock);
    1765     VirtualRegister dst = bytecode.m_dst;
    1766     VirtualRegister base = bytecode.m_base;
    1767     VirtualRegister property = bytecode.m_property;
    1768     ArrayProfile* profile = &metadata.m_arrayProfile;
    1769     ByValInfo* byValInfo = m_codeBlock->addByValInfo(m_bytecodeIndex);
    1770    
    1771     emitGetVirtualRegisters(base, regT0, property, regT1);
    1772 
    1773     emitJumpSlowCaseIfNotInt(regT1);
    1774 
    1775     // This is technically incorrect - we're zero-extending an int32. On the hot path this doesn't matter.
    1776     // We check the value as if it was a uint32 against the m_vectorLength - which will always fail if
    1777     // number was signed since m_vectorLength is always less than intmax (since the total allocation
    1778     // size is always less than 4Gb). As such zero extending will have been correct (and extending the value
    1779     // to 64-bits is necessary since it's used in the address calculation. We zero extend rather than sign
    1780     // extending since it makes it easier to re-tag the value in the slow case.
    1781     zeroExtend32ToWord(regT1, regT1);
    1782 
    1783     emitJumpSlowCaseIfNotJSCell(regT0, base);
    1784     emitArrayProfilingSiteWithCell(regT0, regT2, profile);
    1785     and32(TrustedImm32(IndexingShapeMask), regT2);
    1786 
    1787     JITArrayMode mode = chooseArrayMode(profile);
    1788     PatchableJump badType;
    1789 
    1790     // FIXME: Add support for other types like TypedArrays and Arguments.
    1791     // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034.
    1792     JumpList slowCases = emitLoadForArrayMode(currentInstruction, mode, badType, byValInfo);
    1793    
    1794     move(TrustedImm64(JSValue::encode(jsBoolean(true))), regT0);
    1795 
    1796     if (!JITCode::useDataIC(JITType::BaselineJIT))
    1797         addSlowCase(badType);
    1798     addSlowCase(slowCases);
    1799    
    1800     Label done = label();
    1801    
    1802     emitPutVirtualRegister(dst);
    1803 
    1804     Label nextHotPath = label();
    1805    
    1806     m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeIndex, PatchableJump(), badType, mode, profile, done, nextHotPath));
    1807 }
    1808 
    1809 void JIT::emitSlow_op_has_enumerable_indexed_property(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    1810 {
    1811     linkAllSlowCases(iter);
    1812 
    1813     auto bytecode = currentInstruction->as<OpHasEnumerableIndexedProperty>();
    1814     VirtualRegister dst = bytecode.m_dst;
    1815     VirtualRegister base = bytecode.m_base;
    1816     VirtualRegister property = bytecode.m_property;
    1817     ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;
    1818 
    1819     Label slowPath = label();
    1820    
    1821     emitGetVirtualRegister(base, regT0);
    1822     emitGetVirtualRegister(property, regT1);
    1823 
    1824     Call call;
    1825     if (JITCode::useDataIC(JITType::BaselineJIT)) {
    1826         byValInfo->m_slowOperation = operationHasIndexedPropertyDefault;
    1827         move(TrustedImmPtr(byValInfo), GPRInfo::nonArgGPR0);
    1828         callOperation<decltype(operationHasIndexedPropertyDefault)>(Address(GPRInfo::nonArgGPR0, ByValInfo::offsetOfSlowOperation()), dst, TrustedImmPtr(m_codeBlock->globalObject()), regT0, regT1, GPRInfo::nonArgGPR0);
    1829     } else
    1830         call = callOperation(operationHasIndexedPropertyDefault, dst, TrustedImmPtr(m_codeBlock->globalObject()), regT0, regT1, byValInfo);
    1831 
    1832     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
    1833     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
    1834     m_byValInstructionIndex++;
    1835 }
    1836 
    1837 void JIT::emit_op_get_direct_pname(const Instruction* currentInstruction)
    1838 {
    1839     auto bytecode = currentInstruction->as<OpGetDirectPname>();
    1840     VirtualRegister dst = bytecode.m_dst;
    1841     VirtualRegister base = bytecode.m_base;
    1842     VirtualRegister index = bytecode.m_index;
    1843     VirtualRegister enumerator = bytecode.m_enumerator;
    1844 
    1845     // Check that base is a cell
    1846     emitGetVirtualRegister(base, regT0);
    1847     emitJumpSlowCaseIfNotJSCell(regT0, base);
    1848 
    1849     // Check the structure
    1850     emitGetVirtualRegister(enumerator, regT2);
    1851     load32(Address(regT0, JSCell::structureIDOffset()), regT1);
    1852     addSlowCase(branch32(NotEqual, regT1, Address(regT2, JSPropertyNameEnumerator::cachedStructureIDOffset())));
    1853 
    1854     // Compute the offset
    1855     emitGetVirtualRegister(index, regT1);
    1856     // If index is less than the enumerator's cached inline storage, then it's an inline access
    1857     Jump outOfLineAccess = branch32(AboveOrEqual, regT1, Address(regT2, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
    1858     addPtr(TrustedImm32(JSObject::offsetOfInlineStorage()), regT0);
    1859     signExtend32ToPtr(regT1, regT1);
    1860     load64(BaseIndex(regT0, regT1, TimesEight), regT0);
    1861    
    1862     Jump done = jump();
    1863 
    1864     // Otherwise it's out of line
    1865     outOfLineAccess.link(this);
    1866     loadPtr(Address(regT0, JSObject::butterflyOffset()), regT0);
    1867     sub32(Address(regT2, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), regT1);
    1868     neg32(regT1);
    1869     signExtend32ToPtr(regT1, regT1);
    1870     int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
    1871     load64(BaseIndex(regT0, regT1, TimesEight, offsetOfFirstProperty), regT0);
    1872    
    1873     done.link(this);
    1874     emitValueProfilingSite(bytecode.metadata(m_codeBlock), regT0);
    1875     emitPutVirtualRegister(dst, regT0);
    1876 }
    1877 
    1878 void JIT::emit_op_enumerator_structure_pname(const Instruction* currentInstruction)
    1879 {
    1880     auto bytecode = currentInstruction->as<OpEnumeratorStructurePname>();
    1881     VirtualRegister dst = bytecode.m_dst;
    1882     VirtualRegister enumerator = bytecode.m_enumerator;
    1883     VirtualRegister index = bytecode.m_index;
    1884 
    1885     emitGetVirtualRegister(index, regT0);
    1886     emitGetVirtualRegister(enumerator, regT1);
    1887     Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()));
    1888 
    1889     move(TrustedImm64(JSValue::encode(jsNull())), regT0);
    1890 
    1891     Jump done = jump();
    1892     inBounds.link(this);
    1893 
    1894     loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1);
    1895     signExtend32ToPtr(regT0, regT0);
    1896     load64(BaseIndex(regT1, regT0, TimesEight), regT0);
    1897 
    1898     done.link(this);
    1899     emitPutVirtualRegister(dst);
    1900 }
    1901 
    1902 void JIT::emit_op_enumerator_generic_pname(const Instruction* currentInstruction)
    1903 {
    1904     auto bytecode = currentInstruction->as<OpEnumeratorGenericPname>();
    1905     VirtualRegister dst = bytecode.m_dst;
    1906     VirtualRegister enumerator = bytecode.m_enumerator;
    1907     VirtualRegister index = bytecode.m_index;
    1908 
    1909     emitGetVirtualRegister(index, regT0);
    1910     emitGetVirtualRegister(enumerator, regT1);
    1911     Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
    1912 
    1913     move(TrustedImm64(JSValue::encode(jsNull())), regT0);
    1914 
    1915     Jump done = jump();
    1916     inBounds.link(this);
    1917 
    1918     loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1);
    1919     signExtend32ToPtr(regT0, regT0);
    1920     load64(BaseIndex(regT1, regT0, TimesEight), regT0);
    1921    
    1922     done.link(this);
    1923     emitPutVirtualRegister(dst);
    19241725}
    19251726
  • trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp

    r279049 r280760  
    11431143}
    11441144
    1145 template <typename OpCodeType>
    1146 void JIT::emit_op_has_structure_propertyImpl(const Instruction* currentInstruction)
    1147 {
    1148     auto bytecode = currentInstruction->as<OpCodeType>();
    1149     VirtualRegister dst = bytecode.m_dst;
    1150     VirtualRegister base = bytecode.m_base;
    1151     VirtualRegister enumerator = bytecode.m_enumerator;
    1152 
    1153     emitLoadPayload(base, regT0);
    1154     emitJumpSlowCaseIfNotJSCell(base);
    1155 
    1156     emitLoadPayload(enumerator, regT1);
    1157 
    1158     load32(Address(regT0, JSCell::structureIDOffset()), regT0);
    1159     addSlowCase(branch32(NotEqual, regT0, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset())));
    1160    
    1161     move(TrustedImm32(1), regT0);
    1162     emitStoreBool(dst, regT0);
    1163 }
    1164 
    1165 void JIT::emit_op_has_enumerable_structure_property(const Instruction* currentInstruction)
    1166 {
    1167     emit_op_has_structure_propertyImpl<OpHasEnumerableStructureProperty>(currentInstruction);
    1168 }
    1169 
    1170 void JIT::emit_op_has_own_structure_property(const Instruction* currentInstruction)
    1171 {
    1172     emit_op_has_structure_propertyImpl<OpHasOwnStructureProperty>(currentInstruction);
    1173 }
    1174 
    1175 void JIT::emit_op_in_structure_property(const Instruction* currentInstruction)
    1176 {
    1177     emit_op_has_structure_propertyImpl<OpInStructureProperty>(currentInstruction);
    1178 }
    1179 
    11801145void JIT::privateCompileHasIndexedProperty(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
    11811146{
    11821147    const Instruction* currentInstruction = m_codeBlock->instructions().at(byValInfo->bytecodeIndex).ptr();
    1183    
     1148
    11841149    PatchableJump badType;
    1185    
     1150
    11861151    // FIXME: Add support for other types like TypedArrays and Arguments.
    11871152    // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034.
    … …  
    11911156
    11921157    LinkBuffer patchBuffer(*this, m_codeBlock, LinkBuffer::Profile::InlineCache);
    1193    
     1158
    11941159    patchBuffer.link(badType, byValInfo->slowPathTarget);
    11951160    patchBuffer.link(slowCases, byValInfo->slowPathTarget);
    … …  
    12001165        m_codeBlock, patchBuffer, JITStubRoutinePtrTag,
    12011166        "Baseline has_indexed_property stub for %s, return point %p", toCString(*m_codeBlock).data(), returnAddress.untaggedValue());
    1202    
     1167
    12031168    MacroAssembler::repatchJump(byValInfo->m_badTypeJump, CodeLocationLabel<JITStubRoutinePtrTag>(byValInfo->stubRoutine->code().code()));
    12041169    MacroAssembler::repatchCall(CodeLocationCall<ReturnAddressPtrTag>(MacroAssemblerCodePtr<ReturnAddressPtrTag>(returnAddress)), FunctionPtr<OperationPtrTag>(operationHasIndexedPropertyGeneric));
    1205 }
    1206 
    1207 void JIT::emit_op_has_enumerable_indexed_property(const Instruction* currentInstruction)
    1208 {
    1209     auto bytecode = currentInstruction->as<OpHasEnumerableIndexedProperty>();
    1210     auto& metadata = bytecode.metadata(m_codeBlock);
    1211     VirtualRegister dst = bytecode.m_dst;
    1212     VirtualRegister base = bytecode.m_base;
    1213     VirtualRegister property = bytecode.m_property;
    1214     ArrayProfile* profile = &metadata.m_arrayProfile;
    1215     ByValInfo* byValInfo = m_codeBlock->addByValInfo(m_bytecodeIndex);
    1216    
    1217     emitLoadPayload(base, regT0);
    1218     emitJumpSlowCaseIfNotJSCell(base);
    1219 
    1220     emitLoad(property, regT3, regT1);
    1221     addSlowCase(branchIfNotInt32(regT3));
    1222 
    1223     // This is technically incorrect - we're zero-extending an int32. On the hot path this doesn't matter.
    1224     // We check the value as if it was a uint32 against the m_vectorLength - which will always fail if
    1225     // number was signed since m_vectorLength is always less than intmax (since the total allocation
    1226     // size is always less than 4Gb). As such zero extending will have been correct (and extending the value
    1227     // to 64-bits is necessary since it's used in the address calculation. We zero extend rather than sign
    1228     // extending since it makes it easier to re-tag the value in the slow case.
    1229     zeroExtend32ToWord(regT1, regT1);
    1230 
    1231     emitArrayProfilingSiteWithCell(regT0, regT2, profile);
    1232     and32(TrustedImm32(IndexingShapeMask), regT2);
    1233 
    1234     JITArrayMode mode = chooseArrayMode(profile);
    1235     PatchableJump badType;
    1236 
    1237     // FIXME: Add support for other types like TypedArrays and Arguments.
    1238     // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034.
    1239     JumpList slowCases = emitLoadForArrayMode(currentInstruction, mode, badType, byValInfo);
    1240     move(TrustedImm32(1), regT0);
    1241 
    1242     addSlowCase(badType);
    1243     addSlowCase(slowCases);
    1244    
    1245     Label done = label();
    1246    
    1247     emitStoreBool(dst, regT0);
    1248 
    1249     Label nextHotPath = label();
    1250    
    1251     m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeIndex, PatchableJump(), badType, mode, profile, done, nextHotPath));
    1252 }
    1253 
    1254 void JIT::emitSlow_op_has_enumerable_indexed_property(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    1255 {
    1256     linkAllSlowCases(iter);
    1257 
    1258     auto bytecode = currentInstruction->as<OpHasEnumerableIndexedProperty>();
    1259     VirtualRegister dst = bytecode.m_dst;
    1260     VirtualRegister base = bytecode.m_base;
    1261     VirtualRegister property = bytecode.m_property;
    1262     ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;
    1263 
    1264     Label slowPath = label();
    1265    
    1266     emitLoad(base, regT1, regT0);
    1267     emitLoad(property, regT3, regT2);
    1268     Call call = callOperation(operationHasIndexedPropertyDefault, dst, m_codeBlock->globalObject(), JSValueRegs(regT1, regT0), JSValueRegs(regT3, regT2), byValInfo);
    1269 
    1270     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
    1271     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
    1272     m_byValInstructionIndex++;
    1273 }
    1274 
    1275 void JIT::emit_op_get_direct_pname(const Instruction* currentInstruction)
    1276 {
    1277     auto bytecode = currentInstruction->as<OpGetDirectPname>();
    1278     VirtualRegister dst = bytecode.m_dst;
    1279     VirtualRegister base = bytecode.m_base;
    1280     VirtualRegister index = bytecode.m_index;
    1281     VirtualRegister enumerator = bytecode.m_enumerator;
    1282 
    1283     // Check that base is a cell
    1284     emitLoadPayload(base, regT0);
    1285     emitJumpSlowCaseIfNotJSCell(base);
    1286 
    1287     // Check the structure
    1288     emitLoadPayload(enumerator, regT1);
    1289     load32(Address(regT0, JSCell::structureIDOffset()), regT2);
    1290     addSlowCase(branch32(NotEqual, regT2, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset())));
    1291 
    1292     // Compute the offset
    1293     emitLoadPayload(index, regT2);
    1294     // If index is less than the enumerator's cached inline storage, then it's an inline access
    1295     Jump outOfLineAccess = branch32(AboveOrEqual, regT2, Address(regT1, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
    1296     addPtr(TrustedImm32(JSObject::offsetOfInlineStorage()), regT0);
    1297     load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
    1298     load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
    1299    
    1300     Jump done = jump();
    1301 
    1302     // Otherwise it's out of line
    1303     outOfLineAccess.link(this);
    1304     loadPtr(Address(regT0, JSObject::butterflyOffset()), regT0);
    1305     sub32(Address(regT1, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), regT2);
    1306     neg32(regT2);
    1307     int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
    1308     load32(BaseIndex(regT0, regT2, TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
    1309     load32(BaseIndex(regT0, regT2, TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
    1310    
    1311     done.link(this);
    1312     emitValueProfilingSite(bytecode.metadata(m_codeBlock), JSValueRegs(regT1, regT0));
    1313     emitStore(dst, regT1, regT0);
    1314 }
    1315 
    1316 void JIT::emit_op_enumerator_structure_pname(const Instruction* currentInstruction)
    1317 {
    1318     auto bytecode = currentInstruction->as<OpEnumeratorStructurePname>();
    1319     VirtualRegister dst = bytecode.m_dst;
    1320     VirtualRegister enumerator = bytecode.m_enumerator;
    1321     VirtualRegister index = bytecode.m_index;
    1322 
    1323     emitLoadPayload(index, regT0);
    1324     emitLoadPayload(enumerator, regT1);
    1325     Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()));
    1326 
    1327     move(TrustedImm32(JSValue::NullTag), regT2);
    1328     move(TrustedImm32(0), regT0);
    1329 
    1330     Jump done = jump();
    1331     inBounds.link(this);
    1332 
    1333     loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1);
    1334     loadPtr(BaseIndex(regT1, regT0, ScalePtr), regT0);
    1335     move(TrustedImm32(JSValue::CellTag), regT2);
    1336 
    1337     done.link(this);
    1338     emitStore(dst, regT2, regT0);
    1339 }
    1340 
    1341 void JIT::emit_op_enumerator_generic_pname(const Instruction* currentInstruction)
    1342 {
    1343     auto bytecode = currentInstruction->as<OpEnumeratorGenericPname>();
    1344     VirtualRegister dst = bytecode.m_dst;
    1345     VirtualRegister enumerator = bytecode.m_enumerator;
    1346     VirtualRegister index = bytecode.m_index;
    1347 
    1348     emitLoadPayload(index, regT0);
    1349     emitLoadPayload(enumerator, regT1);
    1350     Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
    1351 
    1352     move(TrustedImm32(JSValue::NullTag), regT2);
    1353     move(TrustedImm32(0), regT0);
    1354 
    1355     Jump done = jump();
    1356     inBounds.link(this);
    1357 
    1358     loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1);
    1359     loadPtr(BaseIndex(regT1, regT0, ScalePtr), regT0);
    1360     move(TrustedImm32(JSValue::CellTag), regT2);
    1361    
    1362     done.link(this);
    1363     emitStore(dst, regT2, regT0);
    13641170}
    13651171
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp

    r279105 r280760  
    3737#include "LinkBuffer.h"
    3838#include "PrivateFieldPutKind.h"
     39#include "ProbeContext.h"
    3940#include "SlowPathCall.h"
    4041#include "StructureStubInfo.h"
    … …  
    8788}
    8889
    89 void JIT::emitSlow_op_get_by_val(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     90template<typename OpcodeType>
     91void JIT::generateGetByValSlowCase(const OpcodeType& bytecode, Vector<SlowCaseEntry>::iterator& iter)
    9092{
    9193    if (hasAnySlowCases(iter)) {
    92         auto bytecode = currentInstruction->as<OpGetByVal>();
    9394        VirtualRegister dst = bytecode.m_dst;
    9495        auto& metadata = bytecode.metadata(m_codeBlock);
    … …  
    135136        gen.reportSlowPathCall(coldPathBegin, call);
    136137    }
     138}
     139
     140void JIT::emitSlow_op_get_by_val(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     141{
     142    generateGetByValSlowCase(currentInstruction->as<OpGetByVal>(), iter);
    137143}
    138144
    … …  
    29782984template void JIT::emit_op_put_by_val<OpPutByVal>(const Instruction*);
    29792985
     2986void JIT::emit_op_enumerator_next(const Instruction* currentInstruction)
     2987{
     2988    auto bytecode = currentInstruction->as<OpEnumeratorNext>();
     2989    auto& metadata = bytecode.metadata(m_codeBlock);
     2990
     2991    VirtualRegister base = bytecode.m_base;
     2992    VirtualRegister mode = bytecode.m_mode;
     2993    VirtualRegister index = bytecode.m_index;
     2994    VirtualRegister propertyName = bytecode.m_propertyName;
     2995    VirtualRegister enumerator = bytecode.m_enumerator;
     2996
     2997    JumpList done;
     2998    JumpList operationCases;
     2999
     3000    GPRReg modeGPR = regT0;
     3001    GPRReg indexGPR = regT1;
     3002    GPRReg baseGPR = regT2;
     3003
     3004    // This is the most common mode set we tend to see, so special case it if we profile it in the LLInt.
     3005    if (metadata.m_enumeratorMetadata == JSPropertyNameEnumerator::OwnStructureMode) {
     3006        GPRReg enumeratorGPR = regT3;
     3007        emitGetVirtualRegister(enumerator, enumeratorGPR);
     3008        operationCases.append(branchTest32(NonZero, Address(enumeratorGPR, JSPropertyNameEnumerator::modeSetOffset()), TrustedImm32(~JSPropertyNameEnumerator::OwnStructureMode)));
     3009        emitGetVirtualRegister(base, baseGPR);
     3010        load32(Address(enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset()), indexGPR);
     3011        operationCases.append(branch32(NotEqual, indexGPR, Address(baseGPR, JSCell::structureIDOffset())));
     3012
     3013        emitGetVirtualRegister(mode, modeGPR);
     3014        emitGetVirtualRegister(index, indexGPR);
     3015        Jump notInit = branchTest32(Zero, modeGPR);
     3016        // Need to use add64 since this is a JSValue int32.
     3017        add64(TrustedImm32(1), indexGPR);
     3018        emitPutVirtualRegister(index, indexGPR);
     3019        notInit.link(this);
     3020        storeTrustedValue(jsNumber(static_cast<uint8_t>(JSPropertyNameEnumerator::OwnStructureMode)), addressFor(mode));
     3021
     3022        Jump outOfBounds = branch32(AboveOrEqual, indexGPR, Address(enumeratorGPR, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()));
     3023        loadPtr(Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), enumeratorGPR);
     3024        // We need to clear the high bits from the number encoding.
     3025        and32(TrustedImm32(-1), indexGPR);
     3026        loadPtr(BaseIndex(enumeratorGPR, indexGPR, ScalePtr), enumeratorGPR);
     3027
     3028        emitPutVirtualRegister(propertyName, enumeratorGPR);
     3029        done.append(jump());
     3030
     3031        outOfBounds.link(this);
     3032        storeTrustedValue(jsNull(), addressFor(propertyName));
     3033        done.append(jump());
     3034    }
     3035
     3036    operationCases.link(this);
     3037
     3038    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_enumerator_next);
     3039    slowPathCall.call();
     3040
     3041    done.link(this);
     3042}
     3043
     3044void JIT::emit_op_enumerator_get_by_val(const Instruction* currentInstruction)
     3045{
     3046    auto bytecode = currentInstruction->as<OpEnumeratorGetByVal>();
     3047    auto& metadata = bytecode.metadata(m_codeBlock);
     3048    VirtualRegister dst = bytecode.m_dst;
     3049    VirtualRegister mode = bytecode.m_mode;
     3050    VirtualRegister base = bytecode.m_base;
     3051    VirtualRegister index = bytecode.m_index;
     3052    VirtualRegister propertyName = bytecode.m_propertyName;
     3053    VirtualRegister enumerator = bytecode.m_enumerator;
     3054    ArrayProfile* profile = &metadata.m_arrayProfile;
     3055
     3056    JumpList doneCases;
     3057
     3058    auto resultGPR = regT0;
     3059
     3060    emitGetVirtualRegister(base, regT0);
     3061    emitGetVirtualRegister(mode, regT2);
     3062    emitGetVirtualRegister(propertyName, regT1);
     3063
     3064    or8(regT2, AbsoluteAddress(&metadata.m_enumeratorMetadata));
     3065
     3066    addSlowCase(branchIfNotCell(regT0));
     3067    // This is always an int32 encoded value.
     3068    Jump isNotOwnStructureMode = branchTest32(NonZero, regT2, TrustedImm32(JSPropertyNameEnumerator::IndexedMode | JSPropertyNameEnumerator::GenericMode));
     3069
     3070    // Check the structure
     3071    emitGetVirtualRegister(enumerator, regT2);
     3072    load32(Address(regT0, JSCell::structureIDOffset()), regT3);
     3073    Jump structureMismatch = branch32(NotEqual, regT3, Address(regT2, JSPropertyNameEnumerator::cachedStructureIDOffset()));
     3074
     3075    // Compute the offset.
     3076    emitGetVirtualRegister(index, regT3);
     3077    // If index is less than the enumerator's cached inline storage, then it's an inline access
     3078    Jump outOfLineAccess = branch32(AboveOrEqual, regT3, Address(regT2, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
     3079    addPtr(TrustedImm32(JSObject::offsetOfInlineStorage()), regT0);
     3080    signExtend32ToPtr(regT3, regT3);
     3081    load64(BaseIndex(regT0, regT3, TimesEight), resultGPR);
     3082
     3083    doneCases.append(jump());
     3084
     3085    // Otherwise it's out of line
     3086    outOfLineAccess.link(this);
     3087    loadPtr(Address(regT0, JSObject::butterflyOffset()), regT0);
     3088    sub32(Address(regT2, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), regT3);
     3089    neg32(regT3);
     3090    signExtend32ToPtr(regT3, regT3);
     3091    int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
     3092    load64(BaseIndex(regT0, regT3, TimesEight, offsetOfFirstProperty), resultGPR);
     3093    doneCases.append(jump());
     3094
     3095    structureMismatch.link(this);
     3096    store8(TrustedImm32(JSPropertyNameEnumerator::HasSeenOwnStructureModeStructureMismatch), &metadata.m_enumeratorMetadata);
     3097
     3098    isNotOwnStructureMode.link(this);
     3099    Jump isNotIndexed = branchTest32(Zero, regT2, TrustedImm32(JSPropertyNameEnumerator::IndexedMode));
     3100    // Replace the string with the index.
     3101    emitGetVirtualRegister(index, regT1);
     3102
     3103    isNotIndexed.link(this);
     3104    emitArrayProfilingSiteWithCell(regT0, regT2, profile);
     3105
     3106    JITGetByValGenerator gen(
     3107        m_codeBlock, JITType::BaselineJIT, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), AccessType::GetByVal, RegisterSet::stubUnavailableRegisters(),
     3108        JSValueRegs(regT0), JSValueRegs(regT1), JSValueRegs(resultGPR), regT2);
     3109    gen.generateFastPath(*this);
     3110    if (!JITCode::useDataIC(JITType::BaselineJIT))
     3111        addSlowCase(gen.slowPathJump());
     3112    else
     3113        addSlowCase();
     3114    m_getByVals.append(gen);
     3115
     3116    doneCases.link(this);
     3117
     3118    emitValueProfilingSite(metadata, JSValueRegs(resultGPR));
     3119    emitPutVirtualRegister(dst);
     3120}
     3121
     3122void JIT::emitSlow_op_enumerator_get_by_val(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     3123{
     3124    generateGetByValSlowCase(currentInstruction->as<OpEnumeratorGetByVal>(), iter);
     3125}
     3126
     3127template <typename OpcodeType, typename SlowPathFunctionType>
     3128void JIT::emit_enumerator_has_propertyImpl(const Instruction* currentInstruction, const OpcodeType& bytecode, SlowPathFunctionType generalCase)
     3129{
     3130    auto& metadata = bytecode.metadata(m_codeBlock);
     3131    VirtualRegister dst = bytecode.m_dst;
     3132    VirtualRegister base = bytecode.m_base;
     3133    VirtualRegister enumerator = bytecode.m_enumerator;
     3134    VirtualRegister mode = bytecode.m_mode;
     3135
     3136    JumpList slowCases;
     3137
     3138    emitGetVirtualRegister(mode, regT0);
     3139    or8(regT0, AbsoluteAddress(&metadata.m_enumeratorMetadata));
     3140
     3141    slowCases.append(branchTest32(Zero, regT0, TrustedImm32(JSPropertyNameEnumerator::OwnStructureMode)));
     3142
     3143    emitGetVirtualRegister(base, regT0);
     3144
     3145    slowCases.append(branchIfNotCell(regT0));
     3146
     3147    emitGetVirtualRegister(enumerator, regT1);
     3148    load32(Address(regT0, JSCell::structureIDOffset()), regT0);
     3149    slowCases.append(branch32(NotEqual, regT0, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset())));
     3150
     3151    move(TrustedImm64(JSValue::encode(jsBoolean(true))), regT0);
     3152    emitPutVirtualRegister(dst);
     3153    Jump done = jump();
     3154
     3155    slowCases.link(this);
     3156
     3157    JITSlowPathCall slowPathCall(this, currentInstruction, generalCase);
     3158    slowPathCall.call();
     3159
     3160    done.link(this);
     3161}
     3162
     3163void JIT::emit_op_enumerator_in_by_val(const Instruction* currentInstruction)
     3164{
     3165    emit_enumerator_has_propertyImpl(currentInstruction, currentInstruction->as<OpEnumeratorInByVal>(), slow_path_enumerator_in_by_val);
     3166}
     3167
     3168void JIT::emit_op_enumerator_has_own_property(const Instruction* currentInstruction)
     3169{
     3170    emit_enumerator_has_propertyImpl(currentInstruction, currentInstruction->as<OpEnumeratorHasOwnProperty>(), slow_path_enumerator_has_own_property);
     3171}
     3172
    29803173#else // USE(JSVALUE64)
    29813174
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp

    r279105 r280760  
    15061506template void JIT::emit_op_put_by_val<OpPutByVal>(const Instruction*);
    15071507
     1508void JIT::emit_op_enumerator_next(const Instruction* currentInstruction)
     1509{
     1510    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_enumerator_next);
     1511    slowPathCall.call();
     1512}
     1513
     1514void JIT::emit_op_enumerator_get_by_val(const Instruction* currentInstruction)
     1515{
     1516    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_enumerator_get_by_val);
     1517    slowPathCall.call();
     1518}
     1519
     1520void JIT::emitSlow_op_enumerator_get_by_val(const Instruction*, Vector<SlowCaseEntry>::iterator&)
     1521{
     1522    UNREACHABLE_FOR_PLATFORM();
     1523}
     1524
     1525void JIT::emit_op_enumerator_in_by_val(const Instruction* currentInstruction)
     1526{
     1527    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_enumerator_in_by_val);
     1528    slowPathCall.call();
     1529}
     1530
     1531void JIT::emit_op_enumerator_has_own_property(const Instruction* currentInstruction)
     1532{
     1533    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_enumerator_has_own_property);
     1534    slowPathCall.call();
     1535}
     1536
    15081537} // namespace JSC
    15091538
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm

    r279343 r280760  
    19931993slowPathOp(define_accessor_property)
    19941994slowPathOp(define_data_property)
    1995 slowPathOp(enumerator_generic_pname)
    1996 slowPathOp(enumerator_structure_pname)
    19971995slowPathOp(get_by_val_with_this)
    1998 slowPathOp(get_direct_pname)
    1999 slowPathOp(get_enumerable_length)
    20001996slowPathOp(get_property_enumerator)
    2001 slowPathOp(has_enumerable_indexed_property)
    2002 slowPathOp(has_enumerable_property)
     1997slowPathOp(enumerator_next)
     1998slowPathOp(enumerator_get_by_val)
     1999slowPathOp(enumerator_in_by_val)
     2000slowPathOp(enumerator_has_own_property)
    20032001
    20042002if not JSVALUE64
    2005     slowPathOp(has_enumerable_structure_property)
    2006     slowPathOp(has_own_structure_property)
    2007     slowPathOp(in_structure_property)
    20082003    slowPathOp(get_prototype_of)
    20092004end
    … …  
    20222017slowPathOp(strcat)
    20232018slowPathOp(throw_static_error)
    2024 slowPathOp(to_index_string)
    20252019slowPathOp(typeof)
    20262020slowPathOp(typeof_is_object)
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r279343 r280760  
    31423142end)
    31433143
    3144 macro hasStructurePropertyImpl(size, get, dispatch, return, slowPathCall)
    3145     get(m_base, t0)
    3146     loadConstantOrVariable(size, t0, t1)
    3147     btqnz t1, notCellMask, .slowPath
    3148 
    3149     loadVariable(get, m_enumerator, t0)
    3150     loadi JSCell::m_structureID[t1], t1
    3151     bineq t1, JSPropertyNameEnumerator::m_cachedStructureID[t0], .slowPath
    3152 
    3153     return(ValueTrue)
    3154 
    3155 .slowPath:
    3156     callSlowPath(slowPathCall)
    3157     dispatch()
    3158 end
    3159 
    3160 llintOpWithReturn(op_has_enumerable_structure_property, OpHasEnumerableStructureProperty, macro (size, get, dispatch, return)
    3161     hasStructurePropertyImpl(size, get, dispatch,  return, _slow_path_has_enumerable_structure_property)
    3162 end)
    3163 
    3164 llintOpWithReturn(op_has_own_structure_property, OpHasOwnStructureProperty, macro (size, get, dispatch, return)
    3165     hasStructurePropertyImpl(size, get, dispatch,  return, _slow_path_has_own_structure_property)
    3166 end)
    3167 
    3168 llintOpWithReturn(op_in_structure_property, OpInStructureProperty, macro (size, get, dispatch, return)
    3169     hasStructurePropertyImpl(size, get, dispatch,  return, _slow_path_in_structure_property)
    3170 end)
    3171 
    31723144op(fuzzer_return_early_from_loop_hint, macro ()
    31733145    loadp CodeBlock[cfr], t0
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r279105 r280760  
    963963}
    964964
    965 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_get_enumerable_length)
    966 {
    967     BEGIN();
    968     auto bytecode = pc->as<OpGetEnumerableLength>();
    969     JSValue enumeratorValue = GET_C(bytecode.m_base).jsValue();
    970     if (enumeratorValue.isUndefinedOrNull())
    971         RETURN(jsNumber(0));
    972 
    973     JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorValue.asCell());
    974 
    975     RETURN(jsNumber(enumerator->indexedLength()));
    976 }
    977 
    978 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_has_enumerable_indexed_property)
    979 {
    980     BEGIN();
    981     auto bytecode = pc->as<OpHasEnumerableIndexedProperty>();
    982     auto& metadata = bytecode.metadata(codeBlock);
    983     JSObject* base = GET_C(bytecode.m_base).jsValue().toObject(globalObject);
    984     CHECK_EXCEPTION();
    985     JSValue property = GET(bytecode.m_property).jsValue();
    986     metadata.m_arrayProfile.observeStructure(base->structure(vm));
    987     ASSERT(property.isUInt32AsAnyInt());
    988     RETURN(jsBoolean(base->hasEnumerableProperty(globalObject, property.asUInt32AsAnyInt())));
    989 }
    990 
    991 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_has_enumerable_structure_property)
    992 {
    993     BEGIN();
    994     auto bytecode = pc->as<OpHasEnumerableStructureProperty>();
    995     JSObject* base = GET_C(bytecode.m_base).jsValue().toObject(globalObject);
    996     CHECK_EXCEPTION();
    997     JSValue property = GET(bytecode.m_property).jsValue();
    998     RELEASE_ASSERT(property.isString());
    999 #if USE(JSVALUE32_64)
    1000     JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
    1001     if (base->structure(vm)->id() == enumerator->cachedStructureID())
    1002         RETURN(jsBoolean(true));
    1003 #endif
    1004     JSString* string = asString(property);
    1005     auto propertyName = string->toIdentifier(globalObject);
    1006     CHECK_EXCEPTION();
    1007     RETURN(jsBoolean(base->hasEnumerableProperty(globalObject, propertyName)));
    1008 }
    1009 
    1010 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_has_own_structure_property)
    1011 {
    1012     BEGIN();
    1013     auto bytecode = pc->as<OpHasOwnStructureProperty>();
    1014     JSValue base = GET_C(bytecode.m_base).jsValue();
    1015 
    1016 #if USE(JSVALUE32_64)
    1017     JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
    1018     if (base.isCell() && base.asCell()->structure(vm)->id() == enumerator->cachedStructureID())
    1019         RETURN(jsBoolean(true));
    1020 #endif
    1021 
    1022     JSValue property = GET(bytecode.m_property).jsValue();
    1023     RELEASE_ASSERT(property.isString());
    1024     JSString* string = asString(property);
    1025     auto propertyName = string->toIdentifier(globalObject);
    1026     CHECK_EXCEPTION();
    1027 
    1028     RETURN(jsBoolean(objectPrototypeHasOwnProperty(globalObject, base, propertyName)));
    1029 }
    1030 
    1031 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_in_structure_property)
    1032 {
    1033     BEGIN();
    1034     auto bytecode = pc->as<OpInStructureProperty>();
    1035     JSValue base = GET_C(bytecode.m_base).jsValue();
    1036 #if USE(JSVALUE32_64)
    1037     JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
    1038     if (base.isCell() && base.asCell()->structure(vm)->id() == enumerator->cachedStructureID())
    1039         RETURN(jsBoolean(true));
    1040 #endif
    1041     JSValue property = GET(bytecode.m_property).jsValue();
    1042     RELEASE_ASSERT(property.isString());
    1043     RETURN(jsBoolean(CommonSlowPaths::opInByVal(globalObject, base, asString(property))));
    1044 }
    1045 
    1046 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_has_enumerable_property)
    1047 {
    1048     BEGIN();
    1049     auto bytecode = pc->as<OpHasEnumerableProperty>();
    1050     JSObject* base = GET_C(bytecode.m_base).jsValue().toObject(globalObject);
    1051     CHECK_EXCEPTION();
    1052     JSValue property = GET(bytecode.m_property).jsValue();
    1053     ASSERT(property.isString());
    1054     JSString* string = asString(property);
    1055     auto propertyName = string->toIdentifier(globalObject);
    1056     CHECK_EXCEPTION();
    1057     RETURN(jsBoolean(base->hasEnumerableProperty(globalObject, propertyName)));
    1058 }
    1059 
    1060 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_get_direct_pname)
    1061 {
    1062     BEGIN();
    1063     auto bytecode = pc->as<OpGetDirectPname>();
    1064     JSValue baseValue = GET_C(bytecode.m_base).jsValue();
    1065     JSValue property = GET(bytecode.m_property).jsValue();
    1066     ASSERT(property.isString());
    1067     JSString* string = asString(property);
    1068     auto propertyName = string->toIdentifier(globalObject);
    1069     CHECK_EXCEPTION();
    1070     RETURN(baseValue.get(globalObject, propertyName));
    1071 }
    1072 
    1073965JSC_DEFINE_COMMON_SLOW_PATH(slow_path_get_property_enumerator)
    1074966{
    … …  
    1085977}
    1086978
    1087 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_enumerator_structure_pname)
    1088 {
    1089     BEGIN();
    1090     auto bytecode = pc->as<OpEnumeratorStructurePname>();
    1091     JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
    1092     uint32_t index = GET(bytecode.m_index).jsValue().asUInt32AsAnyInt();
    1093 
    1094     JSString* propertyName = nullptr;
    1095     if (index < enumerator->endStructurePropertyIndex())
    1096         propertyName = enumerator->propertyNameAtIndex(index);
    1097     RETURN(propertyName ? propertyName : jsNull());
    1098 }
    1099 
    1100 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_enumerator_generic_pname)
    1101 {
    1102     BEGIN();
    1103     auto bytecode = pc->as<OpEnumeratorGenericPname>();
    1104     JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
    1105     uint32_t index = GET(bytecode.m_index).jsValue().asUInt32AsAnyInt();
    1106 
    1107     JSString* propertyName = nullptr;
    1108     if (enumerator->endStructurePropertyIndex() <= index && index < enumerator->endGenericPropertyIndex())
    1109         propertyName = enumerator->propertyNameAtIndex(index);
    1110     RETURN(propertyName ? propertyName : jsNull());
    1111 }
    1112 
    1113 JSC_DEFINE_COMMON_SLOW_PATH(slow_path_to_index_string)
    1114 {
    1115     BEGIN();
    1116     auto bytecode = pc->as<OpToIndexString>();
    1117     JSValue indexValue = GET(bytecode.m_index).jsValue();
    1118     ASSERT(indexValue.isUInt32AsAnyInt());
    1119     RETURN(jsString(vm, Identifier::from(vm, indexValue.asUInt32AsAnyInt()).string()));
     979JSC_DEFINE_COMMON_SLOW_PATH(slow_path_enumerator_next)
     980{
     981    BEGIN();
     982    auto bytecode = pc->as<OpEnumeratorNext>();
     983    auto& metadata = bytecode.metadata(codeBlock);
     984    Register& modeRegister = GET(bytecode.m_mode);
     985    Register& indexRegister = GET(bytecode.m_index);
     986    Register& nameRegister = GET(bytecode.m_propertyName);
     987
     988    auto mode = static_cast<JSPropertyNameEnumerator::Mode>(modeRegister.jsValue().asUInt32());
     989    uint32_t index = indexRegister.jsValue().asUInt32();
     990
     991    JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue());
     992    JSValue baseValue = GET(bytecode.m_base).jsValue();
     993    ASSERT(!baseValue.isUndefinedOrNull());
     994    JSObject* base = baseValue.toObject(globalObject);
     995    CHECK_EXCEPTION();
     996    metadata.m_arrayProfile.observeStructureID(base->structureID());
     997
     998    JSString* name = enumerator->computeNext(globalObject, base, index, mode);
     999    CHECK_EXCEPTION();
     1000
     1001    metadata.m_enumeratorMetadata |= static_cast<uint8_t>(mode);
     1002    modeRegister = jsNumber(static_cast<uint8_t>(mode));
     1003    indexRegister = jsNumber(index);
     1004    nameRegister = name ? name : jsNull();
     1005    END();
     1006}
     1007
     1008JSC_DEFINE_COMMON_SLOW_PATH(slow_path_enumerator_get_by_val)
     1009{
     1010    BEGIN();
     1011    auto bytecode = pc->as<OpEnumeratorGetByVal>();
     1012    JSValue baseValue = GET_C(bytecode.m_base).jsValue();
     1013    auto& metadata = bytecode.metadata(codeBlock);
     1014    auto mode = static_cast<JSPropertyNameEnumerator::Mode>(GET(bytecode.m_mode).jsValue().asUInt32());
     1015    metadata.m_enumeratorMetadata |= static_cast<uint8_t>(mode);
     1016
     1017    JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue());
     1018    unsigned index = GET(bytecode.m_index).jsValue().asInt32();
     1019    switch (mode) {
     1020    case JSPropertyNameEnumerator::IndexedMode: {
     1021        if (LIKELY(baseValue.isCell()))
     1022            metadata.m_arrayProfile.observeStructureID(baseValue.asCell()->structureID());
     1023        RETURN_PROFILED(baseValue.get(globalObject, static_cast<unsigned>(index)));
     1024    }
     1025    case JSPropertyNameEnumerator::OwnStructureMode: {
     1026        if (LIKELY(baseValue.isCell()) && baseValue.asCell()->structureID() == enumerator->cachedStructureID()) {
     1027            // We'll only match the structure ID if the base is an object.
     1028            ASSERT(index < enumerator->endStructurePropertyIndex());
     1029            RETURN_PROFILED(baseValue.getObject()->getDirect(index < enumerator->cachedInlineCapacity() ? index : index - enumerator->cachedInlineCapacity() + firstOutOfLineOffset));
     1030        } else
     1031            metadata.m_enumeratorMetadata |= static_cast<uint8_t>(JSPropertyNameEnumerator::HasSeenOwnStructureModeStructureMismatch);
     1032        FALLTHROUGH;
     1033    }
     1034
     1035    case JSPropertyNameEnumerator::GenericMode: {
     1036        if (baseValue.isCell() && mode != JSPropertyNameEnumerator::OwnStructureMode)
     1037            metadata.m_arrayProfile.observeStructureID(baseValue.asCell()->structureID());
     1038        JSString* string = asString(GET(bytecode.m_propertyName).jsValue());
     1039        auto propertyName = string->toIdentifier(globalObject);
     1040        CHECK_EXCEPTION();
     1041        RETURN_PROFILED(baseValue.get(globalObject, propertyName));
     1042    }
     1043
     1044    default:
     1045        RELEASE_ASSERT_NOT_REACHED();
     1046        break;
     1047    };
     1048    RELEASE_ASSERT_NOT_REACHED();
     1049}
     1050
     1051JSC_DEFINE_COMMON_SLOW_PATH(slow_path_enumerator_in_by_val)
     1052{
     1053    BEGIN();
     1054    auto bytecode = pc->as<OpEnumeratorInByVal>();
     1055    JSValue baseValue = GET_C(bytecode.m_base).jsValue();
     1056    auto& metadata = bytecode.metadata(codeBlock);
     1057    auto mode = static_cast<JSPropertyNameEnumerator::Mode>(GET(bytecode.m_mode).jsValue().asUInt32());
     1058    metadata.m_enumeratorMetadata |= static_cast<uint8_t>(mode);
     1059
     1060    CHECK_EXCEPTION();
     1061    JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue());
     1062    if (auto* base = baseValue.getObject()) {
     1063        if (mode == JSPropertyNameEnumerator::OwnStructureMode && base->structureID() == enumerator->cachedStructureID())
     1064            RETURN(jsBoolean(true));
     1065
     1066        if (mode == JSPropertyNameEnumerator::IndexedMode)
     1067            RETURN(jsBoolean(base->hasProperty(globalObject, GET(bytecode.m_index).jsValue().asUInt32())));
     1068    }
     1069
     1070    JSString* string = asString(GET(bytecode.m_propertyName).jsValue());
     1071    RETURN(jsBoolean(CommonSlowPaths::opInByVal(globalObject, baseValue, string, &metadata.m_arrayProfile)));
     1072}
     1073
     1074JSC_DEFINE_COMMON_SLOW_PATH(slow_path_enumerator_has_own_property)
     1075{
     1076    BEGIN();
     1077    auto bytecode = pc->as<OpEnumeratorHasOwnProperty>();
     1078    JSValue baseValue = GET_C(bytecode.m_base).jsValue();
     1079    auto& metadata = bytecode.metadata(codeBlock);
     1080    auto mode = static_cast<JSPropertyNameEnumerator::Mode>(GET(bytecode.m_mode).jsValue().asUInt32());
     1081    metadata.m_enumeratorMetadata |= static_cast<uint8_t>(mode);
     1082
     1083    JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue());
     1084    if (auto* base = baseValue.getObject()) {
     1085        if (mode == JSPropertyNameEnumerator::OwnStructureMode && base->structureID() == enumerator->cachedStructureID())
     1086            RETURN(jsBoolean(true));
     1087
     1088        if (mode == JSPropertyNameEnumerator::IndexedMode)
     1089            RETURN(jsBoolean(base->hasOwnProperty(globalObject, GET(bytecode.m_index).jsValue().asUInt32())));
     1090    }
     1091
     1092    JSString* string = asString(GET(bytecode.m_propertyName).jsValue());
     1093    auto propertyName = string->toIdentifier(globalObject);
     1094    CHECK_EXCEPTION();
     1095    RETURN(jsBoolean(objectPrototypeHasOwnProperty(globalObject, baseValue, propertyName)));
    11201096}
    11211097
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h

    r279105 r280760  
    255255JSC_DECLARE_COMMON_SLOW_PATH(slow_path_to_primitive);
    256256JSC_DECLARE_COMMON_SLOW_PATH(slow_path_to_property_key);
    257 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_get_enumerable_length);
    258 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_has_enumerable_indexed_property);
    259 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_has_enumerable_structure_property);
    260 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_has_enumerable_property);
    261 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_has_own_structure_property);
    262 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_in_structure_property);
    263 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_get_direct_pname);
    264257JSC_DECLARE_COMMON_SLOW_PATH(slow_path_get_property_enumerator);
    265 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_enumerator_structure_pname);
    266 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_enumerator_generic_pname);
    267 JSC_DECLARE_COMMON_SLOW_PATH(slow_path_to_index_string);
     258JSC_DECLARE_COMMON_SLOW_PATH(slow_path_enumerator_next);
     259JSC_DECLARE_COMMON_SLOW_PATH(slow_path_enumerator_get_by_val);
     260JSC_DECLARE_COMMON_SLOW_PATH(slow_path_enumerator_in_by_val);
     261JSC_DECLARE_COMMON_SLOW_PATH(slow_path_enumerator_has_own_property);
    268262JSC_DECLARE_COMMON_SLOW_PATH(slow_path_profile_type_clear_log);
    269263JSC_DECLARE_COMMON_SLOW_PATH(slow_path_unreachable);
  • trunk/Source/JavaScriptCore/runtime/FileBasedFuzzerAgent.cpp

    r278253 r280760  
    9191
    9292    case op_get_by_val_with_this:
    93     case op_get_direct_pname:
    9493    case op_construct:
    9594    case op_construct_varargs:
  • trunk/Source/JavaScriptCore/runtime/FileBasedFuzzerAgentBase.cpp

    r277909 r280760  
    11/*
    2  * Copyright (C) 2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2019-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
    … …  
    5353    if (opcodeId == op_call_varargs || opcodeId == op_call_eval || opcodeId == op_tail_call || opcodeId == op_tail_call_varargs)
    5454        return op_call;
    55     if (opcodeId == op_get_direct_pname || opcodeId == op_get_by_val_with_this)
     55    if (opcodeId == op_enumerator_get_by_val || opcodeId == op_get_by_val_with_this)
    5656        return op_get_by_val;
    5757    if (opcodeId == op_construct_varargs)
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r280289 r280760  
    14621462#endif
    14631463
     1464    m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::emptyPropertyNameEnumerator)].initLater([] (const Initializer<JSCell>& init) {
     1465        init.set(init.vm.emptyPropertyNameEnumerator());
     1466    });
     1467
    14641468    if (Options::exposeProfilersOnGlobalObject()) {
    14651469#if ENABLE(SAMPLING_PROFILER)
  • trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp

    r278338 r280760  
    5757    , m_cachedInlineCapacity(structure ? structure->inlineCapacity() : 0)
    5858{
     59    if (m_indexedLength)
     60        m_modeSet |= JSPropertyNameEnumerator::IndexedMode;
     61    if (m_endStructurePropertyIndex)
     62        m_modeSet |= JSPropertyNameEnumerator::OwnStructureMode;
     63    if (m_endGenericPropertyIndex - m_endStructurePropertyIndex)
     64        m_modeSet |= JSPropertyNameEnumerator::GenericMode;
    5965}
    6066
    … …  
    149155}
    150156
     157JSString* JSPropertyNameEnumerator::computeNext(JSGlobalObject* globalObject, JSObject* base, uint32_t& index, Mode& mode, bool shouldAllocateIndexedNameString)
     158{
     159    VM& vm = globalObject->vm();
     160    auto scope = DECLARE_THROW_SCOPE(vm);
     161
     162    ASSERT(indexedLength() || sizeOfPropertyNames());
     163
     164    index++;
     165    switch (mode) {
     166    case InitMode: {
     167        mode = IndexedMode;
     168        index = 0;
     169        FALLTHROUGH;
     170    }
     171
     172    case JSPropertyNameEnumerator::IndexedMode: {
     173        while (index < indexedLength() && !base->hasEnumerableProperty(globalObject, index)) {
     174            RETURN_IF_EXCEPTION(scope, nullptr);
     175            index++;
     176        }
     177        scope.assertNoException();
     178
     179        if (index < indexedLength())
     180            return shouldAllocateIndexedNameString ? jsString(vm, Identifier::from(vm, index).string()) : nullptr;
     181
     182        if (!sizeOfPropertyNames())
     183            return nullptr;
     184
     185        mode = OwnStructureMode;
     186        index = 0;
     187        FALLTHROUGH;
     188    }
     189
     190    case JSPropertyNameEnumerator::OwnStructureMode:
     191    case JSPropertyNameEnumerator::GenericMode: {
     192        JSString* name = nullptr;
     193        while (true) {
     194            if (index >= sizeOfPropertyNames())
     195                break;
     196            name = propertyNameAtIndex(index);
     197            if (!name)
     198                break;
     199            if (index < endStructurePropertyIndex() && base->structureID() == cachedStructureID())
     200                break;
     201            auto id = Identifier::fromString(vm, name->value(globalObject));
     202            RETURN_IF_EXCEPTION(scope, nullptr);
     203            if (base->hasEnumerableProperty(globalObject, id))
     204                break;
     205            RETURN_IF_EXCEPTION(scope, nullptr);
     206            name = nullptr;
     207            index++;
     208        }
     209        scope.assertNoException();
     210
     211        if (index >= endStructurePropertyIndex() && index < sizeOfPropertyNames())
     212            mode = GenericMode;
     213        return name;
     214    }
     215
     216    default:
     217        break;
     218    }
     219    RELEASE_ASSERT_NOT_REACHED();
     220    return nullptr;
     221}
     222
    151223} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h

    r273766 r280760  
    2929#include "Operations.h"
    3030#include "PropertyNameArray.h"
    31 #include "Structure.h"
     31#include "StructureChain.h"
    3232
    3333namespace JSC {
    … …  
    3737    using Base = JSCell;
    3838    static constexpr unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
     39
     40    enum Mode : uint8_t {
     41        InitMode = 0,
     42        IndexedMode = 1 << 0,
     43        OwnStructureMode = 1 << 1,
     44        GenericMode = 1 << 2,
     45        // Profiling Only
     46        HasSeenOwnStructureModeStructureMismatch = 1 << 3,
     47    };
     48
     49    static constexpr uint8_t enumerationModeMask = (GenericMode << 1) - 1;
    3950
    4051    template<typename CellType, SubspaceAccess mode>
    … …  
    7586    uint32_t cachedInlineCapacity() const { return m_cachedInlineCapacity; }
    7687    uint32_t sizeOfPropertyNames() const { return endGenericPropertyIndex(); }
     88    uint32_t modeSet() const { return m_modeSet; }
    7789    static ptrdiff_t cachedStructureIDOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedStructureID); }
    7890    static ptrdiff_t indexedLengthOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_indexedLength); }
    … …  
    8092    static ptrdiff_t endGenericPropertyIndexOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_endGenericPropertyIndex); }
    8193    static ptrdiff_t cachedInlineCapacityOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedInlineCapacity); }
     94    static ptrdiff_t modeSetOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_modeSet); }
    8295    static ptrdiff_t cachedPropertyNamesVectorOffset()
    8396    {
    8497        return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames);
    8598    }
     99
     100    JSString* computeNext(JSGlobalObject*, JSObject* base, uint32_t& currentIndex, Mode&, bool shouldAllocateIndexedNameString = true);
    86101
    87102    DECLARE_VISIT_CHILDREN;
    … …  
    100115    uint32_t m_endGenericPropertyIndex;
    101116    uint32_t m_cachedInlineCapacity;
     117    uint32_t m_modeSet { 0 };
    102118};
    103119
    … …  
    135151    }
    136152
    137     enumerator = JSPropertyNameEnumerator::create(vm, structureAfterGettingPropertyNames, indexedLength, numberStructureProperties, WTFMove(propertyNames));
     153    if (!indexedLength && !propertyNames.size())
     154        enumerator = vm.emptyPropertyNameEnumerator();
     155    else
     156        enumerator = JSPropertyNameEnumerator::create(vm, structureAfterGettingPropertyNames, indexedLength, numberStructureProperties, WTFMove(propertyNames));
    138157    if (!indexedLength && successfullyNormalizedChain && structureAfterGettingPropertyNames == structure) {
    139158        enumerator->setCachedPrototypeChain(vm, structure->prototypeChain(globalObject, base));
    … …  
    144163}
    145164
     165using EnumeratorMetadata = std::underlying_type_t<JSPropertyNameEnumerator::Mode>;
     166
    146167} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/PredictionFileCreatingFuzzerAgent.cpp

    r253576 r280760  
    11/*
    2  * Copyright (C) 2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2019-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
    … …  
    5353    case op_get_by_id_with_this:
    5454    case op_get_by_val_with_this:
    55     case op_get_direct_pname:
     55    case op_enumerator_get_by_val:
    5656    case op_construct:
    5757    case op_construct_varargs:
Note: See TracChangeset for help on using the changeset viewer.