Diff
Modified: trunk/JSTests/ChangeLog (262082 => 262083)
--- trunk/JSTests/ChangeLog 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/JSTests/ChangeLog 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1,3 +1,32 @@
+2020-05-22 Saam Barati <[email protected]>
+
+ in_by_val inside structure property for-in loop should use an opcode like has_structure_property but for "in"
+ https://bugs.webkit.org/show_bug.cgi?id=212239
+
+ Reviewed by Tadeu Zagallo.
+
+ * microbenchmarks/in-by-val-inside-for-in-loop.js: Added.
+ (assert):
+ (count):
+ * stress/in-by-val-inside-for-in-loop.js: Added.
+ (assert):
+ (test1.count):
+ (test1):
+ (test2.count):
+ (test2):
+ (test3.count):
+ (test3):
+ (test4.count):
+ (test4):
+ (test5.count):
+ (test5):
+ (test6.count):
+ (test6):
+ (test7.count):
+ (test7):
+ (test8.count):
+ (test8):
+
2020-05-22 Keith Miller <[email protected]>
Checkpoint inlined call return handler needs an exception check when dispatching
Added: trunk/JSTests/microbenchmarks/in-by-val-inside-for-in-loop.js (0 => 262083)
--- trunk/JSTests/microbenchmarks/in-by-val-inside-for-in-loop.js (rev 0)
+++ trunk/JSTests/microbenchmarks/in-by-val-inside-for-in-loop.js 2020-05-22 22:31:13 UTC (rev 262083)
@@ -0,0 +1,25 @@
+function assert(b) {
+ if (!b)
+ throw new Error;
+}
+
+function count(o) {
+ let c = 0;
+ for (let p in o) {
+ if (p in o)
+ ++c;
+ }
+ return c;
+}
+noInline(count);
+
+let o = {
+ a:20,
+ b:30,
+ c:40,
+ d:50
+};
+
+for (let i = 0; i < 300000; ++i) {
+ assert(count(o) === 4);
+}
Added: trunk/JSTests/stress/in-by-val-inside-for-in-loop.js (0 => 262083)
--- trunk/JSTests/stress/in-by-val-inside-for-in-loop.js (rev 0)
+++ trunk/JSTests/stress/in-by-val-inside-for-in-loop.js 2020-05-22 22:31:13 UTC (rev 262083)
@@ -0,0 +1,227 @@
+function assert(b) {
+ if (!b)
+ throw new Error;
+}
+
+function test1() {
+ function count(o) {
+ let c = 0;
+ for (let p in o) {
+ if (p in o)
+ ++c;
+ }
+ return c;
+ }
+ noInline(count);
+
+ let o = {
+ a:20,
+ b:30,
+ c:40,
+ d:50
+ };
+
+ for (let i = 0; i < 1000; ++i) {
+ assert(count(o) === 4);
+ }
+}
+test1();
+
+function test2() {
+ function count(o) {
+ let c = 0;
+ for (let p in o) {
+ if (p === "a")
+ delete o.a;
+ if (p in o)
+ ++c;
+ }
+ return c;
+ }
+ noInline(count);
+
+ let o = {
+ a:20,
+ b:30,
+ c:40,
+ d:50
+ };
+
+ for (let i = 0; i < 1000; ++i) {
+ assert(count(o) === 3);
+ }
+}
+test2();
+
+function test3() {
+ function count(o) {
+ let c = 0;
+ for (let p in o) {
+ p = "a";
+ if (p in o)
+ ++c;
+ }
+ return c;
+ }
+ noInline(count);
+
+ let o = {
+ a:20,
+ b:30,
+ c:40,
+ d:50
+ };
+
+ for (let i = 0; i < 1000; ++i) {
+ assert(count(o) === 4);
+ }
+}
+test3();
+
+function test4() {
+ function count(o) {
+ let c = 0;
+ for (let p in o) {
+ p = "f";
+ if (p in o)
+ ++c;
+ }
+ return c;
+ }
+ noInline(count);
+
+ let o = {
+ a:20,
+ b:30,
+ c:40,
+ d:50
+ };
+
+ for (let i = 0; i < 1000; ++i) {
+ assert(count(o) === 0);
+ }
+}
+test4();
+
+function test5() {
+ function count(o) {
+ let c = 0;
+ for (let p in o) {
+ delete o[p];
+ if (p in o)
+ ++c;
+ }
+ return c;
+ }
+ noInline(count);
+
+ let o = {
+ a:20,
+ b:30,
+ c:40,
+ d:50
+ };
+
+ let p = {
+ a:20,
+ b:30,
+ c:40,
+ d:50
+ };
+
+ o.__proto__ = p;
+
+ for (let i = 0; i < 1000; ++i) {
+ assert(count(o) === 4);
+ }
+}
+test5();
+
+function test6() {
+ function count(o) {
+ let c = 0;
+ for (let p in o) {
+ delete o[p];
+ if (p in o)
+ ++c;
+ }
+ return c;
+ }
+ noInline(count);
+
+ let o = {
+ a:20,
+ b:30,
+ c:40,
+ d:50
+ };
+
+ let p = { };
+
+ o.__proto__ = p;
+
+ for (let i = 0; i < 1000; ++i) {
+ assert(count(o) === 0);
+ }
+}
+test6();
+
+function test7() {
+ function count(o, o2) {
+ let c = 0;
+ for (let p in o) {
+ if (p in o2)
+ ++c;
+ }
+ return c;
+ }
+ noInline(count);
+
+ for (let i = 0; i < 1000; ++i) {
+ let o = {a: 20};
+ if (!!(i % 2)) {
+ let ok = false;
+ try {
+ count(o, null);
+ } catch(e) {
+ assert(e instanceof TypeError);
+ ok = e.toString().indexOf("o2 is not an Object") >= 0;
+ }
+ assert(ok);
+ } else {
+ assert(count(o, {}) === 0);
+ }
+ }
+}
+test7();
+
+function test8() {
+ function count(o, proto) {
+ let c = 0;
+ for (let p in o) {
+ delete o[p];
+ o.__proto__ = proto;
+ if (p in o)
+ ++c;
+ }
+ return c;
+ }
+ noInline(count);
+
+ let hasOwnPropertyCalled = false;
+ let p = new Proxy({}, {
+ has() {
+ hasOwnPropertyCalled = true;
+ return false;
+ }
+ });
+
+ for (let i = 0; i < 1000; ++i) {
+ let o = { a:20 };
+
+ assert(count(o, p) === 0);
+ assert(hasOwnPropertyCalled === true);
+ hasOwnPropertyCalled = false;
+ }
+}
+test8();
Modified: trunk/Source/_javascript_Core/ChangeLog (262082 => 262083)
--- trunk/Source/_javascript_Core/ChangeLog 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1,3 +1,94 @@
+2020-05-22 Saam Barati <[email protected]>
+
+ in_by_val inside structure property for-in loop should use an opcode like has_structure_property but for "in"
+ https://bugs.webkit.org/show_bug.cgi?id=212239
+
+ Reviewed by Tadeu Zagallo.
+
+ There is code inside Speedometer 2 that is like:
+
+ ```
+ for (let p in o) {
+ if (p in o2)
+ ...
+ }
+ ```
+
+ Where o and o2 frequently share the same structure. Elm does this when it's
+ diffing two objects. We already optimize o2[p] (get_by_val) in the above loop
+ for structure properties. This patch adds that same optimization for in_by_val.
+ Because we already emit a "structure" loop for for-in, where we iterate structure
+ properties, the fast path for the above, where o and o2 have the same
+ structure is simply a structure check followed by return true.
+
+ This patch introduces the new opcode: op_in_structure_property. Its fast path is identical
+ to op_has_structure_property. Its slow path, however, behaves like "in", which
+ uses the HasProperty internal method, unlike op_has_structure_property,
+ which uses the GetOwnProperty internal method. This behavior difference is
+ observable using Proxy.
+
+ This a 5% perf improvement in the Elm subtest in Speedometer 2.
+
+ * bytecode/BytecodeList.rb:
+ * bytecode/BytecodeUseDef.cpp:
+ (JSC::computeUsesForBytecodeIndexImpl):
+ (JSC::computeDefsForBytecodeIndexImpl):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitInByVal):
+ (JSC::rewriteOp):
+ (JSC::StructureForInContext::finalize):
+ * bytecompiler/BytecodeGenerator.h:
+ (JSC::StructureForInContext::addInInst):
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileInStructureProperty):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileHasStructurePropertyImpl):
+ (JSC::FTL::DFG::LowerDFGToB3::compileHasStructureProperty):
+ (JSC::FTL::DFG::LowerDFGToB3::compileInStructureProperty):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ (JSC::JIT::privateCompileSlowCases):
+ * jit/JIT.h:
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_in_structure_property):
+ * jit/JITOpcodes32_64.cpp:
+ (JSC::JIT::emit_op_in_structure_property):
+ * llint/LLIntOffsetsExtractor.cpp:
+ * llint/LowLevelInterpreter.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::SLOW_PATH_DECL):
+ * runtime/CommonSlowPaths.h:
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::hasPropertyGeneric const):
+ * runtime/JSPropertyNameEnumerator.h:
+
2020-05-22 Keith Miller <[email protected]>
Checkpoint inlined call return handler needs an exception check when dispatching
Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.rb (262082 => 262083)
--- trunk/Source/_javascript_Core/bytecode/BytecodeList.rb 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.rb 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1105,6 +1105,14 @@
enumerator: VirtualRegister,
}
+op :in_structure_property,
+ args: {
+ dst: VirtualRegister,
+ base: VirtualRegister,
+ property: VirtualRegister,
+ enumerator: VirtualRegister,
+ }
+
op :has_generic_property,
args: {
dst: VirtualRegister,
Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -246,6 +246,7 @@
USES(OpGetByValWithThis, base, thisValue, property)
USES(OpInstanceofCustom, value, constructor, hasInstanceValue)
USES(OpHasStructureProperty, base, property, enumerator)
+ USES(OpInStructureProperty, base, property, enumerator)
USES(OpConstructVarargs, callee, thisValue, arguments)
USES(OpCallVarargs, callee, thisValue, arguments)
USES(OpTailCallVarargs, callee, thisValue, arguments)
@@ -374,6 +375,7 @@
DEFS(OpGetEnumerableLength, dst)
DEFS(OpHasIndexedProperty, dst)
DEFS(OpHasStructureProperty, dst)
+ DEFS(OpInStructureProperty, dst)
DEFS(OpHasGenericProperty, dst)
DEFS(OpGetDirectPname, dst)
DEFS(OpGetPropertyEnumerator, dst)
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -2479,6 +2479,20 @@
RegisterID* BytecodeGenerator::emitInByVal(RegisterID* dst, RegisterID* property, RegisterID* base)
{
+ for (size_t i = m_forInContextStack.size(); i--; ) {
+ ForInContext& context = m_forInContextStack[i].get();
+ if (context.local() != property)
+ continue;
+
+ if (!context.isStructureForInContext())
+ break;
+
+ StructureForInContext& structureContext = context.asStructureForInContext();
+ OpInStructureProperty::emit<OpcodeSize::Wide32>(this, dst, base, property, structureContext.enumerator());
+ structureContext.addInInst(m_lastInstruction.offset(), property->index());
+ return dst;
+ }
+
OpInByVal::emit(this, dst, base, property);
return dst;
}
@@ -5183,6 +5197,41 @@
}
}
+template <typename OldOpType, typename TupleType>
+ALWAYS_INLINE void rewriteOp(BytecodeGenerator& generator, TupleType& instTuple)
+{
+ unsigned instIndex = std::get<0>(instTuple);
+ int propertyRegIndex = std::get<1>(instTuple);
+ auto instruction = generator.m_writer.ref(instIndex);
+ auto end = instIndex + instruction->size();
+ ASSERT(instruction->isWide32());
+
+ generator.m_writer.seek(instIndex);
+
+ auto bytecode = instruction->as<OldOpType>();
+
+ // disable peephole optimizations
+ generator.m_lastOpcodeID = op_end;
+
+ // Change the opcode to get_by_val.
+ // 1. dst stays the same.
+ // 2. base stays the same.
+ // 3. property gets switched to the original property.
+
+ if constexpr (std::is_same<OldOpType, OpGetDirectPname>::value) {
+ static_assert(sizeof(OpGetByVal) <= sizeof(OpGetDirectPname));
+ OpGetByVal::emit<OpcodeSize::Wide32>(&generator, bytecode.m_dst, bytecode.m_base, VirtualRegister(propertyRegIndex));
+ } else if constexpr (std::is_same<OldOpType, OpInStructureProperty>::value) {
+ static_assert(sizeof(OpInByVal) <= sizeof(OpInStructureProperty));
+ OpInByVal::emit<OpcodeSize::Wide32>(&generator, bytecode.m_dst, bytecode.m_base, VirtualRegister(propertyRegIndex));
+ } else
+ RELEASE_ASSERT_NOT_REACHED();
+
+ // 4. nop out the remaining bytes
+ while (generator.m_writer.position() < end)
+ OpNop::emit<OpcodeSize::Narrow>(&generator);
+}
+
void StructureForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlockGenerator* codeBlock, unsigned bodyBytecodeEndOffset)
{
Base::finalize(generator, codeBlock, bodyBytecodeEndOffset);
@@ -5191,30 +5240,13 @@
OpcodeID lastOpcodeID = generator.m_lastOpcodeID;
InstructionStream::MutableRef lastInstruction = generator.m_lastInstruction;
- for (const auto& instTuple : m_getInsts) {
- unsigned instIndex = std::get<0>(instTuple);
- int propertyRegIndex = std::get<1>(instTuple);
- auto instruction = generator.m_writer.ref(instIndex);
- auto end = instIndex + instruction->size();
- ASSERT(instruction->isWide32());
- generator.m_writer.seek(instIndex);
+ for (const auto& instTuple : m_getInsts)
+ rewriteOp<OpGetDirectPname>(generator, instTuple);
- auto bytecode = instruction->as<OpGetDirectPname>();
+ for (const auto& instTuple : m_inInsts)
+ rewriteOp<OpInStructureProperty>(generator, instTuple);
- // disable peephole optimizations
- generator.m_lastOpcodeID = op_end;
-
- // Change the opcode to get_by_val.
- // 1. dst stays the same.
- // 2. base stays the same.
- // 3. property gets switched to the original property.
- OpGetByVal::emit<OpcodeSize::Wide32>(&generator, bytecode.m_dst, bytecode.m_base, VirtualRegister(propertyRegIndex));
-
- // 4. nop out the remaining bytes
- while (generator.m_writer.position() < end)
- OpNop::emit<OpcodeSize::Narrow>(&generator);
- }
generator.m_writer.seek(generator.m_writer.size());
if (generator.m_lastInstruction.offset() + generator.m_lastInstruction->size() != generator.m_writer.size()) {
generator.m_lastOpcodeID = lastOpcodeID;
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (262082 => 262083)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -238,6 +238,7 @@
using Base = ForInContext;
public:
using GetInst = std::tuple<unsigned, int>;
+ using InInst = GetInst;
StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister, unsigned bodyBytecodeStartOffset)
: ForInContext(localRegister, Type::StructureForIn, bodyBytecodeStartOffset)
@@ -256,6 +257,11 @@
m_getInsts.append(GetInst { instIndex, propertyRegIndex });
}
+ void addInInst(unsigned instIndex, int propertyRegIndex)
+ {
+ m_inInsts.append(InInst { instIndex, propertyRegIndex });
+ }
+
void finalize(BytecodeGenerator&, UnlinkedCodeBlockGenerator*, unsigned bodyBytecodeEndOffset);
private:
@@ -263,6 +269,7 @@
RefPtr<RegisterID> m_propertyRegister;
RefPtr<RegisterID> m_enumeratorRegister;
Vector<GetInst> m_getInsts;
+ Vector<InInst> m_inInsts;
};
class IndexedForInContext : public ForInContext {
@@ -381,6 +388,10 @@
friend class IndexedForInContext;
friend class StructureForInContext;
friend class StrictModeScope;
+
+ template <typename OldOpType, typename TupleType>
+ friend void rewriteOp(BytecodeGenerator&, TupleType&);
+
public:
typedef DeclarationStacks::FunctionStack FunctionStack;
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -4114,6 +4114,7 @@
clobberWorld();
break;
}
+ case InStructureProperty:
case HasStructureProperty: {
setNonCellTypeForNode(node, SpecBoolean);
clobberWorld();
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -7824,6 +7824,15 @@
NEXT_OPCODE(op_has_structure_property);
}
+ case op_in_structure_property: {
+ auto bytecode = currentInstruction->as<OpInStructureProperty>();
+ set(bytecode.m_dst, addToGraph(InStructureProperty,
+ get(bytecode.m_base),
+ get(bytecode.m_property),
+ get(bytecode.m_enumerator)));
+ NEXT_OPCODE(op_in_structure_property);
+ }
+
case op_has_indexed_property: {
auto bytecode = currentInstruction->as<OpHasIndexedProperty>();
Node* base = get(bytecode.m_base);
Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -253,6 +253,7 @@
case op_get_enumerable_length:
case op_has_generic_property:
case op_has_structure_property:
+ case op_in_structure_property:
case op_has_indexed_property:
case op_get_direct_pname:
case op_get_property_enumerator:
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -697,6 +697,7 @@
case ToObject:
case HasGenericProperty:
case HasStructureProperty:
+ case InStructureProperty:
case GetPropertyEnumerator:
case GetDirectPname:
case InstanceOfCustom:
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -297,6 +297,7 @@
case HasIndexedProperty:
case HasOwnProperty:
case HasStructureProperty:
+ case InStructureProperty:
case InById:
case InByVal:
case InstanceOf:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -2179,6 +2179,12 @@
fixEdge<KnownCellUse>(node->child3());
break;
}
+ case InStructureProperty: {
+ fixEdge<CellUse>(node->child1());
+ fixEdge<StringUse>(node->child2());
+ fixEdge<KnownCellUse>(node->child3());
+ break;
+ }
case HasIndexedProperty: {
node->setArrayMode(
node->arrayMode().refine(
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -490,6 +490,7 @@
/* Must generate because of Proxies on the prototype chain */ \
macro(HasIndexedProperty, NodeMustGenerate | NodeResultBoolean | NodeHasVarArgs) \
macro(HasStructureProperty, NodeResultBoolean) \
+ macro(InStructureProperty, NodeMustGenerate | NodeResultBoolean) \
macro(HasGenericProperty, NodeResultBoolean) \
macro(GetDirectPname, NodeMustGenerate | NodeHasVarArgs | NodeResultJS) \
macro(GetPropertyEnumerator, NodeMustGenerate | NodeResultJS) \
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -2274,6 +2274,15 @@
RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(base->hasPropertyGeneric(globalObject, propertyName, PropertySlot::InternalMethodType::GetOwnProperty))));
}
+EncodedJSValue JIT_OPERATION operationInStructureProperty(JSGlobalObject* globalObject, JSCell* base, JSCell* property)
+{
+ VM& vm = globalObject->vm();
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+ return JSValue::encode(jsBoolean(CommonSlowPaths::opInByVal(globalObject, base, property)));
+}
+
size_t JIT_OPERATION operationHasIndexedPropertyByInt(JSGlobalObject* globalObject, JSCell* baseCell, int32_t subscript, int32_t internalMethodType)
{
VM& vm = globalObject->vm();
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -99,6 +99,7 @@
EncodedJSValue JIT_OPERATION operationGetPrototypeOf(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(JSGlobalObject*, JSObject*) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationHasGenericProperty(JSGlobalObject*, EncodedJSValue, JSCell*);
+EncodedJSValue JIT_OPERATION operationInStructureProperty(JSGlobalObject*, JSCell*, JSCell*);
size_t JIT_OPERATION operationHasIndexedPropertyByInt(JSGlobalObject*, JSCell*, int32_t, int32_t);
JSCell* JIT_OPERATION operationGetPropertyEnumerator(JSGlobalObject*, EncodedJSValue);
JSCell* JIT_OPERATION operationGetPropertyEnumeratorCell(JSGlobalObject*, JSCell*);
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1206,6 +1206,7 @@
}
case HasGenericProperty:
case HasStructureProperty:
+ case InStructureProperty:
case HasIndexedProperty: {
setPrediction(SpecBoolean);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -618,6 +618,7 @@
case GetEnumerableLength:
case HasGenericProperty:
case HasStructureProperty:
+ case InStructureProperty:
case GetDirectPname:
case GetPropertyEnumerator:
case PhantomNewObject:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -12826,6 +12826,33 @@
blessedBooleanResult(resultRegs.payloadGPR(), node);
}
+void SpeculativeJIT::compileInStructureProperty(Node* node)
+{
+ SpeculateCellOperand base(this, node->child1());
+ SpeculateCellOperand property(this, node->child2());
+ SpeculateCellOperand enumerator(this, node->child3());
+ JSValueRegsTemporary result(this);
+
+ GPRReg baseGPR = base.gpr();
+ GPRReg propertyGPR = property.gpr();
+ JSValueRegs resultRegs = result.regs();
+
+ CCallHelpers::JumpList wrongStructure;
+
+ m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), resultRegs.payloadGPR());
+ wrongStructure.append(m_jit.branch32(MacroAssembler::NotEqual,
+ resultRegs.payloadGPR(),
+ MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset())));
+
+ moveTrueTo(resultRegs.payloadGPR());
+ MacroAssembler::Jump done = m_jit.jump();
+
+ done.link(&m_jit);
+
+ addSlowPathGenerator(slowPathCall(wrongStructure, this, operationInStructureProperty, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyGPR));
+ blessedBooleanResult(resultRegs.payloadGPR(), node);
+}
+
void SpeculativeJIT::compileGetPropertyEnumerator(Node* node)
{
if (node->child1().useKind() == CellUse) {
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1447,6 +1447,7 @@
void compilePutByIdDirect(Node*);
void compilePutByIdWithThis(Node*);
void compileHasStructureProperty(Node*);
+ void compileInStructureProperty(Node*);
void compileGetDirectPname(Node*);
void compileGetPropertyEnumerator(Node*);
void compileGetEnumeratorPname(Node*);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -4057,6 +4057,10 @@
compileHasStructureProperty(node);
break;
}
+ case InStructureProperty: {
+ compileInStructureProperty(node);
+ break;
+ }
case HasIndexedProperty: {
compileHasIndexedProperty(node);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -4988,6 +4988,10 @@
compileHasStructureProperty(node);
break;
}
+ case InStructureProperty: {
+ compileInStructureProperty(node);
+ break;
+ }
case HasIndexedProperty: {
compileHasIndexedProperty(node);
break;
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -280,6 +280,7 @@
case BooleanToNumber:
case HasGenericProperty:
case HasStructureProperty:
+ case InStructureProperty:
case HasIndexedProperty:
case GetDirectPname:
case GetEnumerableLength:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1477,6 +1477,9 @@
case HasStructureProperty:
compileHasStructureProperty();
break;
+ case InStructureProperty:
+ compileInStructureProperty();
+ break;
case GetDirectPname:
compileGetDirectPname();
break;
@@ -12241,37 +12244,53 @@
setJSValue(vmCall(Int64, operationHasGenericProperty, weakPointer(globalObject), base, property));
}
- void compileHasStructureProperty()
+ template <typename SlowPathCall>
+ void compileHasStructurePropertyImpl(LValue base, SlowPathCall slowPathCall)
{
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
- LValue base = lowJSValue(m_node->child1());
LValue property = lowString(m_node->child2());
LValue enumerator = lowCell(m_node->child3());
+ LBasicBlock isCellCase = m_out.newBlock();
LBasicBlock correctStructure = m_out.newBlock();
- LBasicBlock wrongStructure = m_out.newBlock();
+ LBasicBlock slowPath = m_out.newBlock();
LBasicBlock continuation = m_out.newBlock();
+ m_out.branch(isCell(base, provenType(m_node->child1())),
+ usually(isCellCase), rarely(slowPath));
+
+ LBasicBlock lastNext = m_out.appendTo(isCellCase, correctStructure);
+
m_out.branch(m_out.notEqual(
m_out.load32(base, m_heaps.JSCell_structureID),
m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
- rarely(wrongStructure), usually(correctStructure));
+ rarely(slowPath), usually(correctStructure));
- LBasicBlock lastNext = m_out.appendTo(correctStructure, wrongStructure);
+ m_out.appendTo(correctStructure, slowPath);
ValueFromBlock correctStructureResult = m_out.anchor(m_out.booleanTrue);
m_out.jump(continuation);
- m_out.appendTo(wrongStructure, continuation);
- ValueFromBlock wrongStructureResult = m_out.anchor(
+ m_out.appendTo(slowPath, continuation);
+ ValueFromBlock slowPathResult = m_out.anchor(
m_out.equal(
m_out.constInt64(JSValue::encode(jsBoolean(true))),
- vmCall(Int64, operationHasGenericProperty, weakPointer(globalObject), base, property)));
+ vmCall(Int64, slowPathCall, weakPointer(globalObject), base, property)));
m_out.jump(continuation);
m_out.appendTo(continuation, lastNext);
- setBoolean(m_out.phi(Int32, correctStructureResult, wrongStructureResult));
+ setBoolean(m_out.phi(Int32, correctStructureResult, slowPathResult));
}
+ void compileHasStructureProperty()
+ {
+ compileHasStructurePropertyImpl(lowJSValue(m_node->child1()), operationHasGenericProperty);
+ }
+
+ void compileInStructureProperty()
+ {
+ compileHasStructurePropertyImpl(lowCell(m_node->child1()), operationInStructureProperty);
+ }
+
void compileGetDirectPname()
{
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/jit/JIT.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -460,6 +460,7 @@
DEFINE_OP(op_put_to_arguments)
DEFINE_OP(op_has_structure_property)
+ DEFINE_OP(op_in_structure_property)
DEFINE_OP(op_has_indexed_property)
DEFINE_OP(op_get_direct_pname)
DEFINE_OP(op_enumerator_structure_pname)
@@ -616,6 +617,7 @@
DEFINE_SLOWCASE_SLOW_OP(nstricteq)
DEFINE_SLOWCASE_SLOW_OP(get_direct_pname)
DEFINE_SLOWCASE_SLOW_OP(has_structure_property)
+ DEFINE_SLOWCASE_SLOW_OP(in_structure_property)
DEFINE_SLOWCASE_SLOW_OP(resolve_scope)
DEFINE_SLOWCASE_SLOW_OP(check_tdz)
DEFINE_SLOWCASE_SLOW_OP(to_property_key)
Modified: trunk/Source/_javascript_Core/jit/JIT.h (262082 => 262083)
--- trunk/Source/_javascript_Core/jit/JIT.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/jit/JIT.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -619,6 +619,7 @@
void emit_op_unsigned(const Instruction*);
void emit_op_urshift(const Instruction*);
void emit_op_has_structure_property(const Instruction*);
+ void emit_op_in_structure_property(const Instruction*);
void emit_op_has_indexed_property(const Instruction*);
void emit_op_get_direct_pname(const Instruction*);
void emit_op_enumerator_structure_pname(const Instruction*);
Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1372,6 +1372,24 @@
emitPutVirtualRegister(dst);
}
+void JIT::emit_op_in_structure_property(const Instruction* currentInstruction)
+{
+ auto bytecode = currentInstruction->as<OpInStructureProperty>();
+ VirtualRegister dst = bytecode.m_dst;
+ VirtualRegister base = bytecode.m_base;
+ VirtualRegister enumerator = bytecode.m_enumerator;
+
+ emitGetVirtualRegister(base, regT0);
+ emitGetVirtualRegister(enumerator, regT1);
+ emitJumpSlowCaseIfNotJSCell(regT0, base);
+
+ load32(Address(regT0, JSCell::structureIDOffset()), regT0);
+ addSlowCase(branch32(NotEqual, regT0, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset())));
+
+ move(TrustedImm64(JSValue::encode(jsBoolean(true))), regT0);
+ emitPutVirtualRegister(dst);
+}
+
void JIT::privateCompileHasIndexedProperty(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
{
const Instruction* currentInstruction = m_codeBlock->instructions().at(byValInfo->bytecodeIndex).ptr();
Modified: trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1150,6 +1150,25 @@
emitStoreBool(dst, regT0);
}
+void JIT::emit_op_in_structure_property(const Instruction* currentInstruction)
+{
+ auto bytecode = currentInstruction->as<OpInStructureProperty>();
+ VirtualRegister dst = bytecode.m_dst;
+ VirtualRegister base = bytecode.m_base;
+ VirtualRegister enumerator = bytecode.m_enumerator;
+
+ emitLoadPayload(base, regT0);
+ emitJumpSlowCaseIfNotJSCell(base);
+
+ emitLoadPayload(enumerator, regT1);
+
+ load32(Address(regT0, JSCell::structureIDOffset()), regT0);
+ addSlowCase(branch32(NotEqual, regT0, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset())));
+
+ move(TrustedImm32(1), regT0);
+ emitStoreBool(dst, regT0);
+}
+
void JIT::privateCompileHasIndexedProperty(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
{
const Instruction* currentInstruction = m_codeBlock->instructions().at(byValInfo->bytecodeIndex).ptr();
Modified: trunk/Source/_javascript_Core/llint/LLIntOffsetsExtractor.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/llint/LLIntOffsetsExtractor.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/llint/LLIntOffsetsExtractor.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -49,6 +49,7 @@
#include "JSLexicalEnvironment.h"
#include "JSModuleRecord.h"
#include "JSObject.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSString.h"
#include "JSTypeInfo.h"
#include "JumpTable.h"
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (262082 => 262083)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1769,7 +1769,12 @@
slowPathOp(greatereq)
slowPathOp(has_generic_property)
slowPathOp(has_indexed_property)
-slowPathOp(has_structure_property)
+
+if not JSVALUE64
+ slowPathOp(has_structure_property)
+ slowPathOp(in_structure_property)
+end
+
slowPathOp(in_by_id)
slowPathOp(in_by_val)
slowPathOp(is_function)
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (262082 => 262083)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2020-05-22 22:31:13 UTC (rev 262083)
@@ -2847,3 +2847,27 @@
callSlowPath(_llint_slow_path_log_shadow_chicken_tail)
dispatch()
end)
+
+macro hasStructurePropertyImpl(size, get, dispatch, return, slowPathCall)
+ get(m_base, t0)
+ loadConstantOrVariable(size, t0, t1)
+ btqnz t1, notCellMask, .slowPath
+
+ loadVariable(get, m_enumerator, t0)
+ loadi JSCell::m_structureID[t1], t1
+ bineq t1, JSPropertyNameEnumerator::m_cachedStructureID[t0], .slowPath
+
+ return(ValueTrue)
+
+.slowPath:
+ callSlowPath(slowPathCall)
+ dispatch()
+end
+
+llintOpWithReturn(op_has_structure_property, OpHasStructureProperty, macro (size, get, dispatch, return)
+ hasStructurePropertyImpl(size, get, dispatch, return, _slow_path_has_structure_property)
+end)
+
+llintOpWithReturn(op_in_structure_property, OpInStructureProperty, macro (size, get, dispatch, return)
+ hasStructurePropertyImpl(size, get, dispatch, return, _slow_path_in_structure_property)
+end)
Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp (262082 => 262083)
--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp 2020-05-22 22:31:13 UTC (rev 262083)
@@ -1051,10 +1051,12 @@
JSObject* base = GET(bytecode.m_base).jsValue().toObject(globalObject);
CHECK_EXCEPTION();
JSValue property = GET(bytecode.m_property).jsValue();
- ASSERT(property.isString());
+ RELEASE_ASSERT(property.isString());
+#if USE(JSVALUE32_64)
JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
if (base->structure(vm)->id() == enumerator->cachedStructureID())
RETURN(jsBoolean(true));
+#endif
JSString* string = asString(property);
auto propertyName = string->toIdentifier(globalObject);
CHECK_EXCEPTION();
@@ -1061,6 +1063,21 @@
RETURN(jsBoolean(base->hasPropertyGeneric(globalObject, propertyName, PropertySlot::InternalMethodType::GetOwnProperty)));
}
+SLOW_PATH_DECL(slow_path_in_structure_property)
+{
+ BEGIN();
+ auto bytecode = pc->as<OpInStructureProperty>();
+ JSValue base = GET(bytecode.m_base).jsValue();
+#if USE(JSVALUE32_64)
+ JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
+ if (base.isCell() && base.asCell()->structure(vm)->id() == enumerator->cachedStructureID())
+ RETURN(jsBoolean(true));
+#endif
+ JSValue property = GET(bytecode.m_property).jsValue();
+ RELEASE_ASSERT(property.isString());
+ RETURN(jsBoolean(CommonSlowPaths::opInByVal(globalObject, base, asString(property))));
+}
+
SLOW_PATH_DECL(slow_path_has_generic_property)
{
BEGIN();
Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h (262082 => 262083)
--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -254,6 +254,7 @@
SLOW_PATH_HIDDEN_DECL(slow_path_get_enumerable_length);
SLOW_PATH_HIDDEN_DECL(slow_path_has_generic_property);
SLOW_PATH_HIDDEN_DECL(slow_path_has_structure_property);
+SLOW_PATH_HIDDEN_DECL(slow_path_in_structure_property);
SLOW_PATH_HIDDEN_DECL(slow_path_has_indexed_property);
SLOW_PATH_HIDDEN_DECL(slow_path_get_direct_pname);
SLOW_PATH_HIDDEN_DECL(slow_path_get_property_enumerator);
Modified: trunk/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h (262082 => 262083)
--- trunk/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h 2020-05-22 22:27:02 UTC (rev 262082)
+++ trunk/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h 2020-05-22 22:31:13 UTC (rev 262083)
@@ -87,6 +87,8 @@
static void visitChildren(JSCell*, SlotVisitor&);
private:
+ friend class LLIntOffsetsExtractor;
+
JSPropertyNameEnumerator(VM&, Structure*, uint32_t, uint32_t, WriteBarrier<JSString>*, unsigned);
void finishCreation(VM&, RefPtr<PropertyNameArrayData>&&);