super should not depend on __proto__
https://bugs.webkit.org/show_bug.cgi?id=157972
Reviewed by Saam Barati.
JSTests:
* microbenchmarks/object-get-prototype-of-primitive.js: Added.
* stress/class-syntax-derived-default-constructor.js:
* stress/get-prototype-of.js: Added.
* stress/super-property-access.js:
* test262/expectations.yaml: Mark 4 test cases as passing.
Source/JavaScriptCore:
Before this change, both super() call [1] and super.property [2] relied on
Object.prototype.__proto__ to acquire super base, which was observable and
incorrect if __proto__ gets removed.
This patch introduces get_prototype_of bytecode, ensuring returned values
are profiled so the op can be wired to existing DFG and FTL implementations.
In order to avoid performance regression w/o DFG (__proto__ is optimized via
IntrinsicGetterAccessCase), fast paths for LLInt and baseline JIT are added
(64-bit only), utilizing OverridesGetPrototypeOutOfLine type info flag.
This change aligns JSC with V8 and SpiderMonkey, progressing microbenchmarks/
super-get-by-{id,val}-with-this-monomorphic.js by 7-10%. SixSpeed is neutral.
Also, extracts JSValue::getPrototype() method to avoid code duplication and
utilizes it in objectConstructorGetPrototypeOf(), advancing provided
microbenchmark by 40%.
[1]: https://tc39.es/ecma262/#sec-getsuperconstructor (step 5)
[2]: https://tc39.es/ecma262/#sec-getsuperbase (step 5)
* builtins/BuiltinNames.h:
* bytecode/BytecodeIntrinsicRegistry.h:
* bytecode/BytecodeList.rb:
* bytecode/BytecodeUseDef.cpp:
(JSC::computeUsesForBytecodeIndexImpl):
(JSC::computeDefsForBytecodeIndexImpl):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
* bytecode/Opcode.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetPrototypeOf):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::emitSuperBaseForCallee):
(JSC::emitGetSuperFunctionForConstruct):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_getPrototypeOf):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGOperations.cpp:
* jit/IntrinsicEmitter.cpp:
(JSC::IntrinsicGetterAccessCase::canEmitIntrinsicGetter):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_get_prototype_of):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/JSCJSValue.h:
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::getPrototype const):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncProtoGetter):
* runtime/JSObject.cpp:
(JSC::JSObject::calculatedClassName):
* runtime/JSObject.h:
(JSC::JSObject::getPrototype):
* runtime/JSObjectInlines.h:
(JSC::JSObject::canPerformFastPutInlineExcludingProto):
(JSC::JSObject::getPropertySlot):
(JSC::JSObject::getNonIndexPropertySlot):
* runtime/JSProxy.h:
* runtime/JSTypeInfo.h:
(JSC::TypeInfo::overridesGetPrototype const):
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorGetPrototypeOf):
* runtime/ProxyObject.h:
* runtime/Structure.h:
* runtime/Structure.cpp:
(JSC::Structure::validateFlags):
Source/WebCore:
No new tests, no behavior change.
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader): Set OverridesGetPrototype structure flag for CustomGetPrototype IDL attribute.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@263035 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index eeb9f10..469332b 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,90 @@
+2020-06-15 Alexey Shvayka <shvaikalesh@gmail.com>
+
+ super should not depend on __proto__
+ https://bugs.webkit.org/show_bug.cgi?id=157972
+
+ Reviewed by Saam Barati.
+
+ Before this change, both super() call [1] and super.property [2] relied on
+ Object.prototype.__proto__ to acquire super base, which was observable and
+ incorrect if __proto__ gets removed.
+
+ This patch introduces get_prototype_of bytecode, ensuring returned values
+ are profiled so the op can be wired to existing DFG and FTL implementations.
+ In order to avoid performance regression w/o DFG (__proto__ is optimized via
+ IntrinsicGetterAccessCase), fast paths for LLInt and baseline JIT are added
+ (64-bit only), utilizing OverridesGetPrototypeOutOfLine type info flag.
+
+ This change aligns JSC with V8 and SpiderMonkey, progressing microbenchmarks/
+ super-get-by-{id,val}-with-this-monomorphic.js by 7-10%. SixSpeed is neutral.
+
+ Also, extracts JSValue::getPrototype() method to avoid code duplication and
+ utilizes it in objectConstructorGetPrototypeOf(), advancing provided
+ microbenchmark by 40%.
+
+ [1]: https://tc39.es/ecma262/#sec-getsuperconstructor (step 5)
+ [2]: https://tc39.es/ecma262/#sec-getsuperbase (step 5)
+
+ * builtins/BuiltinNames.h:
+ * bytecode/BytecodeIntrinsicRegistry.h:
+ * bytecode/BytecodeList.rb:
+ * bytecode/BytecodeUseDef.cpp:
+ (JSC::computeUsesForBytecodeIndexImpl):
+ (JSC::computeDefsForBytecodeIndexImpl):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::finishCreation):
+ * bytecode/Opcode.h:
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitGetPrototypeOf):
+ * bytecompiler/BytecodeGenerator.h:
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::emitSuperBaseForCallee):
+ (JSC::emitGetSuperFunctionForConstruct):
+ (JSC::BytecodeIntrinsicNode::emit_intrinsic_getPrototypeOf):
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGOperations.cpp:
+ * jit/IntrinsicEmitter.cpp:
+ (JSC::IntrinsicGetterAccessCase::canEmitIntrinsicGetter):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ (JSC::JIT::privateCompileSlowCases):
+ * jit/JIT.h:
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_get_prototype_of):
+ * llint/LowLevelInterpreter.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::SLOW_PATH_DECL):
+ * runtime/CommonSlowPaths.h:
+ * runtime/JSCJSValue.h:
+ * runtime/JSCJSValueInlines.h:
+ (JSC::JSValue::getPrototype const):
+ * runtime/JSGlobalObjectFunctions.cpp:
+ (JSC::globalFuncProtoGetter):
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::calculatedClassName):
+ * runtime/JSObject.h:
+ (JSC::JSObject::getPrototype):
+ * runtime/JSObjectInlines.h:
+ (JSC::JSObject::canPerformFastPutInlineExcludingProto):
+ (JSC::JSObject::getPropertySlot):
+ (JSC::JSObject::getNonIndexPropertySlot):
+ * runtime/JSProxy.h:
+ * runtime/JSTypeInfo.h:
+ (JSC::TypeInfo::overridesGetPrototype const):
+ * runtime/ObjectConstructor.cpp:
+ (JSC::objectConstructorGetPrototypeOf):
+ * runtime/ProxyObject.h:
+ * runtime/Structure.h:
+ * runtime/Structure.cpp:
+ (JSC::Structure::validateFlags):
+
2020-06-13 Devin Rousso <drousso@apple.com>
Make `errors` an own property of `AggregateError` instead of a prototype accessor
diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.h b/Source/JavaScriptCore/builtins/BuiltinNames.h
index 745488be..a88555b 100644
--- a/Source/JavaScriptCore/builtins/BuiltinNames.h
+++ b/Source/JavaScriptCore/builtins/BuiltinNames.h
@@ -65,7 +65,6 @@
macro(create) \
macro(defineProperty) \
macro(defaultPromiseThen) \
- macro(getPrototypeOf) \
macro(getOwnPropertyNames) \
macro(ownKeys) \
macro(Set) \
diff --git a/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h b/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
index 091d78c..9e710b86 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
@@ -42,6 +42,7 @@
macro(argumentCount) \
macro(getByIdDirect) \
macro(getByIdDirectPrivate) \
+ macro(getPrototypeOf) \
macro(getPromiseInternalField) \
macro(getGeneratorInternalField) \
macro(getAsyncGeneratorInternalField) \
diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.rb b/Source/JavaScriptCore/bytecode/BytecodeList.rb
index d3e678b..08aeae9 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeList.rb
+++ b/Source/JavaScriptCore/bytecode/BytecodeList.rb
@@ -498,6 +498,15 @@
offset: unsigned,
}
+op :get_prototype_of,
+ args: {
+ dst: VirtualRegister,
+ value: VirtualRegister,
+ },
+ metadata: {
+ profile: ValueProfile,
+ }
+
op :try_get_by_id,
args: {
dst: VirtualRegister,
diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp b/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp
index b0f2e80..ce470c9 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp
+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp
@@ -167,6 +167,7 @@
USES(OpTryGetById, base)
USES(OpGetById, base)
USES(OpGetByIdDirect, base)
+ USES(OpGetPrototypeOf, value)
USES(OpInById, base)
USES(OpTypeof, value)
USES(OpIsEmpty, operand)
@@ -425,6 +426,7 @@
DEFS(OpGetByIdDirect, dst)
DEFS(OpGetByIdWithThis, dst)
DEFS(OpGetByValWithThis, dst)
+ DEFS(OpGetPrototypeOf, dst)
DEFS(OpOverridesHasInstance, dst)
DEFS(OpInstanceof, dst)
DEFS(OpInstanceofCustom, dst)
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 9502389..e98f6c2 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -514,6 +514,7 @@
LINK(OpTryGetById, profile)
LINK(OpGetByIdDirect, profile)
LINK(OpGetByValWithThis, profile)
+ LINK(OpGetPrototypeOf, profile)
LINK(OpGetFromArguments, profile)
LINK(OpToNumber, profile)
LINK(OpToNumeric, profile)
diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h
index aa8859a..a90dc43 100644
--- a/Source/JavaScriptCore/bytecode/Opcode.h
+++ b/Source/JavaScriptCore/bytecode/Opcode.h
@@ -105,6 +105,7 @@
macro(OpTryGetById) \
macro(OpGetByIdDirect) \
macro(OpGetByValWithThis) \
+ macro(OpGetPrototypeOf) \
macro(OpGetFromArguments) \
macro(OpToNumber) \
macro(OpToNumeric) \
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 0cc8bb7..e646d04 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -2686,6 +2686,12 @@
return dst;
}
+RegisterID* BytecodeGenerator::emitGetPrototypeOf(RegisterID* dst, RegisterID* value)
+{
+ OpGetPrototypeOf::emit(this, dst, value);
+ return dst;
+}
+
RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
{
OpPutByVal::emit(this, base, property, value, ecmaMode());
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index c4b3ed7..5e19245 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -811,6 +811,7 @@
RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&);
RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property);
+ RegisterID* emitGetPrototypeOf(RegisterID* dst, RegisterID* value);
RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
RegisterID* emitPutByVal(RegisterID* base, RegisterID* thisValue, RegisterID* property, RegisterID* value);
RegisterID* emitDirectGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 297d0f6..e94359b 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -196,17 +196,17 @@
static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator)
{
RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator);
- return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto);
+ return generator.emitGetPrototypeOf(generator.newTemporary(), homeObject.get());
}
static RegisterID* emitGetSuperFunctionForConstruct(BytecodeGenerator& generator)
{
if (generator.isDerivedConstructorContext())
- return generator.emitGetById(generator.newTemporary(), generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(), generator.propertyNames().underscoreProto);
+ return generator.emitGetPrototypeOf(generator.newTemporary(), generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment());
RegisterID callee;
callee.setIndex(CallFrameSlot::callee);
- return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().underscoreProto);
+ return generator.emitGetPrototypeOf(generator.newTemporary(), &callee);
}
RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -1156,6 +1156,14 @@
return generator.emitDirectGetById(generator.finalDestination(dst), base.get(), generator.parserArena().identifierArena().makeIdentifier(generator.vm(), symbol));
}
+RegisterID* BytecodeIntrinsicNode::emit_intrinsic_getPrototypeOf(BytecodeGenerator& generator, RegisterID* dst)
+{
+ ArgumentListNode* node = m_args->m_listNode;
+ RefPtr<RegisterID> value = generator.emitNode(node);
+ ASSERT(!node->m_next);
+ return generator.emitGetPrototypeOf(generator.finalDestination(dst), value.get());
+}
+
static JSPromise::Field promiseInternalFieldIndex(BytecodeIntrinsicNode* node)
{
ASSERT(node->entry().type() == BytecodeIntrinsicRegistry::Type::Emitter);
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 7366cf1..a54c2e0 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -3698,9 +3698,7 @@
bool canFold = !value.m_structure.isClear();
JSValue prototype;
value.m_structure.forEach([&] (RegisteredStructure structure) {
- auto getPrototypeMethod = structure->classInfo()->methodTable.getPrototype;
- MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
- if (getPrototypeMethod != defaultGetPrototype) {
+ if (structure->typeInfo().overridesGetPrototype()) {
canFold = false;
return;
}
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 6b5bf17..6f3c737 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -3830,9 +3830,7 @@
bool canFold = !variant.structureSet().isEmpty();
JSValue prototype;
variant.structureSet().forEach([&] (Structure* structure) {
- auto getPrototypeMethod = structure->classInfo()->methodTable.getPrototype;
- MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
- if (getPrototypeMethod != defaultGetPrototype) {
+ if (structure->typeInfo().overridesGetPrototype()) {
canFold = false;
return;
}
@@ -6103,6 +6101,13 @@
NEXT_OPCODE(op_get_by_id_with_this);
}
+
+ case op_get_prototype_of: {
+ auto bytecode = currentInstruction->as<OpGetPrototypeOf>();
+ set(bytecode.m_dst, addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(getPrediction()), get(bytecode.m_value)));
+ NEXT_OPCODE(op_get_prototype_of);
+ }
+
case op_put_by_id: {
auto bytecode = currentInstruction->as<OpPutById>();
Node* value = get(bytecode.m_value);
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index 73101c7..a995f1c 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -174,6 +174,7 @@
case op_get_by_id_with_this:
case op_get_by_id_direct:
case op_get_by_val_with_this:
+ case op_get_prototype_of:
case op_put_by_id:
case op_put_by_id_with_this:
case op_put_by_val_with_this:
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 1192319..58fda9b 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -3268,22 +3268,8 @@
VM& vm = globalObject->vm();
CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
- auto scope = DECLARE_THROW_SCOPE(vm);
-
- JSValue thisValue = JSValue::decode(encodedValue).toThis(globalObject, ECMAMode::strict());
- if (thisValue.isUndefinedOrNull())
- return throwVMError(globalObject, scope, createNotAnObjectError(globalObject, thisValue));
-
- JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue);
- if (!thisObject) {
- JSObject* prototype = thisValue.synthesizePrototype(globalObject);
- EXCEPTION_ASSERT(!!scope.exception() == !prototype);
- if (UNLIKELY(!prototype))
- return JSValue::encode(JSValue());
- return JSValue::encode(prototype);
- }
-
- RELEASE_AND_RETURN(scope, JSValue::encode(thisObject->getPrototype(vm, globalObject)));
+ JSValue value = JSValue::decode(encodedValue);
+ return JSValue::encode(value.getPrototype(globalObject));
}
EncodedJSValue JIT_OPERATION operationDateGetFullYear(VM* vmPointer, DateInstance* date)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 88abe0e..fe87bd8 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -13943,6 +13943,8 @@
return;
}
case ObjectUse: {
+ // FIXME: Add fast path based on OverridesGetPrototype type info flag
+ // https://bugs.webkit.org/show_bug.cgi?id=213191
SpeculateCellOperand value(this, node->child1());
JSValueRegsTemporary result(this);
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
index 70c09ea..08cd82b 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
@@ -4439,6 +4439,8 @@
return;
}
case ObjectUse: {
+ // FIXME: Add fast path based on OverridesGetPrototype type info flag
+ // https://bugs.webkit.org/show_bug.cgi?id=213191
setJSValue(vmCall(Int64, operationGetPrototypeOfObject, weakPointer(globalObject), lowObject(m_node->child1())));
return;
}
diff --git a/Source/JavaScriptCore/jit/IntrinsicEmitter.cpp b/Source/JavaScriptCore/jit/IntrinsicEmitter.cpp
index fa0292b..94f7afe 100644
--- a/Source/JavaScriptCore/jit/IntrinsicEmitter.cpp
+++ b/Source/JavaScriptCore/jit/IntrinsicEmitter.cpp
@@ -61,9 +61,8 @@
return true;
}
case UnderscoreProtoIntrinsic: {
- auto getPrototypeMethod = structure->classInfo()->methodTable.getPrototype;
- MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
- return getPrototypeMethod == defaultGetPrototype;
+ TypeInfo info = structure->typeInfo();
+ return info.isObject() && !info.overridesGetPrototype();
}
default:
return false;
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 5160830..6005cd4 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -318,6 +318,9 @@
DEFINE_SLOW_OP(create_async_generator)
DEFINE_SLOW_OP(new_generator)
DEFINE_SLOW_OP(pow)
+#if !USE(JSVALUE64)
+ DEFINE_SLOW_OP(get_prototype_of)
+#endif
DEFINE_OP(op_add)
DEFINE_OP(op_bitnot)
@@ -470,6 +473,10 @@
DEFINE_OP(op_log_shadow_chicken_prologue)
DEFINE_OP(op_log_shadow_chicken_tail)
+
+#if USE(JSVALUE64)
+ DEFINE_OP(op_get_prototype_of)
+#endif
default:
RELEASE_ASSERT_NOT_REACHED();
}
@@ -624,7 +631,9 @@
DEFINE_SLOWCASE_SLOW_OP(resolve_scope)
DEFINE_SLOWCASE_SLOW_OP(check_tdz)
DEFINE_SLOWCASE_SLOW_OP(to_property_key)
-
+#if USE(JSVALUE64)
+ DEFINE_SLOWCASE_SLOW_OP(get_prototype_of)
+#endif
default:
RELEASE_ASSERT_NOT_REACHED();
}
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index 27557b3..666e0ed 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -528,6 +528,7 @@
void emit_op_get_by_id_direct(const Instruction*);
void emit_op_get_by_val(const Instruction*);
void emit_op_get_argument_by_val(const Instruction*);
+ void emit_op_get_prototype_of(const Instruction*);
void emit_op_in_by_id(const Instruction*);
void emit_op_init_lazy_reg(const Instruction*);
void emit_op_overrides_has_instance(const Instruction*);
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index 9d3d917..59f9852 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -1525,6 +1525,26 @@
emitPutVirtualRegister(dst, regT0);
}
+void JIT::emit_op_get_prototype_of(const Instruction* currentInstruction)
+{
+ auto bytecode = currentInstruction->as<OpGetPrototypeOf>();
+ emitGetVirtualRegister(bytecode.m_value, regT0);
+
+ addSlowCase(branchIfNotCell(regT0));
+ addSlowCase(branchIfNotObject(regT0));
+
+ emitLoadStructure(vm(), regT0, regT2, regT1);
+ addSlowCase(branchTest32(NonZero, Address(regT2, Structure::outOfLineTypeFlagsOffset()), TrustedImm32(OverridesGetPrototypeOutOfLine)));
+
+ load64(Address(regT2, Structure::prototypeOffset()), regT2);
+ Jump hasMonoProto = branchTest64(NonZero, regT2);
+ load64(Address(regT0, offsetRelativeToBase(knownPolyProtoOffset)), regT2);
+ hasMonoProto.link(this);
+
+ emitValueProfilingSite(bytecode.metadata(m_codeBlock));
+ emitStoreCell(bytecode.m_dst, regT2);
+}
+
void JIT::emit_op_enumerator_structure_pname(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpEnumeratorStructurePname>();
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index 4ab82a4..bb8efd5 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -546,6 +546,7 @@
# Type flags constants.
const MasqueradesAsUndefined = constexpr MasqueradesAsUndefined
const ImplementsDefaultHasInstance = constexpr ImplementsDefaultHasInstance
+const OverridesGetPrototypeOutOfLine = constexpr OverridesGetPrototypeOutOfLine
# Bytecode operand constants.
const FirstConstantRegisterIndexNarrow = constexpr FirstConstantRegisterIndex8
@@ -567,6 +568,7 @@
# Copied from PropertyOffset.h
const firstOutOfLineOffset = constexpr firstOutOfLineOffset
+const knownPolyProtoOffset = constexpr knownPolyProtoOffset
# ResolveType
const GlobalProperty = constexpr GlobalProperty
@@ -1774,6 +1776,7 @@
slowPathOp(has_structure_property)
slowPathOp(has_own_structure_property)
slowPathOp(in_structure_property)
+ slowPathOp(get_prototype_of)
end
slowPathOp(in_by_id)
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index 3e193db..c3141b4 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -1495,6 +1495,31 @@
end)
+llintOpWithProfile(op_get_prototype_of, OpGetPrototypeOf, macro (size, get, dispatch, return)
+ get(m_value, t1)
+ loadConstantOrVariable(size, t1, t0)
+
+ btqnz t0, notCellMask, .opGetPrototypeOfSlow
+ bbb JSCell::m_type[t0], ObjectType, .opGetPrototypeOfSlow
+
+ loadStructureWithScratch(t0, t2, t1, t3)
+ btinz Structure::m_outOfLineTypeFlags[t2], OverridesGetPrototypeOutOfLine, .opGetPrototypeOfSlow
+
+ loadq Structure::m_prototype[t2], t2
+ btqz t2, .opGetPrototypeOfPolyProto
+ return(t2)
+
+.opGetPrototypeOfSlow:
+ callSlowPath(_slow_path_get_prototype_of)
+ dispatch()
+
+.opGetPrototypeOfPolyProto:
+ loadi knownPolyProtoOffset, t1
+ loadPropertyAtVariableOffset(t1, t0, t3)
+ return(t3)
+end)
+
+
llintOpWithMetadata(op_put_by_id, OpPutById, macro (size, get, dispatch, metadata, return)
get(m_base, t3)
loadConstantOrVariableCell(size, t3, t0, .opPutByIdSlow)
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
index 345a81c..fdace72 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
@@ -1355,6 +1355,14 @@
RETURN_PROFILED(slot.getValue(globalObject, property));
}
+SLOW_PATH_DECL(slow_path_get_prototype_of)
+{
+ BEGIN();
+ auto bytecode = pc->as<OpGetPrototypeOf>();
+ JSValue value = GET_C(bytecode.m_value).jsValue();
+ RETURN_PROFILED(value.getPrototype(globalObject));
+}
+
SLOW_PATH_DECL(slow_path_put_by_id_with_this)
{
BEGIN();
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
index a76bf3ea..6538a55 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
@@ -276,6 +276,7 @@
SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_with_this);
SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val_with_this);
SLOW_PATH_HIDDEN_DECL(slow_path_get_private_name);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_prototype_of);
SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id_with_this);
SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_with_this);
SLOW_PATH_HIDDEN_DECL(slow_path_define_data_property);
diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.h b/Source/JavaScriptCore/runtime/JSCJSValue.h
index cc2cc10..081496b 100644
--- a/Source/JavaScriptCore/runtime/JSCJSValue.h
+++ b/Source/JavaScriptCore/runtime/JSCJSValue.h
@@ -321,6 +321,7 @@
JS_EXPORT_PRIVATE bool putToPrimitiveByIndex(JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
bool putByIndex(JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
+ JSValue getPrototype(JSGlobalObject*) const;
JSValue toThis(JSGlobalObject*, ECMAMode) const;
static bool equal(JSGlobalObject*, JSValue v1, JSValue v2);
diff --git a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h
index 011d58b..6ed79aa 100644
--- a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h
+++ b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h
@@ -1081,6 +1081,14 @@
return asCell()->methodTable(getVM(globalObject))->putByIndex(asCell(), globalObject, propertyName, value, shouldThrow);
}
+ALWAYS_INLINE JSValue JSValue::getPrototype(JSGlobalObject* globalObject) const
+{
+ VM& vm = getVM(globalObject);
+ if (isObject())
+ return asObject(asCell())->getPrototype(vm, globalObject);
+ return synthesizePrototype(globalObject);
+}
+
inline Structure* JSValue::structureOrNull() const
{
if (isCell())
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
index 38187a7..ea25e8b 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
@@ -693,23 +693,8 @@
EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(JSGlobalObject* globalObject, CallFrame* callFrame)
{
- VM& vm = globalObject->vm();
- auto scope = DECLARE_THROW_SCOPE(vm);
-
JSValue thisValue = callFrame->thisValue().toThis(globalObject, ECMAMode::strict());
- if (thisValue.isUndefinedOrNull())
- return throwVMError(globalObject, scope, createNotAnObjectError(globalObject, thisValue));
-
- JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue);
- if (!thisObject) {
- JSObject* prototype = thisValue.synthesizePrototype(globalObject);
- EXCEPTION_ASSERT(!!scope.exception() == !prototype);
- if (UNLIKELY(!prototype))
- return JSValue::encode(JSValue());
- return JSValue::encode(prototype);
- }
-
- RELEASE_AND_RETURN(scope, JSValue::encode(thisObject->getPrototype(vm, globalObject)));
+ return JSValue::encode(thisValue.getPrototype(globalObject));
}
EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(JSGlobalObject* globalObject, CallFrame* callFrame)
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 2f67e36..4de571f 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -554,8 +554,7 @@
// Get the display name of obj.__proto__.constructor.
// This is useful to get `Foo` for a `new Foo` object.
if (constructorFunctionName.isNull()) {
- MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
- if (LIKELY(structure->classInfo()->methodTable.getPrototype == defaultGetPrototype)) {
+ if (LIKELY(!structure->typeInfo().overridesGetPrototype())) {
JSValue protoValue = object->getPrototypeDirect(vm);
if (protoValue.isObject()) {
JSObject* protoObject = asObject(protoValue);
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 90ed139..3b0c661 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -1369,11 +1369,9 @@
inline JSValue JSObject::getPrototype(VM& vm, JSGlobalObject* globalObject)
{
- auto getPrototypeMethod = methodTable(vm)->getPrototype;
- MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
- if (LIKELY(getPrototypeMethod == defaultGetPrototype))
+ if (LIKELY(!structure(vm)->typeInfo().overridesGetPrototype()))
return getPrototypeDirect(vm);
- return getPrototypeMethod(this, globalObject);
+ return methodTable(vm)->getPrototype(this, globalObject);
}
// Normally, we never shrink the butterfly so if we know an offset is valid for some
diff --git a/Source/JavaScriptCore/runtime/JSObjectInlines.h b/Source/JavaScriptCore/runtime/JSObjectInlines.h
index eb76fac..6b2ef22 100644
--- a/Source/JavaScriptCore/runtime/JSObjectInlines.h
+++ b/Source/JavaScriptCore/runtime/JSObjectInlines.h
@@ -83,8 +83,8 @@
JSValue prototype;
JSObject* obj = this;
while (true) {
- MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
- if (obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || obj->methodTable(vm)->getPrototype != defaultGetPrototype)
+ Structure* structure = obj->structure(vm);
+ if (structure->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || structure->typeInfo().overridesGetPrototype())
return false;
prototype = obj->getPrototypeDirect(vm);
@@ -127,7 +127,6 @@
auto scope = DECLARE_THROW_SCOPE(vm);
auto& structureIDTable = vm.heap.structureIDTable();
JSObject* object = this;
- MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
while (true) {
Structure* structure = structureIDTable.get(object->structureID());
bool hasSlot = structure->classInfo()->methodTable.getOwnPropertySlotByIndex(object, globalObject, propertyName, slot);
@@ -137,7 +136,7 @@
if (object->type() == ProxyObjectType && slot.internalMethodType() == PropertySlot::InternalMethodType::HasProperty)
return false;
JSValue prototype;
- if (LIKELY(structure->classInfo()->methodTable.getPrototype == defaultGetPrototype || slot.internalMethodType() == PropertySlot::InternalMethodType::VMInquiry))
+ if (LIKELY(!structure->typeInfo().overridesGetPrototype() || slot.internalMethodType() == PropertySlot::InternalMethodType::VMInquiry))
prototype = object->getPrototypeDirect(vm);
else {
prototype = object->getPrototype(vm, globalObject);
@@ -165,7 +164,6 @@
auto scope = DECLARE_THROW_SCOPE(vm);
auto& structureIDTable = vm.heap.structureIDTable();
JSObject* object = this;
- MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
while (true) {
Structure* structure = structureIDTable.get(object->structureID());
if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(object->inlineTypeFlags()))) {
@@ -180,7 +178,7 @@
return false;
}
JSValue prototype;
- if (LIKELY(structure->classInfo()->methodTable.getPrototype == defaultGetPrototype || slot.internalMethodType() == PropertySlot::InternalMethodType::VMInquiry))
+ if (LIKELY(!structure->typeInfo().overridesGetPrototype() || slot.internalMethodType() == PropertySlot::InternalMethodType::VMInquiry))
prototype = object->getPrototypeDirect(vm);
else {
prototype = object->getPrototype(vm, globalObject);
diff --git a/Source/JavaScriptCore/runtime/JSProxy.h b/Source/JavaScriptCore/runtime/JSProxy.h
index 336f60a..75fdc57 100644
--- a/Source/JavaScriptCore/runtime/JSProxy.h
+++ b/Source/JavaScriptCore/runtime/JSProxy.h
@@ -32,7 +32,7 @@
class JSProxy : public JSNonFinalObject {
public:
using Base = JSNonFinalObject;
- static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | OverridesAnyFormOfGetPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
+ static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | OverridesAnyFormOfGetPropertyNames | OverridesGetPrototype | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
template<typename CellType, SubspaceAccess>
static IsoSubspace* subspaceFor(VM& vm)
diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h
index afbc1da..0e367b0 100644
--- a/Source/JavaScriptCore/runtime/JSTypeInfo.h
+++ b/Source/JavaScriptCore/runtime/JSTypeInfo.h
@@ -63,6 +63,10 @@
static constexpr unsigned InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero = 1 << 16;
static constexpr unsigned StructureIsImmortal = 1 << 17;
static constexpr unsigned HasPutPropertySecurityCheck = 1 << 18;
+static constexpr unsigned OverridesGetPrototype = 1 << 19;
+
+static constexpr unsigned numberOfInlineBits = 8;
+static constexpr unsigned OverridesGetPrototypeOutOfLine = OverridesGetPrototype >> numberOfInlineBits;
class TypeInfo {
public:
@@ -70,7 +74,7 @@
typedef uint16_t OutOfLineTypeFlags;
TypeInfo(JSType type, unsigned flags)
- : TypeInfo(type, flags & 0xff, flags >> 8)
+ : TypeInfo(type, flags & 0xff, flags >> numberOfInlineBits)
{
ASSERT(!(flags >> 24));
}
@@ -88,7 +92,7 @@
bool isFinalObject() const { return type() == FinalObjectType; }
bool isNumberObject() const { return type() == NumberObjectType; }
- unsigned flags() const { return (static_cast<unsigned>(m_flags2) << 8) | static_cast<unsigned>(m_flags); }
+ unsigned flags() const { return (static_cast<unsigned>(m_flags2) << numberOfInlineBits) | static_cast<unsigned>(m_flags); }
bool masqueradesAsUndefined() const { return isSetOnFlags1<MasqueradesAsUndefined>(); }
bool implementsHasInstance() const { return isSetOnFlags2<ImplementsHasInstance>(); }
bool implementsDefaultHasInstance() const { return isSetOnFlags1<ImplementsDefaultHasInstance>(); }
@@ -101,6 +105,7 @@
bool structureIsImmortal() const { return isSetOnFlags2<StructureIsImmortal>(); }
bool overridesGetPropertyNames() const { return isSetOnFlags2<OverridesGetPropertyNames>(); }
bool overridesAnyFormOfGetPropertyNames() const { return isSetOnFlags2<OverridesAnyFormOfGetPropertyNames>(); }
+ bool overridesGetPrototype() const { return isSetOnFlags2<OverridesGetPrototype>(); }
bool prohibitsPropertyCaching() const { return isSetOnFlags2<ProhibitsPropertyCaching>(); }
bool getOwnPropertySlotIsImpure() const { return isSetOnFlags2<GetOwnPropertySlotIsImpure>(); }
bool getOwnPropertySlotIsImpureForPropertyAbsence() const { return isSetOnFlags2<GetOwnPropertySlotIsImpureForPropertyAbsence>(); }
@@ -148,8 +153,8 @@
template<unsigned flag>
bool isSetOnFlags2() const
{
- static_assert(flag >= (1 << 8) && flag <= (1 << 24));
- return m_flags2 & (flag >> 8);
+ static_assert(flag >= (1 << numberOfInlineBits) && flag <= (1 << 24));
+ return m_flags2 & (flag >> numberOfInlineBits);
}
JSType m_type;
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
index 4d31e1c..3a6f1f3 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -144,11 +144,7 @@
EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(JSGlobalObject* globalObject, CallFrame* callFrame)
{
- VM& vm = globalObject->vm();
- auto scope = DECLARE_THROW_SCOPE(vm);
- JSObject* object = callFrame->argument(0).toObject(globalObject);
- RETURN_IF_EXCEPTION(scope, encodedJSValue());
- RELEASE_AND_RETURN(scope, JSValue::encode(object->getPrototype(vm, globalObject)));
+ return JSValue::encode(callFrame->argument(0).getPrototype(globalObject));
}
EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(JSGlobalObject* globalObject, CallFrame* callFrame)
diff --git a/Source/JavaScriptCore/runtime/ProxyObject.h b/Source/JavaScriptCore/runtime/ProxyObject.h
index d3b65ec..e0861e6 100644
--- a/Source/JavaScriptCore/runtime/ProxyObject.h
+++ b/Source/JavaScriptCore/runtime/ProxyObject.h
@@ -34,7 +34,7 @@
public:
typedef JSNonFinalObject Base;
- static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | OverridesAnyFormOfGetPropertyNames | ProhibitsPropertyCaching;
+ static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | OverridesAnyFormOfGetPropertyNames | OverridesGetPrototype | ProhibitsPropertyCaching;
template<typename CellType, SubspaceAccess mode>
static IsoSubspace* subspaceFor(VM& vm)
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index a79affe..2234291 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -212,6 +212,13 @@
|| overridesGetOwnPropertyNames
|| overridesGetOwnNonIndexPropertyNames)
RELEASE_ASSERT(typeInfo().overridesAnyFormOfGetPropertyNames());
+
+ bool overridesGetPrototype =
+ methodTable.getPrototype != static_cast<MethodTable::GetPrototypeFunctionPtr>(JSObject::getPrototype)
+ && methodTable.getPrototype != JSCell::getPrototype;
+
+ if (overridesGetPrototype)
+ RELEASE_ASSERT(typeInfo().overridesGetPrototype());
}
#else
inline void Structure::validateFlags() { }
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 73b6ae5..6f620a6 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -559,7 +559,12 @@
{
return OBJECT_OFFSETOF(Structure, m_classInfo);
}
-
+
+ static ptrdiff_t outOfLineTypeFlagsOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_outOfLineTypeFlags);
+ }
+
static ptrdiff_t indexingModeIncludingHistoryOffset()
{
return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingModeIncludingHistoryOffset();