Commit 92147e3a authored by Daniel Clark's avatar Daniel Clark Committed by Commit Bot

[modules] Introduce SyntheticModule

This change is a partial implementation of Synthetic Module Record as specified here:
https://heycam.github.io/webidl/#synthetic-module-records

This includes:
- Introduce SyntheticModule class inheriting from Module.
- Extend v8::Module interface in v8.h to include Synthetic Module APIs, with corresponding
  implementations in api.cc.
- Provide SyntheticModule implementations of PrepareInstantiate, FinishInstantiate, and SetExport.
- Provide cctest unit tests for the implementations in the preceding item.

We will follow up with further submissions to implement the remaining members of
SyntheticModule (ResolveExport and Evaluate).

Bug: v8:9292
Change-Id: I25b1b695b5d1c3004677cd685f0dfd95283438fa
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1626829
Commit-Queue: Dan Clark <daniec@microsoft.com>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62433}
parent 778ade12
......@@ -2607,6 +2607,8 @@ v8_source_set("v8_base_without_compiler") {
"src/objects/string.h",
"src/objects/struct-inl.h",
"src/objects/struct.h",
"src/objects/synthetic-module.cc",
"src/objects/synthetic-module.h",
"src/objects/tagged-field-inl.h",
"src/objects/tagged-field.h",
"src/objects/tagged-impl-inl.h",
......
......@@ -1326,6 +1326,34 @@ class V8_EXPORT Module {
* kEvaluated or kErrored.
*/
Local<UnboundModuleScript> GetUnboundModuleScript();
/*
* Callback defined in the embedder. This is responsible for setting
* the module's exported values with calls to SetSyntheticModuleExport().
*/
typedef bool (*SyntheticModuleEvaluationSteps)(Local<Context> context,
Local<Module> module);
/**
* Creates a new SyntheticModule with the specified export names, where
* evaluation_steps will be executed upon module evaluation.
* export_names must not contain duplicates.
* module_name is used solely for logging/debugging and doesn't affect module
* behavior.
*/
static Local<Module> CreateSyntheticModule(
Isolate* isolate, Local<String> module_name,
const std::vector<Local<String>>& export_names,
SyntheticModuleEvaluationSteps evaluation_steps);
/**
* Set this module's exported value for the name export_name to the specified
* export_value. This method must be called only on Modules created via
* CreateSyntheticModule. export_name must be one of the export_names that
* were passed in that CreateSyntheticModule call.
*/
void SetSyntheticModuleExport(Local<String> export_name,
Local<Value> export_value);
};
/**
......
......@@ -2233,6 +2233,7 @@ Local<Value> Module::GetException() const {
int Module::GetModuleRequestsLength() const {
i::Handle<i::Module> self = Utils::OpenHandle(this);
if (self->IsSyntheticModule()) return 0;
return i::Handle<i::SourceTextModule>::cast(self)
->info()
.module_requests()
......@@ -2324,6 +2325,37 @@ MaybeLocal<Value> Module::Evaluate(Local<Context> context) {
RETURN_ESCAPED(result);
}
Local<Module> Module::CreateSyntheticModule(
Isolate* isolate, Local<String> module_name,
const std::vector<Local<v8::String>>& export_names,
v8::Module::SyntheticModuleEvaluationSteps evaluation_steps) {
auto i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::String> i_module_name = Utils::OpenHandle(*module_name);
i::Handle<i::FixedArray> i_export_names = i_isolate->factory()->NewFixedArray(
static_cast<int>(export_names.size()));
for (int i = 0; i < i_export_names->length(); ++i) {
i::Handle<i::String> str = Utils::OpenHandle(*export_names[i]);
i_export_names->set(i, *str);
}
return v8::Utils::ToLocal(
i::Handle<i::Module>(i_isolate->factory()->NewSyntheticModule(
i_module_name, i_export_names, evaluation_steps)));
}
void Module::SetSyntheticModuleExport(Local<String> export_name,
Local<v8::Value> export_value) {
i::Handle<i::String> i_export_name = Utils::OpenHandle(*export_name);
i::Handle<i::Object> i_export_value = Utils::OpenHandle(*export_value);
i::Handle<i::Module> self = Utils::OpenHandle(this);
Utils::ApiCheck(self->IsSyntheticModule(),
"v8::Module::SetSyntheticModuleExport",
"v8::Module::SetSyntheticModuleExport must only be called on "
"a SyntheticModule");
i::SyntheticModule::SetExport(self->GetIsolate(),
i::Handle<i::SyntheticModule>::cast(self),
i_export_name, i_export_value);
}
namespace {
i::Compiler::ScriptDetails GetScriptDetails(
......
......@@ -18,6 +18,7 @@
#include 'src/objects/objects.h'
#include 'src/objects/source-text-module.h'
#include 'src/objects/stack-frame-info.h'
#include 'src/objects/synthetic-module.h'
#include 'src/objects/template-objects.h'
type void;
......@@ -472,6 +473,12 @@ extern class SourceTextModule extends Module {
dfs_ancestor_index: Smi;
}
extern class SyntheticModule extends Module {
name: String;
export_names: FixedArray;
evaluation_steps: Foreign;
}
@abstract
extern class JSModuleNamespace extends JSObject {
module: Module;
......
......@@ -314,6 +314,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case PROPERTY_CELL_TYPE:
case SOURCE_TEXT_MODULE_TYPE:
case SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE:
case SYNTHETIC_MODULE_TYPE:
case CELL_TYPE:
case PREPARSE_DATA_TYPE:
case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE:
......
......@@ -421,6 +421,9 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) {
case SOURCE_TEXT_MODULE_TYPE:
SourceTextModule::cast(*this).SourceTextModuleVerify(isolate);
break;
case SYNTHETIC_MODULE_TYPE:
SyntheticModule::cast(*this).SyntheticModuleVerify(isolate);
break;
case CODE_DATA_CONTAINER_TYPE:
CodeDataContainer::cast(*this).CodeDataContainerVerify(isolate);
break;
......@@ -1582,6 +1585,14 @@ void SourceTextModule::SourceTextModuleVerify(Isolate* isolate) {
CHECK_EQ(requested_modules().length(), info().module_requests().length());
}
void SyntheticModule::SyntheticModuleVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::SyntheticModuleVerify(*this, isolate);
for (int i = 0; i < export_names().length(); i++) {
CHECK(export_names().get(i).IsString());
}
}
void PrototypeInfo::PrototypeInfoVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::PrototypeInfoVerify(*this, isolate);
if (prototype_users().IsWeakArrayList()) {
......
......@@ -420,6 +420,9 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case SOURCE_TEXT_MODULE_TYPE:
SourceTextModule::cast(*this).SourceTextModulePrint(os);
break;
case SYNTHETIC_MODULE_TYPE:
SyntheticModule::cast(*this).SyntheticModulePrint(os);
break;
case FEEDBACK_METADATA_TYPE:
FeedbackMetadata::cast(*this).FeedbackMetadataPrint(os);
break;
......@@ -1758,6 +1761,8 @@ static void PrintModuleFields(Module module, std::ostream& os) {
void Module::ModulePrint(std::ostream& os) { // NOLINT
if (this->IsSourceTextModule()) {
SourceTextModule::cast(*this).SourceTextModulePrint(os);
} else if (this->IsSyntheticModule()) {
SyntheticModule::cast(*this).SyntheticModulePrint(os);
} else {
UNREACHABLE();
}
......@@ -1774,6 +1779,13 @@ void SourceTextModule::SourceTextModulePrint(std::ostream& os) { // NOLINT
os << "\n";
}
void SyntheticModule::SyntheticModulePrint(std::ostream& os) { // NOLINT
PrintHeader(os, "SyntheticModule");
PrintModuleFields(*this, os);
os << "\n - export_names: " << Brief(export_names());
os << "\n";
}
void JSModuleNamespace::JSModuleNamespacePrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, *this, "JSModuleNamespace");
os << "\n - module: " << Brief(module());
......
......@@ -3071,6 +3071,28 @@ Handle<SourceTextModule> Factory::NewSourceTextModule(
return module;
}
Handle<SyntheticModule> Factory::NewSyntheticModule(
Handle<String> module_name, Handle<FixedArray> export_names,
v8::Module::SyntheticModuleEvaluationSteps evaluation_steps) {
ReadOnlyRoots roots(isolate());
Handle<SyntheticModule> module(
SyntheticModule::cast(New(synthetic_module_map(), AllocationType::kOld)),
isolate());
Handle<ObjectHashTable> exports =
ObjectHashTable::New(isolate(), static_cast<int>(export_names->length()));
Handle<Foreign> evaluation_steps_foreign =
NewForeign(reinterpret_cast<i::Address>(evaluation_steps));
module->set_exports(*exports);
module->set_hash(isolate()->GenerateIdentityHash(Smi::kMaxValue));
module->set_module_namespace(roots.undefined_value());
module->set_status(Module::kUninstantiated);
module->set_exception(roots.the_hole_value());
module->set_name(*module_name);
module->set_export_names(*export_names);
module->set_evaluation_steps(*evaluation_steps_foreign);
return module;
}
Handle<JSArrayBuffer> Factory::NewJSArrayBuffer(SharedFlag shared,
AllocationType allocation) {
Handle<JSFunction> array_buffer_fun(
......
......@@ -64,6 +64,7 @@ class SourceTextModuleInfo;
class StackFrameInfo;
class StackTraceFrame;
class StoreHandler;
class SyntheticModule;
class TemplateObjectDescription;
class UncompiledDataWithoutPreparseData;
class UncompiledDataWithPreparseData;
......@@ -690,6 +691,9 @@ class V8_EXPORT_PRIVATE Factory {
Handle<JSModuleNamespace> NewJSModuleNamespace();
Handle<SourceTextModule> NewSourceTextModule(Handle<SharedFunctionInfo> code);
Handle<SyntheticModule> NewSyntheticModule(
Handle<String> module_name, Handle<FixedArray> export_names,
v8::Module::SyntheticModuleEvaluationSteps evaluation_steps);
Handle<JSArrayBuffer> NewJSArrayBuffer(
SharedFlag shared, AllocationType allocation = AllocationType::kYoung);
......
......@@ -56,6 +56,7 @@ namespace internal {
V(SmallOrderedNameDictionary, SmallOrderedNameDictionary) \
V(SourceTextModule, SourceTextModule) \
V(Symbol, Symbol) \
V(SyntheticModule, SyntheticModule) \
V(ThinString, ThinString) \
V(TransitionArray, TransitionArray) \
V(UncompiledDataWithoutPreparseData, UncompiledDataWithoutPreparseData) \
......
......@@ -39,6 +39,7 @@
#include "src/objects/source-text-module.h"
#include "src/objects/stack-frame-info.h"
#include "src/objects/string.h"
#include "src/objects/synthetic-module.h"
#include "src/objects/template-objects-inl.h"
#include "src/regexp/regexp.h"
#include "src/wasm/wasm-objects.h"
......@@ -489,6 +490,8 @@ bool Heap::CreateInitialMaps() {
shared_function_info)
ALLOCATE_MAP(SOURCE_TEXT_MODULE_TYPE, SourceTextModule::kSize,
source_text_module)
ALLOCATE_MAP(SYNTHETIC_MODULE_TYPE, SyntheticModule::kSize,
synthetic_module)
ALLOCATE_MAP(CODE_DATA_CONTAINER_TYPE, CodeDataContainer::kSize,
code_data_container)
......
......@@ -182,7 +182,11 @@ enum InstanceType : uint16_t {
TORQUE_DEFINED_INSTANCE_TYPES(MAKE_TORQUE_INSTANCE_TYPE)
#undef MAKE_TORQUE_INSTANCE_TYPE
ALLOCATION_SITE_TYPE,
// Modules
SOURCE_TEXT_MODULE_TYPE, // FIRST_MODULE_TYPE
SYNTHETIC_MODULE_TYPE, // LAST_MODULE_TYPE
ALLOCATION_SITE_TYPE,
EMBEDDER_DATA_ARRAY_TYPE,
// FixedArrays.
FIXED_ARRAY_TYPE, // FIRST_FIXED_ARRAY_TYPE
......@@ -231,7 +235,6 @@ enum InstanceType : uint16_t {
SMALL_ORDERED_HASH_MAP_TYPE,
SMALL_ORDERED_HASH_SET_TYPE,
SMALL_ORDERED_NAME_DICTIONARY_TYPE,
SOURCE_TEXT_MODULE_TYPE,
STORE_HANDLER_TYPE,
UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE,
UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE,
......@@ -338,6 +341,9 @@ enum InstanceType : uint16_t {
// Boundaries for testing if given HeapObject is a subclass of Microtask.
FIRST_MICROTASK_TYPE = CALLABLE_TASK_TYPE,
LAST_MICROTASK_TYPE = FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE,
// Boundaries of module record types
FIRST_MODULE_TYPE = SOURCE_TEXT_MODULE_TYPE,
LAST_MODULE_TYPE = SYNTHETIC_MODULE_TYPE,
// Boundary for promotion to old space.
LAST_DATA_TYPE = FILLER_TYPE,
// Boundary for objects represented as JSReceiver (i.e. JSObject or JSProxy).
......@@ -449,7 +455,6 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
V(JSWeakSet, JS_WEAK_SET_TYPE) \
V(LoadHandler, LOAD_HANDLER_TYPE) \
V(Map, MAP_TYPE) \
V(Module, SOURCE_TEXT_MODULE_TYPE) \
V(MutableHeapNumber, MUTABLE_HEAP_NUMBER_TYPE) \
V(NameDictionary, NAME_DICTIONARY_TYPE) \
V(NativeContext, NATIVE_CONTEXT_TYPE) \
......@@ -473,6 +478,7 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
V(StoreHandler, STORE_HANDLER_TYPE) \
V(StringTable, STRING_TABLE_TYPE) \
V(Symbol, SYMBOL_TYPE) \
V(SyntheticModule, SYNTHETIC_MODULE_TYPE) \
V(TransitionArray, TRANSITION_ARRAY_TYPE) \
V(UncompiledDataWithoutPreparseData, \
UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE) \
......@@ -513,6 +519,7 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
V(JSMapIterator, FIRST_MAP_ITERATOR_TYPE, LAST_MAP_ITERATOR_TYPE) \
V(JSSetIterator, FIRST_SET_ITERATOR_TYPE, LAST_SET_ITERATOR_TYPE) \
V(Microtask, FIRST_MICROTASK_TYPE, LAST_MICROTASK_TYPE) \
V(Module, FIRST_MODULE_TYPE, LAST_MODULE_TYPE) \
V(Name, FIRST_NAME_TYPE, LAST_NAME_TYPE) \
V(String, FIRST_STRING_TYPE, LAST_STRING_TYPE) \
V(WeakFixedArray, FIRST_WEAK_FIXED_ARRAY_TYPE, LAST_WEAK_FIXED_ARRAY_TYPE)
......
......@@ -360,6 +360,8 @@ VisitorId Map::GetVisitorId(Map map) {
case SOURCE_TEXT_MODULE_TYPE:
return kVisitSourceTextModule;
case SYNTHETIC_MODULE_TYPE:
return kVisitSyntheticModule;
default:
UNREACHABLE();
......
......@@ -68,6 +68,7 @@ enum InstanceType : uint16_t;
V(SourceTextModule) \
V(Struct) \
V(Symbol) \
V(SyntheticModule) \
V(ThinString) \
V(TransitionArray) \
V(UncompiledDataWithoutPreparseData) \
......
......@@ -7,6 +7,7 @@
#include "src/objects/module.h"
#include "src/objects/source-text-module.h"
#include "src/objects/synthetic-module.h"
#include "src/objects/objects-inl.h" // Needed for write barriers
#include "src/objects/scope-info.h"
......@@ -21,13 +22,16 @@ namespace internal {
OBJECT_CONSTRUCTORS_IMPL(Module, HeapObject)
OBJECT_CONSTRUCTORS_IMPL(SourceTextModule, Module)
OBJECT_CONSTRUCTORS_IMPL(SourceTextModuleInfoEntry, Struct)
OBJECT_CONSTRUCTORS_IMPL(SyntheticModule, Module)
OBJECT_CONSTRUCTORS_IMPL(JSModuleNamespace, JSObject)
NEVER_READ_ONLY_SPACE_IMPL(Module)
NEVER_READ_ONLY_SPACE_IMPL(SourceTextModule)
NEVER_READ_ONLY_SPACE_IMPL(SyntheticModule)
CAST_ACCESSOR(Module)
CAST_ACCESSOR(SourceTextModule)
CAST_ACCESSOR(SyntheticModule)
ACCESSORS(Module, exports, ObjectHashTable, kExportsOffset)
ACCESSORS(Module, module_namespace, HeapObject, kModuleNamespaceOffset)
ACCESSORS(Module, exception, Object, kExceptionOffset)
......@@ -44,6 +48,10 @@ ACCESSORS(SourceTextModule, import_meta, Object, kImportMetaOffset)
SMI_ACCESSORS(SourceTextModule, dfs_index, kDfsIndexOffset)
SMI_ACCESSORS(SourceTextModule, dfs_ancestor_index, kDfsAncestorIndexOffset)
ACCESSORS(SyntheticModule, name, String, kNameOffset)
ACCESSORS(SyntheticModule, export_names, FixedArray, kExportNamesOffset)
ACCESSORS(SyntheticModule, evaluation_steps, Foreign, kEvaluationStepsOffset)
SourceTextModuleInfo SourceTextModule::info() const {
return (status() >= kEvaluating)
? SourceTextModuleInfo::cast(code())
......
......@@ -24,12 +24,14 @@ namespace internal {
void Module::PrintStatusTransition(Status new_status) {
if (FLAG_trace_module_status) {
StdoutStream os;
os << "Changing module status from " << status() << " to " << new_status;
os << "Changing module status from " << status() << " to " << new_status
<< " for ";
if (this->IsSourceTextModule()) {
Handle<Script> script(SourceTextModule::cast(*this).script(),
GetIsolate());
os << " for ";
script->GetNameOrSourceURL().Print(os);
} else {
SyntheticModule::cast(*this).name().Print(os);
}
#ifndef OBJECT_PRINT
os << "\n";
......@@ -69,10 +71,15 @@ void Module::ResetGraph(Isolate* isolate, Handle<Module> module) {
DCHECK_NE(module->status(), kInstantiating);
DCHECK_NE(module->status(), kEvaluating);
if (module->status() != kPreInstantiating) return;
Handle<FixedArray> requested_modules =
module->IsSourceTextModule()
? Handle<FixedArray>(
Handle<SourceTextModule>::cast(module)->requested_modules(),
isolate)
: Handle<FixedArray>();
Reset(isolate, module);
if (module->IsSourceTextModule()) {
Handle<FixedArray> requested_modules(
Handle<SourceTextModule>::cast(module)->requested_modules(), isolate);
Reset(isolate, module);
for (int i = 0; i < requested_modules->length(); ++i) {
Handle<Object> descendant(requested_modules->get(i), isolate);
if (descendant->IsModule()) {
......@@ -82,7 +89,8 @@ void Module::ResetGraph(Isolate* isolate, Handle<Module> module) {
}
}
} else {
Reset(isolate, module);
DCHECK(module->IsSyntheticModule());
// Nothing else to do here.
}
}
......@@ -99,13 +107,23 @@ void Module::Reset(Isolate* isolate, Handle<Module> module) {
module->PrintStatusTransition(kUninstantiated);
#endif // DEBUG
int export_count;
if (module->IsSourceTextModule()) {
SourceTextModule::Reset(isolate, Handle<SourceTextModule>::cast(module));
Handle<SourceTextModule> source_text_module =
Handle<SourceTextModule>::cast(module);
export_count = source_text_module->regular_exports().length();
SourceTextModule::Reset(isolate, source_text_module);
} else {
UNREACHABLE();
export_count =
Handle<SyntheticModule>::cast(module)->export_names().length();
// Nothing to do here.
}
DCHECK_EQ(module->status(), kUninstantiated);
Handle<ObjectHashTable> exports = ObjectHashTable::New(isolate, export_count);
module->set_exports(*exports);
module->set_status(kUninstantiated);
}
Object Module::GetException() {
......@@ -125,7 +143,9 @@ MaybeHandle<Cell> Module::ResolveExport(Isolate* isolate, Handle<Module> module,
isolate, Handle<SourceTextModule>::cast(module), module_specifier,
export_name, loc, must_resolve, resolve_set);
} else {
UNREACHABLE();
return SyntheticModule::ResolveExport(
isolate, Handle<SyntheticModule>::cast(module), module_specifier,
export_name, loc, must_resolve, resolve_set);
}
}
......@@ -142,7 +162,7 @@ bool Module::Instantiate(Isolate* isolate, Handle<Module> module,
.GetNameOrSourceURL()
.Print(os);
} else {
UNREACHABLE();
Handle<SyntheticModule>::cast(module)->name().Print(os);
}
#ifndef OBJECT_PRINT
os << "\n";
......@@ -183,7 +203,8 @@ bool Module::PrepareInstantiate(Isolate* isolate, Handle<Module> module,
return SourceTextModule::PrepareInstantiate(
isolate, Handle<SourceTextModule>::cast(module), context, callback);
} else {
UNREACHABLE();
return SyntheticModule::PrepareInstantiate(
isolate, Handle<SyntheticModule>::cast(module), context, callback);
}
}
......@@ -200,7 +221,8 @@ bool Module::FinishInstantiate(Isolate* isolate, Handle<Module> module,
isolate, Handle<SourceTextModule>::cast(module), stack, dfs_index,
zone);
} else {
UNREACHABLE();
return SyntheticModule::FinishInstantiate(
isolate, Handle<SyntheticModule>::cast(module));
}
}
......@@ -215,7 +237,7 @@ MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module) {
.GetNameOrSourceURL()
.Print(os);
} else {
UNREACHABLE();
Handle<SyntheticModule>::cast(module)->name().Print(os);
}
#ifndef OBJECT_PRINT
os << "\n";
......@@ -263,7 +285,8 @@ MaybeHandle<Object> Module::Evaluate(
return SourceTextModule::Evaluate(
isolate, Handle<SourceTextModule>::cast(module), stack, dfs_index);
} else {
UNREACHABLE();
return SyntheticModule::Evaluate(isolate,
Handle<SyntheticModule>::cast(module));
}
}
......
......@@ -54,6 +54,7 @@ class ScriptContextTable;
class SharedFunctionInfo;
class StringStream;
class Symbol;
class SyntheticModule;
class FeedbackCell;
class FeedbackMetadata;
class FeedbackVector;
......@@ -214,6 +215,7 @@ class ZoneForwardList;
V(Struct) \
V(Symbol) \
V(SymbolWrapper) \
V(SyntheticModule) \
V(TemplateInfo) \
V(TemplateList) \
V(ThinString) \
......
......@@ -20,6 +20,7 @@
#include "src/objects/oddball.h"
#include "src/objects/ordered-hash-table.h"
#include "src/objects/source-text-module.h"
#include "src/objects/synthetic-module.h"
#include "src/objects/transitions.h"
#include "src/wasm/wasm-objects-inl.h"
......@@ -1055,6 +1056,9 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
case SOURCE_TEXT_MODULE_TYPE:
return Op::template apply<SourceTextModule::BodyDescriptor>(p1, p2, p3,
p4);
case SYNTHETIC_MODULE_TYPE:
return Op::template apply<SyntheticModule::BodyDescriptor>(p1, p2, p3,
p4);
default:
PrintF("Unknown type: %d\n", type);
UNREACHABLE();
......
......@@ -119,6 +119,9 @@ namespace internal {
\
TORQUE_DEFINED_INSTANCE_TYPES(V) \
\
V(SOURCE_TEXT_MODULE_TYPE) \
V(SYNTHETIC_MODULE_TYPE) \
\
V(ALLOCATION_SITE_TYPE) \
V(EMBEDDER_DATA_ARRAY_TYPE) \
\
......@@ -166,7 +169,6 @@ namespace internal {
V(SMALL_ORDERED_HASH_MAP_TYPE) \
V(SMALL_ORDERED_HASH_SET_TYPE) \
V(SMALL_ORDERED_NAME_DICTIONARY_TYPE) \
V(SOURCE_TEXT_MODULE_TYPE) \
V(STORE_HANDLER_TYPE) \
V(UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE) \
V(UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE) \
......
......@@ -172,6 +172,7 @@
// - PromiseResolveThenableJobTask
// - Module
// - SourceTextModule
// - SyntheticModule
// - SourceTextModuleInfoEntry
// - FeedbackCell
// - FeedbackVector
......
......@@ -451,7 +451,8 @@ bool SourceTextModule::FinishInstantiate(
}));
if (requested_module->status() == kInstantiating) {
DCHECK(requested_module->IsSourceTextModule());
// SyntheticModules go straight to kInstantiated so this must be a
// SourceTextModule
module->set_dfs_ancestor_index(
std::min(module->dfs_ancestor_index(),
Handle<SourceTextModule>::cast(requested_module)
......@@ -613,7 +614,8 @@ MaybeHandle<Object> SourceTextModule::Evaluate(
}));
if (requested_module->status() == kEvaluating) {
DCHECK(requested_module->IsSourceTextModule());
// SyntheticModules go straight to kEvaluated so this must be a
// SourceTextModule
module->set_dfs_ancestor_index(
std::min(module->dfs_ancestor_index(),
Handle<SourceTextModule>::cast(requested_module)
......@@ -640,8 +642,6 @@ void SourceTextModule::Reset(Isolate* isolate,
DCHECK(module->import_meta().IsTheHole(isolate));
Handle<ObjectHashTable> exports =
ObjectHashTable::New(isolate, module->regular_exports().length());
Handle<FixedArray> regular_exports =
factory->NewFixedArray(module->regular_exports().length());
Handle<FixedArray> regular_imports =
......@@ -652,8 +652,6 @@ void SourceTextModule::Reset(Isolate* isolate,
if (module->status() == kInstantiating) {
module->set_code(JSFunction::cast(module->code()).shared());
}
module->set_status(kUninstantiated);
module->set_exports(*exports);
module->set_regular_exports(*regular_exports);
module->set_regular_imports(*regular_imports);
module->set_requested_modules(*requested_modules);
......
// Copyright 2019 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/objects/synthetic-module.h"
#include "src/api/api-inl.h"
#include "src/builtins/accessors.h"
#include "src/objects/js-generator-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/shared-function-info.h"
#include "src/utils/ostreams.h"
namespace v8 {
namespace internal {
// Implements SetSyntheticModuleBinding:
// https://heycam.github.io/webidl/#setsyntheticmoduleexport
void SyntheticModule::SetExport(Isolate* isolate,
Handle<SyntheticModule> module,
Handle<String> export_name,
Handle<Object> export_value) {
Handle<ObjectHashTable> exports(module->exports(), isolate);
Handle<Object> export_object(exports->Lookup(export_name), isolate);
CHECK(export_object->IsCell());
Handle<Cell> export_cell(Handle<Cell>::cast(export_object));
// Spec step 2: Set the mutable binding of export_name to export_value
export_cell->set_value(*export_value);
}
// Implements Synthetic Module Record's ResolveExport concrete method:
// https://heycam.github.io/webidl/#smr-resolveexport
MaybeHandle<Cell> SyntheticModule::ResolveExport(
Isolate* isolate, Handle<SyntheticModule> module,
Handle<String> module_specifier, Handle<String> export_name,
MessageLocation loc, bool must_resolve, ResolveSet* resolve_set) {
UNREACHABLE(); // TODO(SyntheticModules) implement
}
// Implements Synthetic Module Record's Instantiate concrete method :
// https://heycam.github.io/webidl/#smr-instantiate
bool SyntheticModule::PrepareInstantiate(Isolate* isolate,
Handle<SyntheticModule> module,
v8::Local<v8::Context> context,
v8::Module::ResolveCallback callback) {
Handle<ObjectHashTable> exports(module->exports(), isolate);
Handle<FixedArray> export_names(module->export_names(), isolate);
// Spec step 7: For each export_name in module->export_names...
for (int i = 0, n = export_names->length(); i < n; ++i) {
// Spec step 7.1: Create a new mutable binding for export_name.
// Spec step 7.2: Initialize the new mutable binding to undefined.
Handle<Cell> cell =
isolate->factory()->NewCell(isolate->factory()->undefined_value());
Handle<String> name(String::cast(export_names->get(i)), isolate);
CHECK(exports->Lookup(name).IsTheHole(isolate));
exports = ObjectHashTable::Put(exports, name, cell);
}
module->set_exports(*exports);
return true;
}
// Second step of module instantiation. No real work to do for SyntheticModule
// as there are no imports or indirect exports to resolve;
// just update status.
bool SyntheticModule::FinishInstantiate(Isolate* isolate,
Handle<SyntheticModule> module) {
module->SetStatus(kInstantiated);
return true;
}
// Implements Synthetic Module Record's Evaluate concrete method:
// https://heycam.github.io/webidl/#smr-evaluate
MaybeHandle<Object> SyntheticModule::Evaluate(Isolate* isolate,
Handle<SyntheticModule> module) {
UNREACHABLE(); // TODO(SyntheticModules) implement
}
} // namespace internal
} // namespace v8
// Copyright 2019 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.
#ifndef V8_OBJECTS_SYNTHETIC_MODULE_H_
#define V8_OBJECTS_SYNTHETIC_MODULE_H_
#include "src/objects/module.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
// The runtime representation of a Synthetic Module Record, a module that can be
// instantiated by an embedder with embedder-defined exports and evaluation
// steps.
// https://heycam.github.io/webidl/#synthetic-module-records
class SyntheticModule : public Module {
public:
NEVER_READ_ONLY_SPACE
DECL_CAST(SyntheticModule)
DECL_VERIFIER(SyntheticModule)
DECL_PRINTER(SyntheticModule)
// The list of all names exported by this module
DECL_ACCESSORS(name, String)
DECL_ACCESSORS(export_names, FixedArray)
DECL_ACCESSORS(evaluation_steps, Foreign)
static void SetExport(Isolate* isolate, Handle<SyntheticModule> module,
Handle<String> export_name,
Handle<Object> export_value);
// Layout description.
DEFINE_FIELD_OFFSET_CONSTANTS(Module::kHeaderSize,
TORQUE_GENERATED_SYNTHETIC_MODULE_FIELDS)
using BodyDescriptor = SubclassBodyDescriptor<
Module::BodyDescriptor,
FixedBodyDescriptor<kExportNamesOffset, kSize, kSize>>;
private:
friend class Module;
static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExport(
Isolate* isolate, Handle<SyntheticModule> module,
Handle<String> module_specifier, Handle<String> export_name,
MessageLocation loc, bool must_resolve, ResolveSet* resolve_set);
static V8_WARN_UNUSED_RESULT bool PrepareInstantiate(
Isolate* isolate, Handle<SyntheticModule> module,
v8::Local<v8::Context> context, v8::Module::ResolveCallback callback);
static V8_WARN_UNUSED_RESULT bool FinishInstantiate(
Isolate* isolate, Handle<SyntheticModule> module);
static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate(
Isolate* isolate, Handle<SyntheticModule> module);
OBJECT_CONSTRUCTORS(SyntheticModule, Module);
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_SYNTHETIC_MODULE_H_
......@@ -98,7 +98,6 @@ class Symbol;
V(Map, many_closures_cell_map, ManyClosuresCellMap) \
V(Map, module_info_map, ModuleInfoMap) \
V(Map, mutable_heap_number_map, MutableHeapNumberMap) \
V(Map, source_text_module_map, SourceTextModuleMap) \
V(Map, name_dictionary_map, NameDictionaryMap) \
V(Map, no_closures_cell_map, NoClosuresCellMap) \
V(Map, number_dictionary_map, NumberDictionaryMap) \
......@@ -118,7 +117,9 @@ class Symbol;
V(Map, small_ordered_hash_map_map, SmallOrderedHashMapMap) \
V(Map, small_ordered_hash_set_map, SmallOrderedHashSetMap) \
V(Map, small_ordered_name_dictionary_map, SmallOrderedNameDictionaryMap) \
V(Map, source_text_module_map, SourceTextModuleMap) \
V(Map, string_table_map, StringTableMap) \
V(Map, synthetic_module_map, SyntheticModuleMap) \
V(Map, uncompiled_data_without_preparse_data_map, \
UncompiledDataWithoutPreparseDataMap) \
V(Map, uncompiled_data_with_preparse_data_map, \
......
......@@ -23566,6 +23566,11 @@ v8::MaybeLocal<Module> UnexpectedModuleResolveCallback(Local<Context> context,
CHECK_WITH_MSG(false, "Unexpected call to resolve callback");
}
bool UnexpectedSyntheticModuleEvaluationStepsCallback(Local<Context> context,
Local<Module> module) {
CHECK_WITH_MSG(false, "Unexpected call to synthetic module re callback");
}
namespace {
Local<Module> CompileAndInstantiateModule(v8::Isolate* isolate,
......@@ -23588,6 +23593,18 @@ Local<Module> CompileAndInstantiateModule(v8::Isolate* isolate,
return module;
}
Local<Module> CreateAndInstantiateSyntheticModule(
v8::Isolate* isolate, Local<String> module_name, Local<Context> context,
std::vector<v8::Local<v8::String>> export_names,
v8::Module::SyntheticModuleEvaluationSteps evaluation_steps) {
Local<Module> module = v8::Module::CreateSyntheticModule(
isolate, module_name, export_names, evaluation_steps);
module->InstantiateModule(context, UnexpectedModuleResolveCallback)
.ToChecked();
return module;
}
Local<Module> CompileAndInstantiateModuleFromCache(
v8::Isolate* isolate, Local<Context> context, const char* resource_name,
const char* source, v8::ScriptCompiler::CachedData* cache) {
......@@ -23676,6 +23693,76 @@ TEST(ModuleCodeCache) {
}
}
TEST(CreateSyntheticModule) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
auto i_isolate = reinterpret_cast<i::Isolate*>(isolate);
v8::Isolate::Scope iscope(isolate);
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope cscope(context);
std::vector<v8::Local<v8::String>> export_names{v8_str("default")};
Local<Module> module = CreateAndInstantiateSyntheticModule(
isolate, v8_str("CreateSyntheticModule-TestSyntheticModule"), context,
export_names, UnexpectedSyntheticModuleEvaluationStepsCallback);
i::Handle<i::SyntheticModule> i_module =
i::Handle<i::SyntheticModule>::cast(v8::Utils::OpenHandle(*module));
i::Handle<i::ObjectHashTable> exports(i_module->exports(), i_isolate);
i::Handle<i::String> default_name =
i_isolate->factory()->NewStringFromAsciiChecked("default");
CHECK(
i::Handle<i::Object>(exports->Lookup(default_name), i_isolate)->IsCell());
CHECK(i::Handle<i::Cell>::cast(
i::Handle<i::Object>(exports->Lookup(default_name), i_isolate))
->value()
.IsUndefined());
CHECK_EQ(i_module->export_names().length(), 1);
CHECK(i::String::cast(i_module->export_names().get(0)).Equals(*default_name));
CHECK_EQ(i_module->status(), i::Module::kInstantiated);
}
TEST(SyntheticModuleSetExports) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
auto i_isolate = reinterpret_cast<i::Isolate*>(isolate);
v8::Isolate::Scope iscope(isolate);
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope cscope(context);
Local<String> foo_string = v8_str("foo");
Local<String> bar_string = v8_str("bar");
std::vector<v8::Local<v8::String>> export_names{foo_string};
Local<Module> module = CreateAndInstantiateSyntheticModule(
isolate, v8_str("SyntheticModuleSetExports-TestSyntheticModule"), context,
export_names, UnexpectedSyntheticModuleEvaluationStepsCallback);
i::Handle<i::SyntheticModule> i_module =
i::Handle<i::SyntheticModule>::cast(v8::Utils::OpenHandle(*module));
i::Handle<i::ObjectHashTable> exports(i_module->exports(), i_isolate);
i::Handle<i::Cell> foo_cell = i::Handle<i::Cell>::cast(i::Handle<i::Object>(
exports->Lookup(v8::Utils::OpenHandle(*foo_string)), i_isolate));
// During Instantiation there should be a Cell for the export initialized to
// undefined.
CHECK(foo_cell->value().IsUndefined());
module->SetSyntheticModuleExport(foo_string, bar_string);
// After setting the export the Cell should still have the same idenitity.
CHECK_EQ(exports->Lookup(v8::Utils::OpenHandle(*foo_string)), *foo_cell);
// Test that the export value was actually set.
CHECK(i::Handle<i::String>::cast(
i::Handle<i::Object>(foo_cell->value(), i_isolate))
->Equals(*v8::Utils::OpenHandle(*bar_string)));
}
// Tests that the code cache does not confuse the same source code compiled as a
// script and as a module.
TEST(CodeCacheModuleScriptMismatch) {
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment