Title: [223594] trunk
Revision
223594
Author
utatane....@gmail.com
Date
2017-10-18 00:12:53 -0700 (Wed, 18 Oct 2017)

Log Message

[JSC] __proto__ getter should be fast
https://bugs.webkit.org/show_bug.cgi?id=178067

Reviewed by Saam Barati.

JSTests:

* stress/dfg-object-proto-accessor.js: Added.
(shouldBe):
(shouldThrow):
(target):
* stress/dfg-object-proto-getter.js: Added.
(shouldBe):
(shouldThrow):
(target):
* stress/dfg-object-prototype-of.js: Added.
(shouldBe):
(shouldThrow):
(target):
* stress/dfg-reflect-get-prototype-of.js: Added.
(shouldBe):
(shouldThrow):
(target):
* stress/intrinsic-getter-with-poly-proto.js: Added.
(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):
* stress/object-get-prototype-of-filtered.js: Added.
(shouldBe):
(shouldThrow):
(target):
(i.Cocoa):
* stress/object-get-prototype-of-mono-proto.js: Added.
(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):
* stress/object-get-prototype-of-poly-mono-proto.js: Added.
(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):
* stress/object-get-prototype-of-poly-proto.js: Added.
(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):
* stress/object-proto-getter-filtered.js: Added.
(shouldBe):
(shouldThrow):
(target):
(i.Cocoa):
* stress/object-proto-getter-poly-mono-proto.js: Added.
(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):
* stress/object-proto-getter-poly-proto.js: Added.
(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):
* stress/object-prototype-proto-accessors-should-throw-on-undefined-this.js:
* stress/string-proto.js: Added.
(shouldBe):
(target):

Source/_javascript_Core:

In our ES6 class implementation, we access __proto__ field to retrieve super constructor.
Currently, it is handled as an usual getter call to a generic function. And DFG just emits
Call node for this. It is inefficient since typically we know the `prototype` of the given
object when accessing `object.__proto__` since we emit CheckStructure for this `object`.
If Structure has mono proto, we can immediately fold it to constant value. If it is poly proto,
we can still change this to efficient access to poly proto slot.

This patch implements GetPrototypeOf DFG node. This node efficiently accesses to prototype of
the given object. And in AI and ByteCodeParser phase, we attempt to fold it to constant.
ByteCodeParser's folding is a bit important since we have `callee.__proto__` code to get super
constructor. If we can change this to constant, we can reify CallLinkInfo with this constant.
This paves the way to optimizing ArrayConstructor super calls[1], which is particularly important
for ARES-6 ML.

And we also optimize Reflect.getPrototypeOf and Object.getPrototypeOf with this GetPrototypeOf node.

Currently, __proto__ access for poly proto object is not handled well in IC. But we add code handling
poly proto in GetPrototypeOf since Reflect.getPrototypeOf and Object.getPrototypeOf can use it.
Once IC starts handling poly proto & intrinsic getter well, this code will be used for that too.

This patch improves SixSpeed super.es6 by 3.42x.

                         baseline                  patched

super.es6           123.6666+-3.9917     ^     36.1684+-1.0351        ^ definitely 3.4192x faster

[1]: https://bugs.webkit.org/show_bug.cgi?id=178064

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
(JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
(JSC::DFG::ByteCodeParser::handleGetById):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupGetPrototypeOf):
* dfg/DFGHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGHeapLocation.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::shouldSpeculateFunction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculateFunction):
(JSC::DFG::SpeculativeJIT::speculateFinalObject):
(JSC::DFG::SpeculativeJIT::compileGetPrototypeOf):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetPrototypeOf):
(JSC::FTL::DFG::LowerDFGToB3::compileInstanceOf):
* jit/IntrinsicEmitter.cpp:
(JSC::IntrinsicGetterAccessCase::canEmitIntrinsicGetter):
(JSC::IntrinsicGetterAccessCase::emitIntrinsicGetter):
* jit/JITOperations.h:
* runtime/Intrinsic.cpp:
(JSC::intrinsicName):
* runtime/Intrinsic.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::booleanPrototype const):
(JSC::JSGlobalObject::numberPrototype const):
(JSC::JSGlobalObject::booleanObjectStructure const):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncProtoGetter):
* runtime/JSGlobalObjectFunctions.h:
* runtime/ObjectConstructor.cpp:
* runtime/ReflectObject.cpp:

LayoutTests:

* js/object-literal-shorthand-construction-expected.txt:
* js/script-tests/object-literal-shorthand-construction.js:
(set 2):
(get 1):
* js/script-tests/sloppy-getter-setter-global-object.js:
* js/sloppy-getter-setter-global-object-expected.txt:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (223593 => 223594)


--- trunk/JSTests/ChangeLog	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/JSTests/ChangeLog	2017-10-18 07:12:53 UTC (rev 223594)
@@ -1,3 +1,77 @@
+2017-10-18  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] __proto__ getter should be fast
+        https://bugs.webkit.org/show_bug.cgi?id=178067
+
+        Reviewed by Saam Barati.
+
+        * stress/dfg-object-proto-accessor.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (target):
+        * stress/dfg-object-proto-getter.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (target):
+        * stress/dfg-object-prototype-of.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (target):
+        * stress/dfg-reflect-get-prototype-of.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (target):
+        * stress/intrinsic-getter-with-poly-proto.js: Added.
+        (shouldBe):
+        (makePolyProtoObject.foo.C):
+        (makePolyProtoObject.foo):
+        (makePolyProtoObject):
+        (target):
+        * stress/object-get-prototype-of-filtered.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (target):
+        (i.Cocoa):
+        * stress/object-get-prototype-of-mono-proto.js: Added.
+        (shouldBe):
+        (makePolyProtoObject.foo.C):
+        (makePolyProtoObject.foo):
+        (makePolyProtoObject):
+        (target):
+        * stress/object-get-prototype-of-poly-mono-proto.js: Added.
+        (shouldBe):
+        (makePolyProtoObject.foo.C):
+        (makePolyProtoObject.foo):
+        (makePolyProtoObject):
+        (target):
+        * stress/object-get-prototype-of-poly-proto.js: Added.
+        (shouldBe):
+        (makePolyProtoObject.foo.C):
+        (makePolyProtoObject.foo):
+        (makePolyProtoObject):
+        (target):
+        * stress/object-proto-getter-filtered.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (target):
+        (i.Cocoa):
+        * stress/object-proto-getter-poly-mono-proto.js: Added.
+        (shouldBe):
+        (makePolyProtoObject.foo.C):
+        (makePolyProtoObject.foo):
+        (makePolyProtoObject):
+        (target):
+        * stress/object-proto-getter-poly-proto.js: Added.
+        (shouldBe):
+        (makePolyProtoObject.foo.C):
+        (makePolyProtoObject.foo):
+        (makePolyProtoObject):
+        (target):
+        * stress/object-prototype-proto-accessors-should-throw-on-undefined-this.js:
+        * stress/string-proto.js: Added.
+        (shouldBe):
+        (target):
+
 2017-10-17  Ryan Haddad  <ryanhad...@apple.com>
 
         Unreviewed, rolling out r223523.

Added: trunk/JSTests/stress/dfg-object-proto-accessor.js (0 => 223594)


