Diff
Modified: trunk/JSTests/ChangeLog (275270 => 275271)
--- trunk/JSTests/ChangeLog 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/JSTests/ChangeLog 2021-03-31 07:21:37 UTC (rev 275271)
@@ -1,3 +1,22 @@
+2021-03-31 Alexey Shvayka <[email protected]>
+
+ Optimize constructors of ES6 collections
+ https://bugs.webkit.org/show_bug.cgi?id=223953
+
+ Reviewed by Yusuke Suzuki.
+
+ * microbenchmarks/map-constructor.js:
+ * microbenchmarks/set-constructor.js: Added.
+ * microbenchmarks/weak-map-constructor.js: Added.
+ * microbenchmarks/weak-set-constructor.js: Added.
+ * stress/map-constructor-adder.js:
+ * stress/set-constructor-adder.js:
+ * stress/weak-map-constructor-adder-error-cross-realm.js: Added.
+ * stress/weak-map-constructor-adder.js:
+ * stress/weak-set-constructor-adder-error-cross-realm.js: Added.
+ * stress/weak-set-constructor-adder.js:
+ * stress/weak-set-constructor.js:
+
2021-03-29 Ryan Haddad <[email protected]>
Unreviewed test gardening.
Modified: trunk/JSTests/microbenchmarks/map-constructor.js (275270 => 275271)
--- trunk/JSTests/microbenchmarks/map-constructor.js 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/JSTests/microbenchmarks/map-constructor.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -4,28 +4,10 @@
}
noInline(test);
-var array = [
- [0, 0],
- [1, 0],
- [2, 0],
- [3, 0],
- [4, 0],
- [5, 0],
- [6, 0],
- [7, 0],
- [8, 0],
- [9, 0],
- [10, 0],
- [11, 0],
- [12, 0],
- [13, 0],
- [14, 0],
- [15, 0],
- [16, 0],
- [17, 0],
- [18, 0],
- [19, 0],
-];
+var array = [];
+for (var j = 0; j < 50; ++j)
+ array[j] = [j, 0];
+
for (var i = 0; i < 1e4; ++i)
test(array);
Added: trunk/JSTests/microbenchmarks/set-constructor.js (0 => 275271)
--- trunk/JSTests/microbenchmarks/set-constructor.js (rev 0)
+++ trunk/JSTests/microbenchmarks/set-constructor.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -0,0 +1,13 @@
+function test(array)
+{
+ return new Set(array);
+}
+noInline(test);
+
+var array = [];
+
+for (var j = 0; j < 50; ++j)
+ array[j] = j;
+
+for (var i = 0; i < 1e4; ++i)
+ test(array);
Added: trunk/JSTests/microbenchmarks/weak-map-constructor.js (0 => 275271)
--- trunk/JSTests/microbenchmarks/weak-map-constructor.js (rev 0)
+++ trunk/JSTests/microbenchmarks/weak-map-constructor.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -0,0 +1,13 @@
+function test(array)
+{
+ return new WeakMap(array);
+}
+noInline(test);
+
+var array = [];
+
+for (var j = 0; j < 50; ++j)
+ array[j] = [{}, 0];
+
+for (var i = 0; i < 1e4; ++i)
+ test(array);
Added: trunk/JSTests/microbenchmarks/weak-set-constructor.js (0 => 275271)
--- trunk/JSTests/microbenchmarks/weak-set-constructor.js (rev 0)
+++ trunk/JSTests/microbenchmarks/weak-set-constructor.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -0,0 +1,13 @@
+function test(array)
+{
+ return new WeakSet(array);
+}
+noInline(test);
+
+var array = [];
+
+for (var j = 0; j < 50; ++j)
+ array[j] = {};
+
+for (var i = 0; i < 1e4; ++i)
+ test(array);
Modified: trunk/JSTests/stress/map-constructor-adder.js (275270 => 275271)
--- trunk/JSTests/stress/map-constructor-adder.js 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/JSTests/stress/map-constructor-adder.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -1,5 +1,18 @@
// Map constructor with adder change.
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ try {
+ func();
+ } catch (error) {
+ errorThrown = true;
+ if (String(error) !== errorMessage)
+ throw new Error(`Bad error: ${error}`);
+ }
+ if (!errorThrown)
+ throw new Error("Didn't throw!");
+}
+
var originalAdder = Map.prototype.set;
var counter = 0;
@@ -33,14 +46,12 @@
var map = new Map();
var map = new Map([]);
-var error = null;
-try {
- var map = new Map([ [0, 0] ]);
-} catch (e) {
- error = e;
-}
-if (!error)
- throw "Error: error not thrown";
-if (String(error) !== "Error: adder called")
- throw "Error: bad error " + String(error);
+shouldThrow(() => {
+ new Map([ [0, 0] ]);
+}, "Error: adder called");
+
+Map.prototype.set = undefined;
+shouldThrow(() => {
+ new Map([ [0, 0] ]);
+}, "TypeError: 'set' property of a Map should be callable.");
Modified: trunk/JSTests/stress/set-constructor-adder.js (275270 => 275271)
--- trunk/JSTests/stress/set-constructor-adder.js 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/JSTests/stress/set-constructor-adder.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -1,5 +1,18 @@
// Set constructor with adder change.
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ try {
+ func();
+ } catch (error) {
+ errorThrown = true;
+ if (String(error) !== errorMessage)
+ throw new Error(`Bad error: ${error}`);
+ }
+ if (!errorThrown)
+ throw new Error("Didn't throw!");
+}
+
var originalAdder = Set.prototype.add;
var counter = 0;
@@ -21,14 +34,12 @@
var set = new Set();
var set = new Set([]);
-var error = null;
-try {
- var set = new Set([0]);
-} catch (e) {
- error = e;
-}
-if (!error)
- throw "Error: error not thrown";
-if (String(error) !== "Error: adder called")
- throw "Error: bad error " + String(error);
+shouldThrow(() => {
+ new Set([0]);
+}, "Error: adder called");
+
+Set.prototype.add = Symbol();
+shouldThrow(() => {
+ new Set([0]);
+}, "TypeError: 'add' property of a Set should be callable.");
Added: trunk/JSTests/stress/weak-map-constructor-adder-error-cross-realm.js (0 => 275271)
--- trunk/JSTests/stress/weak-map-constructor-adder-error-cross-realm.js (rev 0)
+++ trunk/JSTests/stress/weak-map-constructor-adder-error-cross-realm.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -0,0 +1,14 @@
+const realmA = $vm.createGlobalObject();
+const realmB = $vm.createGlobalObject();
+const realmC = $vm.createGlobalObject();
+
+realmB.WeakMap.prototype.set =
+realmC.WeakMap.prototype.set;
+
+try {
+ Reflect.construct(realmA.WeakMap, [[[0, 0]]], realmB.WeakMap);
+ throw "Didn't throw!";
+} catch (err) {
+ if (!(err instanceof realmC.TypeError))
+ throw "Bad realm of an error!";
+}
Modified: trunk/JSTests/stress/weak-map-constructor-adder.js (275270 => 275271)
--- trunk/JSTests/stress/weak-map-constructor-adder.js 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/JSTests/stress/weak-map-constructor-adder.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -1,5 +1,18 @@
// WeakMap constructor with adder change.
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ try {
+ func();
+ } catch (error) {
+ errorThrown = true;
+ if (String(error) !== errorMessage)
+ throw new Error(`Bad error: ${error}`);
+ }
+ if (!errorThrown)
+ throw new Error("Didn't throw!");
+}
+
var originalAdder = WeakMap.prototype.set;
var counter = 0;
@@ -38,14 +51,12 @@
var map = new WeakMap();
var map = new WeakMap([]);
-var error = null;
-try {
- var map = new WeakMap([ [0, 0] ]);
-} catch (e) {
- error = e;
-}
-if (!error)
- throw "Error: error not thrown";
-if (String(error) !== "Error: adder called")
- throw "Error: bad error " + String(error);
+shouldThrow(() => {
+ new WeakMap([ [0, 0] ]);
+}, "Error: adder called");
+
+WeakMap.prototype.set = null;
+shouldThrow(() => {
+ new WeakMap([ [0, 0] ]);
+}, "TypeError: 'set' property of a WeakMap should be callable.");
Added: trunk/JSTests/stress/weak-set-constructor-adder-error-cross-realm.js (0 => 275271)
--- trunk/JSTests/stress/weak-set-constructor-adder-error-cross-realm.js (rev 0)
+++ trunk/JSTests/stress/weak-set-constructor-adder-error-cross-realm.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -0,0 +1,14 @@
+const realmA = $vm.createGlobalObject();
+const realmB = $vm.createGlobalObject();
+const realmC = $vm.createGlobalObject();
+
+realmB.WeakSet.prototype.add =
+realmC.WeakSet.prototype.add;
+
+try {
+ Reflect.construct(realmA.WeakSet, [[0]], realmB.WeakSet);
+ throw "Didn't throw!";
+} catch (err) {
+ if (!(err instanceof realmC.TypeError))
+ throw "Bad realm of an error!";
+}
Modified: trunk/JSTests/stress/weak-set-constructor-adder.js (275270 => 275271)
--- trunk/JSTests/stress/weak-set-constructor-adder.js 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/JSTests/stress/weak-set-constructor-adder.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -1,5 +1,18 @@
// WeakSet constructor with adder change.
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ try {
+ func();
+ } catch (error) {
+ errorThrown = true;
+ if (String(error) !== errorMessage)
+ throw new Error(`Bad error: ${error}`);
+ }
+ if (!errorThrown)
+ throw new Error("Didn't throw!");
+}
+
var originalAdder = WeakSet.prototype.add;
var counter = 0;
@@ -38,14 +51,12 @@
var set = new WeakSet();
var set = new WeakSet([]);
-var error = null;
-try {
- var set = new WeakSet([ 0 ]);
-} catch (e) {
- error = e;
-}
-if (!error)
- throw new Error("error not thrown");
-if (String(error) !== "Error: adder called")
- throw new Error("bad error " + String(error));
+shouldThrow(() => {
+ new WeakSet([ 0 ]);
+}, "Error: adder called");
+
+WeakSet.prototype.add = "foo";
+shouldThrow(() => {
+ new WeakSet([ 0 ]);
+}, "TypeError: 'add' property of a WeakSet should be callable.");
Modified: trunk/JSTests/stress/weak-set-constructor.js (275270 => 275271)
--- trunk/JSTests/stress/weak-set-constructor.js 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/JSTests/stress/weak-set-constructor.js 2021-03-31 07:21:37 UTC (rev 275271)
@@ -141,6 +141,6 @@
];
for (var item of nonObjectKeys) {
- testTypeError(item, 'TypeError: Attempted to add a non-object key to a WeakSet');
+ testTypeError(item, 'TypeError: Attempted to add a non-object value to a WeakSet');
testCallTypeError(item);
}
Modified: trunk/LayoutTests/ChangeLog (275270 => 275271)
--- trunk/LayoutTests/ChangeLog 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/LayoutTests/ChangeLog 2021-03-31 07:21:37 UTC (rev 275271)
@@ -1,3 +1,12 @@
+2021-03-31 Alexey Shvayka <[email protected]>
+
+ Optimize constructors of ES6 collections
+ https://bugs.webkit.org/show_bug.cgi?id=223953
+
+ Reviewed by Yusuke Suzuki.
+
+ * js/dom/basic-weakset-expected.txt:
+
2021-03-30 Antoine Quint <[email protected]>
Computed style for background-position should not use "left" and "top" keywords
Modified: trunk/LayoutTests/js/dom/basic-weakset-expected.txt (275270 => 275271)
--- trunk/LayoutTests/js/dom/basic-weakset-expected.txt 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/LayoutTests/js/dom/basic-weakset-expected.txt 2021-03-31 07:21:37 UTC (rev 275271)
@@ -7,14 +7,14 @@
PASS WeakSet.prototype instanceof WeakSet is false
PASS new WeakSet() instanceof WeakSet is true
PASS WeakSet() threw exception TypeError: calling WeakSet constructor without new is invalid.
-PASS set.add(0) threw exception TypeError: Attempted to add a non-object key to a WeakSet.
-PASS set.add(0.5) threw exception TypeError: Attempted to add a non-object key to a WeakSet.
-PASS set.add('foo') threw exception TypeError: Attempted to add a non-object key to a WeakSet.
-PASS set.add(true) threw exception TypeError: Attempted to add a non-object key to a WeakSet.
-PASS set.add(false) threw exception TypeError: Attempted to add a non-object key to a WeakSet.
-PASS set.add(null) threw exception TypeError: Attempted to add a non-object key to a WeakSet.
-PASS set.add(undefined) threw exception TypeError: Attempted to add a non-object key to a WeakSet.
-PASS set.add(Symbol.iterator) threw exception TypeError: Attempted to add a non-object key to a WeakSet.
+PASS set.add(0) threw exception TypeError: Attempted to add a non-object value to a WeakSet.
+PASS set.add(0.5) threw exception TypeError: Attempted to add a non-object value to a WeakSet.
+PASS set.add('foo') threw exception TypeError: Attempted to add a non-object value to a WeakSet.
+PASS set.add(true) threw exception TypeError: Attempted to add a non-object value to a WeakSet.
+PASS set.add(false) threw exception TypeError: Attempted to add a non-object value to a WeakSet.
+PASS set.add(null) threw exception TypeError: Attempted to add a non-object value to a WeakSet.
+PASS set.add(undefined) threw exception TypeError: Attempted to add a non-object value to a WeakSet.
+PASS set.add(Symbol.iterator) threw exception TypeError: Attempted to add a non-object value to a WeakSet.
PASS set.has(0) is false
PASS set.has(0.5) is false
PASS set.has('foo') is false
Modified: trunk/Source/_javascript_Core/ChangeLog (275270 => 275271)
--- trunk/Source/_javascript_Core/ChangeLog 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-03-31 07:21:37 UTC (rev 275271)
@@ -1,3 +1,51 @@
+2021-03-31 Alexey Shvayka <[email protected]>
+
+ Optimize constructors of ES6 collections
+ https://bugs.webkit.org/show_bug.cgi?id=223953
+
+ Reviewed by Yusuke Suzuki.
+
+ This patch speeds up the constructors by avoiding call() for non-observable
+ "set" / "add" methods and using getIndex() for Map / WeakMap collections.
+
+ For Map / Set, this change leverages existing cloning helpers, which rely on
+ watchpoints, to avoid even a method lookup. However, slower path is used for
+ subclasses. Results in 1.9x speed-up for common case.
+
+ For WeakMap / WeakSet, adder function is checked by C++ pointer, which enables
+ fast path even for cross-realm subclasses. Results in 2.3x progression.
+
+ Both approaches require special handling of a cross-realm NewTarget to ensure
+ that raised exceptions (OOM / TypeError) belong to realm of the adder function,
+ and not to constructor's or NewTarget's.
+
+ Also, adds descriptve error messages for non-callable "set" / "add" properties.
+
+ * runtime/JSMap.cpp:
+ (JSC::JSMap::isSetFastAndNonObservable):
+ (JSC::JSMap::canCloneFastAndNonObservable): Deleted.
+ * runtime/JSMap.h:
+ * runtime/JSSet.cpp:
+ (JSC::JSSet::isAddFastAndNonObservable):
+ (JSC::JSSet::canCloneFastAndNonObservable): Deleted.
+ * runtime/JSSet.h:
+ * runtime/MapConstructor.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/SetConstructor.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/WeakMapConstructor.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/WeakMapPrototype.cpp:
+ (JSC::WeakMapPrototype::finishCreation):
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/WeakMapPrototype.h:
+ * runtime/WeakSetConstructor.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/WeakSetPrototype.cpp:
+ (JSC::WeakSetPrototype::finishCreation):
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/WeakSetPrototype.h:
+
2021-03-30 Devin Rousso <[email protected]>
REGRESSION(r274607): media controls script is visible in Web Inspector even without the engineering "Show WebKit-internal scripts" enabled
Modified: trunk/Source/_javascript_Core/runtime/JSMap.cpp (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/JSMap.cpp 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/JSMap.cpp 2021-03-31 07:21:37 UTC (rev 275271)
@@ -39,6 +39,21 @@
return instance;
}
+bool JSMap::isSetFastAndNonObservable(Structure* structure)
+{
+ JSGlobalObject* globalObject = structure->globalObject();
+ if (!globalObject->isMapPrototypeSetFastAndNonObservable())
+ return false;
+
+ if (structure->hasPolyProto())
+ return false;
+
+ if (structure->storedPrototype() != globalObject->mapPrototype())
+ return false;
+
+ return true;
+}
+
bool JSMap::isIteratorProtocolFastAndNonObservable()
{
JSGlobalObject* globalObject = this->globalObject();
@@ -60,23 +75,4 @@
return true;
}
-bool JSMap::canCloneFastAndNonObservable(Structure* structure)
-{
- auto setFastAndNonObservable = [&] (Structure* structure) {
- JSGlobalObject* globalObject = structure->globalObject();
- if (!globalObject->isMapPrototypeSetFastAndNonObservable())
- return false;
-
- if (structure->hasPolyProto())
- return false;
-
- if (structure->storedPrototype() != globalObject->mapPrototype())
- return false;
-
- return true;
- };
-
- return isIteratorProtocolFastAndNonObservable() && setFastAndNonObservable(structure);
}
-
-}
Modified: trunk/Source/_javascript_Core/runtime/JSMap.h (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/JSMap.h 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/JSMap.h 2021-03-31 07:21:37 UTC (rev 275271)
@@ -59,8 +59,8 @@
add(globalObject, key, value);
}
+ static bool isSetFastAndNonObservable(Structure*);
bool isIteratorProtocolFastAndNonObservable();
- bool canCloneFastAndNonObservable(Structure*);
JSMap* clone(JSGlobalObject*, VM&, Structure*);
private:
Modified: trunk/Source/_javascript_Core/runtime/JSSet.cpp (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/JSSet.cpp 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/JSSet.cpp 2021-03-31 07:21:37 UTC (rev 275271)
@@ -39,6 +39,21 @@
return instance;
}
+bool JSSet::isAddFastAndNonObservable(Structure* structure)
+{
+ JSGlobalObject* globalObject = structure->globalObject();
+ if (!globalObject->isSetPrototypeAddFastAndNonObservable())
+ return false;
+
+ if (structure->hasPolyProto())
+ return false;
+
+ if (structure->storedPrototype() != globalObject->jsSetPrototype())
+ return false;
+
+ return true;
+}
+
bool JSSet::isIteratorProtocolFastAndNonObservable()
{
JSGlobalObject* globalObject = this->globalObject();
@@ -60,23 +75,4 @@
return true;
}
-bool JSSet::canCloneFastAndNonObservable(Structure* structure)
-{
- auto addFastAndNonObservable = [&] (Structure* structure) {
- JSGlobalObject* globalObject = structure->globalObject();
- if (!globalObject->isSetPrototypeAddFastAndNonObservable())
- return false;
-
- if (structure->hasPolyProto())
- return false;
-
- if (structure->storedPrototype() != globalObject->jsSetPrototype())
- return false;
-
- return true;
- };
-
- return isIteratorProtocolFastAndNonObservable() && addFastAndNonObservable(structure);
}
-
-}
Modified: trunk/Source/_javascript_Core/runtime/JSSet.h (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/JSSet.h 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/JSSet.h 2021-03-31 07:21:37 UTC (rev 275271)
@@ -59,8 +59,8 @@
return instance;
}
+ static bool isAddFastAndNonObservable(Structure*);
bool isIteratorProtocolFastAndNonObservable();
- bool canCloneFastAndNonObservable(Structure*);
JSSet* clone(JSGlobalObject*, VM&, Structure*);
private:
Modified: trunk/Source/_javascript_Core/runtime/MapConstructor.cpp (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/MapConstructor.cpp 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/MapConstructor.cpp 2021-03-31 07:21:37 UTC (rev 275271)
@@ -70,8 +70,9 @@
if (iterable.isUndefinedOrNull())
RELEASE_AND_RETURN(scope, JSValue::encode(JSMap::create(globalObject, vm, mapStructure)));
+ bool canPerformFastSet = JSMap::isSetFastAndNonObservable(mapStructure);
if (auto* iterableMap = jsDynamicCast<JSMap*>(vm, iterable)) {
- if (iterableMap->canCloneFastAndNonObservable(mapStructure))
+ if (canPerformFastSet && iterableMap->isIteratorProtocolFastAndNonObservable())
RELEASE_AND_RETURN(scope, JSValue::encode(iterableMap->clone(globalObject, vm, mapStructure)));
}
@@ -78,12 +79,16 @@
JSMap* map = JSMap::create(globalObject, vm, mapStructure);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- JSValue adderFunction = map->JSObject::get(globalObject, vm.propertyNames->set);
- RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ JSValue adderFunction;
+ CallData adderFunctionCallData;
+ if (!canPerformFastSet) {
+ adderFunction = map->JSObject::get(globalObject, vm.propertyNames->set);
+ RETURN_IF_EXCEPTION(scope, { });
- auto adderFunctionCallData = getCallData(vm, adderFunction);
- if (adderFunctionCallData.type == CallData::Type::None)
- return JSValue::encode(throwTypeError(globalObject, scope));
+ adderFunctionCallData = getCallData(vm, adderFunction);
+ if (UNLIKELY(adderFunctionCallData.type == CallData::Type::None))
+ return throwVMTypeError(globalObject, scope, "'set' property of a Map should be callable."_s);
+ }
scope.release();
forEachInIterable(globalObject, iterable, [&](VM& vm, JSGlobalObject* globalObject, JSValue nextItem) {
@@ -93,17 +98,24 @@
return;
}
- JSValue key = nextItem.get(globalObject, static_cast<unsigned>(0));
+ JSObject* nextObject = asObject(nextItem);
+
+ JSValue key = nextObject->getIndex(globalObject, static_cast<unsigned>(0));
RETURN_IF_EXCEPTION(scope, void());
- JSValue value = nextItem.get(globalObject, static_cast<unsigned>(1));
+ JSValue value = nextObject->getIndex(globalObject, static_cast<unsigned>(1));
RETURN_IF_EXCEPTION(scope, void());
+ scope.release();
+ if (canPerformFastSet) {
+ map->set(mapStructure->globalObject(), key, value);
+ return;
+ }
+
MarkedArgumentBuffer arguments;
arguments.append(key);
arguments.append(value);
ASSERT(!arguments.hasOverflowed());
- scope.release();
call(globalObject, adderFunction, adderFunctionCallData, map, arguments);
});
Modified: trunk/Source/_javascript_Core/runtime/SetConstructor.cpp (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/SetConstructor.cpp 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/SetConstructor.cpp 2021-03-31 07:21:37 UTC (rev 275271)
@@ -70,8 +70,9 @@
if (iterable.isUndefinedOrNull())
RELEASE_AND_RETURN(scope, JSValue::encode(JSSet::create(globalObject, vm, setStructure)));
+ bool canPerformFastAdd = JSSet::isAddFastAndNonObservable(setStructure);
if (auto* iterableSet = jsDynamicCast<JSSet*>(vm, iterable)) {
- if (iterableSet->canCloneFastAndNonObservable(setStructure))
+ if (canPerformFastAdd && iterableSet->isIteratorProtocolFastAndNonObservable())
RELEASE_AND_RETURN(scope, JSValue::encode(iterableSet->clone(globalObject, vm, setStructure)));
}
@@ -78,15 +79,24 @@
JSSet* set = JSSet::create(globalObject, vm, setStructure);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- JSValue adderFunction = set->JSObject::get(globalObject, vm.propertyNames->add);
- RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ JSValue adderFunction;
+ CallData adderFunctionCallData;
+ if (!canPerformFastAdd) {
+ adderFunction = set->JSObject::get(globalObject, vm.propertyNames->add);
+ RETURN_IF_EXCEPTION(scope, { });
- auto adderFunctionCallData = getCallData(vm, adderFunction);
- if (UNLIKELY(adderFunctionCallData.type == CallData::Type::None))
- return JSValue::encode(throwTypeError(globalObject, scope));
+ adderFunctionCallData = getCallData(vm, adderFunction);
+ if (UNLIKELY(adderFunctionCallData.type == CallData::Type::None))
+ return throwVMTypeError(globalObject, scope, "'add' property of a Set should be callable."_s);
+ }
scope.release();
forEachInIterable(globalObject, iterable, [&](VM&, JSGlobalObject* globalObject, JSValue nextValue) {
+ if (canPerformFastAdd) {
+ set->add(setStructure->globalObject(), nextValue);
+ return;
+ }
+
MarkedArgumentBuffer arguments;
arguments.append(nextValue);
ASSERT(!arguments.hasOverflowed());
Modified: trunk/Source/_javascript_Core/runtime/WeakMapConstructor.cpp (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/WeakMapConstructor.cpp 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/WeakMapConstructor.cpp 2021-03-31 07:21:37 UTC (rev 275271)
@@ -75,8 +75,10 @@
auto adderFunctionCallData = getCallData(vm, adderFunction);
if (adderFunctionCallData.type == CallData::Type::None)
- return JSValue::encode(throwTypeError(globalObject, scope));
+ return throwVMTypeError(globalObject, scope, "'set' property of a WeakMap should be callable."_s);
+ bool canPerformFastSet = adderFunctionCallData.type == CallData::Type::Native && adderFunctionCallData.native.function == protoFuncWeakMapSet;
+
scope.release();
forEachInIterable(globalObject, iterable, [&](VM& vm, JSGlobalObject* globalObject, JSValue nextItem) {
auto scope = DECLARE_THROW_SCOPE(vm);
@@ -85,12 +87,22 @@
return;
}
- JSValue key = nextItem.get(globalObject, static_cast<unsigned>(0));
+ JSObject* nextObject = asObject(nextItem);
+
+ JSValue key = nextObject->getIndex(globalObject, static_cast<unsigned>(0));
RETURN_IF_EXCEPTION(scope, void());
- JSValue value = nextItem.get(globalObject, static_cast<unsigned>(1));
+ JSValue value = nextObject->getIndex(globalObject, static_cast<unsigned>(1));
RETURN_IF_EXCEPTION(scope, void());
+ if (canPerformFastSet) {
+ if (key.isObject())
+ weakMap->set(vm, asObject(key), value);
+ else
+ throwTypeError(asObject(adderFunction)->globalObject(vm), scope, WeakMapNonObjectKeyError);
+ return;
+ }
+
MarkedArgumentBuffer arguments;
arguments.append(key);
arguments.append(value);
Modified: trunk/Source/_javascript_Core/runtime/WeakMapPrototype.cpp (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/WeakMapPrototype.cpp 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/WeakMapPrototype.cpp 2021-03-31 07:21:37 UTC (rev 275271)
@@ -31,12 +31,13 @@
namespace JSC {
+const ASCIILiteral WeakMapNonObjectKeyError { "Attempted to set a non-object key in a WeakMap"_s };
+
const ClassInfo WeakMapPrototype::s_info = { "WeakMap", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(WeakMapPrototype) };
static JSC_DECLARE_HOST_FUNCTION(protoFuncWeakMapDelete);
static JSC_DECLARE_HOST_FUNCTION(protoFuncWeakMapGet);
static JSC_DECLARE_HOST_FUNCTION(protoFuncWeakMapHas);
-static JSC_DECLARE_HOST_FUNCTION(protoFuncWeakMapSet);
void WeakMapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
@@ -109,7 +110,7 @@
return JSValue::encode(jsUndefined());
JSValue key = callFrame->argument(0);
if (!key.isObject())
- return JSValue::encode(throwTypeError(globalObject, scope, "Attempted to set a non-object key in a WeakMap"_s));
+ return JSValue::encode(throwTypeError(globalObject, scope, WeakMapNonObjectKeyError));
map->set(vm, asObject(key), callFrame->argument(1));
return JSValue::encode(callFrame->thisValue());
}
Modified: trunk/Source/_javascript_Core/runtime/WeakMapPrototype.h (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/WeakMapPrototype.h 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/WeakMapPrototype.h 2021-03-31 07:21:37 UTC (rev 275271)
@@ -29,6 +29,10 @@
namespace JSC {
+extern const ASCIILiteral WeakMapNonObjectKeyError;
+
+JSC_DECLARE_HOST_FUNCTION(protoFuncWeakMapSet);
+
class WeakMapPrototype final : public JSNonFinalObject {
public:
using Base = JSNonFinalObject;
Modified: trunk/Source/_javascript_Core/runtime/WeakSetConstructor.cpp (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/WeakSetConstructor.cpp 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/WeakSetConstructor.cpp 2021-03-31 07:21:37 UTC (rev 275271)
@@ -75,10 +75,20 @@
auto adderFunctionCallData = getCallData(vm, adderFunction);
if (adderFunctionCallData.type == CallData::Type::None)
- return JSValue::encode(throwTypeError(globalObject, scope));
+ return throwVMTypeError(globalObject, scope, "'add' property of a WeakSet should be callable."_s);
+ bool canPerformFastAdd = adderFunctionCallData.type == CallData::Type::Native && adderFunctionCallData.native.function == protoFuncWeakSetAdd;
+
scope.release();
forEachInIterable(globalObject, iterable, [&](VM&, JSGlobalObject* globalObject, JSValue nextValue) {
+ if (canPerformFastAdd) {
+ if (nextValue.isObject())
+ weakSet->add(vm, asObject(nextValue));
+ else
+ throwTypeError(asObject(adderFunction)->globalObject(vm), scope, WeakSetNonObjectValueError);
+ return;
+ }
+
MarkedArgumentBuffer arguments;
arguments.append(nextValue);
ASSERT(!arguments.hasOverflowed());
Modified: trunk/Source/_javascript_Core/runtime/WeakSetPrototype.cpp (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/WeakSetPrototype.cpp 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/WeakSetPrototype.cpp 2021-03-31 07:21:37 UTC (rev 275271)
@@ -31,11 +31,12 @@
namespace JSC {
+const ASCIILiteral WeakSetNonObjectValueError { "Attempted to add a non-object value to a WeakSet"_s };
+
const ClassInfo WeakSetPrototype::s_info = { "WeakSet", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(WeakSetPrototype) };
static JSC_DECLARE_HOST_FUNCTION(protoFuncWeakSetDelete);
static JSC_DECLARE_HOST_FUNCTION(protoFuncWeakSetHas);
-static JSC_DECLARE_HOST_FUNCTION(protoFuncWeakSetAdd);
void WeakSetPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
@@ -96,7 +97,7 @@
return JSValue::encode(jsUndefined());
JSValue key = callFrame->argument(0);
if (!key.isObject())
- return JSValue::encode(throwTypeError(globalObject, scope, "Attempted to add a non-object key to a WeakSet"_s));
+ return JSValue::encode(throwTypeError(globalObject, scope, WeakSetNonObjectValueError));
set->add(vm, asObject(key));
return JSValue::encode(callFrame->thisValue());
}
Modified: trunk/Source/_javascript_Core/runtime/WeakSetPrototype.h (275270 => 275271)
--- trunk/Source/_javascript_Core/runtime/WeakSetPrototype.h 2021-03-31 05:52:41 UTC (rev 275270)
+++ trunk/Source/_javascript_Core/runtime/WeakSetPrototype.h 2021-03-31 07:21:37 UTC (rev 275271)
@@ -29,6 +29,10 @@
namespace JSC {
+extern const ASCIILiteral WeakSetNonObjectValueError;
+
+JSC_DECLARE_HOST_FUNCTION(protoFuncWeakSetAdd);
+
class WeakSetPrototype final : public JSNonFinalObject {
public:
using Base = JSNonFinalObject;