diff options
Diffstat (limited to 'deps/v8/src/builtins/builtins-shadowrealm-gen.cc')
-rw-r--r-- | deps/v8/src/builtins/builtins-shadowrealm-gen.cc | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/deps/v8/src/builtins/builtins-shadowrealm-gen.cc b/deps/v8/src/builtins/builtins-shadowrealm-gen.cc new file mode 100644 index 0000000000..03bc854c9c --- /dev/null +++ b/deps/v8/src/builtins/builtins-shadowrealm-gen.cc @@ -0,0 +1,186 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/builtins/builtins-utils-gen.h" +#include "src/builtins/builtins.h" +#include "src/codegen/code-stub-assembler.h" + +namespace v8 { +namespace internal { + +class ShadowRealmBuiltinsAssembler : public CodeStubAssembler { + public: + explicit ShadowRealmBuiltinsAssembler(compiler::CodeAssemblerState* state) + : CodeStubAssembler(state) {} + + protected: + TNode<JSObject> AllocateJSWrappedFunction(TNode<Context> context); +}; + +TNode<JSObject> ShadowRealmBuiltinsAssembler::AllocateJSWrappedFunction( + TNode<Context> context) { + TNode<NativeContext> native_context = LoadNativeContext(context); + TNode<Map> map = CAST( + LoadContextElement(native_context, Context::WRAPPED_FUNCTION_MAP_INDEX)); + return AllocateJSObjectFromMap(map); +} + +// https://tc39.es/proposal-shadowrealm/#sec-getwrappedvalue +TF_BUILTIN(ShadowRealmGetWrappedValue, ShadowRealmBuiltinsAssembler) { + auto context = Parameter<Context>(Descriptor::kContext); + auto creation_context = Parameter<Context>(Descriptor::kCreationContext); + auto value = Parameter<Object>(Descriptor::kValue); + + Label if_primitive(this), if_callable(this), unwrap(this), wrap(this), + bailout(this, Label::kDeferred); + + // 2. Return value. + GotoIf(TaggedIsSmi(value), &if_primitive); + GotoIfNot(IsJSReceiver(CAST(value)), &if_primitive); + + // 1. If Type(value) is Object, then + // 1a. If IsCallable(value) is false, throw a TypeError exception. + // 1b. Return ? WrappedFunctionCreate(callerRealm, value). + Branch(IsCallable(CAST(value)), &if_callable, &bailout); + + BIND(&if_primitive); + Return(value); + + BIND(&if_callable); + TVARIABLE(Object, target); + target = value; + // WrappedFunctionCreate + // https://tc39.es/proposal-shadowrealm/#sec-wrappedfunctioncreate + Branch(IsJSWrappedFunction(CAST(value)), &unwrap, &wrap); + + BIND(&unwrap); + // The intermediate wrapped functions are not user-visible. And calling a + // wrapped function won't cause a side effect in the creation realm. + // Unwrap here to avoid nested unwrapping at the call site. + TNode<JSWrappedFunction> target_wrapped_function = CAST(value); + target = LoadObjectField(target_wrapped_function, + JSWrappedFunction::kWrappedTargetFunctionOffset); + Goto(&wrap); + + BIND(&wrap); + // 1. Let internalSlotsList be the internal slots listed in Table 2, plus + // [[Prototype]] and [[Extensible]]. + // 2. Let wrapped be ! MakeBasicObject(internalSlotsList). + // 3. Set wrapped.[[Prototype]] to + // callerRealm.[[Intrinsics]].[[%Function.prototype%]]. + // 4. Set wrapped.[[Call]] as described in 2.1. + TNode<JSObject> wrapped = AllocateJSWrappedFunction(creation_context); + + // 5. Set wrapped.[[WrappedTargetFunction]] to Target. + StoreObjectFieldNoWriteBarrier( + wrapped, JSWrappedFunction::kWrappedTargetFunctionOffset, target.value()); + // 6. Set wrapped.[[Realm]] to callerRealm. + StoreObjectFieldNoWriteBarrier(wrapped, JSWrappedFunction::kContextOffset, + creation_context); + + // 7. Let result be CopyNameAndLength(wrapped, Target, "wrapped"). + // 8. If result is an Abrupt Completion, throw a TypeError exception. + // TODO(v8:11989): https://github.com/tc39/proposal-shadowrealm/pull/348 + + // 9. Return wrapped. + Return(wrapped); + + BIND(&bailout); + ThrowTypeError(context, MessageTemplate::kNotCallable, value); +} + +// https://tc39.es/proposal-shadowrealm/#sec-wrapped-function-exotic-objects-call-thisargument-argumentslist +TF_BUILTIN(CallWrappedFunction, ShadowRealmBuiltinsAssembler) { + auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount); + TNode<IntPtrT> argc_ptr = ChangeInt32ToIntPtr(argc); + auto wrapped_function = Parameter<JSWrappedFunction>(Descriptor::kFunction); + auto context = Parameter<Context>(Descriptor::kContext); + + PerformStackCheck(context); + + Label call_exception(this, Label::kDeferred), + target_not_callable(this, Label::kDeferred); + + // 1. Let target be F.[[WrappedTargetFunction]]. + TNode<JSReceiver> target = CAST(LoadObjectField( + wrapped_function, JSWrappedFunction::kWrappedTargetFunctionOffset)); + // 2. Assert: IsCallable(target) is true. + CSA_DCHECK(this, IsCallable(target)); + + // 4. Let callerRealm be ? GetFunctionRealm(F). + TNode<Context> caller_context = LoadObjectField<Context>( + wrapped_function, JSWrappedFunction::kContextOffset); + // 3. Let targetRealm be ? GetFunctionRealm(target). + TNode<Context> target_context = + GetFunctionRealm(caller_context, target, &target_not_callable); + // 5. NOTE: Any exception objects produced after this point are associated + // with callerRealm. + + CodeStubArguments args(this, argc_ptr); + TNode<Object> receiver = args.GetReceiver(); + + // 6. Let wrappedArgs be a new empty List. + TNode<FixedArray> wrapped_args = + CAST(AllocateFixedArray(ElementsKind::PACKED_ELEMENTS, argc_ptr)); + // Fill the fixed array so that heap verifier doesn't complain about it. + FillFixedArrayWithValue(ElementsKind::PACKED_ELEMENTS, wrapped_args, + IntPtrConstant(0), argc_ptr, + RootIndex::kUndefinedValue); + + // 8. Let wrappedThisArgument to ? GetWrappedValue(targetRealm, thisArgument). + // Create wrapped value in the target realm. + TNode<Object> wrapped_receiver = + CallBuiltin(Builtin::kShadowRealmGetWrappedValue, caller_context, + target_context, receiver); + StoreFixedArrayElement(wrapped_args, 0, wrapped_receiver); + // 7. For each element arg of argumentsList, do + BuildFastLoop<IntPtrT>( + IntPtrConstant(0), args.GetLengthWithoutReceiver(), + [&](TNode<IntPtrT> index) { + // 7a. Let wrappedValue be ? GetWrappedValue(targetRealm, arg). + // Create wrapped value in the target realm. + TNode<Object> wrapped_value = + CallBuiltin(Builtin::kShadowRealmGetWrappedValue, caller_context, + target_context, args.AtIndex(index)); + // 7b. Append wrappedValue to wrappedArgs. + StoreFixedArrayElement( + wrapped_args, IntPtrAdd(index, IntPtrConstant(1)), wrapped_value); + }, + 1, IndexAdvanceMode::kPost); + + TVARIABLE(Object, var_exception); + TNode<Object> result; + { + compiler::ScopedExceptionHandler handler(this, &call_exception, + &var_exception); + TNode<Int32T> args_count = Int32Constant(0); // args already on the stack + Callable callable = CodeFactory::CallVarargs(isolate()); + + // 9. Let result be the Completion Record of Call(target, + // wrappedThisArgument, wrappedArgs). + result = CallStub(callable, target_context, target, args_count, argc, + wrapped_args); + } + + // 10. If result.[[Type]] is normal or result.[[Type]] is return, then + // 10a. Return ? GetWrappedValue(callerRealm, result.[[Value]]). + TNode<Object> wrapped_result = + CallBuiltin(Builtin::kShadowRealmGetWrappedValue, caller_context, + caller_context, result); + args.PopAndReturn(wrapped_result); + + // 11. Else, + BIND(&call_exception); + // 11a. Throw a TypeError exception. + // TODO(v8:11989): provide a non-observable inspection. + ThrowTypeError(context, MessageTemplate::kCallShadowRealmFunctionThrown, + var_exception.value()); + + BIND(&target_not_callable); + // A wrapped value should not be non-callable. + Unreachable(); +} + +} // namespace internal +} // namespace v8 |