--- trunk/JSTests/stress/dfg-object-proto-accessor.js	                        (rev 0)
+++ trunk/JSTests/stress/dfg-object-proto-accessor.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,115 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target({}), Object.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i) {
+        shouldThrow(() => target(null), `TypeError: null is not an object (evaluating 'object.__proto__')`);
+        shouldThrow(() => target(undefined), `TypeError: undefined is not an object (evaluating 'object.__proto__')`);
+    }
+}());
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target("Cocoa"), String.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(42), Number.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(42.195), Number.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(true), Boolean.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(Symbol("Cocoa")), Symbol.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i) {
+        shouldBe(target("Cocoa"), String.prototype);
+        shouldBe(target(42), Number.prototype);
+        shouldBe(target(42.195), Number.prototype);
+        shouldBe(target(true), Boolean.prototype);
+        shouldBe(target(Symbol("Cocoa")), Symbol.prototype);
+    }
+}());

Added: trunk/JSTests/stress/dfg-object-proto-getter.js (0 => 223594)


--- trunk/JSTests/stress/dfg-object-proto-getter.js	                        (rev 0)
+++ trunk/JSTests/stress/dfg-object-proto-getter.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,117 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+var protoFunction = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__").get;
+
+(function () {
+    function target(object)
+    {
+        return protoFunction.call(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target({}), Object.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return protoFunction.call(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i) {
+        shouldThrow(() => target(null), `TypeError: null is not an object (evaluating 'protoFunction.call(object)')`);
+        shouldThrow(() => target(undefined), `TypeError: undefined is not an object (evaluating 'protoFunction.call(object)')`);
+    }
+}());
+
+(function () {
+    function target(object)
+    {
+        return protoFunction.call(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target("Cocoa"), String.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return protoFunction.call(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(42), Number.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return protoFunction.call(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(42.195), Number.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return protoFunction.call(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(true), Boolean.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return protoFunction.call(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(Symbol("Cocoa")), Symbol.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return protoFunction.call(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i) {
+        shouldBe(target("Cocoa"), String.prototype);
+        shouldBe(target(42), Number.prototype);
+        shouldBe(target(42.195), Number.prototype);
+        shouldBe(target(true), Boolean.prototype);
+        shouldBe(target(Symbol("Cocoa")), Symbol.prototype);
+    }
+}());

Added: trunk/JSTests/stress/dfg-object-prototype-of.js (0 => 223594)


--- trunk/JSTests/stress/dfg-object-prototype-of.js	                        (rev 0)
+++ trunk/JSTests/stress/dfg-object-prototype-of.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,115 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target({}), Object.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i) {
+        shouldThrow(() => target(null), `TypeError: null is not an object (evaluating 'Object.getPrototypeOf(object)')`);
+        shouldThrow(() => target(undefined), `TypeError: undefined is not an object (evaluating 'Object.getPrototypeOf(object)')`);
+    }
+}());
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target("Cocoa"), String.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(42), Number.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(42.195), Number.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(true), Boolean.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target(Symbol("Cocoa")), Symbol.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i) {
+        shouldBe(target("Cocoa"), String.prototype);
+        shouldBe(target(42), Number.prototype);
+        shouldBe(target(42.195), Number.prototype);
+        shouldBe(target(true), Boolean.prototype);
+        shouldBe(target(Symbol("Cocoa")), Symbol.prototype);
+    }
+}());

Added: trunk/JSTests/stress/dfg-reflect-get-prototype-of.js (0 => 223594)


--- trunk/JSTests/stress/dfg-reflect-get-prototype-of.js	                        (rev 0)
+++ trunk/JSTests/stress/dfg-reflect-get-prototype-of.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,58 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+(function () {
+    function target(object)
+    {
+        return Reflect.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i)
+        shouldBe(target({}), Object.prototype);
+}());
+
+(function () {
+    function target(object)
+    {
+        return Reflect.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i) {
+        shouldThrow(() => target(null), `TypeError: Reflect.getPrototypeOf requires the first argument be an object`);
+        shouldThrow(() => target(undefined), `TypeError: Reflect.getPrototypeOf requires the first argument be an object`);
+    }
+}());
+
+(function () {
+    function target(object)
+    {
+        return Reflect.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e3; ++i) {
+        shouldThrow(() => target("Cocoa"), `TypeError: Reflect.getPrototypeOf requires the first argument be an object`);
+        shouldThrow(() => target(42), `TypeError: Reflect.getPrototypeOf requires the first argument be an object`);
+        shouldThrow(() => target(true), `TypeError: Reflect.getPrototypeOf requires the first argument be an object`);
+    }
+}());

Added: trunk/JSTests/stress/intrinsic-getter-with-poly-proto.js (0 => 223594)


--- trunk/JSTests/stress/intrinsic-getter-with-poly-proto.js	                        (rev 0)
+++ trunk/JSTests/stress/intrinsic-getter-with-poly-proto.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,31 @@
+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);

Added: trunk/JSTests/stress/object-get-prototype-of-filtered.js (0 => 223594)


--- trunk/JSTests/stress/object-get-prototype-of-filtered.js	                        (rev 0)
+++ trunk/JSTests/stress/object-get-prototype-of-filtered.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,64 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+// In this case, we cannot handle it as GetPrototypeOf since GetById is opaque.
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e4; ++i) {
+        var object = {};
+        object[`Cocoa${i}`] = `Cocoa`;
+        shouldBe(target(object), Object.prototype);
+    }
+}());
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e4; ++i) {
+        var array = [];
+        array[`Cocoa${i}`] = `Cocoa`;
+        shouldBe(target(array), Array.prototype);
+    }
+}());
+
+(function () {
+    function target(object)
+    {
+        return Object.getPrototypeOf(object);
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e4; ++i) {
+        function Cocoa() { }
+        Cocoa[`Cocoa${i}`] = `Cocoa`;
+        shouldBe(target(Cocoa), Function.prototype);
+    }
+}());

Added: trunk/JSTests/stress/object-get-prototype-of-mono-proto.js (0 => 223594)


--- trunk/JSTests/stress/object-get-prototype-of-mono-proto.js	                        (rev 0)
+++ trunk/JSTests/stress/object-get-prototype-of-mono-proto.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,34 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function makePolyProtoObject() {
+    function foo() {
+        class C {
+            constructor() {
+                this._field = 42;
+                this.hello = 33;
+            }
+        };
+        return new C;
+    }
+    for (let i = 0; i < 15; ++i)
+        foo();
+    return foo();
+}
+
+function target(object)
+{
+    return [object.hello, Object.getPrototypeOf(object)];
+}
+noInline(target);
+
+var polyProtoObject = makePolyProtoObject();
+var prototype = Reflect.getPrototypeOf(polyProtoObject);
+var object1 = { __proto__: prototype, hello: 44 };
+var object2 = { hello: 45 };
+for (var i = 0; i < 1e5; ++i) {
+    shouldBe(target(object1)[1], prototype);
+    shouldBe(target(object2)[1], Object.prototype);
+}

Added: trunk/JSTests/stress/object-get-prototype-of-poly-mono-proto.js (0 => 223594)


--- trunk/JSTests/stress/object-get-prototype-of-poly-mono-proto.js	                        (rev 0)
+++ trunk/JSTests/stress/object-get-prototype-of-poly-mono-proto.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -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;
+                this.hello = 33;
+            }
+        };
+        return new C;
+    }
+    for (let i = 0; i < 15; ++i)
+        foo();
+    return foo();
+}
+
+function target(object)
+{
+    return [object.hello, Object.getPrototypeOf(object)];
+}
+noInline(target);
+
+var polyProtoObject = makePolyProtoObject();
+var prototype = Reflect.getPrototypeOf(polyProtoObject);
+var object = { __proto__: prototype, hello: 44 };
+for (var i = 0; i < 1e5; ++i) {
+    shouldBe(target(polyProtoObject)[1], prototype);
+    shouldBe(target(object)[1], prototype);
+}

Added: trunk/JSTests/stress/object-get-prototype-of-poly-proto.js (0 => 223594)


