[JSC] Allow poly proto for intrinsic getters
https://bugs.webkit.org/show_bug.cgi?id=179550

Reviewed by Saam Barati.

JSTests:

This change is also tested by existing tests.

    1. stress/intrinsic-getter-with-poly-proto.js
    2. stress/poly-proto-intrinsic-getter-correctness.js

* stress/intrinsic-getter-with-poly-proto-getter-change.js: Added.
(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):
* stress/intrinsic-getter-with-poly-proto-proto-change.js: Added.
(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):

Source/JavaScriptCore:

This patch allows intrinsic getters to accept poly proto.
We propagate PolyProtoAccessChain in IntrinsicGetterAccessCase to perform
poly proto checks. And we extend UnderscoreProtoIntrinsic to emit
code for poly proto case.

* bytecode/IntrinsicGetterAccessCase.cpp:
(JSC::IntrinsicGetterAccessCase::IntrinsicGetterAccessCase):
(JSC::IntrinsicGetterAccessCase::create):
* bytecode/IntrinsicGetterAccessCase.h:
* jit/IntrinsicEmitter.cpp:
(JSC::IntrinsicGetterAccessCase::canEmitIntrinsicGetter):
(JSC::IntrinsicGetterAccessCase::emitIntrinsicGetter):
* jit/Repatch.cpp:
(JSC::tryCacheGetByID):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@225071 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 4d60be4..db6ac11 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,25 @@
+2017-11-21  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] Allow poly proto for intrinsic getters
+        https://bugs.webkit.org/show_bug.cgi?id=179550
+
+        Reviewed by Saam Barati.
+
+        This patch allows intrinsic getters to accept poly proto.
+        We propagate PolyProtoAccessChain in IntrinsicGetterAccessCase to perform
+        poly proto checks. And we extend UnderscoreProtoIntrinsic to emit
+        code for poly proto case.
+
+        * bytecode/IntrinsicGetterAccessCase.cpp:
+        (JSC::IntrinsicGetterAccessCase::IntrinsicGetterAccessCase):
+        (JSC::IntrinsicGetterAccessCase::create):
+        * bytecode/IntrinsicGetterAccessCase.h:
+        * jit/IntrinsicEmitter.cpp:
+        (JSC::IntrinsicGetterAccessCase::canEmitIntrinsicGetter):
+        (JSC::IntrinsicGetterAccessCase::emitIntrinsicGetter):
+        * jit/Repatch.cpp:
+        (JSC::tryCacheGetByID):
+
 2017-11-20  Don Olmstead  <don.olmstead@sony.com>
 
         Detect __declspec within JSBase.h
diff --git a/Source/JavaScriptCore/bytecode/IntrinsicGetterAccessCase.cpp b/Source/JavaScriptCore/bytecode/IntrinsicGetterAccessCase.cpp
index b631dba..c8134f8 100644
--- a/Source/JavaScriptCore/bytecode/IntrinsicGetterAccessCase.cpp
+++ b/Source/JavaScriptCore/bytecode/IntrinsicGetterAccessCase.cpp
@@ -32,15 +32,15 @@
 
 namespace JSC {
 
-IntrinsicGetterAccessCase::IntrinsicGetterAccessCase(VM& vm, JSCell* owner, PropertyOffset offset, Structure* structure, const ObjectPropertyConditionSet& conditionSet, JSFunction* intrinsicFunction)
-    : Base(vm, owner, IntrinsicGetter, offset, structure, conditionSet, nullptr)
+IntrinsicGetterAccessCase::IntrinsicGetterAccessCase(VM& vm, JSCell* owner, PropertyOffset offset, Structure* structure, const ObjectPropertyConditionSet& conditionSet, JSFunction* intrinsicFunction, std::unique_ptr<PolyProtoAccessChain> prototypeAccessChain)
+    : Base(vm, owner, IntrinsicGetter, offset, structure, conditionSet, WTFMove(prototypeAccessChain))
 {
     m_intrinsicFunction.set(vm, owner, intrinsicFunction);
 }
 
-std::unique_ptr<AccessCase> IntrinsicGetterAccessCase::create(VM& vm, JSCell* owner, PropertyOffset offset, Structure* structure, const ObjectPropertyConditionSet& conditionSet, JSFunction* intrinsicFunction)
+std::unique_ptr<AccessCase> IntrinsicGetterAccessCase::create(VM& vm, JSCell* owner, PropertyOffset offset, Structure* structure, const ObjectPropertyConditionSet& conditionSet, JSFunction* intrinsicFunction, std::unique_ptr<PolyProtoAccessChain> prototypeAccessChain)
 {
-    return std::unique_ptr<AccessCase>(new IntrinsicGetterAccessCase(vm, owner, offset, structure, conditionSet, intrinsicFunction));
+    return std::unique_ptr<AccessCase>(new IntrinsicGetterAccessCase(vm, owner, offset, structure, conditionSet, intrinsicFunction, WTFMove(prototypeAccessChain)));
 }
 
 IntrinsicGetterAccessCase::~IntrinsicGetterAccessCase()
diff --git a/Source/JavaScriptCore/bytecode/IntrinsicGetterAccessCase.h b/Source/JavaScriptCore/bytecode/IntrinsicGetterAccessCase.h
index 67d42f8..b3980e488 100644
--- a/Source/JavaScriptCore/bytecode/IntrinsicGetterAccessCase.h
+++ b/Source/JavaScriptCore/bytecode/IntrinsicGetterAccessCase.h
@@ -42,16 +42,14 @@
     static bool canEmitIntrinsicGetter(JSFunction*, Structure*);
     void emitIntrinsicGetter(AccessGenerationState&);
 
-    // FIXME: Make this work with poly proto:
-    // https://bugs.webkit.org/show_bug.cgi?id=177318
-    static std::unique_ptr<AccessCase> create(VM&, JSCell*, PropertyOffset, Structure*, const ObjectPropertyConditionSet&, JSFunction* intrinsicFunction);
+    static std::unique_ptr<AccessCase> create(VM&, JSCell*, PropertyOffset, Structure*, const ObjectPropertyConditionSet&, JSFunction* intrinsicFunction, std::unique_ptr<PolyProtoAccessChain>);
 
     std::unique_ptr<AccessCase> clone() const override;
 
     ~IntrinsicGetterAccessCase();
 
 private:
-    IntrinsicGetterAccessCase(VM&, JSCell*, PropertyOffset, Structure*, const ObjectPropertyConditionSet&, JSFunction* intrinsicFunction);
+    IntrinsicGetterAccessCase(VM&, JSCell*, PropertyOffset, Structure*, const ObjectPropertyConditionSet&, JSFunction* intrinsicFunction, std::unique_ptr<PolyProtoAccessChain>);
 
     WriteBarrier<JSFunction> m_intrinsicFunction;
 };
