Diff
Modified: trunk/JSTests/ChangeLog (286068 => 286069)
--- trunk/JSTests/ChangeLog 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/JSTests/ChangeLog 2021-11-19 19:17:04 UTC (rev 286069)
@@ -1,3 +1,29 @@
+2021-11-19 Joseph Griego <[email protected]>
+
+ [JSC] Shadow realms: set correct Function prototype on wrapped functions
+ https://bugs.webkit.org/show_bug.cgi?id=233143
+
+ Reviewed by Yusuke Suzuki.
+
+ At present, the Function prototype set on each of the returned wrapped
+ functions will be the Function object from the realm the shadow realm
+ builtin is from--to comply with the latest draft of the shadow realms
+ spec [1], wrapped function objects should have the Function prototype
+ from the realm the wrapper object is destined for, instead.
+
+ At present, this requires tracking both the calling (destination) and
+ target (source) realm and switching between the two as function
+ arguments are wrapped (when the notion of source and destination realm
+ also flips)
+
+ Adds a simple builtin (moveFunctionToRealm) that can switch the Function
+ prototype given only the Shadow Realm object corresponding to the
+ correct global object.
+
+ Also marks the corresponding part of test262 as passing.
+
+ * test262/expectations.yaml:
+
2021-11-19 Angelos Oikonomopoulos <[email protected]>
[JSC] Workaround for failing mips tests
Modified: trunk/JSTests/stress/shadow-realm-evaluate.js (286068 => 286069)
--- trunk/JSTests/stress/shadow-realm-evaluate.js 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/JSTests/stress/shadow-realm-evaluate.js 2021-11-19 19:17:04 UTC (rev 286069)
@@ -77,6 +77,7 @@
let wrappedInvokeAndAdd = realm.evaluate("function invokeAndAdd(xFn, yFn) { return xFn() + yFn(); }; invokeAndAdd");
shouldBe(wrappedInvokeAndAdd(() => { return 1 }, () => { return 2 }), 3);
shouldBe($.globalObjectFor(wrappedInvokeAndAdd), globalThis);
+ shouldBe(Object.getPrototypeOf(wrappedInvokeAndAdd), Function.prototype);
// name and length properties from wrapped function are absent
shouldBe(Object.getOwnPropertyDescriptor(wrappedInvokeAndAdd, "length"), undefined);
@@ -122,6 +123,7 @@
let f = doEval(realm, '(x) => { return x() + globalThis.secret; }');
shouldBe($.globalObjectFor(f), globalThis);
shouldBe(f(() => { return 41; }), 42);
+ shouldBe(Object.getPrototypeOf(f), Function.prototype);
}
// (potential) inlining of wrapped function uses correct global object
let f = doEval(realm, '(x) => { return x() + globalThis.secret; }');
@@ -128,6 +130,7 @@
for (var i = 0; i < 10000; ++i) {
shouldBe($.globalObjectFor(f), globalThis);
shouldBe(f(() => { return 41; }), 42);
+ shouldBe(Object.getPrototypeOf(f), Function.prototype);
}
// (potential) inlining inside a realm uses correct global object
let loopInside = doEval(realm, '(x) => { let acc = 0; for (var i = 0; i < 10000; ++i) { acc += x(); }; return acc; }');
@@ -151,3 +154,23 @@
shouldBe(evaluateLength.writable, false);
shouldBe(evaluateLength.configurable, true);
}
+
+// Enclosing realm is hidden from shaodw realm even when playing Function prototype tricks
+{
+ let realm = new ShadowRealm();
+ foo = 42;
+
+ realm.evaluate("foo = false");
+
+ let realmFn = realm.evaluate(`(f) => {
+ let ourFn = Object.getPrototypeOf(f).constructor;
+ return (new ourFn("return this"))().foo
+ }`);
+
+ let retrievedFoo = realmFn(() => {});
+ let aFunction = Object.getPrototypeOf(realmFn).constructor;
+ let anotherFoo = (new aFunction("return this"))().foo;
+
+ shouldBe(retrievedFoo, false);
+ shouldBe(anotherFoo, 42);
+}
Modified: trunk/JSTests/test262/expectations.yaml (286068 => 286069)
--- trunk/JSTests/test262/expectations.yaml 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/JSTests/test262/expectations.yaml 2021-11-19 19:17:04 UTC (rev 286069)
@@ -1137,9 +1137,6 @@
test/built-ins/RegExp/quantifier-integer-limit.js:
default: 'SyntaxError: Invalid regular _expression_: number too large in {} quantifier'
strict mode: 'SyntaxError: Invalid regular _expression_: number too large in {} quantifier'
-test/built-ins/ShadowRealm/prototype/evaluate/wrapped-function-proto-from-caller-realm.js:
- default: 'Test262Error: callable arguments passed into WrappedFunction should be wrapped in target realm Expected SameValue(«false», «true») to be true'
- strict mode: 'Test262Error: callable arguments passed into WrappedFunction should be wrapped in target realm Expected SameValue(«false», «true») to be true'
test/built-ins/Temporal/Instant/prototype/toString/timezone-offset.js:
default: 'Test262Error: offset of UTC is +00:00 Expected SameValue(«1970-01-01T00:00:00Z», «1970-01-01T00:00:00+00:00») to be true'
strict mode: 'Test262Error: offset of UTC is +00:00 Expected SameValue(«1970-01-01T00:00:00Z», «1970-01-01T00:00:00+00:00») to be true'
Modified: trunk/Source/_javascript_Core/ChangeLog (286068 => 286069)
--- trunk/Source/_javascript_Core/ChangeLog 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-11-19 19:17:04 UTC (rev 286069)
@@ -1,3 +1,45 @@
+2021-11-19 Joseph Griego <[email protected]>
+
+ [JSC] Shadow realms: set correct Function prototype on wrapped functions
+ https://bugs.webkit.org/show_bug.cgi?id=233143
+
+ Reviewed by Yusuke Suzuki.
+
+ At present, the Function prototype set on each of the returned wrapped
+ functions will be the Function object from the realm the shadow realm
+ builtin is from--to comply with the latest draft of the shadow realms
+ spec [1], wrapped function objects should have the Function prototype
+ from the realm the wrapper object is destined for, instead.
+
+ At present, this requires tracking both the calling (destination) and
+ target (source) realm and switching between the two as function
+ arguments are wrapped (when the notion of source and destination realm
+ also flips)
+
+ Adds a simple builtin (moveFunctionToRealm) that can switch the Function
+ prototype given only the Shadow Realm object corresponding to the
+ correct global object.
+
+ Also marks the corresponding part of test262 as passing.
+
+ [1] https://tc39.es/proposal-shadowrealm/ sections 2.1, 2.2
+
+
+
+ * builtins/BuiltinNames.h:
+ * builtins/ShadowRealmPrototype.js:
+ (wrapped):
+ (globalPrivate.wrap):
+ (evaluate):
+ (importValue):
+ (globalPrivate.wrap.wrapped): Deleted.
+ * bytecode/LinkTimeConstant.h:
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::init):
+ * runtime/ShadowRealmPrototype.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/ShadowRealmPrototype.h:
+
2021-11-19 Robin Morisset <[email protected]>
AirFixObviousSpills should be optimized
Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (286068 => 286069)
--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2021-11-19 19:17:04 UTC (rev 286069)
@@ -118,6 +118,7 @@
macro(this) \
macro(importInRealm) \
macro(evalInRealm) \
+ macro(moveFunctionToRealm) \
macro(thisTimeValue) \
macro(newTargetLocal) \
macro(derivedConstructor) \
Modified: trunk/Source/_javascript_Core/builtins/ShadowRealmPrototype.js (286068 => 286069)
--- trunk/Source/_javascript_Core/builtins/ShadowRealmPrototype.js 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/Source/_javascript_Core/builtins/ShadowRealmPrototype.js 2021-11-19 19:17:04 UTC (rev 286069)
@@ -23,8 +23,11 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+// Wrap a value at the boundary between the incubating realm and `shadowRealm`:
+// if `fromShadowRealm` is false, we are wrapping an object from the incubating
+// realm; if true, we are wrapping an object from the shadow realm
@globalPrivate
-function wrap(target)
+function wrap(fromShadowRealm, shadowRealm, target)
{
"use strict";
@@ -33,13 +36,23 @@
var length = arguments.length;
var wrappedArgs = @newArrayWithSize(length);
for (var index = 0; index < length; ++index)
- @putByValDirect(wrappedArgs, index, @wrap(arguments[index]));
+ // Note that for arguments, we flip `fromShadowRealm` since to
+ // wrap a function from realm A to work in realm B, we need to
+ // wrap the arguments (from realm B) to work in realm A before
+ // calling the wrapped function
+ @putByValDirect(wrappedArgs, index, @wrap(!fromShadowRealm, shadowRealm, arguments[index]));
var result = target.@apply(@undefined, wrappedArgs);
- return @wrap(result);
+ return @wrap(fromShadowRealm, shadowRealm, result);
};
delete wrapped['name'];
delete wrapped['length'];
+
+ // Because this function (wrap) will run with the incubating realm
+ // active, we only need to fix the prototype on `wrapped` if we are
+ // moving the function from the incubating realm to the shadow realm
+ if (!fromShadowRealm)
+ @moveFunctionToRealm(wrapped, shadowRealm);
return wrapped;
} else if (@isObject(target)) {
@throwTypeError("value passing between realms must be callable or primitive");
@@ -58,7 +71,7 @@
@throwTypeError("`%ShadowRealm%.evaluate requires that the |sourceText| argument be a string");
var result = @evalInRealm(this, sourceText)
- return @wrap(result);
+ return @wrap(true, this, result);
}
function importValue(specifier, exportName)
@@ -76,7 +89,7 @@
if (lookup === @undefined)
@throwTypeError("%ShadowRealm%.importValue requires |exportName| to exist in the |specifier|");
- return @wrap(lookup);
+ return @wrap(true, this, lookup);
};
var crossRealmThrow = (error) => {
Modified: trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h (286068 => 286069)
--- trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2021-11-19 19:17:04 UTC (rev 286069)
@@ -80,6 +80,7 @@
v(thisTimeValue, nullptr) \
v(importInRealm, nullptr) \
v(evalInRealm, nullptr) \
+ v(moveFunctionToRealm, nullptr) \
v(isConstructor, nullptr) \
v(sameValue, nullptr) \
v(regExpProtoFlagsGetter, nullptr) \
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (286068 => 286069)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2021-11-19 19:17:04 UTC (rev 286069)
@@ -1460,6 +1460,9 @@
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::evalInRealm)].initLater([] (const Initializer<JSCell>& init) {
init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 0, String(), evalInRealm));
});
+ m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::moveFunctionToRealm)].initLater([] (const Initializer<JSCell>& init) {
+ init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 0, String(), moveFunctionToRealm));
+ });
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::thisTimeValue)].initLater([] (const Initializer<JSCell>& init) {
init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 0, String(), dateProtoFuncGetTime, DatePrototypeGetTimeIntrinsic));
});
Modified: trunk/Source/_javascript_Core/runtime/ShadowRealmPrototype.cpp (286068 => 286069)
--- trunk/Source/_javascript_Core/runtime/ShadowRealmPrototype.cpp 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/Source/_javascript_Core/runtime/ShadowRealmPrototype.cpp 2021-11-19 19:17:04 UTC (rev 286069)
@@ -124,4 +124,22 @@
RELEASE_AND_RETURN(scope, JSValue::encode(result));
}
+JSC_DEFINE_HOST_FUNCTION(moveFunctionToRealm, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue wrappedFnArg = callFrame->argument(0);
+ JSFunction* wrappedFn = jsDynamicCast<JSFunction*>(vm, wrappedFnArg);
+ JSValue targetRealmArg = callFrame->argument(1);
+ ShadowRealmObject* targetRealm = jsDynamicCast<ShadowRealmObject*>(vm, targetRealmArg);
+ ASSERT(targetRealm);
+ RETURN_IF_EXCEPTION(scope, { });
+
+ bool isBuiltin = false;
+ JSGlobalObject* targetGlobalObj = targetRealm->globalObject();
+ wrappedFn->setPrototype(vm, targetGlobalObj, targetGlobalObj->strictFunctionStructure(isBuiltin)->storedPrototype());
+ RELEASE_AND_RETURN(scope, JSValue::encode(jsUndefined()));
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/ShadowRealmPrototype.h (286068 => 286069)
--- trunk/Source/_javascript_Core/runtime/ShadowRealmPrototype.h 2021-11-19 19:05:53 UTC (rev 286068)
+++ trunk/Source/_javascript_Core/runtime/ShadowRealmPrototype.h 2021-11-19 19:17:04 UTC (rev 286069)
@@ -63,5 +63,6 @@
JSC_DECLARE_HOST_FUNCTION(importInRealm);
JSC_DECLARE_HOST_FUNCTION(evalInRealm);
+JSC_DECLARE_HOST_FUNCTION(moveFunctionToRealm);
} // namespace JSC