--- trunk/JSTests/stress/object-get-prototype-of-poly-proto.js	                        (rev 0)
+++ trunk/JSTests/stress/object-get-prototype-of-poly-proto.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,30 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function makePolyProtoObject() {
+    function foo() {
+        class C {
+            constructor() {
+                this._field = 42;
+                this.hello = 33;
+            }
+        };
+        return new C;
+    }
+    for (let i = 0; i < 15; ++i)
+        foo();
+    return foo();
+}
+
+function target(object)
+{
+    return [object.hello, Object.getPrototypeOf(object)];
+}
+noInline(target);
+
+var polyProtoObject = makePolyProtoObject();
+var prototype = Reflect.getPrototypeOf(polyProtoObject);
+for (var i = 0; i < 1e5; ++i)
+    shouldBe(target(polyProtoObject)[1], prototype);

Added: trunk/JSTests/stress/object-proto-getter-filtered.js (0 => 223594)


--- trunk/JSTests/stress/object-proto-getter-filtered.js	                        (rev 0)
+++ trunk/JSTests/stress/object-proto-getter-filtered.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,62 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e4; ++i) {
+        var object = {};
+        object[`Cocoa${i}`] = `Cocoa`;
+        shouldBe(target(object), Object.prototype);
+    }
+}());
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e4; ++i) {
+        var array = [];
+        array[`Cocoa${i}`] = `Cocoa`;
+        shouldBe(target(array), Array.prototype);
+    }
+}());
+
+(function () {
+    function target(object)
+    {
+        return object.__proto__;
+    }
+    noInline(target);
+
+    for (var i = 0; i < 1e4; ++i) {
+        function Cocoa() { }
+        Cocoa[`Cocoa${i}`] = `Cocoa`;
+        shouldBe(target(Cocoa), Function.prototype);
+    }
+}());

Added: trunk/JSTests/stress/object-proto-getter-poly-mono-proto.js (0 => 223594)


--- trunk/JSTests/stress/object-proto-getter-poly-mono-proto.js	                        (rev 0)
+++ trunk/JSTests/stress/object-proto-getter-poly-mono-proto.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,34 @@
+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);
+var object = {
+    __proto__: prototype
+};
+for (var i = 0; i < 1e5; ++i) {
+    shouldBe(target(polyProtoObject), prototype);
+    shouldBe(target(object), prototype);
+}

Added: trunk/JSTests/stress/object-proto-getter-poly-proto.js (0 => 223594)


--- trunk/JSTests/stress/object-proto-getter-poly-proto.js	                        (rev 0)
+++ trunk/JSTests/stress/object-proto-getter-poly-proto.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,29 @@
+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);

Modified: trunk/JSTests/stress/object-prototype-proto-accessors-should-throw-on-undefined-this.js (223593 => 223594)


--- trunk/JSTests/stress/object-prototype-proto-accessors-should-throw-on-undefined-this.js	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/JSTests/stress/object-prototype-proto-accessors-should-throw-on-undefined-this.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -34,5 +34,5 @@
     }
 }
 
-runTest(10000, testInvokeGetter, undefined, "TypeError: Object.prototype.__proto__ called on null or undefined");
+runTest(10000, testInvokeGetter, undefined, "TypeError: undefined is not an object (evaluating 'getter()')");
 runTest(10100, testInvokeSetter, undefined, "TypeError: Object.prototype.__proto__ called on null or undefined");

Added: trunk/JSTests/stress/string-proto.js (0 => 223594)


--- trunk/JSTests/stress/string-proto.js	                        (rev 0)
+++ trunk/JSTests/stress/string-proto.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -0,0 +1,12 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function target(value)
+{
+    return value.__proto__;
+}
+noInline(target);
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(target("Cocoa"), String.prototype)

Modified: trunk/LayoutTests/ChangeLog (223593 => 223594)


--- trunk/LayoutTests/ChangeLog	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/LayoutTests/ChangeLog	2017-10-18 07:12:53 UTC (rev 223594)
@@ -1,3 +1,17 @@
+2017-10-18  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] __proto__ getter should be fast
+        https://bugs.webkit.org/show_bug.cgi?id=178067
+
+        Reviewed by Saam Barati.
+
+        * js/object-literal-shorthand-construction-expected.txt:
+        * js/script-tests/object-literal-shorthand-construction.js:
+        (set 2):
+        (get 1):
+        * js/script-tests/sloppy-getter-setter-global-object.js:
+        * js/sloppy-getter-setter-global-object-expected.txt:
+
 2017-10-17  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         [Regression] Webkit "-apple-system" font fallback token handles font weights of PingFang incorrectly.

Modified: trunk/LayoutTests/js/object-literal-shorthand-construction-expected.txt (223593 => 223594)


--- trunk/LayoutTests/js/object-literal-shorthand-construction-expected.txt	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/LayoutTests/js/object-literal-shorthand-construction-expected.txt	2017-10-18 07:12:53 UTC (rev 223594)
@@ -64,7 +64,7 @@
 PASS this.__proto__ = [] threw exception TypeError: Cannot set prototype of immutable prototype object.
 PASS ({__proto__: this.__proto__}) instanceof Array is false
 PASS __proto__ = [] threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
-PASS ({__proto__: __proto__}) instanceof Array threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
+PASS ({__proto__: __proto__}) instanceof Array threw exception TypeError: undefined is not an object (evaluating '__proto__').
 SyntaxErrors
 PASS ({break}) threw exception SyntaxError: Cannot use the keyword 'break' as a shorthand property name..
 PASS ({case}) threw exception SyntaxError: Cannot use the keyword 'case' as a shorthand property name..

Modified: trunk/LayoutTests/js/script-tests/object-literal-shorthand-construction.js (223593 => 223594)


--- trunk/LayoutTests/js/script-tests/object-literal-shorthand-construction.js	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/LayoutTests/js/script-tests/object-literal-shorthand-construction.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -113,7 +113,7 @@
 shouldThrow("this.__proto__ = []");
 shouldBeFalse("({__proto__: this.__proto__}) instanceof Array");
 shouldThrow("__proto__ = []", '"TypeError: Object.prototype.__proto__ called on null or undefined"');
-shouldThrow("({__proto__: __proto__}) instanceof Array", '"TypeError: Object.prototype.__proto__ called on null or undefined"');
+shouldThrow("({__proto__: __proto__}) instanceof Array", '"TypeError: undefined is not an object (evaluating \'__proto__\')"');
 
 // Keywords - Syntax Errors
 debug("SyntaxErrors");

Modified: trunk/LayoutTests/js/script-tests/sloppy-getter-setter-global-object.js (223593 => 223594)


--- trunk/LayoutTests/js/script-tests/sloppy-getter-setter-global-object.js	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/LayoutTests/js/script-tests/sloppy-getter-setter-global-object.js	2017-10-18 07:12:53 UTC (rev 223594)
@@ -25,12 +25,12 @@
 shouldNotThrow("Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get()");
 shouldNotThrow("Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set(['foo'])");
 
-shouldThrow("(0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)()", "\"TypeError: Object.prototype.__proto__ called on null or undefined\"");
+shouldThrow("(0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)()", "\"TypeError: undefined is not an object (evaluating '(0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)()')\"");
 shouldThrow("(0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set)(['foo'])", "\"TypeError: Object.prototype.__proto__ called on null or undefined\"");
 
 
 var top_level_sloppy_getter = Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get;
-shouldThrow("top_level_sloppy_getter();", "\"TypeError: Object.prototype.__proto__ called on null or undefined\"");
+shouldThrow("top_level_sloppy_getter();", "\"TypeError: undefined is not an object (evaluating 'top_level_sloppy_getter()')\"");
 
 var top_level_sloppy_setter = Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set;
 shouldThrow("top_level_sloppy_setter(['foo']);", "\"TypeError: Object.prototype.__proto__ called on null or undefined\"");

