Skip to content

Commit 94283dc

Browse files
gsathyaCommit bot
authored andcommitted
[ESNext] Implement DynamicImportCall
This patch implements the runtime semantics of dynamic import. We create a new ASTNode so that we can pass the JSFunction closure() to the runtime function from which we get the script_url. d8 implements the embedder logic required to load and evaluate the modules. The API is mostly implemented as specified. BUG=8:5785 Review-Url: https://codereview.chromium.org/2703563002 Cr-Commit-Position: refs/heads/master@{#44551}
1 parent 81c7135 commit 94283dc

58 files changed

Lines changed: 905 additions & 52 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

include/v8.h

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,28 @@ class V8_EXPORT Module {
11051105
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Evaluate(Local<Context> context);
11061106
};
11071107

1108+
/**
1109+
* This is an unfinished experimental feature, and is only exposed
1110+
* here for internal testing purposes. DO NOT USE.
1111+
*
1112+
* A compiled JavaScript module.
1113+
*/
1114+
class V8_EXPORT DynamicImportResult {
1115+
public:
1116+
/**
1117+
* Resolves the promise with the namespace object of the given
1118+
* module.
1119+
*/
1120+
V8_WARN_UNUSED_RESULT bool FinishDynamicImportSuccess(Local<Context> context,
1121+
Local<Module> module);
1122+
1123+
/**
1124+
* Rejects the promise with the given exception.
1125+
*/
1126+
V8_WARN_UNUSED_RESULT bool FinishDynamicImportFailure(Local<Context> context,
1127+
Local<Value> exception);
1128+
};
1129+
11081130
/**
11091131
* A compiled JavaScript script, tied to a Context which was active when the
11101132
* script was compiled.
@@ -5948,6 +5970,25 @@ typedef void (*BeforeCallEnteredCallback)(Isolate*);
59485970
typedef void (*CallCompletedCallback)(Isolate*);
59495971
typedef void (*DeprecatedCallCompletedCallback)();
59505972

5973+
/**
5974+
* HostImportDynamicallyCallback is called when we require the
5975+
* embedder to load a module. This is used as part of the dynamic
5976+
* import syntax. The behavior of this callback is not specified in
5977+
* EcmaScript.
5978+
*
5979+
* The referrer is the name of the file which calls the dynamic
5980+
* import. The referrer can be used to resolve the module location.
5981+
*
5982+
* The specifier is the name of the module that should be imported.
5983+
*
5984+
* The DynamicImportResult object is used to signal success or failure
5985+
* by calling it's respective methods.
5986+
*
5987+
*/
5988+
typedef void (*HostImportModuleDynamicallyCallback)(
5989+
Isolate* isolate, Local<String> referrer, Local<String> specifier,
5990+
Local<DynamicImportResult> result);
5991+
59515992
/**
59525993
* PromiseHook with type kInit is called when a new promise is
59535994
* created. When a new promise is created as part of the chain in the
@@ -6495,7 +6536,8 @@ class V8_EXPORT Isolate {
64956536
add_histogram_sample_callback(nullptr),
64966537
array_buffer_allocator(nullptr),
64976538
external_references(nullptr),
6498-
allow_atomics_wait(true) {}
6539+
allow_atomics_wait(true),
6540+
host_import_module_dynamically_callback_(nullptr) {}
64996541

65006542
/**
65016543
* The optional entry_hook allows the host application to provide the
@@ -6558,6 +6600,16 @@ class V8_EXPORT Isolate {
65586600
* this isolate.
65596601
*/
65606602
bool allow_atomics_wait;
6603+
6604+
/**
6605+
* This is an unfinished experimental feature, and is only exposed
6606+
* here for internal testing purposes. DO NOT USE.
6607+
*
6608+
* This specifies the callback called by the upcoming dynamic
6609+
* import() language feature to load modules.
6610+
*/
6611+
HostImportModuleDynamicallyCallback
6612+
host_import_module_dynamically_callback_;
65616613
};
65626614

65636615

src/api.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,39 @@ Local<UnboundScript> Script::GetUnboundScript() {
20442044
i::Handle<i::SharedFunctionInfo>(i::JSFunction::cast(*obj)->shared()));
20452045
}
20462046

