Title: [240040] trunk
Revision
240040
Author
mark....@apple.com
Date
2019-01-16 10:10:44 -0800 (Wed, 16 Jan 2019)

Log Message

JSFunction::canUseAllocationProfile() should account for builtin functions with no own prototypes.
https://bugs.webkit.org/show_bug.cgi?id=193423
<rdar://problem/46209355>

Reviewed by Saam Barati.

JSTests:

* microbenchmarks/sinkable-new-object-with-builtin-constructor.js: Added.
* stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-1.js: Added.
* stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-2.js: Added.
* stress/jsfunction-cannot-use-allocation-profile-with-builtin-functions-with-no-prototype.js: Added.

Source/_javascript_Core:

JSFunction::canUseAllocationProfile() should return false for most builtins
because the majority of them have no prototype property.  The only exception to
this is the few builtin functions that are explicitly used as constructors.

For these builtin constructors, JSFunction::canUseAllocationProfile() should also
return false if the prototype property is a getter or custom getter because
getting the prototype would then be effectful.

* dfg/DFGOperations.cpp:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/JSFunctionInlines.h:
(JSC::JSFunction::canUseAllocationProfile):
* runtime/PropertySlot.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (240039 => 240040)


--- trunk/JSTests/ChangeLog	2019-01-16 17:11:47 UTC (rev 240039)
+++ trunk/JSTests/ChangeLog	2019-01-16 18:10:44 UTC (rev 240040)
@@ -1,3 +1,16 @@
+2019-01-15  Mark Lam  <mark....@apple.com>
+
+        JSFunction::canUseAllocationProfile() should account for builtin functions with no own prototypes.
+        https://bugs.webkit.org/show_bug.cgi?id=193423
+        <rdar://problem/46209355>
+
+        Reviewed by Saam Barati.
+
+        * microbenchmarks/sinkable-new-object-with-builtin-constructor.js: Added.
+        * stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-1.js: Added.
+        * stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-2.js: Added.
+        * stress/jsfunction-cannot-use-allocation-profile-with-builtin-functions-with-no-prototype.js: Added.
+
 2019-01-15  Yusuke Suzuki  <yusukesuz...@slowstart.org>
 
         [JSC] Use KnownStringUse for GetByVal(Array::String) since AI would offer wider type information and offer non-string type after removing Check(String)

Added: trunk/JSTests/microbenchmarks/sinkable-new-object-with-builtin-constructor.js (0 => 240040)


--- trunk/JSTests/microbenchmarks/sinkable-new-object-with-builtin-constructor.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/sinkable-new-object-with-builtin-constructor.js	2019-01-16 18:10:44 UTC (rev 240040)
@@ -0,0 +1,28 @@
+function sumOfArithSeries(limit) {
+    return limit * (limit + 1) / 2;
+}
+
+var n = 10000000;
+
+function bar() { }
+
+function foo(b) {
+    var result = 0;
+    for (var i = 0; i < n; ++i) {
+        var iter = ([i, i + 1])[Symbol.iterator]();
+        if (b) {
+            bar(o, p);
+            return;
+        }
+        for (x of iter)
+            result += x;
+    }
+    return result;
+}
+
+noInline(bar);
+noInline(foo);
+
+var result = foo(false);
+if (result != sumOfArithSeries(n - 1) + sumOfArithSeries(n))
+    throw "Error: bad result: " + result;

Added: trunk/JSTests/stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-1.js (0 => 240040)


--- trunk/JSTests/stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-1.js	                        (rev 0)
+++ trunk/JSTests/stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-1.js	2019-01-16 18:10:44 UTC (rev 240040)
@@ -0,0 +1,15 @@
+var invokeCount = 0;
+
+Object.defineProperty(Function.prototype, 'prototype', {
+    get: function () {
+        invokeCount++;
+    }
+});
+
+new Promise(resolve => {
+    for (var i = 0; i < 10000; ++i)
+        new resolve();
+
+    if (invokeCount != 10000)
+        $vm.crash();
+});

Added: trunk/JSTests/stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-2.js (0 => 240040)


--- trunk/JSTests/stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-2.js	                        (rev 0)
+++ trunk/JSTests/stress/constructing-builtin-functions-with-getter-prototype-should-only-call-getter-once-per-new-2.js	2019-01-16 18:10:44 UTC (rev 240040)
@@ -0,0 +1,15 @@
+new Promise(resolve => {
+    var invokeCount = 0;
+
+    Object.defineProperty(resolve, 'prototype', {
+        get: function () {
+            invokeCount++;
+        }
+    });
+
+    for (var i = 0; i < 10000; ++i)
+        new resolve();
+
+    if (invokeCount != 10000)
+        $vm.crash();
+});

Added: trunk/JSTests/stress/jsfunction-cannot-use-allocation-profile-with-builtin-functions-with-no-prototype.js (0 => 240040)


