• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 
5 #include "src/builtins/builtins-utils-inl.h"
6 #include "src/codegen/compiler.h"
7 #include "src/logging/counters.h"
8 #include "src/objects/js-shadow-realms-inl.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 // https://tc39.es/proposal-shadowrealm/#sec-shadowrealm-constructor
BUILTIN(ShadowRealmConstructor)14 BUILTIN(ShadowRealmConstructor) {
15   HandleScope scope(isolate);
16   // 1. If NewTarget is undefined, throw a TypeError exception.
17   if (args.new_target()->IsUndefined(isolate)) {  // [[Call]]
18     THROW_NEW_ERROR_RETURN_FAILURE(
19         isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
20                               isolate->factory()->ShadowRealm_string()));
21   }
22   // [[Construct]]
23   Handle<JSFunction> target = args.target();
24   Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
25 
26   // 3. Let realmRec be CreateRealm().
27   // 5. Let context be a new execution context.
28   // 6. Set the Function of context to null.
29   // 7. Set the Realm of context to realmRec.
30   // 8. Set the ScriptOrModule of context to null.
31   // 10. Perform ? SetRealmGlobalObject(realmRec, undefined, undefined).
32   // 11. Perform ? SetDefaultGlobalBindings(O.[[ShadowRealm]]).
33   // 12. Perform ? HostInitializeShadowRealm(O.[[ShadowRealm]]).
34   // These steps are combined in
35   // Isolate::RunHostCreateShadowRealmContextCallback and Context::New.
36   // The host operation is hoisted for not creating a half-initialized
37   // ShadowRealm object, which can fail the heap verification.
38   Handle<NativeContext> native_context;
39   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
40       isolate, native_context,
41       isolate->RunHostCreateShadowRealmContextCallback());
42 
43   // 2. Let O be ? OrdinaryCreateFromConstructor(NewTarget,
44   // "%ShadowRealm.prototype%", « [[ShadowRealm]], [[ExecutionContext]] »).
45   Handle<JSObject> result;
46   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
47       isolate, result,
48       JSObject::New(target, new_target, Handle<AllocationSite>::null()));
49   Handle<JSShadowRealm> O = Handle<JSShadowRealm>::cast(result);
50 
51   // 4. Set O.[[ShadowRealm]] to realmRec.
52   // 9. Set O.[[ExecutionContext]] to context.
53   O->set_native_context(*native_context);
54 
55   // 13. Return O.
56   return *O;
57 }
58 
59 namespace {
60 
61 // https://tc39.es/proposal-shadowrealm/#sec-getwrappedvalue
GetWrappedValue(Isolate * isolate,Handle<NativeContext> creation_context,Handle<Object> value)62 MaybeHandle<Object> GetWrappedValue(Isolate* isolate,
63                                     Handle<NativeContext> creation_context,
64                                     Handle<Object> value) {
65   // 1. If Type(value) is Object, then
66   if (!value->IsJSReceiver()) {
67     // 2. Return value.
68     return value;
69   }
70   // 1a. If IsCallable(value) is false, throw a TypeError exception.
71   if (!value->IsCallable()) {
72     // The TypeError thrown is created with creation Realm's TypeError
73     // constructor instead of the executing Realm's.
74     THROW_NEW_ERROR_RETURN_VALUE(
75         isolate,
76         NewError(Handle<JSFunction>(creation_context->type_error_function(),
77                                     isolate),
78                  MessageTemplate::kNotCallable),
79         {});
80   }
81   // 1b. Return ? WrappedFunctionCreate(callerRealm, value).
82   return JSWrappedFunction::Create(isolate, creation_context,
83                                    Handle<JSReceiver>::cast(value));
84 }
85 
86 }  // namespace
87 
88 // https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.evaluate
BUILTIN(ShadowRealmPrototypeEvaluate)89 BUILTIN(ShadowRealmPrototypeEvaluate) {
90   HandleScope scope(isolate);
91 
92   Handle<Object> source_text = args.atOrUndefined(isolate, 1);
93   // 1. Let O be this value.
94   Handle<Object> receiver = args.receiver();
95 
96   Factory* factory = isolate->factory();
97 
98   // 2. Perform ? ValidateShadowRealmObject(O).
99   if (!receiver->IsJSShadowRealm()) {
100     THROW_NEW_ERROR_RETURN_FAILURE(
101         isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver));
102   }
103   Handle<JSShadowRealm> shadow_realm = Handle<JSShadowRealm>::cast(receiver);
104 
105   // 3. If Type(sourceText) is not String, throw a TypeError exception.
106   if (!source_text->IsString()) {
107     THROW_NEW_ERROR_RETURN_FAILURE(
108         isolate,
109         NewTypeError(MessageTemplate::kInvalidShadowRealmEvaluateSourceText));
110   }
111 
112   // 4. Let callerRealm be the current Realm Record.
113   Handle<NativeContext> caller_context = isolate->native_context();
114 
115   // 5. Let evalRealm be O.[[ShadowRealm]].
116   Handle<NativeContext> eval_context =
117       Handle<NativeContext>(shadow_realm->native_context(), isolate);
118   // 6. Return ? PerformShadowRealmEval(sourceText, callerRealm, evalRealm).
119 
120   // PerformShadowRealmEval
121   // https://tc39.es/proposal-shadowrealm/#sec-performshadowrealmeval
122   // 1. Perform ? HostEnsureCanCompileStrings(callerRealm, evalRealm).
123   // Run embedder pre-checks before executing the source code.
124   MaybeHandle<String> validated_source;
125   bool unhandled_object;
126   std::tie(validated_source, unhandled_object) =
127       Compiler::ValidateDynamicCompilationSource(isolate, eval_context,
128                                                  source_text);
129   if (unhandled_object) {
130     THROW_NEW_ERROR_RETURN_FAILURE(
131         isolate,
132         NewTypeError(MessageTemplate::kInvalidShadowRealmEvaluateSourceText));
133   }
134 
135   Handle<JSObject> eval_global_proxy(eval_context->global_proxy(), isolate);
136   MaybeHandle<Object> result;
137   bool is_parse_failed = false;
138   {
139     // 8. If runningContext is not already suspended, suspend runningContext.
140     // 9. Let evalContext be a new ECMAScript code execution context.
141     // 10. Set evalContext's Function to null.
142     // 11. Set evalContext's Realm to evalRealm.
143     // 12. Set evalContext's ScriptOrModule to null.
144     // 13. Set evalContext's VariableEnvironment to varEnv.
145     // 14. Set evalContext's LexicalEnvironment to lexEnv.
146     // 15. Push evalContext onto the execution context stack; evalContext is now
147     // the running execution context.
148     SaveAndSwitchContext save(isolate, *eval_context);
149 
150     // 2. Perform the following substeps in an implementation-defined order,
151     // possibly interleaving parsing and error detection:
152     // 2a. Let script be ParseText(! StringToCodePoints(sourceText), Script).
153     // 2b. If script is a List of errors, throw a SyntaxError exception.
154     // 2c. If script Contains ScriptBody is false, return undefined.
155     // 2d. Let body be the ScriptBody of script.
156     // 2e. If body Contains NewTarget is true, throw a SyntaxError
157     // exception.
158     // 2f. If body Contains SuperProperty is true, throw a SyntaxError
159     // exception.
160     // 2g. If body Contains SuperCall is true, throw a SyntaxError exception.
161     // 3. Let strictEval be IsStrict of script.
162     // 4. Let runningContext be the running execution context.
163     // 5. Let lexEnv be NewDeclarativeEnvironment(evalRealm.[[GlobalEnv]]).
164     // 6. Let varEnv be evalRealm.[[GlobalEnv]].
165     // 7. If strictEval is true, set varEnv to lexEnv.
166     Handle<JSFunction> function;
167     MaybeHandle<JSFunction> maybe_function =
168         Compiler::GetFunctionFromValidatedString(eval_context, validated_source,
169                                                  NO_PARSE_RESTRICTION,
170                                                  kNoSourcePosition);
171     if (maybe_function.is_null()) {
172       is_parse_failed = true;
173     } else {
174       function = maybe_function.ToHandleChecked();
175 
176       // 16. Let result be EvalDeclarationInstantiation(body, varEnv,
177       // lexEnv, null, strictEval).
178       // 17. If result.[[Type]] is normal, then
179       // 20a. Set result to the result of evaluating body.
180       // 18. If result.[[Type]] is normal and result.[[Value]] is empty, then
181       // 21a. Set result to NormalCompletion(undefined).
182       result =
183           Execution::Call(isolate, function, eval_global_proxy, 0, nullptr);
184 
185       // 19. Suspend evalContext and remove it from the execution context stack.
186       // 20. Resume the context that is now on the top of the execution context
187       // stack as the running execution context. Done by the scope.
188     }
189   }
190 
191   if (result.is_null()) {
192     DCHECK(isolate->has_pending_exception());
193     Handle<Object> pending_exception =
194         Handle<Object>(isolate->pending_exception(), isolate);
195     isolate->clear_pending_exception();
196     if (is_parse_failed) {
197       Handle<JSObject> error_object = Handle<JSObject>::cast(pending_exception);
198       Handle<String> message = Handle<String>::cast(JSReceiver::GetDataProperty(
199           isolate, error_object, factory->message_string()));
200 
201       return isolate->ReThrow(
202           *factory->NewError(isolate->syntax_error_function(), message));
203     }
204     // 21. If result.[[Type]] is not normal, throw a TypeError exception.
205     // TODO(v8:11989): provide a non-observable inspection on the
206     // pending_exception to the newly created TypeError.
207     // https://github.com/tc39/proposal-shadowrealm/issues/353
208     THROW_NEW_ERROR_RETURN_FAILURE(
209         isolate, NewTypeError(MessageTemplate::kCallShadowRealmFunctionThrown));
210   }
211   // 22. Return ? GetWrappedValue(callerRealm, result.[[Value]]).
212   Handle<Object> wrapped_result;
213   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
214       isolate, wrapped_result,
215       GetWrappedValue(isolate, caller_context, result.ToHandleChecked()));
216   return *wrapped_result;
217 }
218 
219 // https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.importvalue
BUILTIN(ShadowRealmPrototypeImportValue)220 BUILTIN(ShadowRealmPrototypeImportValue) {
221   HandleScope scope(isolate);
222   return ReadOnlyRoots(isolate).undefined_value();
223 }
224 
225 }  // namespace internal
226 }  // namespace v8
227