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