Modified: trunk/LayoutTests/js/sloppy-getter-setter-global-object-expected.txt (223593 => 223594)


--- trunk/LayoutTests/js/sloppy-getter-setter-global-object-expected.txt	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/LayoutTests/js/sloppy-getter-setter-global-object-expected.txt	2017-10-18 07:12:53 UTC (rev 223594)
@@ -8,9 +8,9 @@
 PASS Object.prototype.valueOf.call(null); threw exception TypeError: null is not an object (evaluating 'Object.prototype.valueOf.call(null)').
 PASS Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get() did not throw exception.
 PASS Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set(['foo']) did not throw exception.
-PASS (0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)() threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
+PASS (0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)() threw exception TypeError: undefined is not an object (evaluating '(0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)()').
 PASS (0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set)(['foo']) threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
-PASS top_level_sloppy_getter(); threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
+PASS top_level_sloppy_getter(); threw exception TypeError: undefined is not an object (evaluating 'top_level_sloppy_getter()').
 PASS top_level_sloppy_setter(['foo']); threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
 PASS successfullyParsed is true
 

Modified: trunk/Source/_javascript_Core/ChangeLog (223593 => 223594)


--- trunk/Source/_javascript_Core/ChangeLog	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-10-18 07:12:53 UTC (rev 223594)
@@ -1,3 +1,98 @@
+2017-10-18  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] __proto__ getter should be fast
+        https://bugs.webkit.org/show_bug.cgi?id=178067
+
+        Reviewed by Saam Barati.
+
+        In our ES6 class implementation, we access __proto__ field to retrieve super constructor.
+        Currently, it is handled as an usual getter call to a generic function. And DFG just emits
+        Call node for this. It is inefficient since typically we know the `prototype` of the given
+        object when accessing `object.__proto__` since we emit CheckStructure for this `object`.
+        If Structure has mono proto, we can immediately fold it to constant value. If it is poly proto,
+        we can still change this to efficient access to poly proto slot.
+
+        This patch implements GetPrototypeOf DFG node. This node efficiently accesses to prototype of
+        the given object. And in AI and ByteCodeParser phase, we attempt to fold it to constant.
+        ByteCodeParser's folding is a bit important since we have `callee.__proto__` code to get super
+        constructor. If we can change this to constant, we can reify CallLinkInfo with this constant.
+        This paves the way to optimizing ArrayConstructor super calls[1], which is particularly important
+        for ARES-6 ML.
+
+        And we also optimize Reflect.getPrototypeOf and Object.getPrototypeOf with this GetPrototypeOf node.
+
+        Currently, __proto__ access for poly proto object is not handled well in IC. But we add code handling
+        poly proto in GetPrototypeOf since Reflect.getPrototypeOf and Object.getPrototypeOf can use it.
+        Once IC starts handling poly proto & intrinsic getter well, this code will be used for that too.
+
+        This patch improves SixSpeed super.es6 by 3.42x.
+
+                                 baseline                  patched
+
+        super.es6           123.6666+-3.9917     ^     36.1684+-1.0351        ^ definitely 3.4192x faster
+
+        [1]: https://bugs.webkit.org/show_bug.cgi?id=178064
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        (JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixupGetPrototypeOf):
+        * dfg/DFGHeapLocation.cpp:
+        (WTF::printInternal):
+        * dfg/DFGHeapLocation.h:
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasHeapPrediction):
+        (JSC::DFG::Node::shouldSpeculateFunction):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::speculateFunction):
+        (JSC::DFG::SpeculativeJIT::speculateFinalObject):
+        (JSC::DFG::SpeculativeJIT::compileGetPrototypeOf):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetPrototypeOf):
+        (JSC::FTL::DFG::LowerDFGToB3::compileInstanceOf):
+        * jit/IntrinsicEmitter.cpp:
+        (JSC::IntrinsicGetterAccessCase::canEmitIntrinsicGetter):
+        (JSC::IntrinsicGetterAccessCase::emitIntrinsicGetter):
+        * jit/JITOperations.h:
+        * runtime/Intrinsic.cpp:
+        (JSC::intrinsicName):
+        * runtime/Intrinsic.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::booleanPrototype const):
+        (JSC::JSGlobalObject::numberPrototype const):
+        (JSC::JSGlobalObject::booleanObjectStructure const):
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::globalFuncProtoGetter):
+        * runtime/JSGlobalObjectFunctions.h:
+        * runtime/ObjectConstructor.cpp:
+        * runtime/ReflectObject.cpp:
+
 2017-10-17  Ryan Haddad  <ryanhad...@apple.com>
 
         Unreviewed, rolling out r223523.

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -2740,6 +2740,48 @@
         forNode(node).setType(SpecInt32Only);
         break;
     }
+
+    case GetPrototypeOf: {
+        AbstractValue& value = forNode(node->child1());
+        if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
+            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) {
+                    canFold = false;
+                    return;
+                }
+
+                if (structure->hasPolyProto()) {
+                    canFold = false;
+                    return;
+                }
+                if (!prototype)
+                    prototype = structure->storedPrototype();
+                else if (prototype != structure->storedPrototype())
+                    canFold = false;
+            });
+
+            if (prototype && canFold) {
+                setConstant(node, *m_graph.freeze(prototype));
+                break;
+            }
+        }
+
+        switch (node->child1().useKind()) {
+        case ArrayUse:
+        case FunctionUse:
+        case FinalObjectUse:
+            break;
+        default:
+            clobberWorld(node->origin.semantic, clobberLimit);
+            break;
+        }
+        forNode(node).setType(m_graph, SpecObject | SpecOther);
+        break;
+    }
         
     case GetByOffset: {
         StorageAccessData& data = ""

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -238,7 +238,7 @@
     template<typename ChecksFunctor>
     bool handleDOMJITCall(Node* callee, int resultOperand, const DOMJIT::Signature*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks);
     template<typename ChecksFunctor>
-    bool handleIntrinsicGetter(int resultOperand, const GetByIdVariant& intrinsicVariant, Node* thisNode, const ChecksFunctor& insertChecks);
+    bool handleIntrinsicGetter(int resultOperand, SpeculatedType prediction, const GetByIdVariant& intrinsicVariant, Node* thisNode, const ChecksFunctor& insertChecks);
     template<typename ChecksFunctor>
     bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType, const ChecksFunctor& insertChecks);
     template<typename ChecksFunctor>
@@ -2599,6 +2599,24 @@
         return true;
     }
 
