v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
builtins-shadow-realm-gen.cc
Go to the documentation of this file.
1// Copyright 2022 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
10#include "src/objects/module.h"
11
12namespace v8 {
13namespace internal {
14
16
47
49 TNode<Context> context, TNode<Object> target) {
51 TNode<Map> map = CAST(
52 LoadContextElement(native_context, Context::WRAPPED_FUNCTION_MAP_INDEX));
55 wrapped, JSWrappedFunction::kWrappedTargetFunctionOffset, target);
56 StoreObjectFieldNoWriteBarrier(wrapped, JSWrappedFunction::kContextOffset,
57 context);
58 return wrapped;
59}
60
78
81 TNode<NativeContext> caller_context, TNode<NativeContext> eval_context,
82 TNode<String> specifier, TNode<String> export_name) {
83 const TNode<Context> function_context =
84 CreateImportValueFulfilledFunctionContext(caller_context, eval_context,
85 specifier, export_name);
87 RootIndex::kShadowRealmImportValueFulfilledSharedFun, function_context,
88 {});
89}
90
92 TNode<IntPtrT> index,
93 TNode<Name> name,
94 Label* bailout) {
96 GotoIfNot(TaggedEqual(key, name), bailout);
97 TNode<Object> value = LoadValueByDescriptorEntry(array, index);
98 GotoIfNot(IsAccessorInfo(CAST(value)), bailout);
99}
100
102 TNode<Context> context, MessageTemplate fallback_message,
103 TNode<Object> exception) {
104 TNode<Smi> template_index = SmiConstant(static_cast<int>(fallback_message));
105 CallRuntime(Runtime::kShadowRealmThrow, context, template_index, exception);
106 Unreachable();
107}
108
109// https://tc39.es/proposal-shadowrealm/#sec-getwrappedvalue
110TF_BUILTIN(ShadowRealmGetWrappedValue, ShadowRealmBuiltinsAssembler) {
111 auto context = Parameter<Context>(Descriptor::kContext);
112 auto creation_context = Parameter<Context>(Descriptor::kCreationContext);
113 auto target_context = Parameter<Context>(Descriptor::kTargetContext);
114 auto value = Parameter<Object>(Descriptor::kValue);
115
116 Label if_primitive(this), if_callable(this), unwrap(this), wrap(this),
117 slow_wrap(this, Label::kDeferred), bailout(this, Label::kDeferred);
118
119 // 2. Return value.
120 GotoIf(TaggedIsSmi(value), &if_primitive);
121 GotoIfNot(JSAnyIsNotPrimitive(CAST(value)), &if_primitive);
122
123 // 1. If Type(value) is Object, then
124 // 1a. If IsCallable(value) is false, throw a TypeError exception.
125 // 1b. Return ? WrappedFunctionCreate(callerRealm, value).
126 Branch(IsCallable(CAST(value)), &if_callable, &bailout);
127
128 BIND(&if_primitive);
129 Return(value);
130
131 BIND(&if_callable);
132 TVARIABLE(Object, target);
133 target = value;
134 // WrappedFunctionCreate
135 // https://tc39.es/proposal-shadowrealm/#sec-wrappedfunctioncreate
136 Branch(IsJSWrappedFunction(CAST(value)), &unwrap, &wrap);
137
138 BIND(&unwrap);
139 // The intermediate wrapped functions are not user-visible. And calling a
140 // wrapped function won't cause a side effect in the creation realm.
141 // Unwrap here to avoid nested unwrapping at the call site.
142 TNode<JSWrappedFunction> target_wrapped_function = CAST(value);
143 target = LoadObjectField(target_wrapped_function,
144 JSWrappedFunction::kWrappedTargetFunctionOffset);
145 Goto(&wrap);
146
147 BIND(&wrap);
148 // Disallow wrapping of slow-mode functions. We need to figure out
149 // whether the length and name property are in the original state.
150 TNode<Map> map = LoadMap(CAST(target.value()));
151 GotoIf(IsDictionaryMap(map), &slow_wrap);
152
153 // Check whether the length and name properties are still present as
154 // AccessorInfo objects. If so, their value can be recomputed even if
155 // the actual value on the object changes.
156 TNode<Uint32T> bit_field3 = LoadMapBitField3(map);
157 TNode<IntPtrT> number_of_own_descriptors = Signed(
158 DecodeWordFromWord32<Map::Bits3::NumberOfOwnDescriptorsBits>(bit_field3));
159 GotoIf(IntPtrLessThan(
160 number_of_own_descriptors,
162 &slow_wrap);
163
164 // We don't need to check the exact accessor here because the only case
165 // custom accessor arise is with function templates via API, and in that
166 // case the object is in dictionary mode
167#if V8_ENABLE_WEBASSEMBLY
168 TNode<DescriptorArray> descriptors = CAST(LoadMapInstanceDescriptors(map));
169#else
170 TNode<DescriptorArray> descriptors = LoadMapInstanceDescriptors(map);
171#endif // V8_ENABLE_WEBASSEMBLY
172 CheckAccessor(
173 descriptors,
174 IntPtrConstant(
176 LengthStringConstant(), &slow_wrap);
177 CheckAccessor(
178 descriptors,
179 IntPtrConstant(
181 NameStringConstant(), &slow_wrap);
182
183 // Verify that prototype matches the function prototype of the target
184 // context.
185 TNode<Object> prototype = LoadMapPrototype(map);
186 TNode<Object> function_map =
187 LoadContextElement(target_context, Context::WRAPPED_FUNCTION_MAP_INDEX);
188 TNode<Object> function_prototype = LoadMapPrototype(CAST(function_map));
189 GotoIf(TaggedNotEqual(prototype, function_prototype), &slow_wrap);
190
191 // 1. Let internalSlotsList be the internal slots listed in Table 2, plus
192 // [[Prototype]] and [[Extensible]].
193 // 2. Let wrapped be ! MakeBasicObject(internalSlotsList).
194 // 3. Set wrapped.[[Prototype]] to
195 // callerRealm.[[Intrinsics]].[[%Function.prototype%]].
196 // 4. Set wrapped.[[Call]] as described in 2.1.
197 // 5. Set wrapped.[[WrappedTargetFunction]] to Target.
198 // 6. Set wrapped.[[Realm]] to callerRealm.
199 // 7. Let result be CopyNameAndLength(wrapped, Target, "wrapped").
200 // 8. If result is an Abrupt Completion, throw a TypeError exception.
201 // Installed with default accessors.
202 TNode<JSObject> wrapped =
203 AllocateJSWrappedFunction(creation_context, target.value());
204
205 // 9. Return wrapped.
206 Return(wrapped);
207
208 BIND(&slow_wrap);
209 {
210 Return(CallRuntime(Runtime::kShadowRealmWrappedFunctionCreate, context,
211 creation_context, target.value()));
212 }
213
214 BIND(&bailout);
215 ThrowTypeError(context, MessageTemplate::kNotCallable, value);
216}
217
218// https://tc39.es/proposal-shadowrealm/#sec-wrapped-function-exotic-objects-call-thisargument-argumentslist
220 auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
221 TNode<IntPtrT> argc_ptr = ChangeInt32ToIntPtr(argc);
222 auto wrapped_function = Parameter<JSWrappedFunction>(Descriptor::kFunction);
223 auto context = Parameter<Context>(Descriptor::kContext);
224
225 PerformStackCheck(context);
226
227 Label call_exception(this, Label::kDeferred),
228 target_not_callable(this, Label::kDeferred);
229
230 // 1. Let target be F.[[WrappedTargetFunction]].
231 TNode<JSReceiver> target = CAST(LoadObjectField(
232 wrapped_function, JSWrappedFunction::kWrappedTargetFunctionOffset));
233 // 2. Assert: IsCallable(target) is true.
234 CSA_DCHECK(this, IsCallable(target));
235
236 // 4. Let callerRealm be ? GetFunctionRealm(F).
237 TNode<Context> caller_context = LoadObjectField<Context>(
238 wrapped_function, JSWrappedFunction::kContextOffset);
239 // 3. Let targetRealm be ? GetFunctionRealm(target).
240 TNode<Context> target_context =
241 GetFunctionRealm(caller_context, target, &target_not_callable);
242 // 5. NOTE: Any exception objects produced after this point are associated
243 // with callerRealm.
244
245 CodeStubArguments args(this, argc_ptr);
246 TNode<Object> receiver = args.GetReceiver();
247
248 // 6. Let wrappedArgs be a new empty List.
249 TNode<FixedArray> wrapped_args =
250 CAST(AllocateFixedArray(ElementsKind::PACKED_ELEMENTS, argc_ptr));
251 // Fill the fixed array so that heap verifier doesn't complain about it.
252 FillFixedArrayWithValue(ElementsKind::PACKED_ELEMENTS, wrapped_args,
253 IntPtrConstant(0), argc_ptr,
254 RootIndex::kUndefinedValue);
255
256 // 8. Let wrappedThisArgument to ? GetWrappedValue(targetRealm, thisArgument).
257 // Create wrapped value in the target realm.
258 TNode<Object> wrapped_receiver =
259 CallBuiltin(Builtin::kShadowRealmGetWrappedValue, caller_context,
260 target_context, caller_context, receiver);
261 StoreFixedArrayElement(wrapped_args, 0, wrapped_receiver);
262 // 7. For each element arg of argumentsList, do
263 BuildFastLoop<IntPtrT>(
264 IntPtrConstant(0), args.GetLengthWithoutReceiver(),
265 [&](TNode<IntPtrT> index) {
266 // 7a. Let wrappedValue be ? GetWrappedValue(targetRealm, arg).
267 // Create wrapped value in the target realm.
268 TNode<Object> wrapped_value =
269 CallBuiltin(Builtin::kShadowRealmGetWrappedValue, caller_context,
270 target_context, caller_context, args.AtIndex(index));
271 // 7b. Append wrappedValue to wrappedArgs.
272 StoreFixedArrayElement(
273 wrapped_args, IntPtrAdd(index, IntPtrConstant(1)), wrapped_value);
274 },
275 1, LoopUnrollingMode::kNo, IndexAdvanceMode::kPost);
276
277 TVARIABLE(Object, var_exception);
279 {
280 compiler::ScopedExceptionHandler handler(this, &call_exception,
281 &var_exception);
282 TNode<Int32T> args_count = Int32Constant(0); // args already on the stack
283
284 // 9. Let result be the Completion Record of Call(target,
285 // wrappedThisArgument, wrappedArgs).
286 result = CallBuiltin(Builtin::kCallVarargs, target_context, target,
287 args_count, argc, wrapped_args);
288 }
289
290 // 10. If result.[[Type]] is normal or result.[[Type]] is return, then
291 // 10a. Return ? GetWrappedValue(callerRealm, result.[[Value]]).
292 TNode<JSAny> wrapped_result =
293 CallBuiltin<JSAny>(Builtin::kShadowRealmGetWrappedValue, caller_context,
294 caller_context, target_context, result);
295 args.PopAndReturn(wrapped_result);
296
297 // 11. Else,
298 BIND(&call_exception);
299 // 11a. Throw a TypeError exception.
300 ShadowRealmThrow(context, MessageTemplate::kCallWrappedFunctionThrew,
301 var_exception.value());
302
303 BIND(&target_not_callable);
304 // A wrapped value should not be non-callable.
305 Unreachable();
306}
307
308// https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.importvalue
309TF_BUILTIN(ShadowRealmPrototypeImportValue, ShadowRealmBuiltinsAssembler) {
310 const char* const kMethodName = "ShadowRealm.prototype.importValue";
311 TNode<Context> context = Parameter<Context>(Descriptor::kContext);
312 // 1. Let O be this value.
313 TNode<Object> O = Parameter<Object>(Descriptor::kReceiver);
314 // 2. Perform ? ValidateShadowRealmObject(O).
315 ThrowIfNotInstanceType(context, O, JS_SHADOW_REALM_TYPE, kMethodName);
316
317 // 3. Let specifierString be ? ToString(specifier).
318 TNode<Object> specifier = Parameter<Object>(Descriptor::kSpecifier);
319 TNode<String> specifier_string = ToString_Inline(context, specifier);
320 // 4. Let exportNameString be ? ToString(exportName).
321 TNode<Object> export_name = Parameter<Object>(Descriptor::kExportName);
322 TNode<String> export_name_string = ToString_Inline(context, export_name);
323 // 5. Let callerRealm be the current Realm Record.
324 TNode<NativeContext> caller_context = LoadNativeContext(context);
325 // 6. Let evalRealm be O.[[ShadowRealm]].
326 // 7. Let evalContext be O.[[ExecutionContext]].
327 TNode<NativeContext> eval_context =
328 CAST(LoadObjectField(CAST(O), JSShadowRealm::kNativeContextOffset));
329 // 8. Return ? ShadowRealmImportValue(specifierString, exportNameString,
330 // callerRealm, evalRealm, evalContext).
331 TNode<Object> result = ImportValue(caller_context, eval_context,
332 specifier_string, export_name_string);
333 Return(result);
334}
335
336// https://tc39.es/proposal-shadowrealm/#sec-shadowrealmimportvalue
338 TNode<NativeContext> caller_context, TNode<NativeContext> eval_context,
339 TNode<String> specifier, TNode<String> export_name) {
340 // 1. Assert: evalContext is an execution context associated to a ShadowRealm
341 // instance's [[ExecutionContext]].
342 // 2. Let innerCapability be ! NewPromiseCapability(%Promise%).
343 // 3. Let runningContext be the running execution context.
344 // 4. If runningContext is not already suspended, suspend runningContext.
345 // 5. Push evalContext onto the execution context stack; evalContext is now
346 // the running execution context.
347 // 6. Perform ! HostImportModuleDynamically(null, specifierString,
348 // innerCapability).
349 // 7. Suspend evalContext and remove it from the execution context stack.
350 // 8. Resume the context that is now on the top of the execution context stack
351 // as the running execution context.
352 TNode<Object> inner_capability =
353 CallRuntime(Runtime::kShadowRealmImportValue, eval_context, specifier);
354
355 // 9. Let steps be the steps of an ExportGetter function as described below.
356 // 10. Let onFulfilled be ! CreateBuiltinFunction(steps, 1, "", «
357 // [[ExportNameString]] », callerRealm).
358 // 11. Set onFulfilled.[[ExportNameString]] to exportNameString.
360 caller_context, eval_context, specifier, export_name);
361
362 TNode<JSFunction> on_rejected = CAST(LoadContextElement(
363 caller_context, Context::SHADOW_REALM_IMPORT_VALUE_REJECTED_INDEX));
364 // 12. Let promiseCapability be ! NewPromiseCapability(%Promise%).
365 TNode<JSPromise> promise = NewJSPromise(caller_context);
366 // 13. Return ! PerformPromiseThen(innerCapability.[[Promise]], onFulfilled,
367 // callerRealm.[[Intrinsics]].[[%ThrowTypeError%]], promiseCapability).
368 return CallBuiltin(Builtin::kPerformPromiseThen, caller_context,
369 inner_capability, on_fulfilled, on_rejected, promise);
370}
371
372// ExportGetter of
373// https://tc39.es/proposal-shadowrealm/#sec-shadowrealmimportvalue
374TF_BUILTIN(ShadowRealmImportValueFulfilled, ShadowRealmBuiltinsAssembler) {
375 // An ExportGetter function is an anonymous built-in function with a
376 // [[ExportNameString]] internal slot. When an ExportGetter function is called
377 // with argument exports, it performs the following steps:
378 // 8. Let realm be f.[[Realm]].
379 TNode<Context> context = Parameter<Context>(Descriptor::kContext);
380 TNode<Context> eval_context = CAST(LoadContextElement(
381 context, ImportValueFulfilledFunctionContextSlot::kEvalContextSlot));
382
383 Label get_export_exception(this, Label::kDeferred);
384
385 // 2. Let f be the active function object.
386 // 3. Let string be f.[[ExportNameString]].
387 // 4. Assert: Type(string) is String.
388 TNode<String> export_name_string = CAST(LoadContextElement(
389 context, ImportValueFulfilledFunctionContextSlot::kExportNameSlot));
390
391 // 1. Assert: exports is a module namespace exotic object.
393 Parameter<JSModuleNamespace>(Descriptor::kExports);
394
395 // 5. Let hasOwn be ? HasOwnProperty(exports, string).
396 // 6. If hasOwn is false, throw a TypeError exception.
397 // 7. Let value be ? Get(exports, string).
398
399 // The only exceptions thrown by Runtime::kGetModuleNamespaceExport are
400 // either the export is not found or the module is not initialized.
401 TVARIABLE(Object, var_exception);
403 {
404 compiler::ScopedExceptionHandler handler(this, &get_export_exception,
405 &var_exception);
406 value = CallRuntime(Runtime::kGetModuleNamespaceExport, eval_context,
407 exports, export_name_string);
408 }
409
410 // 9. Return ? GetWrappedValue(realm, value).
411 TNode<NativeContext> caller_context = LoadNativeContext(context);
412 TNode<Object> wrapped_result =
413 CallBuiltin(Builtin::kShadowRealmGetWrappedValue, caller_context,
414 caller_context, eval_context, value);
415 Return(wrapped_result);
416
417 BIND(&get_export_exception);
418 {
419 TNode<String> specifier_string = CAST(LoadContextElement(
420 context, ImportValueFulfilledFunctionContextSlot::kSpecifierSlot));
421 ThrowTypeError(context, MessageTemplate::kUnresolvableExport,
422 specifier_string, export_name_string);
423 }
424}
425
426TF_BUILTIN(ShadowRealmImportValueRejected, ShadowRealmBuiltinsAssembler) {
427 TNode<Context> context = Parameter<Context>(Descriptor::kContext);
428 TNode<Object> exception = Parameter<Object>(Descriptor::kException);
429 ShadowRealmThrow(context, MessageTemplate::kImportShadowRealmRejected,
430 exception);
431}
432
434
435} // namespace internal
436} // namespace v8
#define BIND(label)
#define TVARIABLE(...)
#define CSA_DCHECK(csa,...)
#define TF_BUILTIN(Name, AssemblerBase)
TNode< Name > LoadKeyByDescriptorEntry(TNode< DescriptorArray > descriptors, TNode< IntPtrT > descriptor)
TNode< Object > LoadValueByDescriptorEntry(TNode< DescriptorArray > descriptors, TNode< IntPtrT > descriptor)
TNode< BoolT > TaggedEqual(TNode< AnyTaggedT > a, TNode< AnyTaggedT > b)
TNode< JSFunction > AllocateRootFunctionWithContext(RootIndex function, TNode< Context > context, std::optional< TNode< NativeContext > > maybe_native_context)
void StoreObjectFieldNoWriteBarrier(TNode< HeapObject > object, TNode< IntPtrT > offset, TNode< T > value)
TNode< NativeContext > LoadNativeContext(TNode< Context > context)
void StoreContextElementNoWriteBarrier(TNode< Context > context, int slot_index, TNode< Object > value)
TNode< JSObject > AllocateJSObjectFromMap(TNode< Map > map, std::optional< TNode< HeapObject > > properties=std::nullopt, std::optional< TNode< FixedArray > > elements=std::nullopt, AllocationFlags flags=AllocationFlag::kNone, SlackTrackingMode slack_tracking_mode=kNoSlackTracking)
static const int kMinDescriptorsForFastBindAndWrap
TNode< Context > CreateImportValueFulfilledFunctionContext(TNode< NativeContext > caller_context, TNode< NativeContext > eval_context, TNode< String > specifier, TNode< String > export_name)
ShadowRealmBuiltinsAssembler(compiler::CodeAssemblerState *state)
TNode< Object > ImportValue(TNode< NativeContext > caller_context, TNode< NativeContext > eval_context, TNode< String > specifier, TNode< String > export_name)
void CheckAccessor(TNode< DescriptorArray > array, TNode< IntPtrT > index, TNode< Name > name, Label *bailout)
void ShadowRealmThrow(TNode< Context > context, MessageTemplate fallback_message, TNode< Object > exception)
TNode< JSFunction > AllocateImportValueFulfilledFunction(TNode< NativeContext > caller_context, TNode< NativeContext > eval_context, TNode< String > specifier, TNode< String > export_name)
TNode< JSObject > AllocateJSWrappedFunction(TNode< Context > context, TNode< Object > target)
void GotoIfNot(TNode< IntegralT > condition, Label *false_label, GotoHint goto_hint=GotoHint::kNone)
TNode< Smi > SmiConstant(Tagged< Smi > value)
TNode< T > CallRuntime(Runtime::FunctionId function, TNode< Object > context, TArgs... args)
TNode< T > CallBuiltin(Builtin id, TNode< Object > context, TArgs... args)
#define CAST(x)
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
TNode< Context > context
TNode< Object > receiver
ZoneVector< RpoNumber > & result
MovableLabel handler
Map::Bits1::HasPrototypeSlotBit Map::Bits1::HasNamedInterceptorBit Map::Bits1::IsUndetectableBit Map::Bits1::IsConstructorBit Map::Bits2::IsImmutablePrototypeBit Map::Bits3::IsDeprecatedBit Map::Bits3::IsPrototypeMapBit bit_field3
Definition map-inl.h:137
return value
Definition map-inl.h:893
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877