diff --git a/Source/JavaScriptCore/jit/IntrinsicEmitter.cpp b/Source/JavaScriptCore/jit/IntrinsicEmitter.cpp
index 934e2db..8e8e98b 100644
--- a/Source/JavaScriptCore/jit/IntrinsicEmitter.cpp
+++ b/Source/JavaScriptCore/jit/IntrinsicEmitter.cpp
@@ -64,8 +64,6 @@
         return true;
     }
     case UnderscoreProtoIntrinsic: {
-        if (structure->hasPolyProto())
-            return false;
         auto getPrototypeMethod = structure->classInfo()->methodTable.getPrototype;
         MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
         return getPrototypeMethod == defaultGetPrototype;
@@ -133,8 +131,10 @@
     }
 
     case UnderscoreProtoIntrinsic: {
-        ASSERT(structure()->hasMonoProto());
-        jit.moveValue(structure()->storedPrototype(), valueRegs);
+        if (structure()->hasPolyProto())
+            jit.loadValue(CCallHelpers::Address(baseGPR, offsetRelativeToBase(knownPolyProtoOffset)), valueRegs);
+        else
+            jit.moveValue(structure()->storedPrototype(), valueRegs);
         state.succeed();
         return;
     }
diff --git a/Source/JavaScriptCore/jit/Repatch.cpp b/Source/JavaScriptCore/jit/Repatch.cpp
index e92321c..1b34051 100644
--- a/Source/JavaScriptCore/jit/Repatch.cpp
+++ b/Source/JavaScriptCore/jit/Repatch.cpp
@@ -321,13 +321,9 @@
                     RELEASE_ASSERT_NOT_REACHED();
 
                 newCase = ProxyableAccessCase::create(vm, codeBlock, type, offset, structure, conditionSet, loadTargetFromProxy, slot.watchpointSet(), WTFMove(prototypeAccessChain));
-            } else if (!loadTargetFromProxy && getter && IntrinsicGetterAccessCase::canEmitIntrinsicGetter(getter, structure) && !prototypeAccessChain) {
-                // FIXME: We should make this work with poly proto, but for our own sanity, we probably
-                // want to do a pointer check on the actual getter. A good time to make this work would
-                // be when we can inherit from builtin types in poly proto fashion:
-                // https://bugs.webkit.org/show_bug.cgi?id=177318
-                newCase = IntrinsicGetterAccessCase::create(vm, codeBlock, slot.cachedOffset(), structure, conditionSet, getter);
-            } else {
+            } else if (!loadTargetFromProxy && getter && IntrinsicGetterAccessCase::canEmitIntrinsicGetter(getter, structure))
+                newCase = IntrinsicGetterAccessCase::create(vm, codeBlock, slot.cachedOffset(), structure, conditionSet, getter, WTFMove(prototypeAccessChain));
+            else {
                 if (slot.isCacheableValue() || slot.isUnset()) {
                     newCase = ProxyableAccessCase::create(vm, codeBlock, slot.isUnset() ? AccessCase::Miss : AccessCase::Load,
                         offset, structure, conditionSet, loadTargetFromProxy, slot.watchpointSet(), WTFMove(prototypeAccessChain));