+    case ObjectGetPrototypeOfIntrinsic: {
+        if (argumentCountIncludingThis != 2)
+            return false;
+
+        insertChecks();
+        set(VirtualRegister(resultOperand), addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(1, registerOffset))));
+        return true;
+    }
+
+    case ReflectGetPrototypeOfIntrinsic: {
+        if (argumentCountIncludingThis != 2)
+            return false;
+
+        insertChecks();
+        set(VirtualRegister(resultOperand), addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(prediction), Edge(get(virtualRegisterForArgument(1, registerOffset)), ObjectUse)));
+        return true;
+    }
+
     case IsTypedArrayViewIntrinsic: {
         ASSERT(argumentCountIncludingThis == 2);
 
@@ -2946,7 +2964,7 @@
 
 
 template<typename ChecksFunctor>
-bool ByteCodeParser::handleIntrinsicGetter(int resultOperand, const GetByIdVariant& variant, Node* thisNode, const ChecksFunctor& insertChecks)
+bool ByteCodeParser::handleIntrinsicGetter(int resultOperand, SpeculatedType prediction, const GetByIdVariant& variant, Node* thisNode, const ChecksFunctor& insertChecks)
 {
     switch (variant.intrinsic()) {
     case TypedArrayByteLengthIntrinsic: {
@@ -3013,6 +3031,40 @@
         return true;
     }
 
+    case UnderscoreProtoIntrinsic: {
+        insertChecks();
+
+        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) {
+                canFold = false;
+                return;
+            }
+
+            if (structure->hasPolyProto()) {
+                canFold = false;
+                return;
+            }
+            if (!prototype)
+                prototype = structure->storedPrototype();
+            else if (prototype != structure->storedPrototype())
+                canFold = false;
+        });
+
+        // OK, only one prototype is found. We perform constant folding here.
+        // This information is important for super's constructor call to get new.target constant.
+        if (prototype && canFold) {
+            set(VirtualRegister(resultOperand), weakJSConstant(prototype));
+            return true;
+        }
+
+        set(VirtualRegister(resultOperand), addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(prediction), thisNode));
+        return true;
+    }
+
     default:
         return false;
     }
@@ -3796,7 +3848,7 @@
     
     Node* getter = addToGraph(GetGetter, loadedValue);
 
-    if (handleIntrinsicGetter(destinationOperand, variant, base,
+    if (handleIntrinsicGetter(destinationOperand, prediction, variant, base,
             [&] () {
                 addToGraph(CheckCell, OpInfo(m_graph.freeze(variant.intrinsicFunction())), getter);
             })) {

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -1114,6 +1114,23 @@
         read(MiscFields);
         def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node->child1()), LazyNode(node));
         return;
+
+    case GetPrototypeOf: {
+        switch (node->child1().useKind()) {
+        case ArrayUse:
+        case FunctionUse:
+        case FinalObjectUse:
+            read(JSCell_structureID);
+            read(JSObject_butterfly);
+            read(NamedProperties); // Poly proto could load prototype from its slot.
+            def(HeapLocation(PrototypeLoc, NamedProperties, node->child1()), LazyNode(node));
+            return;
+        default:
+            read(World);
+            write(Heap);
+            return;
+        }
+    }
         
     case GetByOffset:
     case GetGetterSetterByOffset: {

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -238,6 +238,7 @@
     case StringCharAt:
     case StringCharCodeAt:
     case GetTypedArrayByteOffset:
+    case GetPrototypeOf:
     case PutByValDirect:
     case PutByVal:
     case PutByValAlias:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -1603,6 +1603,11 @@
             break;
         }
 
+        case GetPrototypeOf: {
+            fixupGetPrototypeOf(node);
+            break;
+        }
+
         case Phi:
         case Upsilon:
         case EntrySwitch:
@@ -2302,6 +2307,59 @@
         }
     }
 
+    void fixupGetPrototypeOf(Node* node)
+    {
+        // Reflect.getPrototypeOf only accepts Objects. For Reflect.getPrototypeOf, ByteCodeParser attaches ObjectUse edge filter before fixup phase.
+        if (node->child1().useKind() != ObjectUse) {
+            if (node->child1()->shouldSpeculateString()) {
+                insertCheck<StringUse>(node->child1().node());
+                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->stringPrototype()));
+                return;
+            }
+            if (node->child1()->shouldSpeculateInt32()) {
+                insertCheck<Int32Use>(node->child1().node());
+                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->numberPrototype()));
+                return;
+            }
+            if (enableInt52() && node->child1()->shouldSpeculateAnyInt()) {
+                insertCheck<Int52RepUse>(node->child1().node());
+                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->numberPrototype()));
+                return;
+            }
+            if (node->child1()->shouldSpeculateNumber()) {
+                insertCheck<NumberUse>(node->child1().node());
+                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->numberPrototype()));
+                return;
+            }
+            if (node->child1()->shouldSpeculateSymbol()) {
+                insertCheck<SymbolUse>(node->child1().node());
+                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->symbolPrototype()));
+                return;
+            }
+            if (node->child1()->shouldSpeculateBoolean()) {
+                insertCheck<BooleanUse>(node->child1().node());
+                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->booleanPrototype()));
+                return;
+            }
+        }
+
+        if (node->child1()->shouldSpeculateFinalObject()) {
+            fixEdge<FinalObjectUse>(node->child1());
+            node->clearFlags(NodeMustGenerate);
+            return;
+        }
+        if (node->child1()->shouldSpeculateArray()) {
+            fixEdge<ArrayUse>(node->child1());
+            node->clearFlags(NodeMustGenerate);
+            return;
+        }
+        if (node->child1()->shouldSpeculateFunction()) {
+            fixEdge<FunctionUse>(node->child1());
+            node->clearFlags(NodeMustGenerate);
+            return;
+        }
+    }
+
     void fixupToThis(Node* node)
     {
         ECMAMode ecmaMode = m_graph.executableFor(node->origin.semantic)->isStrictMode() ? StrictMode : NotStrictMode;

Modified: trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -151,6 +151,10 @@
     case TypedArrayByteOffsetLoc:
         out.print("TypedArrayByteOffsetLoc");
         return;
+
+    case PrototypeLoc:
+        out.print("PrototypeLoc");
+        return;
         
     case StructureLoc:
         out.print("StructureLoc");

Modified: trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -60,6 +60,7 @@
     SetterLoc,
     StructureLoc,
     TypedArrayByteOffsetLoc,
+    PrototypeLoc,
     StackLoc,
     StackPayloadLoc,
     MapBucketLoc,

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -1548,6 +1548,7 @@
         case GetById:
         case GetByIdFlush:
         case GetByIdWithThis:
+        case GetPrototypeOf:
         case TryGetById:
         case GetByVal:
         case GetByValWithThis:
@@ -2311,6 +2312,11 @@
         return isArraySpeculation(prediction());
     }
 
