[modules] Introduce v8::Module to the API and return it from CompileModule
R=neis@chromium.org BUG=v8:1569 Review-Url: https://codereview.chromium.org/2347933002 Cr-Commit-Position: refs/heads/master@{#39481}
This commit is contained in:
parent
61a6b6f236
commit
aa6db9d990
37
include/v8.h
37
include/v8.h
@ -1070,6 +1070,26 @@ class V8_EXPORT UnboundScript {
|
||||
static const int kNoScriptId = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an unfinished experimental feature, and is only exposed
|
||||
* here for internal testing purposes. DO NOT USE.
|
||||
*
|
||||
* A compiled JavaScript module.
|
||||
*/
|
||||
class V8_EXPORT Module {
|
||||
public:
|
||||
/**
|
||||
* ModuleDeclarationInstantiation
|
||||
*
|
||||
* Returns false if an exception occurred during instantiation.
|
||||
*/
|
||||
V8_WARN_UNUSED_RESULT bool Instantiate(Local<Context> context);
|
||||
|
||||
/**
|
||||
* ModuleEvaluation
|
||||
*/
|
||||
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Evaluate(Local<Context> context);
|
||||
};
|
||||
|
||||
/**
|
||||
* A compiled JavaScript script, tied to a Context which was active when the
|
||||
@ -1373,18 +1393,17 @@ class V8_EXPORT ScriptCompiler {
|
||||
static uint32_t CachedDataVersionTag();
|
||||
|
||||
/**
|
||||
* Compile an ES6 module.
|
||||
*
|
||||
* This is an unfinished experimental feature, and is only exposed
|
||||
* here for internal testing purposes.
|
||||
* Only parsing works at the moment. Do not use.
|
||||
* here for internal testing purposes. DO NOT USE.
|
||||
*
|
||||
* TODO(adamk): Script is likely the wrong return value for this;
|
||||
* should return some new Module type.
|
||||
* Compile an ES module, returning a Module that encapsulates
|
||||
* the compiled code.
|
||||
*
|
||||
* Corresponds to the ParseModule abstract operation in the
|
||||
* ECMAScript specification.
|
||||
*/
|
||||
static V8_WARN_UNUSED_RESULT MaybeLocal<Script> CompileModule(
|
||||
Local<Context> context, Source* source,
|
||||
CompileOptions options = kNoCompileOptions);
|
||||
static V8_WARN_UNUSED_RESULT MaybeLocal<Module> CompileModule(
|
||||
Isolate* isolate, Source* source);
|
||||
|
||||
/**
|
||||
* Compile a function for a given context. This is equivalent to running
|
||||
|
87
src/api.cc
87
src/api.cc
@ -1858,20 +1858,10 @@ MaybeLocal<Value> Script::Run(Local<Context> context) {
|
||||
i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
|
||||
auto fun = i::Handle<i::JSFunction>::cast(Utils::OpenHandle(this));
|
||||
|
||||
i::Handle<i::Object> receiver;
|
||||
i::Handle<i::Object> receiver = isolate->global_proxy();
|
||||
Local<Value> result;
|
||||
|
||||
if (fun->shared()->scope_info()->scope_type() == i::MODULE_SCOPE) {
|
||||
receiver = isolate->factory()->undefined_value();
|
||||
i::Handle<i::Object> argv[] = {
|
||||
handle(isolate->native_context()->current_module())};
|
||||
has_pending_exception = !ToLocal<Value>(
|
||||
i::Execution::Call(isolate, fun, receiver, 1, argv), &result);
|
||||
} else {
|
||||
receiver = isolate->global_proxy();
|
||||
has_pending_exception = !ToLocal<Value>(
|
||||
i::Execution::Call(isolate, fun, receiver, 0, nullptr), &result);
|
||||
}
|
||||
has_pending_exception = !ToLocal<Value>(
|
||||
i::Execution::Call(isolate, fun, receiver, 0, nullptr), &result);
|
||||
|
||||
RETURN_ON_FAILED_EXECUTION(Value);
|
||||
RETURN_ESCAPED(result);
|
||||
@ -1894,6 +1884,51 @@ Local<UnboundScript> Script::GetUnboundScript() {
|
||||
i::Handle<i::SharedFunctionInfo>(i::JSFunction::cast(*obj)->shared()));
|
||||
}
|
||||
|
||||
bool Module::Instantiate(Local<Context> v8_context) {
|
||||
i::Handle<i::Module> self = Utils::OpenHandle(this);
|
||||
i::Isolate* isolate = self->GetIsolate();
|
||||
|
||||
// Already instantiated.
|
||||
if (self->code()->IsJSFunction()) return true;
|
||||
|
||||
i::Handle<i::SharedFunctionInfo> shared(
|
||||
i::SharedFunctionInfo::cast(self->code()), isolate);
|
||||
i::Handle<i::Context> context = Utils::OpenHandle(*v8_context);
|
||||
i::Handle<i::JSFunction> function =
|
||||
isolate->factory()->NewFunctionFromSharedFunctionInfo(
|
||||
shared, handle(context->native_context(), isolate));
|
||||
self->set_code(*function);
|
||||
|
||||
// TODO(adamk): This could fail in the future when Instantiate
|
||||
// does linking.
|
||||
return true;
|
||||
}
|
||||
|
||||
MaybeLocal<Value> Module::Evaluate(Local<Context> context) {
|
||||
PREPARE_FOR_EXECUTION_WITH_CONTEXT_IN_RUNTIME_CALL_STATS_SCOPE(
|
||||
"v8", "V8.Execute", context, Script, Run, MaybeLocal<Value>(),
|
||||
InternalEscapableScope, true);
|
||||
i::HistogramTimerScope execute_timer(isolate->counters()->execute(), true);
|
||||
i::AggregatingHistogramTimerScope timer(isolate->counters()->compile_lazy());
|
||||
i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
|
||||
|
||||
i::Handle<i::Module> self = Utils::OpenHandle(this);
|
||||
// It's an API error to call Evaluate before Instantiate.
|
||||
CHECK(self->code()->IsJSFunction());
|
||||
|
||||
i::Handle<i::JSFunction> function(i::JSFunction::cast(self->code()), isolate);
|
||||
DCHECK_EQ(i::MODULE_SCOPE, function->shared()->scope_info()->scope_type());
|
||||
i::Handle<i::Object> receiver = isolate->factory()->undefined_value();
|
||||
|
||||
Local<Value> result;
|
||||
i::Handle<i::Object> argv[] = {self};
|
||||
has_pending_exception = !ToLocal<Value>(
|
||||
i::Execution::Call(isolate, function, receiver, arraysize(argv), argv),
|
||||
&result);
|
||||
|
||||
RETURN_ON_FAILED_EXECUTION(Value);
|
||||
RETURN_ESCAPED(result);
|
||||
}
|
||||
|
||||
MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
|
||||
Isolate* v8_isolate, Source* source, CompileOptions options,
|
||||
@ -2004,32 +2039,22 @@ Local<Script> ScriptCompiler::Compile(
|
||||
RETURN_TO_LOCAL_UNCHECKED(Compile(context, source, options), Script);
|
||||
}
|
||||
|
||||
|
||||
MaybeLocal<Script> ScriptCompiler::CompileModule(Local<Context> context,
|
||||
Source* source,
|
||||
CompileOptions options) {
|
||||
auto isolate = context->GetIsolate();
|
||||
MaybeLocal<Module> ScriptCompiler::CompileModule(Isolate* isolate,
|
||||
Source* source) {
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
|
||||
auto maybe = CompileUnboundInternal(isolate, source, options, true);
|
||||
Local<UnboundScript> generic;
|
||||
if (!maybe.ToLocal(&generic)) return MaybeLocal<Script>();
|
||||
v8::Context::Scope scope(context);
|
||||
auto result = generic->BindToCurrentContext();
|
||||
auto maybe = CompileUnboundInternal(isolate, source, kNoCompileOptions, true);
|
||||
Local<UnboundScript> unbound;
|
||||
if (!maybe.ToLocal(&unbound)) return MaybeLocal<Module>();
|
||||
|
||||
i::Handle<i::SharedFunctionInfo> shared = Utils::OpenHandle(*generic);
|
||||
i::Handle<i::SharedFunctionInfo> shared = Utils::OpenHandle(*unbound);
|
||||
i::Handle<i::FixedArray> regular_exports =
|
||||
i::handle(shared->scope_info()->ModuleDescriptorInfo()->regular_exports(),
|
||||
i_isolate);
|
||||
int regular_exports_length = regular_exports->length();
|
||||
|
||||
i::Handle<i::Module> module =
|
||||
i_isolate->factory()->NewModule(regular_exports_length);
|
||||
|
||||
// TODO(neis): Storing the module into the native context is a temporary hack
|
||||
// to pass it to the Script::Run function. This will be removed once we
|
||||
// support modules in the API.
|
||||
i_isolate->native_context()->set_current_module(*module);
|
||||
i_isolate->factory()->NewModule(shared, regular_exports_length);
|
||||
|
||||
// TODO(neis): This will create multiple cells for the same local variable if
|
||||
// exported under multiple names, which is wrong but cannot be observed at the
|
||||
@ -2044,7 +2069,7 @@ MaybeLocal<Script> ScriptCompiler::CompileModule(Local<Context> context,
|
||||
i::Module::CreateExport(module, export_name);
|
||||
}
|
||||
|
||||
return result;
|
||||
return ToApiHandle<Module>(module);
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,7 +69,6 @@ class RegisteredExtension {
|
||||
static RegisteredExtension* first_extension_;
|
||||
};
|
||||
|
||||
|
||||
#define OPEN_HANDLE_LIST(V) \
|
||||
V(Template, TemplateInfo) \
|
||||
V(FunctionTemplate, FunctionTemplateInfo) \
|
||||
@ -101,6 +100,7 @@ class RegisteredExtension {
|
||||
V(Symbol, Symbol) \
|
||||
V(Script, JSFunction) \
|
||||
V(UnboundScript, SharedFunctionInfo) \
|
||||
V(Module, Module) \
|
||||
V(Function, JSReceiver) \
|
||||
V(Message, JSMessageObject) \
|
||||
V(Context, Context) \
|
||||
|
44
src/d8.cc
44
src/d8.cc
@ -460,18 +460,12 @@ ScriptCompiler::CachedData* CompileForCachedData(
|
||||
// Compile a string within the current v8 context.
|
||||
MaybeLocal<Script> Shell::CompileString(
|
||||
Isolate* isolate, Local<String> source, Local<Value> name,
|
||||
ScriptCompiler::CompileOptions compile_options, SourceType source_type) {
|
||||
ScriptCompiler::CompileOptions compile_options) {
|
||||
Local<Context> context(isolate->GetCurrentContext());
|
||||
ScriptOrigin origin(name);
|
||||
// TODO(adamk): Make use of compile options for Modules.
|
||||
if (compile_options == ScriptCompiler::kNoCompileOptions ||
|
||||
source_type == MODULE) {
|
||||
if (compile_options == ScriptCompiler::kNoCompileOptions) {
|
||||
ScriptCompiler::Source script_source(source, origin);
|
||||
return source_type == SCRIPT
|
||||
? ScriptCompiler::Compile(context, &script_source,
|
||||
compile_options)
|
||||
: ScriptCompiler::CompileModule(context, &script_source,
|
||||
compile_options);
|
||||
return ScriptCompiler::Compile(context, &script_source, compile_options);
|
||||
}
|
||||
|
||||
ScriptCompiler::CachedData* data =
|
||||
@ -485,7 +479,6 @@ MaybeLocal<Script> Shell::CompileString(
|
||||
DCHECK(false); // A new compile option?
|
||||
}
|
||||
if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
|
||||
DCHECK_EQ(SCRIPT, source_type);
|
||||
MaybeLocal<Script> result =
|
||||
ScriptCompiler::Compile(context, &cached_source, compile_options);
|
||||
CHECK(data == NULL || !data->rejected);
|
||||
@ -507,14 +500,31 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
|
||||
Local<Context> realm =
|
||||
Local<Context>::New(isolate, data->realms_[data->realm_current_]);
|
||||
Context::Scope context_scope(realm);
|
||||
Local<Script> script;
|
||||
if (!Shell::CompileString(isolate, source, name, options.compile_options,
|
||||
source_type).ToLocal(&script)) {
|
||||
// Print errors that happened during compilation.
|
||||
if (report_exceptions) ReportException(isolate, &try_catch);
|
||||
return false;
|
||||
if (source_type == SCRIPT) {
|
||||
Local<Script> script;
|
||||
if (!Shell::CompileString(isolate, source, name, options.compile_options)
|
||||
.ToLocal(&script)) {
|
||||
// Print errors that happened during compilation.
|
||||
if (report_exceptions) ReportException(isolate, &try_catch);
|
||||
return false;
|
||||
}
|
||||
maybe_result = script->Run(realm);
|
||||
} else {
|
||||
DCHECK_EQ(MODULE, source_type);
|
||||
Local<Module> module;
|
||||
ScriptOrigin origin(name);
|
||||
ScriptCompiler::Source script_source(source, origin);
|
||||
// TODO(adamk): Make use of compile options for Modules.
|
||||
if (!ScriptCompiler::CompileModule(isolate, &script_source)
|
||||
.ToLocal(&module)) {
|
||||
// Print errors that happened during compilation.
|
||||
if (report_exceptions) ReportException(isolate, &try_catch);
|
||||
return false;
|
||||
}
|
||||
// This can't fail until we support linking.
|
||||
CHECK(module->Instantiate(realm));
|
||||
maybe_result = module->Evaluate(realm);
|
||||
}
|
||||
maybe_result = script->Run(realm);
|
||||
EmptyMessageQueues(isolate);
|
||||
data->realm_current_ = data->realm_switch_;
|
||||
}
|
||||
|
3
src/d8.h
3
src/d8.h
@ -335,8 +335,7 @@ class Shell : public i::AllStatic {
|
||||
|
||||
static MaybeLocal<Script> CompileString(
|
||||
Isolate* isolate, Local<String> source, Local<Value> name,
|
||||
v8::ScriptCompiler::CompileOptions compile_options,
|
||||
SourceType source_type);
|
||||
v8::ScriptCompiler::CompileOptions compile_options);
|
||||
static bool ExecuteString(Isolate* isolate, Local<String> source,
|
||||
Local<Value> name, bool print_result,
|
||||
bool report_exceptions,
|
||||
|
@ -1705,9 +1705,11 @@ Handle<JSGeneratorObject> Factory::NewJSGeneratorObject(
|
||||
JSGeneratorObject);
|
||||
}
|
||||
|
||||
Handle<Module> Factory::NewModule(int min_size) {
|
||||
Handle<Module> module = Handle<Module>::cast(NewStruct(MODULE_TYPE));
|
||||
Handle<Module> Factory::NewModule(Handle<SharedFunctionInfo> code,
|
||||
int min_size) {
|
||||
Handle<ObjectHashTable> exports = ObjectHashTable::New(isolate(), min_size);
|
||||
Handle<Module> module = Handle<Module>::cast(NewStruct(MODULE_TYPE));
|
||||
module->set_code(*code);
|
||||
module->set_exports(*exports);
|
||||
return module;
|
||||
}
|
||||
|
@ -477,7 +477,7 @@ class Factory final {
|
||||
|
||||
Handle<JSGeneratorObject> NewJSGeneratorObject(Handle<JSFunction> function);
|
||||
|
||||
Handle<Module> NewModule(int min_size);
|
||||
Handle<Module> NewModule(Handle<SharedFunctionInfo> code, int min_size);
|
||||
|
||||
Handle<JSArrayBuffer> NewJSArrayBuffer(
|
||||
SharedFlag shared = SharedFlag::kNotShared,
|
||||
|
@ -901,6 +901,8 @@ void Box::BoxVerify() {
|
||||
|
||||
void Module::ModuleVerify() {
|
||||
CHECK(IsModule());
|
||||
CHECK(code()->IsSharedFunctionInfo() || code()->IsJSFunction());
|
||||
code()->ObjectVerify();
|
||||
exports()->ObjectVerify();
|
||||
// TODO(neis): Check more.
|
||||
}
|
||||
|
@ -5701,6 +5701,7 @@ BOOL_ACCESSORS(PrototypeInfo, bit_field, should_be_fast_map, kShouldBeFastBit)
|
||||
ACCESSORS(ContextExtension, scope_info, ScopeInfo, kScopeInfoOffset)
|
||||
ACCESSORS(ContextExtension, extension, Object, kExtensionOffset)
|
||||
|
||||
ACCESSORS(Module, code, Object, kCodeOffset)
|
||||
ACCESSORS(Module, exports, ObjectHashTable, kExportsOffset)
|
||||
|
||||
ACCESSORS(AccessorPair, getter, Object, kGetterOffset)
|
||||
|
@ -1147,6 +1147,7 @@ void Box::BoxPrint(std::ostream& os) { // NOLINT
|
||||
|
||||
void Module::ModulePrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "Module");
|
||||
os << "\n - code: " << Brief(code());
|
||||
os << "\n - exports: " << Brief(exports());
|
||||
os << "\n";
|
||||
}
|
||||
|
@ -7871,6 +7871,11 @@ class Module : public Struct {
|
||||
DECLARE_VERIFIER(Module)
|
||||
DECLARE_PRINTER(Module)
|
||||
|
||||
// The code representing this Module, either a
|
||||
// SharedFunctionInfo or a JSFunction depending
|
||||
// on whether it's been instantiated.
|
||||
DECL_ACCESSORS(code, Object)
|
||||
|
||||
DECL_ACCESSORS(exports, ObjectHashTable)
|
||||
|
||||
static void CreateExport(Handle<Module> module, Handle<String> name);
|
||||
@ -7878,7 +7883,8 @@ class Module : public Struct {
|
||||
Handle<Object> value);
|
||||
static Handle<Object> LoadExport(Handle<Module> module, Handle<String> name);
|
||||
|
||||
static const int kExportsOffset = HeapObject::kHeaderSize;
|
||||
static const int kCodeOffset = HeapObject::kHeaderSize;
|
||||
static const int kExportsOffset = kCodeOffset + kPointerSize;
|
||||
static const int kSize = kExportsOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user