[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/JSTests/ChangeLog b/JSTests/ChangeLog
index 1bfbf11..96bf4cf 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,28 @@
+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 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):
+
2017-11-20 Guillaume Emont <guijemont@igalia.com>
Skip stress/unshiftCountSlowCase-correct-postCapacity.js on embedded Linux
diff --git a/JSTests/stress/intrinsic-getter-with-poly-proto-getter-change.js b/JSTests/stress/intrinsic-getter-with-poly-proto-getter-change.js
new file mode 100644
index 0000000..56b425a
--- /dev/null
+++ b/JSTests/stress/intrinsic-getter-with-poly-proto-getter-change.js
@@ -0,0 +1,33 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function makePolyProtoObject() {
+ function foo() {
+ class C {
+ constructor() {
+ this._field = 42;
+ }
+ };
+ return new C;
+ }
+ for (let i = 0; i < 15; ++i)
+ foo();
+ return foo();
+}
+
+function target(object)
+{
+ return object.__proto__;
+}
+noInline(target);
+
+var polyProtoObject = makePolyProtoObject();
+var prototype = Reflect.getPrototypeOf(polyProtoObject);
+for (var i = 0; i < 1e5; ++i)
+ shouldBe(target(polyProtoObject), prototype);
+Object.defineProperty(Object.prototype, "__proto__", {
+ get: function () { return null; }
+});
+shouldBe(target(polyProtoObject), null);
diff --git a/JSTests/stress/intrinsic-getter-with-poly-proto-proto-change.js b/JSTests/stress/intrinsic-getter-with-poly-proto-proto-change.js
new file mode 100644
index 0000000..c77d8e3
--- /dev/null
+++ b/JSTests/stress/intrinsic-getter-with-poly-proto-proto-change.js
@@ -0,0 +1,32 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function makePolyProtoObject() {
+ function foo() {
+ class C {
+ constructor() {
+ this._field = 42;
+ }
+ };
+ return new C;
+ }
+ for (let i = 0; i < 15; ++i)
+ foo();
+ return foo();
+}
+
+function target(object)
+{
+ return object.__proto__;
+}
+noInline(target);
+
+var polyProtoObject = makePolyProtoObject();
+var prototype = Reflect.getPrototypeOf(polyProtoObject);
+for (var i = 0; i < 1e5; ++i)
+ shouldBe(target(polyProtoObject), prototype);
+
+polyProtoObject.__proto__ = null
+shouldBe(target(polyProtoObject), undefined)
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));