Commit aa6db9d9 authored by adamk's avatar adamk Committed by Commit bot

[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}
parent 61a6b6f2
...@@ -1070,6 +1070,26 @@ class V8_EXPORT UnboundScript { ...@@ -1070,6 +1070,26 @@ class V8_EXPORT UnboundScript {
static const int kNoScriptId = 0; 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 * A compiled JavaScript script, tied to a Context which was active when the
...@@ -1373,18 +1393,17 @@ class V8_EXPORT ScriptCompiler { ...@@ -1373,18 +1393,17 @@ class V8_EXPORT ScriptCompiler {
static uint32_t CachedDataVersionTag(); static uint32_t CachedDataVersionTag();
/** /**
* Compile an ES6 module.
*
* This is an unfinished experimental feature, and is only exposed * This is an unfinished experimental feature, and is only exposed
* here for internal testing purposes. * here for internal testing purposes. DO NOT USE.
* Only parsing works at the moment. Do not use.
* *
* TODO(adamk): Script is likely the wrong return value for this; * Compile an ES module, returning a Module that encapsulates
* should return some new Module type. * the compiled code.
*
* Corresponds to the ParseModule abstract operation in the
* ECMAScript specification.
*/ */
static V8_WARN_UNUSED_RESULT MaybeLocal<Script> CompileModule( static V8_WARN_UNUSED_RESULT MaybeLocal<Module> CompileModule(
Local<Context> context, Source* source, Isolate* isolate, Source* source);
CompileOptions options = kNoCompileOptions);
/** /**
* Compile a function for a given context. This is equivalent to running * Compile a function for a given context. This is equivalent to running
......
...@@ -1858,20 +1858,10 @@ MaybeLocal<Value> Script::Run(Local<Context> context) { ...@@ -1858,20 +1858,10 @@ MaybeLocal<Value> Script::Run(Local<Context> context) {
i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate); i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
auto fun = i::Handle<i::JSFunction>::cast(Utils::OpenHandle(this)); 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; Local<Value> result;
has_pending_exception = !ToLocal<Value>(
if (fun->shared()->scope_info()->scope_type() == i::MODULE_SCOPE) { i::Execution::Call(isolate, fun, receiver, 0, nullptr), &result);
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);
}
RETURN_ON_FAILED_EXECUTION(Value); RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result); RETURN_ESCAPED(result);
...@@ -1894,6 +1884,51 @@ Local<UnboundScript> Script::GetUnboundScript() { ...@@ -1894,6 +1884,51 @@ Local<UnboundScript> Script::GetUnboundScript() {
i::Handle<i::SharedFunctionInfo>(i::JSFunction::cast(*obj)->shared())); 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( MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
Isolate* v8_isolate, Source* source, CompileOptions options, Isolate* v8_isolate, Source* source, CompileOptions options,
...@@ -2004,32 +2039,22 @@ Local<Script> ScriptCompiler::Compile( ...@@ -2004,32 +2039,22 @@ Local<Script> ScriptCompiler::Compile(
RETURN_TO_LOCAL_UNCHECKED(Compile(context, source, options), Script); RETURN_TO_LOCAL_UNCHECKED(Compile(context, source, options), Script);
} }
MaybeLocal<Module> ScriptCompiler::CompileModule(Isolate* isolate,
MaybeLocal<Script> ScriptCompiler::CompileModule(Local<Context> context, Source* source) {
Source* source,
CompileOptions options) {
auto isolate = context->GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
auto maybe = CompileUnboundInternal(isolate, source, options, true); auto maybe = CompileUnboundInternal(isolate, source, kNoCompileOptions, true);
Local<UnboundScript> generic; Local<UnboundScript> unbound;
if (!maybe.ToLocal(&generic)) return MaybeLocal<Script>(); if (!maybe.ToLocal(&unbound)) return MaybeLocal<Module>();
v8::Context::Scope scope(context);
auto result = generic->BindToCurrentContext();
i::Handle<i::SharedFunctionInfo> shared = Utils::OpenHandle(*generic); i::Handle<i::SharedFunctionInfo> shared = Utils::OpenHandle(*unbound);
i::Handle<i::FixedArray> regular_exports = i::Handle<i::FixedArray> regular_exports =
i::handle(shared->scope_info()->ModuleDescriptorInfo()->regular_exports(), i::handle(shared->scope_info()->ModuleDescriptorInfo()->regular_exports(),
i_isolate); i_isolate);
int regular_exports_length = regular_exports->length(); int regular_exports_length = regular_exports->length();
i::Handle<i::Module> module = i::Handle<i::Module> module =
i_isolate->factory()->NewModule(regular_exports_length); i_isolate->factory()->NewModule(shared, 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);
// TODO(neis): This will create multiple cells for the same local variable if // 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 // exported under multiple names, which is wrong but cannot be observed at the
...@@ -2044,7 +2069,7 @@ MaybeLocal<Script> ScriptCompiler::CompileModule(Local<Context> context, ...@@ -2044,7 +2069,7 @@ MaybeLocal<Script> ScriptCompiler::CompileModule(Local<Context> context,
i::Module::CreateExport(module, export_name); i::Module::CreateExport(module, export_name);
} }
return result; return ToApiHandle<Module>(module);
} }
......
...@@ -69,7 +69,6 @@ class RegisteredExtension { ...@@ -69,7 +69,6 @@ class RegisteredExtension {
static RegisteredExtension* first_extension_; static RegisteredExtension* first_extension_;
}; };
#define OPEN_HANDLE_LIST(V) \ #define OPEN_HANDLE_LIST(V) \
V(Template, TemplateInfo) \ V(Template, TemplateInfo) \
V(FunctionTemplate, FunctionTemplateInfo) \ V(FunctionTemplate, FunctionTemplateInfo) \
...@@ -101,6 +100,7 @@ class RegisteredExtension { ...@@ -101,6 +100,7 @@ class RegisteredExtension {
V(Symbol, Symbol) \ V(Symbol, Symbol) \
V(Script, JSFunction) \ V(Script, JSFunction) \
V(UnboundScript, SharedFunctionInfo) \ V(UnboundScript, SharedFunctionInfo) \
V(Module, Module) \
V(Function, JSReceiver) \ V(Function, JSReceiver) \
V(Message, JSMessageObject) \ V(Message, JSMessageObject) \
V(Context, Context) \ V(Context, Context) \
......
...@@ -460,18 +460,12 @@ ScriptCompiler::CachedData* CompileForCachedData( ...@@ -460,18 +460,12 @@ ScriptCompiler::CachedData* CompileForCachedData(
// Compile a string within the current v8 context. // Compile a string within the current v8 context.
MaybeLocal<Script> Shell::CompileString( MaybeLocal<Script> Shell::CompileString(
Isolate* isolate, Local<String> source, Local<Value> name, Isolate* isolate, Local<String> source, Local<Value> name,
ScriptCompiler::CompileOptions compile_options, SourceType source_type) { ScriptCompiler::CompileOptions compile_options) {
Local<Context> context(isolate->GetCurrentContext()); Local<Context> context(isolate->GetCurrentContext());
ScriptOrigin origin(name); ScriptOrigin origin(name);
// TODO(adamk): Make use of compile options for Modules. if (compile_options == ScriptCompiler::kNoCompileOptions) {
if (compile_options == ScriptCompiler::kNoCompileOptions ||
source_type == MODULE) {
ScriptCompiler::Source script_source(source, origin); ScriptCompiler::Source script_source(source, origin);
return source_type == SCRIPT return ScriptCompiler::Compile(context, &script_source, compile_options);
? ScriptCompiler::Compile(context, &script_source,
compile_options)
: ScriptCompiler::CompileModule(context, &script_source,
compile_options);
} }
ScriptCompiler::CachedData* data = ScriptCompiler::CachedData* data =
...@@ -485,7 +479,6 @@ MaybeLocal<Script> Shell::CompileString( ...@@ -485,7 +479,6 @@ MaybeLocal<Script> Shell::CompileString(
DCHECK(false); // A new compile option? DCHECK(false); // A new compile option?
} }
if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions; if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
DCHECK_EQ(SCRIPT, source_type);
MaybeLocal<Script> result = MaybeLocal<Script> result =
ScriptCompiler::Compile(context, &cached_source, compile_options); ScriptCompiler::Compile(context, &cached_source, compile_options);
CHECK(data == NULL || !data->rejected); CHECK(data == NULL || !data->rejected);
...@@ -507,14 +500,31 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source, ...@@ -507,14 +500,31 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
Local<Context> realm = Local<Context> realm =
Local<Context>::New(isolate, data->realms_[data->realm_current_]); Local<Context>::New(isolate, data->realms_[data->realm_current_]);
Context::Scope context_scope(realm); Context::Scope context_scope(realm);
Local<Script> script; if (source_type == SCRIPT) {
if (!Shell::CompileString(isolate, source, name, options.compile_options, Local<Script> script;
source_type).ToLocal(&script)) { if (!Shell::CompileString(isolate, source, name, options.compile_options)
// Print errors that happened during compilation. .ToLocal(&script)) {
if (report_exceptions) ReportException(isolate, &try_catch); // Print errors that happened during compilation.
return false; 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); EmptyMessageQueues(isolate);
data->realm_current_ = data->realm_switch_; data->realm_current_ = data->realm_switch_;
} }
......
...@@ -335,8 +335,7 @@ class Shell : public i::AllStatic { ...@@ -335,8 +335,7 @@ class Shell : public i::AllStatic {
static MaybeLocal<Script> CompileString( static MaybeLocal<Script> CompileString(
Isolate* isolate, Local<String> source, Local<Value> name, Isolate* isolate, Local<String> source, Local<Value> name,
v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::CompileOptions compile_options);
SourceType source_type);
static bool ExecuteString(Isolate* isolate, Local<String> source, static bool ExecuteString(Isolate* isolate, Local<String> source,
Local<Value> name, bool print_result, Local<Value> name, bool print_result,
bool report_exceptions, bool report_exceptions,
......
...@@ -1705,9 +1705,11 @@ Handle<JSGeneratorObject> Factory::NewJSGeneratorObject( ...@@ -1705,9 +1705,11 @@ Handle<JSGeneratorObject> Factory::NewJSGeneratorObject(
JSGeneratorObject); JSGeneratorObject);
} }
Handle<Module> Factory::NewModule(int min_size) { Handle<Module> Factory::NewModule(Handle<SharedFunctionInfo> code,
Handle<Module> module = Handle<Module>::cast(NewStruct(MODULE_TYPE)); int min_size) {
Handle<ObjectHashTable> exports = ObjectHashTable::New(isolate(), 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); module->set_exports(*exports);
return module; return module;
} }
......
...@@ -477,7 +477,7 @@ class Factory final { ...@@ -477,7 +477,7 @@ class Factory final {
Handle<JSGeneratorObject> NewJSGeneratorObject(Handle<JSFunction> function); Handle<JSGeneratorObject> NewJSGeneratorObject(Handle<JSFunction> function);
Handle<Module> NewModule(int min_size); Handle<Module> NewModule(Handle<SharedFunctionInfo> code, int min_size);
Handle<JSArrayBuffer> NewJSArrayBuffer( Handle<JSArrayBuffer> NewJSArrayBuffer(
SharedFlag shared = SharedFlag::kNotShared, SharedFlag shared = SharedFlag::kNotShared,
......
...@@ -901,6 +901,8 @@ void Box::BoxVerify() { ...@@ -901,6 +901,8 @@ void Box::BoxVerify() {
void Module::ModuleVerify() { void Module::ModuleVerify() {
CHECK(IsModule()); CHECK(IsModule());
CHECK(code()->IsSharedFunctionInfo() || code()->IsJSFunction());
code()->ObjectVerify();
exports()->ObjectVerify(); exports()->ObjectVerify();
// TODO(neis): Check more. // TODO(neis): Check more.
} }
......
...@@ -5701,6 +5701,7 @@ BOOL_ACCESSORS(PrototypeInfo, bit_field, should_be_fast_map, kShouldBeFastBit) ...@@ -5701,6 +5701,7 @@ BOOL_ACCESSORS(PrototypeInfo, bit_field, should_be_fast_map, kShouldBeFastBit)
ACCESSORS(ContextExtension, scope_info, ScopeInfo, kScopeInfoOffset) ACCESSORS(ContextExtension, scope_info, ScopeInfo, kScopeInfoOffset)
ACCESSORS(ContextExtension, extension, Object, kExtensionOffset) ACCESSORS(ContextExtension, extension, Object, kExtensionOffset)
ACCESSORS(Module, code, Object, kCodeOffset)
ACCESSORS(Module, exports, ObjectHashTable, kExportsOffset) ACCESSORS(Module, exports, ObjectHashTable, kExportsOffset)
ACCESSORS(AccessorPair, getter, Object, kGetterOffset) ACCESSORS(AccessorPair, getter, Object, kGetterOffset)
......
...@@ -1147,6 +1147,7 @@ void Box::BoxPrint(std::ostream& os) { // NOLINT ...@@ -1147,6 +1147,7 @@ void Box::BoxPrint(std::ostream& os) { // NOLINT
void Module::ModulePrint(std::ostream& os) { // NOLINT void Module::ModulePrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "Module"); HeapObject::PrintHeader(os, "Module");
os << "\n - code: " << Brief(code());
os << "\n - exports: " << Brief(exports()); os << "\n - exports: " << Brief(exports());
os << "\n"; os << "\n";
} }
......
...@@ -7871,6 +7871,11 @@ class Module : public Struct { ...@@ -7871,6 +7871,11 @@ class Module : public Struct {
DECLARE_VERIFIER(Module) DECLARE_VERIFIER(Module)
DECLARE_PRINTER(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) DECL_ACCESSORS(exports, ObjectHashTable)
static void CreateExport(Handle<Module> module, Handle<String> name); static void CreateExport(Handle<Module> module, Handle<String> name);
...@@ -7878,7 +7883,8 @@ class Module : public Struct { ...@@ -7878,7 +7883,8 @@ class Module : public Struct {
Handle<Object> value); Handle<Object> value);
static Handle<Object> LoadExport(Handle<Module> module, Handle<String> name); 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; static const int kSize = kExportsOffset + kPointerSize;
private: private:
......
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