+    bool shouldSpeculateFunction()
+    {
+        return isFunctionSpeculation(prediction());
+    }
+
     bool shouldSpeculateProxyObject()
     {
         return isProxyObjectSpeculation(prediction());

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -251,6 +251,7 @@
     macro(CheckTypeInfoFlags, NodeMustGenerate) /* Takes an OpInfo with the flags you want to test are set */\
     macro(CheckSubClass, NodeMustGenerate) \
     macro(ParseInt, NodeMustGenerate | NodeResultJS) \
+    macro(GetPrototypeOf, NodeMustGenerate | NodeResultJS) \
     \
     /* Atomics object functions. */\
     macro(AtomicsAdd, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -52,6 +52,7 @@
 #include "JSCInlines.h"
 #include "JSFixedArray.h"
 #include "JSGenericTypedArrayViewConstructorInlines.h"
+#include "JSGlobalObjectFunctions.h"
 #include "JSLexicalEnvironment.h"
 #include "JSMap.h"
 #include "JSSet.h"
@@ -2518,6 +2519,36 @@
     return *bucket;
 }
 
+EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(ExecState* exec, JSObject* thisObject)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    return JSValue::encode(thisObject->getPrototype(vm, exec));
+}
+
+EncodedJSValue JIT_OPERATION operationGetPrototypeOf(ExecState* exec, EncodedJSValue encodedValue)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSValue thisValue = JSValue::decode(encodedValue).toThis(exec, StrictMode);
+    if (thisValue.isUndefinedOrNull())
+        return throwVMError(exec, scope, createNotAnObjectError(exec, thisValue));
+
+    JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue);
+    if (!thisObject) {
+        JSObject* prototype = thisValue.synthesizePrototype(exec);
+        EXCEPTION_ASSERT(!!scope.exception() == !prototype);
+        if (UNLIKELY(!prototype))
+            return JSValue::encode(JSValue());
+        return JSValue::encode(prototype);
+    }
+
+    scope.release();
+    return JSValue::encode(thisObject->getPrototype(vm, exec));
+}
+
 void JIT_OPERATION operationThrowDFG(ExecState* exec, EncodedJSValue valueToThrow)
 {
     VM& vm = exec->vm();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -77,6 +77,8 @@
 EncodedJSValue JIT_OPERATION operationToNumber(ExecState*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetPrototypeOf(ExecState*, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(ExecState*, JSObject*) WTF_INTERNAL;
 char* JIT_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL;
 char* JIT_OPERATION operationNewArrayBuffer(ExecState*, Structure*, size_t, size_t) WTF_INTERNAL;
 char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -723,7 +723,8 @@
         case GetArgument:
         case CallDOMGetter:
         case GetDynamicVar:
-        case WeakMapGet: {
+        case WeakMapGet:
+        case GetPrototypeOf: {
             setPrediction(m_currentNode->getHeapPrediction());
             break;
         }

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -401,6 +401,7 @@
     case GetMyArgumentByValOutOfBounds:
     case ForwardVarargs:
     case CreateRest:
+    case GetPrototypeOf:
     case StringReplace:
     case StringReplaceRegExp:
     case GetRegExpObjectLastIndex:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -9186,6 +9186,11 @@
     speculateObject(edge, operand.gpr());
 }
 
+void SpeculativeJIT::speculateFunction(Edge edge, GPRReg cell)
+{
+    speculateCellType(edge, cell, SpecFunction, JSFunctionType);
+}
+
 void SpeculativeJIT::speculateFunction(Edge edge)
 {
     if (!needsTypeCheck(edge, SpecFunction))
@@ -9192,9 +9197,14 @@
         return;
     
     SpeculateCellOperand operand(this, edge);
-    speculateCellType(edge, operand.gpr(), SpecFunction, JSFunctionType);
+    speculateFunction(edge, operand.gpr());
 }
 
+void SpeculativeJIT::speculateFinalObject(Edge edge, GPRReg cell)
+{
+    speculateCellType(edge, cell, SpecFinalObject, FinalObjectType);
+}
+
 void SpeculativeJIT::speculateFinalObject(Edge edge)
 {
     if (!needsTypeCheck(edge, SpecFinalObject))
@@ -9201,7 +9211,7 @@
         return;
     
     SpeculateCellOperand operand(this, edge);
-    speculateCellType(edge, operand.gpr(), SpecFinalObject, FinalObjectType);
+    speculateFinalObject(edge, operand.gpr());
 }
 
 void SpeculativeJIT::speculateRegExpObject(Edge edge, GPRReg cell)
@@ -10767,6 +10777,125 @@
     jsValueResult(resultRegs, node);
 }
 
+void SpeculativeJIT::compileGetPrototypeOf(Node* node)
+{
+    switch (node->child1().useKind()) {
+    case ArrayUse:
+    case FunctionUse:
+    case FinalObjectUse: {
+        SpeculateCellOperand object(this, node->child1());
+        GPRTemporary temp(this);
+        GPRTemporary temp2(this);
+
+        GPRReg objectGPR = object.gpr();
+        GPRReg tempGPR = temp.gpr();
+        GPRReg temp2GPR = temp2.gpr();
+
+        switch (node->child1().useKind()) {
+        case ArrayUse:
+            speculateArray(node->child1(), objectGPR);
+            break;
+        case FunctionUse:
+            speculateFunction(node->child1(), objectGPR);
+            break;
+        case FinalObjectUse:
+            speculateFinalObject(node->child1(), objectGPR);
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+
+        m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, tempGPR, temp2GPR);
+
+        AbstractValue& value = m_state.forNode(node->child1());
+        if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
+            bool hasPolyProto = false;
+            bool hasMonoProto = false;
+            value.m_structure.forEach([&] (RegisteredStructure structure) {
+                if (structure->hasPolyProto())
+                    hasPolyProto = true;
+                else
+                    hasMonoProto = true;
+            });
+
+            if (hasMonoProto && !hasPolyProto) {
+#if USE(JSVALUE64)
+                m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
+                jsValueResult(tempGPR, node);
+#else
+                m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
+                m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
+                jsValueResult(temp2GPR, tempGPR, node);
+#endif
+                return;
+            }
+
+            if (hasPolyProto && !hasMonoProto) {
+#if USE(JSVALUE64)
+                m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
+                m_jit.zeroExtend32ToPtr(tempGPR, tempGPR);
+                m_jit.load64(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage()), tempGPR);
+                jsValueResult(tempGPR, node);
+#else
+                m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
+                m_jit.load32(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage() + TagOffset), temp2GPR);
+                m_jit.load32(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage() + PayloadOffset), tempGPR);
+                jsValueResult(temp2GPR, tempGPR, node);
+#endif
+                return;
+            }
+        }
+
+#if USE(JSVALUE64)
+        m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
+        auto isMonoProto = m_jit.branchIfNotInt32(JSValueRegs(tempGPR));
+        m_jit.zeroExtend32ToPtr(tempGPR, tempGPR);
+        m_jit.load64(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage()), tempGPR);
+        isMonoProto.link(&m_jit);
+        jsValueResult(tempGPR, node);
+#else
+        m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
+        m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
+        auto isMonoProto = m_jit.branch32(CCallHelpers::NotEqual, temp2GPR, TrustedImm32(JSValue::Int32Tag));
+        m_jit.load32(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage() + TagOffset), temp2GPR);
+        m_jit.load32(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage() + PayloadOffset), tempGPR);
+        isMonoProto.link(&m_jit);
+        jsValueResult(temp2GPR, tempGPR, node);
+#endif
+        return;
+    }
+    case ObjectUse: {
+        SpeculateCellOperand value(this, node->child1());
+        JSValueRegsTemporary result(this);
+
+        GPRReg valueGPR = value.gpr();
+        JSValueRegs resultRegs = result.regs();
+
+        speculateObject(node->child1(), valueGPR);
+
+        flushRegisters();
+        callOperation(operationGetPrototypeOfObject, resultRegs, valueGPR);
+        m_jit.exceptionCheck();
+        jsValueResult(resultRegs, node);
+        return;
+    }
+    default: {
+        JSValueOperand value(this, node->child1());
+        JSValueRegsTemporary result(this);
+
+        JSValueRegs valueRegs = value.jsValueRegs();
+        JSValueRegs resultRegs = result.regs();
+
+        flushRegisters();
+        callOperation(operationGetPrototypeOf, resultRegs, valueRegs);
+        m_jit.exceptionCheck();
+        jsValueResult(resultRegs, node);
+        return;
+    }
+    }
+}
+
 } } // namespace JSC::DFG
 
 #endif

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -987,6 +987,11 @@
         m_jit.setupArgumentsWithExecState(object, TrustedImmPtr(static_cast<size_t>(size)));
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(J_JITOperation_EO operation, JSValueRegs result, GPRReg object)
+    {
+        m_jit.setupArgumentsWithExecState(object);
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(P_JITOperation_EPS operation, GPRReg result, GPRReg old, size_t size)
     {
         m_jit.setupArgumentsWithExecState(old, TrustedImmPtr(size));
@@ -2835,6 +2840,7 @@
     void compileWeakMapGet(Node*);
     void compileLoadKeyFromMapBucket(Node*);
     void compileLoadValueFromMapBucket(Node*);
+    void compileGetPrototypeOf(Node*);
     
 #if USE(JSVALUE32_64)
     template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
@@ -3084,7 +3090,9 @@
     void speculateObject(Edge);
     void speculateArray(Edge, GPRReg cell);
     void speculateArray(Edge);
+    void speculateFunction(Edge, GPRReg cell);
     void speculateFunction(Edge);
+    void speculateFinalObject(Edge, GPRReg cell);
     void speculateFinalObject(Edge);
     void speculateRegExpObject(Edge, GPRReg cell);
     void speculateRegExpObject(Edge);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -4434,6 +4434,11 @@
         compileGetTypedArrayByteOffset(node);
         break;
     }
+
+    case GetPrototypeOf: {
+        compileGetPrototypeOf(node);
+        break;
+    }
         
     case GetByOffset: {
         StorageOperand storage(this, node->child1());

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -4650,6 +4650,11 @@
         compileGetTypedArrayByteOffset(node);
         break;
     }
+
+    case GetPrototypeOf: {
+        compileGetPrototypeOf(node);
+        break;
+    }
         
     case GetByOffset:
     case GetGetterSetterByOffset: {

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -144,6 +144,7 @@
     case ReallocatePropertyStorage:
     case NukeStructureAndSetButterfly:
     case GetTypedArrayByteOffset:
+    case GetPrototypeOf:
     case NotifyWrite:
     case StoreBarrier:
     case FencedStoreBarrier:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -821,6 +821,9 @@
         case GetTypedArrayByteOffset:
             compileGetTypedArrayByteOffset();
             break;
+        case GetPrototypeOf:
+            compileGetPrototypeOf();
+            break;
         case AllocatePropertyStorage:
             compileAllocatePropertyStorage();
             break;
@@ -3429,6 +3432,82 @@
 
         setInt32(m_out.castToInt32(m_out.phi(pointerType(), simpleOut, wastefulOut)));
     }
+
+    void compileGetPrototypeOf()
+    {
+        switch (m_node->child1().useKind()) {
+        case ArrayUse:
+        case FunctionUse:
+        case FinalObjectUse: {
+            LValue object = lowCell(m_node->child1());
+            switch (m_node->child1().useKind()) {
+            case ArrayUse:
+                speculateArray(m_node->child1(), object);
+                break;
+            case FunctionUse:
+                speculateFunction(m_node->child1(), object);
+                break;
+            case FinalObjectUse:
+                speculateFinalObject(m_node->child1(), object);
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
+            }
+
+            LValue structure = loadStructure(object);
+
+            AbstractValue& value = m_state.forNode(m_node->child1());
+            if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
+                bool hasPolyProto = false;
+                bool hasMonoProto = false;
+                value.m_structure.forEach([&] (RegisteredStructure structure) {
+                    if (structure->hasPolyProto())
+                        hasPolyProto = true;
+                    else
+                        hasMonoProto = true;
+                });
+
+                if (hasMonoProto && !hasPolyProto) {
+                    setJSValue(m_out.load64(structure, m_heaps.Structure_prototype));
+                    return;
+                }
+
+                if (hasPolyProto && !hasMonoProto) {
+                    LValue prototypeBits = m_out.load64(structure, m_heaps.Structure_prototype);
+                    LValue index = m_out.bitAnd(prototypeBits, m_out.constInt64(UINT_MAX));
+                    setJSValue(m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), object, index, ScaleEight, JSObject::offsetOfInlineStorage())));
+                    return;
+                }
+            }
+
+            LBasicBlock continuation = m_out.newBlock();
+            LBasicBlock loadPolyProto = m_out.newBlock();
+
+            LValue prototypeBits = m_out.load64(structure, m_heaps.Structure_prototype);
+            ValueFromBlock directPrototype = m_out.anchor(prototypeBits);
+            m_out.branch(isInt32(prototypeBits), unsure(loadPolyProto), unsure(continuation));
+
+            LBasicBlock lastNext = m_out.appendTo(loadPolyProto, continuation);
+            LValue index = m_out.bitAnd(prototypeBits, m_out.constInt64(UINT_MAX));
+            ValueFromBlock polyProto = m_out.anchor(
+                m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), object, index, ScaleEight, JSObject::offsetOfInlineStorage())));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            setJSValue(m_out.phi(Int64, directPrototype, polyProto));
+            return;
+        }
+        case ObjectUse: {
+            setJSValue(vmCall(Int64, m_out.operation(operationGetPrototypeOfObject), m_callFrame, lowObject(m_node->child1())));
+            return;
+        }
+        default: {
+            setJSValue(vmCall(Int64, m_out.operation(operationGetPrototypeOf), m_callFrame, lowJSValue(m_node->child1())));
+            return;
+        }
+        }
+    }
     
     void compileGetArrayLength()
     {
@@ -9003,7 +9082,7 @@
         LValue structure = loadStructure(value);
 
         LValue prototypeBits = m_out.load64(structure, m_heaps.Structure_prototype);
-        ValueFromBlock directProtoype = m_out.anchor(prototypeBits);
+        ValueFromBlock directPrototype = m_out.anchor(prototypeBits);
         m_out.branch(isInt32(prototypeBits), unsure(loadPolyProto), unsure(comparePrototype));
 
         m_out.appendTo(loadPolyProto, comparePrototype);
@@ -9013,7 +9092,7 @@
         m_out.jump(comparePrototype);
 
         m_out.appendTo(comparePrototype, notYetInstance);
-        LValue currentPrototype = m_out.phi(Int64, directProtoype, polyProto);
+        LValue currentPrototype = m_out.phi(Int64, directPrototype, polyProto);
         ValueFromBlock isInstanceResult = m_out.anchor(m_out.booleanTrue);
         m_out.branch(
             m_out.equal(currentPrototype, prototype),

Modified: trunk/Source/_javascript_Core/jit/IntrinsicEmitter.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/jit/IntrinsicEmitter.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/jit/IntrinsicEmitter.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -63,6 +63,13 @@
         
         return true;
     }
+    case UnderscoreProtoIntrinsic: {
+        if (structure->hasPolyProto())
+            return false;
+        auto getPrototypeMethod = structure->classInfo()->methodTable.getPrototype;
+        MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
+        return getPrototypeMethod == defaultGetPrototype;
+    }
     default:
         return false;
     }