2047+
bool DynamicImportResult::FinishDynamicImportSuccess(Local<Context> context,
2048+
Local<Module> module) {
2049+
PREPARE_FOR_EXECUTION_BOOL(context, Module, FinishDynamicImportSuccess);
2050+
auto promise = Utils::OpenHandle(this);
2051+
i::Handle<i::Module> module_obj = Utils::OpenHandle(*module);
2052+
i::Handle<i::JSModuleNamespace> module_namespace =
2053+
i::Module::GetModuleNamespace(module_obj);
2054+
i::Handle<i::Object> argv[] = {promise, module_namespace};
2055+
has_pending_exception =
2056+
i::Execution::Call(isolate, isolate->promise_resolve(),
2057+
isolate->factory()->undefined_value(), arraysize(argv),
2058+
argv)
2059+
.is_null();
2060+
RETURN_ON_FAILED_EXECUTION_BOOL();
2061+
return true;
2062+
}
2063+
2064+
bool DynamicImportResult::FinishDynamicImportFailure(Local<Context> context,
2065+
Local<Value> exception) {
2066+
PREPARE_FOR_EXECUTION_BOOL(context, Module, FinishDynamicImportFailure);
2067+
auto promise = Utils::OpenHandle(this);
2068+
// We pass true to trigger the debugger's on exception handler.
2069+
i::Handle<i::Object> argv[] = {promise, Utils::OpenHandle(*exception),
2070+
isolate->factory()->ToBoolean(true)};
2071+
has_pending_exception =
2072+
i::Execution::Call(isolate, isolate->promise_internal_reject(),
2073+
isolate->factory()->undefined_value(), arraysize(argv),
2074+
argv)
2075+
.is_null();
2076+
RETURN_ON_FAILED_EXECUTION_BOOL();
2077+
return true;
2078+
}
2079+
20472080
int Module::GetModuleRequestsLength() const {
20482081
i::Handle<i::Module> self = Utils::OpenHandle(this);
20492082
return self->info()->module_requests()->length();
@@ -8231,6 +8264,12 @@ Isolate* IsolateNewImpl(internal::Isolate* isolate,
82318264

82328265
isolate->set_api_external_references(params.external_references);
82338266
isolate->set_allow_atomics_wait(params.allow_atomics_wait);
8267+
8268+
if (params.host_import_module_dynamically_callback_ != nullptr) {
8269+
isolate->SetHostImportModuleDynamicallyCallback(
8270+
params.host_import_module_dynamically_callback_);
8271+
}
8272+
82348273
SetResourceConstraints(isolate, params.constraints);
82358274
// TODO(jochen): Once we got rid of Isolate::Current(), we can remove this.
82368275
Isolate::Scope isolate_scope(v8_isolate);

src/api.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ class RegisteredExtension {
111111
V(NativeWeakMap, JSWeakMap) \
112112
V(debug::GeneratorObject, JSGeneratorObject) \
113113
V(debug::Script, Script) \
114-
V(Promise, JSPromise)
114+
V(Promise, JSPromise) \
115+
V(DynamicImportResult, JSPromise)
115116

116117
class Utils {
117118
public:
@@ -185,6 +186,8 @@ class Utils {
185186
v8::internal::Handle<v8::internal::Object> obj);
186187
static inline Local<Promise> PromiseToLocal(
187188
v8::internal::Handle<v8::internal::JSObject> obj);
189+
static inline Local<DynamicImportResult> PromiseToDynamicImportResult(
190+
v8::internal::Handle<v8::internal::JSPromise> obj);
188191
static inline Local<StackTrace> StackTraceToLocal(
189192
v8::internal::Handle<v8::internal::JSArray> obj);
190193
static inline Local<StackFrame> StackFrameToLocal(
@@ -317,6 +320,7 @@ MAKE_TO_LOCAL(SignatureToLocal, FunctionTemplateInfo, Signature)
317320
MAKE_TO_LOCAL(AccessorSignatureToLocal, FunctionTemplateInfo, AccessorSignature)
318321
MAKE_TO_LOCAL(MessageToLocal, Object, Message)
319322
MAKE_TO_LOCAL(PromiseToLocal, JSObject, Promise)
323+
MAKE_TO_LOCAL(PromiseToDynamicImportResult, JSPromise, DynamicImportResult)
320324
MAKE_TO_LOCAL(StackTraceToLocal, JSArray, StackTrace)
321325
MAKE_TO_LOCAL(StackFrameToLocal, StackFrameInfo, StackFrame)
322326
MAKE_TO_LOCAL(NumberToLocal, Object, Number)

src/asmjs/asm-wasm-builder.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
302302

303303
void VisitGetIterator(GetIterator* expr) { UNREACHABLE(); }
304304

305+
void VisitImportCallExpression(ImportCallExpression* expr) { UNREACHABLE(); }
306+
305307
void VisitIfStatement(IfStatement* stmt) {
306308
DCHECK_EQ(kFuncScope, scope_);
307309
RECURSE(Visit(stmt->condition()));

src/ast/ast-expression-rewriter.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,12 @@ void AstExpressionRewriter::VisitGetIterator(GetIterator* node) {
376376
AST_REWRITE_PROPERTY(Expression, node, iterable);
377377
}
378378

379+
void AstExpressionRewriter::VisitImportCallExpression(
380+
ImportCallExpression* node) {
381+
REWRITE_THIS(node);
382+
AST_REWRITE_PROPERTY(Expression, node, argument);
383+
}
384+
379385
void AstExpressionRewriter::VisitDoExpression(DoExpression* node) {
380386
REWRITE_THIS(node);
381387
AST_REWRITE_PROPERTY(Block, node, block);

src/ast/ast-numbering.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,13 @@ void AstNumberingVisitor::VisitGetIterator(GetIterator* node) {
472472
ReserveFeedbackSlots(node);
473473
}
474474

475+
void AstNumberingVisitor::VisitImportCallExpression(
476+
ImportCallExpression* node) {
477+
IncrementNodeCount();
478+
DisableFullCodegenAndCrankshaft(kDynamicImport);
479+
Visit(node->argument());
480+
}
481+
475482
void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
476483
IncrementNodeCount();
477484
DisableSelfOptimization();

src/ast/ast-traversal-visitor.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,13 @@ void AstTraversalVisitor<Subclass>::VisitGetIterator(GetIterator* expr) {
476476
RECURSE_EXPRESSION(Visit(expr->iterable()));
477477
}
478478

479+
template <class Subclass>
480+
void AstTraversalVisitor<Subclass>::VisitImportCallExpression(
481+
ImportCallExpression* expr) {
482+
PROCESS_EXPRESSION(expr);
483+
RECURSE_EXPRESSION(Visit(expr->argument()));
484+
}
485+
479486
template <class Subclass>
480487
void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference(
481488
SuperPropertyReference* expr) {

src/ast/ast.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ namespace internal {
105105
V(EmptyParentheses) \
106106
V(GetIterator) \
107107
V(DoExpression) \
108-
V(RewritableExpression)
108+
V(RewritableExpression) \
109+
V(ImportCallExpression)
109110

110111
#define AST_NODE_LIST(V) \
111112
DECLARATION_NODE_LIST(V) \
@@ -2973,6 +2974,21 @@ class SuperCallReference final : public Expression {
29732974
VariableProxy* this_function_var_;
29742975
};
29752976

2977+
// This AST Node is used to represent a dynamic import call --
2978+
// import(argument).
2979+
class ImportCallExpression final : public Expression {
2980+
public:
2981+
Expression* argument() const { return argument_; }
2982+
void set_argument(Expression* argument) { argument_ = argument; }
2983+
2984+
private:
2985+
friend class AstNodeFactory;
2986+
2987+
ImportCallExpression(Expression* argument, int pos)
2988+
: Expression(pos, kImportCallExpression), argument_(argument) {}
2989+
2990+
Expression* argument_;
2991+
};
29762992

29772993
// This class is produced when parsing the () in arrow functions without any
29782994
// arguments and is not actually a valid expression.
@@ -3623,6 +3639,10 @@ class AstNodeFactory final BASE_EMBEDDED {
36233639
return new (zone_) GetIterator(iterable, hint, pos);
36243640
}
36253641

3642+
ImportCallExpression* NewImportCallExpression(Expression* args, int pos) {
3643+
return new (zone_) ImportCallExpression(args, pos);
3644+
}
3645+
36263646
Zone* zone() const { return zone_; }
36273647
void set_zone(Zone* zone) { zone_ = zone; }
36283648

src/ast/prettyprinter.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,12 @@ void CallPrinter::VisitGetIterator(GetIterator* node) {
384384
if (was_found) done_ = true;
385385
}
386386

387+
void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) {
388+
Print("ImportCall(");
389+
Find(node->argument(), true);
390+
Print(")");
391+
}
392+
387393
void CallPrinter::VisitThisFunction(ThisFunction* node) {}
388394

389395

@@ -1203,6 +1209,11 @@ void AstPrinter::VisitGetIterator(GetIterator* node) {
12031209
Visit(node->iterable());
12041210
}
12051211

1212+
void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) {
1213+
IndentedScope indent(this, "IMPORT-CALL", node->position());
1214+
Visit(node->argument());
1215+
}
1216+
12061217
void AstPrinter::VisitThisFunction(ThisFunction* node) {
12071218
IndentedScope indent(this, "THIS-FUNCTION", node->position());
12081219
}

src/bailout-reason.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ namespace internal {
5858
"Encountered a do-expression with unmodelable control statements") \
5959
V(kDoPushArgumentNotImplementedForDoubleType, \
6060
"DoPushArgument not implemented for double type") \
61+
V(kDynamicImport, "Dynamic module import") \
6162
V(kEliminatedBoundsCheckFailed, "Eliminated bounds check failed") \
6263
V(kEmitLoadRegisterUnsupportedDoubleImmediate, \
6364
"EmitLoadRegister: Unsupported double immediate") \

0 commit comments

Comments
 (0)