--- trunk/JSTests/stress/jsfunction-cannot-use-allocation-profile-with-builtin-functions-with-no-prototype.js	                        (rev 0)
+++ trunk/JSTests/stress/jsfunction-cannot-use-allocation-profile-with-builtin-functions-with-no-prototype.js	2019-01-16 18:10:44 UTC (rev 240040)
@@ -0,0 +1,9 @@
+Object.defineProperty(Function.prototype, 'prototype', {
+    get: function () {
+        throw new Error('hello');
+    }
+});
+
+new Promise(resolve => {
+    new resolve();
+});

Modified: trunk/Source/_javascript_Core/ChangeLog (240039 => 240040)


--- trunk/Source/_javascript_Core/ChangeLog	2019-01-16 17:11:47 UTC (rev 240039)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-01-16 18:10:44 UTC (rev 240040)
@@ -1,3 +1,26 @@
+2019-01-15  Mark Lam  <mark....@apple.com>
+
+        JSFunction::canUseAllocationProfile() should account for builtin functions with no own prototypes.
+        https://bugs.webkit.org/show_bug.cgi?id=193423
+        <rdar://problem/46209355>
+
+        Reviewed by Saam Barati.
+
+        JSFunction::canUseAllocationProfile() should return false for most builtins
+        because the majority of them have no prototype property.  The only exception to
+        this is the few builtin functions that are explicitly used as constructors.
+
+        For these builtin constructors, JSFunction::canUseAllocationProfile() should also
+        return false if the prototype property is a getter or custom getter because
+        getting the prototype would then be effectful.
+
+        * dfg/DFGOperations.cpp:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/JSFunctionInlines.h:
+        (JSC::JSFunction::canUseAllocationProfile):
+        * runtime/PropertySlot.h:
+
 2019-01-15  Yusuke Suzuki  <yusukesuz...@slowstart.org>
 
         [JSC] Use KnownStringUse for GetByVal(Array::String) since AI would offer wider type information and offer non-string type after removing Check(String)

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (240039 => 240040)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2019-01-16 17:11:47 UTC (rev 240039)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2019-01-16 18:10:44 UTC (rev 240040)
@@ -301,7 +301,7 @@
     auto scope = DECLARE_THROW_SCOPE(vm);
     if (constructor->type() == JSFunctionType && jsCast<JSFunction*>(constructor)->canUseAllocationProfile()) {
         auto rareData = jsCast<JSFunction*>(constructor)->ensureRareDataAndAllocationProfile(exec, inlineCapacity);
-        RETURN_IF_EXCEPTION(scope, nullptr);
+        scope.releaseAssertNoException();
         ObjectAllocationProfile* allocationProfile = rareData->objectAllocationProfile();
         Structure* structure = allocationProfile->structure();
         JSObject* result = constructEmptyObject(exec, structure);

Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp (240039 => 240040)


--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp	2019-01-16 17:11:47 UTC (rev 240039)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp	2019-01-16 18:10:44 UTC (rev 240040)
@@ -243,6 +243,7 @@
 
         size_t inlineCapacity = bytecode.inlineCapacity;
         ObjectAllocationProfile* allocationProfile = constructor->ensureRareDataAndAllocationProfile(exec, inlineCapacity)->objectAllocationProfile();
+        throwScope.releaseAssertNoException();
         Structure* structure = allocationProfile->structure();
         result = constructEmptyObject(exec, structure);
         if (structure->hasPolyProto()) {

Modified: trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h (240039 => 240040)


--- trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h	2019-01-16 17:11:47 UTC (rev 240039)
+++ trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h	2019-01-16 18:10:44 UTC (rev 240040)
@@ -110,9 +110,17 @@
 
 inline bool JSFunction::canUseAllocationProfile()
 {
-    if (isHostFunction())
-        return false;
+    if (isHostOrBuiltinFunction()) {
+        if (isHostFunction())
+            return false;
 
+        VM& vm = globalObject()->vm();
+        unsigned attributes;
+        JSValue prototype = getDirect(vm, vm.propertyNames->prototype, attributes);
+        if (!prototype || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue))
+            return false;
+    }
+
     // If we don't have a prototype property, we're not guaranteed it's
     // non-configurable. For example, user code can define the prototype
     // as a getter. JS semantics require that the getter is called every

Modified: trunk/Source/_javascript_Core/runtime/PropertySlot.h (240039 => 240040)


--- trunk/Source/_javascript_Core/runtime/PropertySlot.h	2019-01-16 17:11:47 UTC (rev 240039)
+++ trunk/Source/_javascript_Core/runtime/PropertySlot.h	2019-01-16 18:10:44 UTC (rev 240040)
@@ -45,6 +45,7 @@
     CustomAccessor    = 1 << 5,
     CustomValue       = 1 << 6,
     CustomAccessorOrValue = CustomAccessor | CustomValue,
+    AccessorOrCustomAccessorOrValue = Accessor | CustomAccessor | CustomValue,
 
     // Things that are used by static hashtables are not in the attributes byte in PropertyMapEntry.
     Function          = 1 << 8,  // property is a function - only used by static hashtables
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to