@@ -125,6 +132,13 @@
         return;
     }
 
+    case UnderscoreProtoIntrinsic: {
+        ASSERT(structure()->hasMonoProto());
+        jit.moveValue(structure()->storedPrototype(), valueRegs);
+        state.succeed();
+        return;
+    }
+
     default:
         break;
     }

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (223593 => 223594)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -176,6 +176,7 @@
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EZIcfZ)(ExecState*, int32_t, InlineCallFrame*, int32_t);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EZZ)(ExecState*, int32_t, int32_t);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EZSymtabJ)(ExecState*, int32_t, SymbolTable*, EncodedJSValue);
+typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EO)(ExecState*, JSObject*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EOIUi)(ExecState*, JSObject*, UniquedStringImpl*, uint32_t);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJI)(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
 typedef JSCell* (JIT_OPERATION *C_JITOperation_EPUi)(ExecState*, void*, uint32_t);

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -111,6 +111,10 @@
         return "RegExpTestIntrinsic";
     case RegExpTestFastIntrinsic:
         return "RegExpTestFastIntrinsic";
+    case ObjectGetPrototypeOfIntrinsic:
+        return "ObjectGetPrototypeOfIntrinsic";
+    case ReflectGetPrototypeOfIntrinsic:
+        return "ReflectGetPrototypeOfIntrinsic";
     case StringPrototypeValueOfIntrinsic:
         return "StringPrototypeValueOfIntrinsic";
     case StringPrototypeReplaceIntrinsic:
@@ -189,6 +193,8 @@
         return "TypedArrayByteLengthIntrinsic";
     case TypedArrayByteOffsetIntrinsic:
         return "TypedArrayByteOffsetIntrinsic";
+    case UnderscoreProtoIntrinsic:
+        return "UnderscoreProtoIntrinsic";
     case DFGTrueIntrinsic:
         return "DFGTrueIntrinsic";
     case OSRExitIntrinsic:

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (223593 => 223594)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -68,6 +68,8 @@
     RegExpExecIntrinsic,
     RegExpTestIntrinsic,
     RegExpTestFastIntrinsic,
+    ObjectGetPrototypeOfIntrinsic,
+    ReflectGetPrototypeOfIntrinsic,
     StringPrototypeValueOfIntrinsic,
     StringPrototypeReplaceIntrinsic,
     StringPrototypeReplaceRegExpIntrinsic,
@@ -109,6 +111,7 @@
     TypedArrayLengthIntrinsic,
     TypedArrayByteLengthIntrinsic,
     TypedArrayByteOffsetIntrinsic,
+    UnderscoreProtoIntrinsic,
 
     // Debugging intrinsics. These are meant to be used as testing hacks within
     // jsc.cpp and should never be exposed to users.

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -449,7 +449,7 @@
     m_nullSetterFunction.set(vm, this, NullSetterFunction::create(vm, NullSetterFunction::createStructure(vm, this, m_functionPrototype.get())));
     m_objectPrototype.set(vm, this, ObjectPrototype::create(vm, this, ObjectPrototype::createStructure(vm, this, jsNull())));
     GetterSetter* protoAccessor = GetterSetter::create(vm, this);
-    protoAccessor->setGetter(vm, this, JSFunction::create(vm, this, 0, makeString("get ", vm.propertyNames->underscoreProto.string()), globalFuncProtoGetter));
+    protoAccessor->setGetter(vm, this, JSFunction::create(vm, this, 0, makeString("get ", vm.propertyNames->underscoreProto.string()), globalFuncProtoGetter, UnderscoreProtoIntrinsic));
     protoAccessor->setSetter(vm, this, JSFunction::create(vm, this, 0, makeString("set ", vm.propertyNames->underscoreProto.string()), globalFuncProtoSetter));
     m_objectPrototype->putDirectNonIndexAccessor(vm, vm.propertyNames->underscoreProto, protoAccessor, PropertyAttribute::Accessor | PropertyAttribute::DontEnum);
     m_functionPrototype->structure()->setPrototypeWithoutTransition(vm, m_objectPrototype.get());

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (223593 => 223594)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -23,6 +23,7 @@
 
 #include "ArrayAllocationProfile.h"
 #include "ArrayBufferSharingMode.h"
+#include "BooleanPrototype.h"
 #include "ExceptionHelpers.h"
 #include "InternalFunction.h"
 #include "JSArray.h"
@@ -121,6 +122,7 @@
     macro(String, string, stringObject, StringObject, String, object) \
     macro(Symbol, symbol, symbolObject, SymbolObject, Symbol, object) \
     macro(Number, number, numberObject, NumberObject, Number, object) \
+    macro(Boolean, boolean, booleanObject, BooleanObject, Boolean, object) \
     macro(Error, error, error, ErrorInstance, Error, object) \
     macro(Map, map, map, JSMap, Map, object) \
     macro(Set, set, set, JSSet, Set, object) \
@@ -135,7 +137,6 @@
 
 #define FOR_EACH_LAZY_BUILTIN_TYPE(macro) \
     macro(Date, date, date, DateInstance, Date, object) \
-    macro(Boolean, boolean, booleanObject, BooleanObject, Boolean, object) \
     DEFINE_STANDARD_BUILTIN(macro, WeakMap, weakMap) \
     DEFINE_STANDARD_BUILTIN(macro, WeakSet, weakSet) \
 
@@ -565,10 +566,10 @@
     ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
     FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
     ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
-    JSObject* booleanPrototype() const { return m_booleanObjectStructure.prototype(this); }
+    BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); }
     StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
     SymbolPrototype* symbolPrototype() const { return m_symbolPrototype.get(); }
