[ShadowRealm] Implement ShadowRealm.prototype.importValue

As per https://tc39.es/ecma262/#sec-hostimportmoduledynamically defined,
referencingScriptOrModule in HostImportModuleDynamically can be a Script
Record, a Module Record, or null.
So to https://tc39.es/proposal-shadowrealm/#sec-shadowrealmimportvalue,
the HostImportModuleDynamicallyCallback is been invoked with a `null`
resource_name. This may not be considered a breaking change as the
parameter resource_name is defined as Local<Value>.

Updates d8's DoHostImportModuleDynamically to handle null resource_name,
and resolve the dynamically imported specifier relative to the executing
script's origin. In this way, we have to set ModuleEmbedderData.origin
even if the JavaScript source to be evaluated is Script. Also, a
ModuleEmbedderData is created for each ShadowRealm to separate their
module maps from the initiator context's.

Bug: v8:11989
Change-Id: If70fb140657da4f2dd92eedfcc4515211602aa46
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3522883
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Chengzhong Wu <legendecas@gmail.com>
Cr-Commit-Position: refs/heads/main@{#80118}
This commit is contained in:
legendecas 2022-04-20 22:29:28 +08:00 committed by V8 LUCI CQ
parent 9ad39743d0
commit 9135859a91
27 changed files with 557 additions and 205 deletions

View File

@ -872,7 +872,11 @@ namespace internal {
CPP(ShadowRealmConstructor) \
TFS(ShadowRealmGetWrappedValue, kCreationContext, kTargetContext, kValue) \
CPP(ShadowRealmPrototypeEvaluate) \
CPP(ShadowRealmPrototypeImportValue) \
TFJ(ShadowRealmPrototypeImportValue, kJSArgcReceiverSlots + 2, kReceiver, \
kSpecifier, kExportName) \
TFJ(ShadowRealmImportValueFulfilled, kJSArgcReceiverSlots + 1, kReceiver, \
kExports) \
TFJ(ShadowRealmImportValueRejected, kDontAdaptArgumentsSentinel) \
\
/* SharedArrayBuffer */ \
CPP(SharedArrayBufferPrototypeGetByteLength) \

View File

@ -216,11 +216,5 @@ BUILTIN(ShadowRealmPrototypeEvaluate) {
return *wrapped_result;
}
// https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.importvalue
BUILTIN(ShadowRealmPrototypeImportValue) {
HandleScope scope(isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
} // namespace internal
} // namespace v8

View File

@ -6,6 +6,8 @@
#include "src/builtins/builtins.h"
#include "src/codegen/code-stub-assembler.h"
#include "src/objects/descriptor-array.h"
#include "src/objects/js-shadow-realms.h"
#include "src/objects/module.h"
namespace v8 {
namespace internal {
@ -15,11 +17,27 @@ class ShadowRealmBuiltinsAssembler : public CodeStubAssembler {
explicit ShadowRealmBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
enum ImportValueFulfilledFunctionContextSlot {
kEvalContextSlot = Context::MIN_CONTEXT_SLOTS,
kSpecifierSlot,
kExportNameSlot,
kContextLength,
};
protected:
TNode<JSObject> AllocateJSWrappedFunction(TNode<Context> context,
TNode<Object> target);
void CheckAccessor(TNode<DescriptorArray> array, TNode<IntPtrT> index,
TNode<Name> name, Label* bailout);
TNode<Object> ImportValue(TNode<NativeContext> caller_context,
TNode<NativeContext> eval_context,
TNode<String> specifier, TNode<String> export_name);
TNode<Context> CreateImportValueFulfilledFunctionContext(
TNode<NativeContext> caller_context, TNode<NativeContext> eval_context,
TNode<String> specifier, TNode<String> export_name);
TNode<JSFunction> AllocateImportValueFulfilledFunction(
TNode<NativeContext> caller_context, TNode<NativeContext> eval_context,
TNode<String> specifier, TNode<String> export_name);
};
TNode<JSObject> ShadowRealmBuiltinsAssembler::AllocateJSWrappedFunction(
@ -35,6 +53,40 @@ TNode<JSObject> ShadowRealmBuiltinsAssembler::AllocateJSWrappedFunction(
return wrapped;
}
TNode<Context>
ShadowRealmBuiltinsAssembler::CreateImportValueFulfilledFunctionContext(
TNode<NativeContext> caller_context, TNode<NativeContext> eval_context,
TNode<String> specifier, TNode<String> export_name) {
const TNode<Context> context = AllocateSyntheticFunctionContext(
caller_context, ImportValueFulfilledFunctionContextSlot::kContextLength);
StoreContextElementNoWriteBarrier(
context, ImportValueFulfilledFunctionContextSlot::kEvalContextSlot,
eval_context);
StoreContextElementNoWriteBarrier(
context, ImportValueFulfilledFunctionContextSlot::kSpecifierSlot,
specifier);
StoreContextElementNoWriteBarrier(
context, ImportValueFulfilledFunctionContextSlot::kExportNameSlot,
export_name);
return context;
}
TNode<JSFunction>
ShadowRealmBuiltinsAssembler::AllocateImportValueFulfilledFunction(
TNode<NativeContext> caller_context, TNode<NativeContext> eval_context,
TNode<String> specifier, TNode<String> export_name) {
const TNode<Context> function_context =
CreateImportValueFulfilledFunctionContext(caller_context, eval_context,
specifier, export_name);
const TNode<Map> function_map = CAST(LoadContextElement(
caller_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX));
const TNode<SharedFunctionInfo> info =
ShadowRealmImportValueFulfilledSFIConstant();
return AllocateFunctionWithMapAndContext(function_map, info,
function_context);
}
void ShadowRealmBuiltinsAssembler::CheckAccessor(TNode<DescriptorArray> array,
TNode<IntPtrT> index,
TNode<Name> name,
@ -244,5 +296,131 @@ TF_BUILTIN(CallWrappedFunction, ShadowRealmBuiltinsAssembler) {
Unreachable();
}
// https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.importvalue
TF_BUILTIN(ShadowRealmPrototypeImportValue, ShadowRealmBuiltinsAssembler) {
const char* const kMethodName = "ShadowRealm.prototype.importValue";
TNode<Context> context = Parameter<Context>(Descriptor::kContext);
// 1. Let O be this value.
TNode<Object> O = Parameter<Object>(Descriptor::kReceiver);
// 2. Perform ? ValidateShadowRealmObject(O).
ThrowIfNotInstanceType(context, O, JS_SHADOW_REALM_TYPE, kMethodName);
// 3. Let specifierString be ? ToString(specifier).
TNode<Object> specifier = Parameter<Object>(Descriptor::kSpecifier);
TNode<String> specifier_string = ToString_Inline(context, specifier);
// 4. Let exportNameString be ? ToString(exportName).
TNode<Object> export_name = Parameter<Object>(Descriptor::kExportName);
TNode<String> export_name_string = ToString_Inline(context, export_name);
// 5. Let callerRealm be the current Realm Record.
TNode<NativeContext> caller_context = LoadNativeContext(context);
// 6. Let evalRealm be O.[[ShadowRealm]].
// 7. Let evalContext be O.[[ExecutionContext]].
TNode<NativeContext> eval_context =
CAST(LoadObjectField(CAST(O), JSShadowRealm::kNativeContextOffset));
// 8. Return ? ShadowRealmImportValue(specifierString, exportNameString,
// callerRealm, evalRealm, evalContext).
TNode<Object> result = ImportValue(caller_context, eval_context,
specifier_string, export_name_string);
Return(result);
}
// https://tc39.es/proposal-shadowrealm/#sec-shadowrealmimportvalue
TNode<Object> ShadowRealmBuiltinsAssembler::ImportValue(
TNode<NativeContext> caller_context, TNode<NativeContext> eval_context,
TNode<String> specifier, TNode<String> export_name) {
// 1. Assert: evalContext is an execution context associated to a ShadowRealm
// instance's [[ExecutionContext]].
// 2. Let innerCapability be ! NewPromiseCapability(%Promise%).
// 3. Let runningContext be the running execution context.
// 4. If runningContext is not already suspended, suspend runningContext.
// 5. Push evalContext onto the execution context stack; evalContext is now
// the running execution context.
// 6. Perform ! HostImportModuleDynamically(null, specifierString,
// innerCapability).
// 7. Suspend evalContext and remove it from the execution context stack.
// 8. Resume the context that is now on the top of the execution context stack
// as the running execution context.
TNode<Object> inner_capability =
CallRuntime(Runtime::kShadowRealmImportValue, eval_context, specifier);
// 9. Let steps be the steps of an ExportGetter function as described below.
// 10. Let onFulfilled be ! CreateBuiltinFunction(steps, 1, "", «
// [[ExportNameString]] », callerRealm).
// 11. Set onFulfilled.[[ExportNameString]] to exportNameString.
TNode<JSFunction> on_fulfilled = AllocateImportValueFulfilledFunction(
caller_context, eval_context, specifier, export_name);
TNode<JSFunction> on_rejected = CAST(LoadContextElement(
caller_context, Context::SHADOW_REALM_IMPORT_VALUE_REJECTED_INDEX));
// 12. Let promiseCapability be ! NewPromiseCapability(%Promise%).
TNode<JSPromise> promise = NewJSPromise(caller_context);
// 13. Return ! PerformPromiseThen(innerCapability.[[Promise]], onFulfilled,
// callerRealm.[[Intrinsics]].[[%ThrowTypeError%]], promiseCapability).
return CallBuiltin(Builtin::kPerformPromiseThen, caller_context,
inner_capability, on_fulfilled, on_rejected, promise);
}
// ExportGetter of
// https://tc39.es/proposal-shadowrealm/#sec-shadowrealmimportvalue
TF_BUILTIN(ShadowRealmImportValueFulfilled, ShadowRealmBuiltinsAssembler) {
// An ExportGetter function is an anonymous built-in function with a
// [[ExportNameString]] internal slot. When an ExportGetter function is called
// with argument exports, it performs the following steps:
// 8. Let realm be f.[[Realm]].
TNode<Context> context = Parameter<Context>(Descriptor::kContext);
TNode<Context> eval_context = CAST(LoadContextElement(
context, ImportValueFulfilledFunctionContextSlot::kEvalContextSlot));
Label get_export_exception(this, Label::kDeferred);
// 2. Let f be the active function object.
// 3. Let string be f.[[ExportNameString]].
// 4. Assert: Type(string) is String.
TNode<String> export_name_string = CAST(LoadContextElement(
context, ImportValueFulfilledFunctionContextSlot::kExportNameSlot));
// 1. Assert: exports is a module namespace exotic object.
TNode<JSModuleNamespace> exports =
Parameter<JSModuleNamespace>(Descriptor::kExports);
// 5. Let hasOwn be ? HasOwnProperty(exports, string).
// 6. If hasOwn is false, throw a TypeError exception.
// 7. Let value be ? Get(exports, string).
// The only exceptions thrown by Runtime::kGetModuleNamespaceExport are
// either the export is not found or the module is not initialized.
TVARIABLE(Object, var_exception);
TNode<Object> value;
{
compiler::ScopedExceptionHandler handler(this, &get_export_exception,
&var_exception);
value = CallRuntime(Runtime::kGetModuleNamespaceExport, eval_context,
exports, export_name_string);
}
// 9. Return ? GetWrappedValue(realm, value).
TNode<NativeContext> caller_context = LoadNativeContext(context);
TNode<Object> wrapped_result =
CallBuiltin(Builtin::kShadowRealmGetWrappedValue, caller_context,
caller_context, eval_context, value);
Return(wrapped_result);
BIND(&get_export_exception);
{
TNode<String> specifier_string = CAST(LoadContextElement(
context, ImportValueFulfilledFunctionContextSlot::kSpecifierSlot));
ThrowTypeError(context, MessageTemplate::kUnresolvableExport,
specifier_string, export_name_string);
}
}
TF_BUILTIN(ShadowRealmImportValueRejected, ShadowRealmBuiltinsAssembler) {
TNode<Context> context = Parameter<Context>(Descriptor::kContext);
// TODO(v8:11989): provide a non-observable inspection on the
// pending_exception to the newly created TypeError.
// https://github.com/tc39/proposal-shadowrealm/issues/353
ThrowTypeError(context, MessageTemplate::kImportShadowRealmRejected);
}
} // namespace internal
} // namespace v8

View File

@ -6520,6 +6520,10 @@ TNode<BoolT> CodeStubAssembler::IsJSStringIterator(TNode<HeapObject> object) {
return HasInstanceType(object, JS_STRING_ITERATOR_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsJSShadowRealm(TNode<HeapObject> object) {
return HasInstanceType(object, JS_SHADOW_REALM_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsJSRegExpStringIterator(
TNode<HeapObject> object) {
return HasInstanceType(object, JS_REG_EXP_STRING_ITERATOR_TYPE);

View File

@ -111,6 +111,9 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(ProxyRevokeSharedFun, proxy_revoke_shared_fun, ProxyRevokeSharedFun) \
V(RegExpSpeciesProtector, regexp_species_protector, RegExpSpeciesProtector) \
V(SetIteratorProtector, set_iterator_protector, SetIteratorProtector) \
V(ShadowRealmImportValueFulfilledSFI, \
shadow_realm_import_value_fulfilled_sfi, \
ShadowRealmImportValueFulfilledSFI) \
V(SingleCharacterStringCache, single_character_string_cache, \
SingleCharacterStringCache) \
V(StringIteratorProtector, string_iterator_protector, \
@ -2582,6 +2585,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsJSPromise(TNode<HeapObject> object);
TNode<BoolT> IsJSProxy(TNode<HeapObject> object);
TNode<BoolT> IsJSStringIterator(TNode<HeapObject> object);
TNode<BoolT> IsJSShadowRealm(TNode<HeapObject> object);
TNode<BoolT> IsJSRegExpStringIterator(TNode<HeapObject> object);
TNode<BoolT> IsJSReceiverInstanceType(TNode<Int32T> instance_type);
TNode<BoolT> IsJSReceiverMap(TNode<Map> map);

View File

@ -105,6 +105,7 @@ namespace internal {
T(ImportOutsideModule, "Cannot use import statement outside a module") \
T(ImportMetaOutsideModule, "Cannot use 'import.meta' outside a module") \
T(ImportMissingSpecifier, "import() requires a specifier") \
T(ImportShadowRealmRejected, "Cannot import in the ShadowRealm") \
T(IncompatibleMethodReceiver, "Method % called on incompatible receiver %") \
T(InstanceofNonobjectProto, \
"Function has non-object prototype '%' in instanceof check") \

View File

@ -653,6 +653,100 @@ namespace {
const int kHostDefinedOptionsLength = 2;
const uint32_t kHostDefinedOptionsMagicConstant = 0xF1F2F3F0;
std::string ToSTLString(Isolate* isolate, Local<String> v8_str) {
String::Utf8Value utf8(isolate, v8_str);
// Should not be able to fail since the input is a String.
CHECK(*utf8);
return *utf8;
}
// Per-context Module data, allowing sharing of module maps
// across top-level module loads.
class ModuleEmbedderData {
private:
class ModuleGlobalHash {
public:
explicit ModuleGlobalHash(Isolate* isolate) : isolate_(isolate) {}
size_t operator()(const Global<Module>& module) const {
return module.Get(isolate_)->GetIdentityHash();
}
private:
Isolate* isolate_;
};
public:
explicit ModuleEmbedderData(Isolate* isolate)
: module_to_specifier_map(10, ModuleGlobalHash(isolate)),
json_module_to_parsed_json_map(
10, module_to_specifier_map.hash_function()) {}
static ModuleType ModuleTypeFromImportAssertions(
Local<Context> context, Local<FixedArray> import_assertions,
bool hasPositions) {
Isolate* isolate = context->GetIsolate();
const int kV8AssertionEntrySize = hasPositions ? 3 : 2;
for (int i = 0; i < import_assertions->Length();
i += kV8AssertionEntrySize) {
Local<String> v8_assertion_key =
import_assertions->Get(context, i).As<v8::String>();
std::string assertion_key = ToSTLString(isolate, v8_assertion_key);
if (assertion_key == "type") {
Local<String> v8_assertion_value =
import_assertions->Get(context, i + 1).As<String>();
std::string assertion_value = ToSTLString(isolate, v8_assertion_value);
if (assertion_value == "json") {
return ModuleType::kJSON;
} else {
// JSON is currently the only supported non-JS type
return ModuleType::kInvalid;
}
}
}
// If no type is asserted, default to JS.
return ModuleType::kJavaScript;
}
// Map from (normalized module specifier, module type) pair to Module.
std::map<std::pair<std::string, ModuleType>, Global<Module>> module_map;
// Map from Module to its URL as defined in the ScriptOrigin
std::unordered_map<Global<Module>, std::string, ModuleGlobalHash>
module_to_specifier_map;
// Map from JSON Module to its parsed content, for use in module
// JSONModuleEvaluationSteps
std::unordered_map<Global<Module>, Global<Value>, ModuleGlobalHash>
json_module_to_parsed_json_map;
// Origin location used for resolving modules when referrer is null.
std::string origin;
};
enum { kModuleEmbedderDataIndex, kInspectorClientIndex };
std::shared_ptr<ModuleEmbedderData> InitializeModuleEmbedderData(
Local<Context> context) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
const size_t kModuleEmbedderDataEstimate = 4 * 1024; // module map.
i::Handle<i::Managed<ModuleEmbedderData>> module_data_managed =
i::Managed<ModuleEmbedderData>::Allocate(
i_isolate, kModuleEmbedderDataEstimate, context->GetIsolate());
v8::Local<v8::Value> module_data = Utils::ToLocal(module_data_managed);
context->SetEmbedderData(kModuleEmbedderDataIndex, module_data);
return module_data_managed->get();
}
std::shared_ptr<ModuleEmbedderData> GetModuleDataFromContext(
Local<Context> context) {
v8::Local<v8::Value> module_data =
context->GetEmbedderData(kModuleEmbedderDataIndex);
i::Handle<i::Managed<ModuleEmbedderData>> module_data_managed =
i::Handle<i::Managed<ModuleEmbedderData>>::cast(
Utils::OpenHandle<Value, i::Object>(module_data));
return module_data_managed->get();
}
ScriptOrigin CreateScriptOrigin(Isolate* isolate, Local<String> resource_name,
v8::ScriptType type) {
Local<PrimitiveArray> options =
@ -741,6 +835,10 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
ScriptOrigin origin =
CreateScriptOrigin(isolate, name, ScriptType::kClassic);
std::shared_ptr<ModuleEmbedderData> module_data =
GetModuleDataFromContext(realm);
module_data->origin = ToSTLString(isolate, name);
for (int i = 1; i < options.repeat_compile; ++i) {
HandleScope handle_scope_for_compiling(isolate);
if (CompileString<Script>(isolate, context, source, origin).IsEmpty()) {
@ -844,13 +942,6 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
namespace {
std::string ToSTLString(Isolate* isolate, Local<String> v8_str) {
String::Utf8Value utf8(isolate, v8_str);
// Should not be able to fail since the input is a String.
CHECK(*utf8);
return *utf8;
}
bool IsAbsolutePath(const std::string& path) {
#if defined(_WIN32) || defined(_WIN64)
// This is an incorrect approximation, but should
@ -919,98 +1010,23 @@ std::string NormalizePath(const std::string& path,
return os.str();
}
// Per-context Module data, allowing sharing of module maps
// across top-level module loads.
class ModuleEmbedderData {
private:
class ModuleGlobalHash {
public:
explicit ModuleGlobalHash(Isolate* isolate) : isolate_(isolate) {}
size_t operator()(const Global<Module>& module) const {
return module.Get(isolate_)->GetIdentityHash();
}
private:
Isolate* isolate_;
};
public:
explicit ModuleEmbedderData(Isolate* isolate)
: module_to_specifier_map(10, ModuleGlobalHash(isolate)),
json_module_to_parsed_json_map(10, ModuleGlobalHash(isolate)) {}
static ModuleType ModuleTypeFromImportAssertions(
Local<Context> context, Local<FixedArray> import_assertions,
bool hasPositions) {
Isolate* isolate = context->GetIsolate();
const int kV8AssertionEntrySize = hasPositions ? 3 : 2;
for (int i = 0; i < import_assertions->Length();
i += kV8AssertionEntrySize) {
Local<String> v8_assertion_key =
import_assertions->Get(context, i).As<v8::String>();
std::string assertion_key = ToSTLString(isolate, v8_assertion_key);
if (assertion_key == "type") {
Local<String> v8_assertion_value =
import_assertions->Get(context, i + 1).As<String>();
std::string assertion_value = ToSTLString(isolate, v8_assertion_value);
if (assertion_value == "json") {
return ModuleType::kJSON;
} else {
// JSON is currently the only supported non-JS type
return ModuleType::kInvalid;
}
}
}
// If no type is asserted, default to JS.
return ModuleType::kJavaScript;
}
// Map from (normalized module specifier, module type) pair to Module.
std::map<std::pair<std::string, ModuleType>, Global<Module>> module_map;
// Map from Module to its URL as defined in the ScriptOrigin
std::unordered_map<Global<Module>, std::string, ModuleGlobalHash>
module_to_specifier_map;
// Map from JSON Module to its parsed content, for use in module
// JSONModuleEvaluationSteps
std::unordered_map<Global<Module>, Global<Value>, ModuleGlobalHash>
json_module_to_parsed_json_map;
};
enum { kModuleEmbedderDataIndex, kInspectorClientIndex };
void InitializeModuleEmbedderData(Local<Context> context) {
context->SetAlignedPointerInEmbedderData(
kModuleEmbedderDataIndex, new ModuleEmbedderData(context->GetIsolate()));
}
ModuleEmbedderData* GetModuleDataFromContext(Local<Context> context) {
return static_cast<ModuleEmbedderData*>(
context->GetAlignedPointerFromEmbedderData(kModuleEmbedderDataIndex));
}
void DisposeModuleEmbedderData(Local<Context> context) {
delete GetModuleDataFromContext(context);
context->SetAlignedPointerInEmbedderData(kModuleEmbedderDataIndex, nullptr);
}
MaybeLocal<Module> ResolveModuleCallback(Local<Context> context,
Local<String> specifier,
Local<FixedArray> import_assertions,
Local<Module> referrer) {
Isolate* isolate = context->GetIsolate();
ModuleEmbedderData* d = GetModuleDataFromContext(context);
auto specifier_it =
d->module_to_specifier_map.find(Global<Module>(isolate, referrer));
CHECK(specifier_it != d->module_to_specifier_map.end());
std::shared_ptr<ModuleEmbedderData> module_data =
GetModuleDataFromContext(context);
auto specifier_it = module_data->module_to_specifier_map.find(
Global<Module>(isolate, referrer));
CHECK(specifier_it != module_data->module_to_specifier_map.end());
std::string absolute_path = NormalizePath(ToSTLString(isolate, specifier),
DirName(specifier_it->second));
ModuleType module_type = ModuleEmbedderData::ModuleTypeFromImportAssertions(
context, import_assertions, true);
auto module_it =
d->module_map.find(std::make_pair(absolute_path, module_type));
CHECK(module_it != d->module_map.end());
module_data->module_map.find(std::make_pair(absolute_path, module_type));
CHECK(module_it != module_data->module_map.end());
return module_it->second.Get(isolate);
}
@ -1032,13 +1048,14 @@ MaybeLocal<Module> Shell::FetchModuleTree(Local<Module> referrer,
}
}
ModuleEmbedderData* d = GetModuleDataFromContext(context);
std::shared_ptr<ModuleEmbedderData> module_data =
GetModuleDataFromContext(context);
if (source_text.IsEmpty()) {
std::string msg = "d8: Error reading module from " + file_name;
if (!referrer.IsEmpty()) {
auto specifier_it =
d->module_to_specifier_map.find(Global<Module>(isolate, referrer));
CHECK(specifier_it != d->module_to_specifier_map.end());
auto specifier_it = module_data->module_to_specifier_map.find(
Global<Module>(isolate, referrer));
CHECK(specifier_it != module_data->module_to_specifier_map.end());
msg += "\n imported by " + specifier_it->second;
}
isolate->ThrowError(
@ -1074,7 +1091,7 @@ MaybeLocal<Module> Shell::FetchModuleTree(Local<Module> referrer,
String::NewFromUtf8(isolate, file_name.c_str()).ToLocalChecked(),
export_names, Shell::JSONModuleEvaluationSteps);
CHECK(d->json_module_to_parsed_json_map
CHECK(module_data->json_module_to_parsed_json_map
.insert(std::make_pair(Global<Module>(isolate, module),
Global<Value>(isolate, parsed_json)))
.second);
@ -1082,11 +1099,11 @@ MaybeLocal<Module> Shell::FetchModuleTree(Local<Module> referrer,
UNREACHABLE();
}
CHECK(d->module_map
CHECK(module_data->module_map
.insert(std::make_pair(std::make_pair(file_name, module_type),
Global<Module>(isolate, module)))
.second);
CHECK(d->module_to_specifier_map
CHECK(module_data->module_to_specifier_map
.insert(std::make_pair(Global<Module>(isolate, module), file_name))
.second);
@ -1109,7 +1126,7 @@ MaybeLocal<Module> Shell::FetchModuleTree(Local<Module> referrer,
return MaybeLocal<Module>();
}
if (d->module_map.count(
if (module_data->module_map.count(
std::make_pair(absolute_path, request_module_type))) {
continue;
}
@ -1127,10 +1144,11 @@ MaybeLocal<Value> Shell::JSONModuleEvaluationSteps(Local<Context> context,
Local<Module> module) {
Isolate* isolate = context->GetIsolate();
ModuleEmbedderData* d = GetModuleDataFromContext(context);
auto json_value_it =
d->json_module_to_parsed_json_map.find(Global<Module>(isolate, module));
CHECK(json_value_it != d->json_module_to_parsed_json_map.end());
std::shared_ptr<ModuleEmbedderData> module_data =
GetModuleDataFromContext(context);
auto json_value_it = module_data->json_module_to_parsed_json_map.find(
Global<Module>(isolate, module));
CHECK(json_value_it != module_data->json_module_to_parsed_json_map.end());
Local<Value> json_value = json_value_it->second.Get(isolate);
TryCatch try_catch(isolate);
@ -1151,11 +1169,12 @@ MaybeLocal<Value> Shell::JSONModuleEvaluationSteps(Local<Context> context,
}
struct DynamicImportData {
DynamicImportData(Isolate* isolate_, Local<String> referrer_,
Local<String> specifier_,
DynamicImportData(Isolate* isolate_, Local<Context> context_,
Local<Value> referrer_, Local<String> specifier_,
Local<FixedArray> import_assertions_,
Local<Promise::Resolver> resolver_)
: isolate(isolate_) {
context.Reset(isolate, context_);
referrer.Reset(isolate, referrer_);
specifier.Reset(isolate, specifier_);
import_assertions.Reset(isolate, import_assertions_);
@ -1163,7 +1182,10 @@ struct DynamicImportData {
}
Isolate* isolate;
Global<String> referrer;
// The initiating context. It can be the Realm created by d8, or the context
// created by ShadowRealm built-in.
Global<Context> context;
Global<Value> referrer;
Global<String> specifier;
Global<FixedArray> import_assertions;
Global<Promise::Resolver> resolver;
@ -1235,7 +1257,8 @@ MaybeLocal<Promise> Shell::HostImportModuleDynamically(
Local<Promise::Resolver> resolver;
if (!maybe_resolver.ToLocal(&resolver)) return MaybeLocal<Promise>();
if (!IsValidHostDefinedOptions(context, host_defined_options,
if (!resource_name->IsNull() &&
!IsValidHostDefinedOptions(context, host_defined_options,
resource_name)) {
resolver
->Reject(context, v8::Exception::TypeError(String::NewFromUtf8Literal(
@ -1243,7 +1266,7 @@ MaybeLocal<Promise> Shell::HostImportModuleDynamically(
.ToChecked();
} else {
DynamicImportData* data =
new DynamicImportData(isolate, resource_name.As<String>(), specifier,
new DynamicImportData(isolate, context, resource_name, specifier,
import_assertions, resolver);
PerIsolateData::Get(isolate)->AddDynamicImportData(data);
isolate->EnqueueMicrotask(Shell::DoHostImportModuleDynamically, data);
@ -1257,10 +1280,11 @@ void Shell::HostInitializeImportMetaObject(Local<Context> context,
Isolate* isolate = context->GetIsolate();
HandleScope handle_scope(isolate);
ModuleEmbedderData* d = GetModuleDataFromContext(context);
auto specifier_it =
d->module_to_specifier_map.find(Global<Module>(isolate, module));
CHECK(specifier_it != d->module_to_specifier_map.end());
std::shared_ptr<ModuleEmbedderData> module_data =
GetModuleDataFromContext(context);
auto specifier_it = module_data->module_to_specifier_map.find(
Global<Module>(isolate, module));
CHECK(specifier_it != module_data->module_to_specifier_map.end());
Local<String> url_key =
String::NewFromUtf8Literal(isolate, "url", NewStringType::kInternalized);
@ -1271,7 +1295,14 @@ void Shell::HostInitializeImportMetaObject(Local<Context> context,
MaybeLocal<Context> Shell::HostCreateShadowRealmContext(
Local<Context> initiator_context) {
return v8::Context::New(initiator_context->GetIsolate());
Local<Context> context = v8::Context::New(initiator_context->GetIsolate());
std::shared_ptr<ModuleEmbedderData> shadow_realm_data =
InitializeModuleEmbedderData(context);
std::shared_ptr<ModuleEmbedderData> initiator_data =
GetModuleDataFromContext(initiator_context);
shadow_realm_data->origin = initiator_data->origin;
return context;
}
void Shell::DoHostImportModuleDynamically(void* import_data) {
@ -1281,16 +1312,16 @@ void Shell::DoHostImportModuleDynamically(void* import_data) {
Isolate* isolate(import_data_->isolate);
HandleScope handle_scope(isolate);
Local<String> referrer(import_data_->referrer.Get(isolate));
Local<Context> realm = import_data_->context.Get(isolate);
Local<Value> referrer(import_data_->referrer.Get(isolate));
Local<String> specifier(import_data_->specifier.Get(isolate));
Local<FixedArray> import_assertions(
import_data_->import_assertions.Get(isolate));
Local<Promise::Resolver> resolver(import_data_->resolver.Get(isolate));
PerIsolateData* data = PerIsolateData::Get(isolate);
PerIsolateData::Get(isolate)->DeleteDynamicImportData(import_data_);
data->DeleteDynamicImportData(import_data_);
Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
Context::Scope context_scope(realm);
ModuleType module_type = ModuleEmbedderData::ModuleTypeFromImportAssertions(
@ -1306,17 +1337,21 @@ void Shell::DoHostImportModuleDynamically(void* import_data) {
return;
}
std::string source_url = ToSTLString(isolate, referrer);
std::shared_ptr<ModuleEmbedderData> module_data =
GetModuleDataFromContext(realm);
std::string source_url = referrer->IsNull()
? module_data->origin
: ToSTLString(isolate, referrer.As<String>());
std::string dir_name =
DirName(NormalizePath(source_url, GetWorkingDirectory()));
std::string file_name = ToSTLString(isolate, specifier);
std::string absolute_path = NormalizePath(file_name, dir_name);
ModuleEmbedderData* d = GetModuleDataFromContext(realm);
Local<Module> root_module;
auto module_it =
d->module_map.find(std::make_pair(absolute_path, module_type));
if (module_it != d->module_map.end()) {
module_data->module_map.find(std::make_pair(absolute_path, module_type));
if (module_it != module_data->module_map.end()) {
root_module = module_it->second.Get(isolate);
} else if (!FetchModuleTree(Local<Module>(), realm, absolute_path,
module_type)
@ -1374,11 +1409,12 @@ bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
// isolate->ReportPendingMessages().
TryCatch try_catch(isolate);
ModuleEmbedderData* d = GetModuleDataFromContext(realm);
std::shared_ptr<ModuleEmbedderData> module_data =
GetModuleDataFromContext(realm);
Local<Module> root_module;
auto module_it = d->module_map.find(
auto module_it = module_data->module_map.find(
std::make_pair(absolute_path, ModuleType::kJavaScript));
if (module_it != d->module_map.end()) {
if (module_it != module_data->module_map.end()) {
root_module = module_it->second.Get(isolate);
} else if (!FetchModuleTree(Local<Module>(), realm, absolute_path,
ModuleType::kJavaScript)
@ -1388,6 +1424,8 @@ bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
return false;
}
module_data->origin = absolute_path;
MaybeLocal<Value> maybe_result;
if (root_module->InstantiateModule(realm, ResolveModuleCallback)
.FromMaybe(false)) {
@ -1616,14 +1654,7 @@ PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
}
PerIsolateData::RealmScope::~RealmScope() {
// Drop realms to avoid keeping them alive. We don't dispose the
// module embedder data for the first realm here, but instead do
// it in RunShell or in RunMain, if not running in interactive mode
for (int i = 1; i < data_->realm_count_; ++i) {
Global<Context>& realm = data_->realms_[i];
if (realm.IsEmpty()) continue;
DisposeModuleEmbedderData(realm.Get(data_->isolate_));
}
// Drop realms to avoid keeping them alive.
data_->realm_count_ = 0;
delete[] data_->realms_;
}
@ -1805,7 +1836,6 @@ void Shell::DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
Isolate* isolate = args.GetIsolate();
PerIsolateData* data = PerIsolateData::Get(isolate);
Local<Context> context = data->realms_[index].Get(isolate);
DisposeModuleEmbedderData(context);
data->realms_[index].Reset();
// ContextDisposedNotification expects the disposed context to be entered.
v8::Context::Scope scope(context);
@ -3715,9 +3745,6 @@ void Shell::RunShell(Isolate* isolate) {
kProcessMessageQueue);
}
printf("\n");
// We need to explicitly clean up the module embedder data for
// the interative shell context.
DisposeModuleEmbedderData(context);
}
class InspectorFrontend final : public v8_inspector::V8Inspector::Channel {
@ -4031,7 +4058,6 @@ void SourceGroup::ExecuteInThread() {
Execute(isolate);
Shell::CompleteMessageLoop(isolate);
}
DisposeModuleEmbedderData(context);
}
Shell::CollectGarbage(isolate);
}
@ -4306,7 +4332,6 @@ void Worker::ExecuteInThread() {
}
}
}
DisposeModuleEmbedderData(context);
}
Shell::CollectGarbage(isolate_);
}
@ -4707,9 +4732,6 @@ int Shell::RunMain(Isolate* isolate, bool last_run) {
if (!options.isolate_sources[0].Execute(isolate)) success = false;
if (!CompleteMessageLoop(isolate)) success = false;
}
if (!use_existing_context) {
DisposeModuleEmbedderData(context);
}
WriteLcovData(isolate, options.lcov_file);
if (last_run && i::FLAG_stress_snapshot) {
static constexpr bool kClearRecompilableData = true;

View File

@ -4655,7 +4655,7 @@ MaybeHandle<JSPromise> NewRejectedPromise(Isolate* isolate,
} // namespace
MaybeHandle<JSPromise> Isolate::RunHostImportModuleDynamicallyCallback(
Handle<Script> referrer, Handle<Object> specifier,
MaybeHandle<Script> maybe_referrer, Handle<Object> specifier,
MaybeHandle<Object> maybe_import_assertions_argument) {
v8::Local<v8::Context> api_context =
v8::Utils::ToLocal(Handle<Context>::cast(native_context()));
@ -4684,13 +4684,23 @@ MaybeHandle<JSPromise> Isolate::RunHostImportModuleDynamicallyCallback(
clear_pending_exception();
return NewRejectedPromise(this, api_context, exception);
}
Handle<FixedArray> host_defined_options;
Handle<Object> resource_name;
if (maybe_referrer.is_null()) {
host_defined_options = factory()->empty_fixed_array();
resource_name = factory()->null_value();
} else {
Handle<Script> referrer = maybe_referrer.ToHandleChecked();
host_defined_options = handle(referrer->host_defined_options(), this);
resource_name = handle(referrer->name(), this);
}
if (host_import_module_dynamically_callback_) {
ASSIGN_RETURN_ON_SCHEDULED_EXCEPTION_VALUE(
this, promise,
host_import_module_dynamically_callback_(
api_context,
v8::Utils::ToLocal(handle(referrer->host_defined_options(), this)),
v8::Utils::ToLocal(handle(referrer->name(), this)),
api_context, v8::Utils::ToLocal(host_defined_options),
v8::Utils::ToLocal(resource_name),
v8::Utils::ToLocal(specifier_str),
ToApiHandle<v8::FixedArray>(import_assertions_array)),
MaybeHandle<JSPromise>());
@ -4698,9 +4708,8 @@ MaybeHandle<JSPromise> Isolate::RunHostImportModuleDynamicallyCallback(
// TODO(cbruni, v8:12302): Avoid creating tempory ScriptOrModule objects.
auto script_or_module = i::Handle<i::ScriptOrModule>::cast(
this->factory()->NewStruct(i::SCRIPT_OR_MODULE_TYPE));
script_or_module->set_resource_name(referrer->name());
script_or_module->set_host_defined_options(
referrer->host_defined_options());
script_or_module->set_resource_name(*resource_name);
script_or_module->set_host_defined_options(*host_defined_options);
ASSIGN_RETURN_ON_SCHEDULED_EXCEPTION_VALUE(
this, promise,
host_import_module_dynamically_with_import_assertions_callback_(

View File

@ -1762,7 +1762,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
void SetHostImportModuleDynamicallyCallback(
HostImportModuleDynamicallyCallback callback);
MaybeHandle<JSPromise> RunHostImportModuleDynamicallyCallback(
Handle<Script> referrer, Handle<Object> specifier,
MaybeHandle<Script> maybe_referrer, Handle<Object> specifier,
MaybeHandle<Object> maybe_import_assertions_argument);
void SetHostInitializeImportMetaObjectCallback(

View File

@ -1067,6 +1067,13 @@ void Heap::CreateInitialObjects() {
CreateSharedFunctionInfo(isolate_, Builtin::kProxyRevoke, 0);
set_proxy_revoke_shared_fun(*info);
}
// ShadowRealm:
{
Handle<SharedFunctionInfo> info = CreateSharedFunctionInfo(
isolate_, Builtin::kShadowRealmImportValueFulfilled, 0);
set_shadow_realm_import_value_fulfilled_sfi(*info);
}
}
void Heap::CreateInternalAccessorInfoObjects() {

View File

@ -4554,6 +4554,17 @@ void Genesis::InitializeGlobal_harmony_shadow_realm() {
native_context()->set_wrapped_function_map(*map);
}
// Internal steps of ShadowRealmImportValue
{
Handle<JSFunction> shadow_realm_import_value_rejected =
SimpleCreateFunction(isolate(), factory->empty_string(),
Builtin::kShadowRealmImportValueRejected, 1,
false);
shadow_realm_import_value_rejected->shared().set_native(false);
native_context()->set_shadow_realm_import_value_rejected(
*shadow_realm_import_value_rejected);
}
}
void Genesis::InitializeGlobal_harmony_struct() {

View File

@ -353,6 +353,8 @@ enum ContextLookupFlags {
V(SET_ADD_INDEX, JSFunction, set_add) \
V(SET_DELETE_INDEX, JSFunction, set_delete) \
V(SET_HAS_INDEX, JSFunction, set_has) \
V(SHADOW_REALM_IMPORT_VALUE_REJECTED_INDEX, JSFunction, \
shadow_realm_import_value_rejected) \
V(SYNTAX_ERROR_FUNCTION_INDEX, JSFunction, syntax_error_function) \
V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \
V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function) \

View File

@ -367,6 +367,11 @@ Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate,
return ns;
}
bool JSModuleNamespace::HasExport(Isolate* isolate, Handle<String> name) {
Handle<Object> object(module().exports().Lookup(name), isolate);
return !object->IsTheHole(isolate);
}
MaybeHandle<Object> JSModuleNamespace::GetExport(Isolate* isolate,
Handle<String> name) {
Handle<Object> object(module().exports().Lookup(name), isolate);

View File

@ -147,6 +147,8 @@ class JSModuleNamespace
V8_WARN_UNUSED_RESULT MaybeHandle<Object> GetExport(Isolate* isolate,
Handle<String> name);
bool HasExport(Isolate* isolate, Handle<String> name);
// Return the (constant) property attributes for the referenced property,
// which is assumed to correspond to an export. If the export is
// uninitialized, schedule an exception and return Nothing.

View File

@ -292,7 +292,9 @@ class Symbol;
PromiseThrowerFinallySharedFun) \
V(SharedFunctionInfo, promise_value_thunk_finally_shared_fun, \
PromiseValueThunkFinallySharedFun) \
V(SharedFunctionInfo, proxy_revoke_shared_fun, ProxyRevokeSharedFun)
V(SharedFunctionInfo, proxy_revoke_shared_fun, ProxyRevokeSharedFun) \
V(SharedFunctionInfo, shadow_realm_import_value_fulfilled_sfi, \
ShadowRealmImportValueFulfilledSFI)
// These root references can be updated by the mutator.
#define STRONG_MUTABLE_MOVABLE_ROOT_LIST(V) \

View File

@ -59,5 +59,17 @@ RUNTIME_FUNCTION(Runtime_GetImportMetaObject) {
SourceTextModule::GetImportMeta(isolate, module));
}
RUNTIME_FUNCTION(Runtime_GetModuleNamespaceExport) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<JSModuleNamespace> module_namespace = args.at<JSModuleNamespace>(0);
Handle<String> name = args.at<String>(1);
if (!module_namespace->HasExport(isolate, name)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
}
RETURN_RESULT_OR_FAILURE(isolate, module_namespace->GetExport(isolate, name));
}
} // namespace internal
} // namespace v8

View File

@ -18,5 +18,27 @@ RUNTIME_FUNCTION(Runtime_ShadowRealmWrappedFunctionCreate) {
isolate, JSWrappedFunction::Create(isolate, native_context, value));
}
// https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.importvalue
RUNTIME_FUNCTION(Runtime_ShadowRealmImportValue) {
DCHECK_EQ(1, args.length());
HandleScope scope(isolate);
Handle<String> specifier = args.at<String>(0);
Handle<JSPromise> inner_capability;
MaybeHandle<Object> import_assertions;
MaybeHandle<Script> referrer;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, inner_capability,
isolate->RunHostImportModuleDynamicallyCallback(referrer, specifier,
import_assertions));
// Check that the promise is created in the eval_context.
DCHECK(
inner_capability->GetCreationContext().ToHandleChecked().is_identical_to(
isolate->native_context()));
return *inner_capability;
}
} // namespace internal
} // namespace v8

View File

@ -277,7 +277,8 @@ namespace internal {
#define FOR_EACH_INTRINSIC_MODULE(F, I) \
F(DynamicImportCall, -1 /* [2, 3] */, 1) \
I(GetImportMetaObject, 0, 1) \
F(GetModuleNamespace, 1, 1)
F(GetModuleNamespace, 1, 1) \
F(GetModuleNamespaceExport, 2, 1)
#define FOR_EACH_INTRINSIC_NUMBERS(F, I) \
F(ArrayBufferMaxByteLength, 0, 1) \
@ -440,7 +441,8 @@ namespace internal {
F(ThrowConstAssignError, 0, 1)
#define FOR_EACH_INTRINSIC_SHADOW_REALM(F, I) \
F(ShadowRealmWrappedFunctionCreate, 2, 1)
F(ShadowRealmWrappedFunctionCreate, 2, 1) \
F(ShadowRealmImportValue, 1, 1)
#define FOR_EACH_INTRINSIC_STRINGS(F, I) \
F(FlattenString, 1, 1) \

View File

@ -83,7 +83,7 @@ bytecodes: [
/* 48 E> */ B(DefineKeyedOwnProperty), R(this), R(0), U8(0),
/* 53 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 58 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(297),
B(Wide), B(LdaSmi), I16(298),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -115,7 +115,7 @@ bytecodes: [
/* 41 E> */ B(DefineKeyedOwnProperty), R(this), R(0), U8(0),
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 51 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(296),
B(Wide), B(LdaSmi), I16(297),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -149,7 +149,7 @@ bytecodes: [
B(Star2),
B(LdaImmutableCurrentContextSlot), U8(3),
/* 58 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(297),
B(Wide), B(LdaSmi), I16(298),
B(Star3),
B(LdaConstant), U8(0),
B(Star4),
@ -181,7 +181,7 @@ bytecodes: [
/* 41 E> */ B(DefineKeyedOwnProperty), R(this), R(0), U8(0),
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 51 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(296),
B(Wide), B(LdaSmi), I16(297),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),

View File

@ -58,7 +58,7 @@ bytecodes: [
B(Star2),
B(LdaImmutableCurrentContextSlot), U8(3),
/* 54 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(295),
B(Wide), B(LdaSmi), I16(296),
B(Star3),
B(LdaConstant), U8(0),
B(Star4),
@ -91,7 +91,7 @@ bytecodes: [
/* 44 E> */ B(DefineKeyedOwnProperty), R(this), R(0), U8(0),
/* 49 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 54 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(295),
B(Wide), B(LdaSmi), I16(296),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),

View File

@ -24,7 +24,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(1),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(289),
B(Wide), B(LdaSmi), I16(290),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -61,13 +61,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(289),
B(Wide), B(LdaSmi), I16(290),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
/* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(295),
B(Wide), B(LdaSmi), I16(296),
B(Star2),
B(LdaConstant), U8(1),
B(Star3),
@ -99,13 +99,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(289),
B(Wide), B(LdaSmi), I16(290),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(295),
B(Wide), B(LdaSmi), I16(296),
B(Star1),
B(LdaConstant), U8(1),
B(Star2),
@ -145,7 +145,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(289),
B(Wide), B(LdaSmi), I16(290),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -167,7 +167,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(289),
B(Wide), B(LdaSmi), I16(290),
B(Star3),
B(LdaConstant), U8(0),
B(Star4),
@ -182,7 +182,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(289),
B(Wide), B(LdaSmi), I16(290),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -216,13 +216,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(289),
B(Wide), B(LdaSmi), I16(290),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(297),
B(Wide), B(LdaSmi), I16(298),
B(Star1),
B(LdaConstant), U8(1),
B(Star2),
@ -253,13 +253,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(289),
B(Wide), B(LdaSmi), I16(290),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 58 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(296),
B(Wide), B(LdaSmi), I16(297),
B(Star1),
B(LdaConstant), U8(1),
B(Star2),
@ -292,13 +292,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(289),
B(Wide), B(LdaSmi), I16(290),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
/* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(297),
B(Wide), B(LdaSmi), I16(298),
B(Star2),
B(LdaConstant), U8(1),
B(Star3),
@ -327,7 +327,7 @@ bytecode array length: 19
bytecodes: [
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 51 E> */ B(GetKeyedProperty), R(this), U8(0),
B(Wide), B(LdaSmi), I16(296),
B(Wide), B(LdaSmi), I16(297),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),

View File

@ -0,0 +1,67 @@
// 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.
// Flags: --harmony-shadow-realm --allow-natives-syntax
var shadowRealm = new ShadowRealm();
globalThis.foobar = 'outer-scope';
{
const promise = shadowRealm.importValue('./shadowrealm-skip-1.mjs', 'func');
// Promise is created in caller realm.
assertInstanceof(promise, Promise);
assertPromiseResult(promise.then(func => {
// Check that side-effects in the ShadowRealm not propagated to the caller.
assertEquals(globalThis.foobar, 'outer-scope');
// Check that the func is created in the current Realm.
assertEquals(typeof func, 'function');
assertTrue(func instanceof Function);
// Should return the inner global value.
assertEquals(func(), 'inner-scope');
}));
}
{
const promise = shadowRealm.importValue('./shadowrealm-skip-1.mjs', 'foo');
// Promise is created in caller realm.
assertInstanceof(promise, Promise);
assertPromiseResult(promise.then(foo => {
assertEquals(foo, 'bar');
}));
}
{
const promise = shadowRealm.importValue('./shadowrealm-skip-1.mjs', 'obj');
// Promise is created in caller realm.
assertInstanceof(promise, Promise);
assertThrowsAsync(promise, TypeError, "[object Object] is not a function");
}
{
const promise = shadowRealm.importValue('./shadowrealm-skip-1.mjs', 'not_exists');
// Promise is created in caller realm.
assertInstanceof(promise, Promise);
assertThrowsAsync(promise, TypeError, "The requested module './shadowrealm-skip-1.mjs' does not provide an export named 'not_exists'");
}
{
const promise = shadowRealm.importValue('./shadowrealm-skip-not-found.mjs', 'foo');
// Promise is created in caller realm.
assertInstanceof(promise, Promise);
assertThrowsAsync(promise, TypeError, 'Cannot import in the ShadowRealm');
}
{
const promise = shadowRealm.importValue('./shadowrealm-skip-2-throw.mjs', 'foo');
// Promise is created in caller realm.
assertInstanceof(promise, Promise);
assertThrowsAsync(promise, TypeError, 'Cannot import in the ShadowRealm');
}
// Invalid args
assertThrows(() => ShadowRealm.prototype.importValue.call(1, '', ''), TypeError, 'Method ShadowRealm.prototype.importValue called on incompatible receiver 1')
assertThrows(() => ShadowRealm.prototype.importValue.call({}, '', ''), TypeError, 'Method ShadowRealm.prototype.importValue called on incompatible receiver #<Object>')

View File

@ -0,0 +1,7 @@
export const foo = 'bar';
export const obj = {};
export const func = function () {
return globalThis.foobar;
};
// Generates side-effects to the globalThis.
globalThis.foobar = 'inner-scope';

View File

@ -0,0 +1,2 @@
export const foo = 'bar';
throw new Error('foobar');

View File

@ -31,6 +31,7 @@
# tested standalone.
'modules-skip*': [SKIP],
'harmony/modules-skip*': [SKIP],
'harmony/shadowrealm-skip*': [SKIP],
'regress/modules-skip*': [SKIP],
'wasm/exceptions-utils': [SKIP],
'wasm/wasm-module-builder': [SKIP],

View File

@ -2985,13 +2985,6 @@
# https://bugs.chromium.org/p/v8/issues/detail?id=11989
'built-ins/ShadowRealm/prototype/evaluate/globalthis-ordinary-object': [FAIL],
'built-ins/ShadowRealm/prototype/importValue/exportName-tostring': [FAIL],
'built-ins/ShadowRealm/prototype/importValue/import-value': [FAIL],
'built-ins/ShadowRealm/prototype/importValue/specifier-tostring': [FAIL],
'built-ins/ShadowRealm/prototype/importValue/throws-if-import-value-does-not-exist': [FAIL],
'built-ins/ShadowRealm/prototype/importValue/throws-typeerror-import-syntax-error': [FAIL],
'built-ins/ShadowRealm/prototype/importValue/throws-typeerror-import-throws': [FAIL],
'built-ins/ShadowRealm/prototype/importValue/validates-realm-object': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=12085
'language/statements/class/subclass/derived-class-return-override-catch-finally': [FAIL],

View File

@ -538,27 +538,28 @@ KNOWN_OBJECTS = {
("old_space", 0x04b39): "StringSplitCache",
("old_space", 0x04f41): "RegExpMultipleCache",
("old_space", 0x05349): "BuiltinsConstantsTable",
("old_space", 0x05775): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x05799): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x057bd): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x057e1): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x05805): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x05829): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x0584d): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x05871): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x05895): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x058b9): "PromiseAllResolveElementSharedFun",
("old_space", 0x058dd): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x05901): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x05925): "PromiseAnyRejectElementSharedFun",
("old_space", 0x05949): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x0596d): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x05991): "PromiseCatchFinallySharedFun",
("old_space", 0x059b5): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x059d9): "PromiseThenFinallySharedFun",
("old_space", 0x059fd): "PromiseThrowerFinallySharedFun",
("old_space", 0x05a21): "PromiseValueThunkFinallySharedFun",
("old_space", 0x05a45): "ProxyRevokeSharedFun",
("old_space", 0x05779): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x0579d): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x057c1): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x057e5): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x05809): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x0582d): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x05851): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x05875): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x05899): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x058bd): "PromiseAllResolveElementSharedFun",
("old_space", 0x058e1): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x05905): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x05929): "PromiseAnyRejectElementSharedFun",
("old_space", 0x0594d): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x05971): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x05995): "PromiseCatchFinallySharedFun",
("old_space", 0x059b9): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x059dd): "PromiseThenFinallySharedFun",
("old_space", 0x05a01): "PromiseThrowerFinallySharedFun",
("old_space", 0x05a25): "PromiseValueThunkFinallySharedFun",
("old_space", 0x05a49): "ProxyRevokeSharedFun",
("old_space", 0x05a6d): "ShadowRealmImportValueFulfilledSFI",
}
# Lower 32 bits of first page addresses for various heap spaces.