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();