-    JSObject* numberPrototype() const { return m_numberPrototype.get(); }
+    NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); }
     JSObject* datePrototype() const { return m_dateStructure.prototype(this); }
     RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
     ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); }
@@ -616,7 +617,7 @@
         return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure;
     }
         
-    Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(this); }
+    Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
     Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(this); }
     Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(this); }
     Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(this); }

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -64,7 +64,7 @@
 
 namespace JSC {
 
-static const char* const ObjectProtoCalledOnNullOrUndefinedError = "Object.prototype.__proto__ called on null or undefined";
+const char* const ObjectProtoCalledOnNullOrUndefinedError = "Object.prototype.__proto__ called on null or undefined";
 
 template<unsigned charactersCount>
 static Bitmap<256> makeCharacterBitmap(const char (&characters)[charactersCount])
@@ -706,11 +706,11 @@
 
     JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
     if (thisValue.isUndefinedOrNull())
-        return throwVMTypeError(exec, scope, ASCIILiteral(ObjectProtoCalledOnNullOrUndefinedError));
+        return throwVMError(exec, scope, createNotAnObjectError(exec, thisValue));
 
     JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue);
     if (!thisObject) {
-        JSObject* prototype = exec->thisValue().synthesizePrototype(exec);
+        JSObject* prototype = thisValue.synthesizePrototype(exec);
         EXCEPTION_ASSERT(!!scope.exception() == !prototype);
         if (UNLIKELY(!prototype))
             return JSValue::encode(JSValue());

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h (223593 => 223594)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2017-10-18 07:12:53 UTC (rev 223594)
@@ -35,6 +35,8 @@
 // FIXME: These functions should really be in JSGlobalObject.cpp, but putting them there
 // is a 0.5% reduction.
 
+extern const char* const ObjectProtoCalledOnNullOrUndefinedError;
+
 EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState*);
 EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState*);
 EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState*);

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -67,7 +67,7 @@
 
 /* Source for ObjectConstructor.lut.h
 @begin objectConstructorTable
-  getPrototypeOf            objectConstructorGetPrototypeOf             DontEnum|Function 1
+  getPrototypeOf            objectConstructorGetPrototypeOf             DontEnum|Function 1 ObjectGetPrototypeOfIntrinsic
   setPrototypeOf            objectConstructorSetPrototypeOf             DontEnum|Function 2
   getOwnPropertyDescriptor  objectConstructorGetOwnPropertyDescriptor   DontEnum|Function 2
   getOwnPropertyDescriptors objectConstructorGetOwnPropertyDescriptors  DontEnum|Function 1

Modified: trunk/Source/_javascript_Core/runtime/ReflectObject.cpp (223593 => 223594)


--- trunk/Source/_javascript_Core/runtime/ReflectObject.cpp	2017-10-18 06:02:20 UTC (rev 223593)
+++ trunk/Source/_javascript_Core/runtime/ReflectObject.cpp	2017-10-18 07:12:53 UTC (rev 223594)
@@ -63,7 +63,7 @@
     deleteProperty           JSBuiltin                             DontEnum|Function 2
     get                      reflectObjectGet                      DontEnum|Function 2
     getOwnPropertyDescriptor reflectObjectGetOwnPropertyDescriptor DontEnum|Function 2
-    getPrototypeOf           reflectObjectGetPrototypeOf           DontEnum|Function 1
+    getPrototypeOf           reflectObjectGetPrototypeOf           DontEnum|Function 1 ReflectGetPrototypeOfIntrinsic
     has                      JSBuiltin                             DontEnum|Function 2
     isExtensible             reflectObjectIsExtensible             DontEnum|Function 1
     ownKeys                  reflectObjectOwnKeys                  DontEnum|Function 1
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to