mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-09 17:31:47 +09:00
Issue #1691 - Part 4: Finish implementing call import. https://bugzilla.mozilla.org/show_bug.cgi?id=1499140
(cherry picked from commit 7bf7d64887944b127a72090dd62eb57f67c5089d)
This commit is contained in:
parent
3f4985ce6c
commit
7a6dab0b38
35 changed files with 533 additions and 24 deletions
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "builtin/ModuleObject.h"
|
||||
|
||||
#include "builtin/Promise.h"
|
||||
#include "builtin/SelfHostingDefines.h"
|
||||
#include "frontend/ParseNode.h"
|
||||
#include "frontend/SharedContext.h"
|
||||
|
|
@ -1030,6 +1031,22 @@ ModuleObject::Evaluate(JSContext* cx, HandleModuleObject self)
|
|||
return InvokeSelfHostedMethod(cx, self, cx->names().ModuleEvaluate);
|
||||
}
|
||||
|
||||
/* static */ ModuleNamespaceObject*
|
||||
ModuleObject::GetOrCreateModuleNamespace(JSContext* cx, HandleModuleObject self)
|
||||
{
|
||||
FixedInvokeArgs<1> args(cx);
|
||||
args[0].setObject(*self);
|
||||
|
||||
RootedValue result(cx);
|
||||
if (!CallSelfHostedFunction(cx, cx->names().GetModuleNamespace, UndefinedHandleValue, args,
|
||||
&result))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &result.toObject().as<ModuleNamespaceObject>();
|
||||
}
|
||||
|
||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, namespace_, NamespaceSlot)
|
||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, status, StatusSlot)
|
||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, evaluationError, EvaluationErrorSlot)
|
||||
|
|
@ -1519,3 +1536,88 @@ js::GetOrCreateModuleMetaObject(JSContext* cx, HandleObject moduleArg)
|
|||
|
||||
return metaObject;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::CallModuleResolveHook(JSContext* cx, HandleValue referencingPrivate, HandleString specifier)
|
||||
{
|
||||
JS::ModuleResolveHook moduleResolveHook = cx->runtime()->moduleResolveHook;
|
||||
if (!moduleResolveHook) {
|
||||
JS_ReportErrorASCII(cx, "Module resolve hook not set");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedObject result(cx, moduleResolveHook(cx, referencingPrivate, specifier));
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!result->is<ModuleObject>()) {
|
||||
JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::StartDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, HandleValue specifierArg)
|
||||
{
|
||||
RootedObject promiseConstructor(cx, JS::GetPromiseConstructor(cx));
|
||||
if (!promiseConstructor) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedObject promiseObject(cx, JS::NewPromiseObject(cx, nullptr));
|
||||
if (!promiseObject) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Handle<PromiseObject*> promise = promiseObject.as<PromiseObject>();
|
||||
|
||||
RootedString specifier(cx, ToString(cx, specifierArg));
|
||||
if (!specifier) {
|
||||
if (!RejectPromiseWithPendingError(cx, promise))
|
||||
return nullptr;
|
||||
return promise;
|
||||
}
|
||||
|
||||
JS::ModuleDynamicImportHook importHook = cx->runtime()->moduleDynamicImportHook;
|
||||
MOZ_ASSERT(importHook);
|
||||
if (!importHook(cx, referencingPrivate, specifier, promise)) {
|
||||
if (!RejectPromiseWithPendingError(cx, promise))
|
||||
return nullptr;
|
||||
return promise;
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
bool
|
||||
js::FinishDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, HandleString specifier,
|
||||
HandleObject promiseArg)
|
||||
{
|
||||
Handle<PromiseObject*> promise = promiseArg.as<PromiseObject>();
|
||||
|
||||
if (cx->isExceptionPending()) {
|
||||
return RejectPromiseWithPendingError(cx, promise);
|
||||
}
|
||||
|
||||
RootedObject result(cx, CallModuleResolveHook(cx, referencingPrivate, specifier));
|
||||
if (!result) {
|
||||
return RejectPromiseWithPendingError(cx, promise);
|
||||
}
|
||||
|
||||
RootedModuleObject module(cx, &result->as<ModuleObject>());
|
||||
if (module->status() != MODULE_STATUS_EVALUATED) {
|
||||
JS_ReportErrorASCII(cx, "Unevaluated or errored module returned by module resolve hook");
|
||||
return RejectPromiseWithPendingError(cx, promise);
|
||||
}
|
||||
|
||||
RootedObject ns(cx, ModuleObject::GetOrCreateModuleNamespace(cx, module));
|
||||
if (!ns) {
|
||||
return RejectPromiseWithPendingError(cx, promise);
|
||||
}
|
||||
|
||||
RootedValue value(cx, ObjectValue(*ns));
|
||||
return PromiseObject::resolve(cx, promise, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,6 +288,9 @@ class ModuleObject : public NativeObject
|
|||
static bool Instantiate(JSContext* cx, HandleModuleObject self);
|
||||
static bool Evaluate(JSContext* cx, HandleModuleObject self);
|
||||
|
||||
static ModuleNamespaceObject* GetOrCreateModuleNamespace(JSContext* cx,
|
||||
HandleModuleObject self);
|
||||
|
||||
void setMetaObject(JSObject* obj);
|
||||
|
||||
// For BytecodeEmitter.
|
||||
|
|
@ -374,6 +377,16 @@ class MOZ_STACK_CLASS ModuleBuilder
|
|||
JSObject*
|
||||
GetOrCreateModuleMetaObject(JSContext* cx, HandleObject module);
|
||||
|
||||
JSObject*
|
||||
CallModuleResolveHook(JSContext* cx, HandleValue referencingPrivate, HandleString specifier);
|
||||
|
||||
JSObject*
|
||||
StartDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, HandleValue specifier);
|
||||
|
||||
bool
|
||||
FinishDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, HandleString specifier,
|
||||
HandleObject promise);
|
||||
|
||||
} // namespace js
|
||||
|
||||
template<>
|
||||
|
|
|
|||
|
|
@ -3863,6 +3863,16 @@ OriginalPromiseThenBuiltin(JSContext* cx, HandleValue promiseVal, HandleValue on
|
|||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
js::RejectPromiseWithPendingError(JSContext* cx, Handle<PromiseObject*> promise)
|
||||
{
|
||||
// Not much we can do about uncatchable exceptions, just bail.
|
||||
RootedValue exn(cx);
|
||||
if (!GetAndClearException(cx, &exn))
|
||||
return false;
|
||||
return PromiseObject::reject(cx, promise, exn);
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx,
|
||||
Handle<PromiseObject*> promise,
|
||||
Handle<PromiseReactionRecord*> reaction);
|
||||
|
|
|
|||
|
|
@ -146,6 +146,9 @@ OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
|
|||
MOZ_MUST_USE JSObject*
|
||||
PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
RejectPromiseWithPendingError(JSContext* cx, Handle<PromiseObject*> promise);
|
||||
|
||||
MOZ_MUST_USE PromiseObject*
|
||||
CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal);
|
||||
|
||||
|
|
|
|||
|
|
@ -9088,8 +9088,14 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
|||
break;
|
||||
|
||||
case PNK_CALL_IMPORT:
|
||||
reportError(nullptr, JSMSG_NO_DYNAMIC_IMPORT);
|
||||
return false;
|
||||
if (!cx->asJSContext()->runtime()->moduleDynamicImportHook) {
|
||||
reportError(nullptr, JSMSG_NO_DYNAMIC_IMPORT);
|
||||
return false;
|
||||
}
|
||||
if (!emitTree(pn->as<BinaryNode>().right()) || !emit1(JSOP_DYNAMIC_IMPORT)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case PNK_SETTHIS:
|
||||
if (!emitSetThis(&pn->as<BinaryNode>()))
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
|||
}
|
||||
|
||||
BinaryNodeType newCallImport(Node importHolder, Node singleArg) {
|
||||
return new_<BinaryNode>(PNK_CALL_IMPORT, JSOP_NOP, importHolder, singleArg);
|
||||
return new_<BinaryNode>(PNK_CALL_IMPORT, JSOP_DYNAMIC_IMPORT, importHolder, singleArg);
|
||||
}
|
||||
|
||||
UnaryNodeType newExprStatement(Node expr, uint32_t end) {
|
||||
|
|
|
|||
|
|
@ -837,7 +837,6 @@ class NameResolver
|
|||
|
||||
case PNK_CALL_IMPORT: {
|
||||
BinaryNode* node = &cur->as<BinaryNode>();
|
||||
MOZ_ASSERT(cur->isArity(PN_BINARY));
|
||||
if (!resolve(node->right(), prefix))
|
||||
return false;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -541,6 +541,8 @@ IsTypeofKind(ParseNodeKind kind)
|
|||
* PNK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
|
||||
* pn_kid: array comprehension expression
|
||||
* PNK_NOP (NullaryNode)
|
||||
* PNK_IMPORT_META (BinaryNode)
|
||||
* PNK_CALL_IMPORT (BinaryNode)
|
||||
*/
|
||||
enum ParseNodeArity
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10515,6 +10515,10 @@ Parser<ParseHandler>::importExpr(YieldHandling yieldHandling)
|
|||
|
||||
MUST_MATCH_TOKEN_MOD(TOK_RP, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
|
||||
|
||||
if (!context->asJSContext()->runtime()->moduleDynamicImportHook && !abortIfSyntaxParser()) {
|
||||
return null();
|
||||
}
|
||||
|
||||
return handler.newCallImport(importHolder, arg);
|
||||
} else {
|
||||
error(JSMSG_UNEXPECTED_TOKEN, TokenKindToDesc(next));
|
||||
|
|
|
|||
|
|
@ -4708,3 +4708,28 @@ BaselineCompiler::emit_JSOP_IMPORTMETA()
|
|||
frame.push(ObjectValue(*metaObject));
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject* (*StartDynamicModuleImportFn)(JSContext*, HandleValue, HandleValue);
|
||||
static const VMFunction StartDynamicModuleImportInfo =
|
||||
FunctionInfo<StartDynamicModuleImportFn>(js::StartDynamicModuleImport,
|
||||
"StartDynamicModuleImport");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_DYNAMIC_IMPORT()
|
||||
{
|
||||
RootedValue referencingPrivate(cx, FindScriptOrModulePrivateForScript(script));
|
||||
|
||||
// Put specifier value in R0.
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
prepareVMCall();
|
||||
pushArg(R0);
|
||||
pushArg(referencingPrivate);
|
||||
if (!callVM(StartDynamicModuleImportInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,7 +241,8 @@ namespace jit {
|
|||
_(JSOP_JUMPTARGET) \
|
||||
_(JSOP_IS_CONSTRUCTING) \
|
||||
_(JSOP_TRY_DESTRUCTURING_ITERCLOSE) \
|
||||
_(JSOP_IMPORTMETA)
|
||||
_(JSOP_IMPORTMETA) \
|
||||
_(JSOP_DYNAMIC_IMPORT)
|
||||
|
||||
class BaselineCompiler : public BaselineCompilerSpecific
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2402,6 +2402,19 @@ CodeGenerator::visitNullarySharedStub(LNullarySharedStub* lir)
|
|||
}
|
||||
}
|
||||
|
||||
typedef JSObject* (*StartDynamicModuleImportFn)(JSContext*, HandleValue, HandleValue);
|
||||
static const VMFunction StartDynamicModuleImportInfo =
|
||||
FunctionInfo<StartDynamicModuleImportFn>(js::StartDynamicModuleImport,
|
||||
"StartDynamicModuleImport");
|
||||
|
||||
void
|
||||
CodeGenerator::visitDynamicImport(LDynamicImport* lir)
|
||||
{
|
||||
pushArg(ToValue(lir, LDynamicImport::SpecifierIndex));
|
||||
pushArg(ToValue(lir, LDynamicImport::ReferencingPrivateIndex));
|
||||
callVM(StartDynamicModuleImportInfo, lir);
|
||||
}
|
||||
|
||||
typedef JSObject* (*LambdaFn)(JSContext*, HandleFunction, HandleObject);
|
||||
static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda, "Lambda");
|
||||
|
||||
|
|
|
|||
|
|
@ -442,6 +442,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
|
||||
void visitRandom(LRandom* ins);
|
||||
void visitSignExtend(LSignExtend* ins);
|
||||
void visitDynamicImport(LDynamicImport* lir);
|
||||
|
||||
#ifdef DEBUG
|
||||
void emitDebugForceBailing(LInstruction* lir);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "jit/Lowering.h"
|
||||
#include "jit/MIRGraph.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/EnvironmentObject.h"
|
||||
#include "vm/Opcodes.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
|
@ -2208,6 +2209,9 @@ IonBuilder::inspectOpcode(JSOp op)
|
|||
case JSOP_IMPORTMETA:
|
||||
return jsop_importmeta();
|
||||
|
||||
case JSOP_DYNAMIC_IMPORT:
|
||||
return jsop_dynamic_import();
|
||||
|
||||
case JSOP_DEBUGCHECKSELFHOSTED:
|
||||
{
|
||||
#ifdef DEBUG
|
||||
|
|
@ -14264,6 +14268,20 @@ IonBuilder::jsop_importmeta()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_dynamic_import()
|
||||
{
|
||||
Value referencingPrivate = FindScriptOrModulePrivateForScript(script());
|
||||
MConstant* ref = constant(referencingPrivate);
|
||||
|
||||
MDefinition* specifier = current->pop();
|
||||
|
||||
MDynamicImport* ins = MDynamicImport::New(alloc(), ref, specifier);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
MInstruction*
|
||||
IonBuilder::addConvertElementsToDoubles(MDefinition* elements)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -789,6 +789,7 @@ class IonBuilder
|
|||
MOZ_MUST_USE bool jsop_checkobjcoercible();
|
||||
MOZ_MUST_USE bool jsop_pushcallobj();
|
||||
MOZ_MUST_USE bool jsop_importmeta();
|
||||
MOZ_MUST_USE bool jsop_dynamic_import();
|
||||
|
||||
/* Inlining. */
|
||||
|
||||
|
|
|
|||
|
|
@ -2427,6 +2427,15 @@ LIRGenerator::visitNullarySharedStub(MNullarySharedStub* ins)
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitDynamicImport(MDynamicImport* ins)
|
||||
{
|
||||
LDynamicImport* lir = new(alloc()) LDynamicImport(useBoxAtStart(ins->referencingPrivate()),
|
||||
useBoxAtStart(ins->specifier()));
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitLambda(MLambda* ins)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitCheckIsCallable(MCheckIsCallable* ins);
|
||||
void visitCheckObjCoercible(MCheckObjCoercible* ins);
|
||||
void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins);
|
||||
void visitDynamicImport(MDynamicImport* ins);
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
|||
|
|
@ -8379,6 +8379,22 @@ class MSubstr
|
|||
}
|
||||
};
|
||||
|
||||
class MDynamicImport : public MBinaryInstruction,
|
||||
public BoxInputsPolicy::Data
|
||||
{
|
||||
explicit MDynamicImport(MDefinition* referencingPrivate, MDefinition* specifier)
|
||||
: MBinaryInstruction(referencingPrivate, specifier)
|
||||
{
|
||||
setResultType(MIRType::Object);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(DynamicImport)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, referencingPrivate))
|
||||
NAMED_OPERANDS((1, specifier))
|
||||
};
|
||||
|
||||
struct LambdaFunctionInfo
|
||||
{
|
||||
// The functions used in lambdas are the canonical original function in
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ namespace jit {
|
|||
_(GlobalNameConflictsCheck) \
|
||||
_(Debugger) \
|
||||
_(NewTarget) \
|
||||
_(DynamicImport) \
|
||||
_(ArrowNewTarget) \
|
||||
_(CheckReturn) \
|
||||
_(CheckIsObj) \
|
||||
|
|
|
|||
|
|
@ -4939,6 +4939,26 @@ class LNullarySharedStub : public LCallInstructionHelper<BOX_PIECES, 0, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LDynamicImport : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(DynamicImport)
|
||||
|
||||
static const size_t ReferencingPrivateIndex = 0;
|
||||
static const size_t SpecifierIndex = BOX_PIECES;
|
||||
|
||||
explicit LDynamicImport(const LBoxAllocation& referencingPrivate,
|
||||
const LBoxAllocation& specifier)
|
||||
{
|
||||
setBoxOperand(ReferencingPrivateIndex, referencingPrivate);
|
||||
setBoxOperand(SpecifierIndex, specifier);
|
||||
}
|
||||
|
||||
const MDynamicImport* mir() const {
|
||||
return mir_->toDynamicImport();
|
||||
}
|
||||
};
|
||||
|
||||
class LLambdaForSingleton : public LCallInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -401,6 +401,7 @@
|
|||
_(GlobalNameConflictsCheck) \
|
||||
_(Debugger) \
|
||||
_(NewTarget) \
|
||||
_(DynamicImport) \
|
||||
_(ArrowNewTarget) \
|
||||
_(CheckReturn) \
|
||||
_(CheckIsObj) \
|
||||
|
|
|
|||
|
|
@ -592,6 +592,7 @@ MSG_DEF(JSMSG_MISSING_NAMESPACE_EXPORT, 0, JSEXN_SYNTAXERR, "export not found f
|
|||
MSG_DEF(JSMSG_MISSING_EXPORT, 1, JSEXN_SYNTAXERR, "local binding for export '{0}' not found")
|
||||
MSG_DEF(JSMSG_BAD_MODULE_STATUS, 0, JSEXN_INTERNALERR, "module record has unexpected status")
|
||||
MSG_DEF(JSMSG_NO_DYNAMIC_IMPORT, 0, JSEXN_SYNTAXERR, "dynamic module import is not implemented")
|
||||
MSG_DEF(JSMSG_IMPORT_SCRIPT_NOT_FOUND, 0, JSEXN_TYPEERR, "can't find referencing script for dynamic module import")
|
||||
|
||||
// Promise
|
||||
MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.")
|
||||
|
|
|
|||
|
|
@ -4712,6 +4712,29 @@ JS::SetModuleMetadataHook(JSContext* cx, JS::ModuleMetadataHook func)
|
|||
cx->runtime()->moduleMetadataHook = func;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::ModuleDynamicImportHook)
|
||||
JS::GetModuleDynamicImportHook(JSContext* cx)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
return cx->runtime()->moduleDynamicImportHook;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::SetModuleDynamicImportHook(JSContext* cx, JS::ModuleDynamicImportHook func)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
cx->runtime()->moduleDynamicImportHook = func;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::FinishDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, HandleString specifier,
|
||||
HandleObject promise)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
|
||||
return js::FinishDynamicModuleImport(cx, referencingPrivate, specifier, promise);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, JS::MutableHandleObject module)
|
||||
|
|
|
|||
|
|
@ -4353,6 +4353,25 @@ GetModuleMetadataHook(JSContext* cx);
|
|||
extern JS_PUBLIC_API(void)
|
||||
SetModuleMetadataHook(JSContext* cx, ModuleMetadataHook func);
|
||||
|
||||
using ModuleDynamicImportHook = bool (*)(JSContext* cx, HandleValue referencingPrivate,
|
||||
HandleString specifier, HandleObject promise);
|
||||
|
||||
/**
|
||||
* Get the HostResolveImportedModule hook for the runtime.
|
||||
*/
|
||||
extern JS_PUBLIC_API(ModuleDynamicImportHook)
|
||||
GetModuleDynamicImportHook(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Set the HostResolveImportedModule hook for the runtime to the given function.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
SetModuleDynamicImportHook(JSContext* cx, ModuleDynamicImportHook func);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
FinishDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, HandleString specifier,
|
||||
HandleObject promise);
|
||||
|
||||
/**
|
||||
* Parse the given source buffer as a module in the scope of the current global
|
||||
* of cx and return a source text module record.
|
||||
|
|
|
|||
|
|
@ -33,11 +33,28 @@ Reflect.Loader = new class {
|
|||
return module;
|
||||
}
|
||||
|
||||
["import"](name, referrer) {
|
||||
["import"](name, referencingInfo) {
|
||||
let module = this.loadAndParse(name);
|
||||
module.declarationInstantiation();
|
||||
return module.evaluation();
|
||||
}
|
||||
};
|
||||
|
||||
setModuleResolveHook((module, requestName) => Reflect.Loader.loadAndParse(requestName));
|
||||
setModuleResolveHook((referencingInfo, requestName) => {
|
||||
let path = ReflectLoader.resolve(requestName, referencingInfo);
|
||||
return ReflectLoader.loadAndParse(path);
|
||||
});
|
||||
|
||||
setModuleMetadataHook((module, metaObject) => {
|
||||
ReflectLoader.populateImportMeta(module, metaObject);
|
||||
});
|
||||
|
||||
setModuleDynamicImportHook((referencingInfo, specifier, promise) => {
|
||||
try {
|
||||
let path = ReflectLoader.resolve(specifier, referencingInfo);
|
||||
ReflectLoader.loadAndExecute(path);
|
||||
finishDynamicModuleImport(referencingInfo, specifier, promise);
|
||||
} catch (err) {
|
||||
abortDynamicModuleImport(referencingInfo, specifier, promise, err);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -603,6 +603,32 @@ EnvironmentPreparer::invoke(HandleObject scope, Closure& closure)
|
|||
return;
|
||||
}
|
||||
|
||||
static bool
|
||||
RegisterScriptPathWithModuleLoader(JSContext* cx, HandleScript script, const char* filename)
|
||||
{
|
||||
// Set the private value associated with a script to a object containing the
|
||||
// script's filename so that the module loader can use it to resolve
|
||||
// relative imports.
|
||||
|
||||
RootedString path(cx, JS_NewStringCopyZ(cx, filename));
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject infoObject(cx, JS_NewPlainObject(cx));
|
||||
if (!infoObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue pathValue(cx, StringValue(path));
|
||||
if (!JS_DefineProperty(cx, infoObject, "path", pathValue, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::SetScriptPrivate(script, ObjectValue(*infoObject));
|
||||
return true;
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
|
||||
{
|
||||
|
|
@ -635,6 +661,10 @@ RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
|
|||
MOZ_ASSERT(script);
|
||||
}
|
||||
|
||||
if (!RegisterScriptPathWithModuleLoader(cx, script, filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (dumpEntrainedVariables)
|
||||
AnalyzeEntrainedVariables(cx, script);
|
||||
|
|
@ -4035,7 +4065,7 @@ SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
static JSObject*
|
||||
CallModuleResolveHook(JSContext* cx, HandleValue referencingPrivate, HandleString specifier)
|
||||
ShellModuleResolveHook(JSContext* cx, HandleValue referencingPrivate, HandleString specifier)
|
||||
{
|
||||
ShellContext* sc = GetShellContext(cx);
|
||||
|
||||
|
|
@ -4119,6 +4149,109 @@ ShellModuleMetadataHook(JSContext* cx, HandleObject module, HandleObject metaObj
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
SetModuleDynamicImportHook(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 1) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"setModuleDynamicImportHook", "0", "s");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
|
||||
const char* typeName = InformalValueTypeName(args[0]);
|
||||
JS_ReportErrorASCII(cx, "expected hook function, got %s", typeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle<GlobalObject*> global = cx->global();
|
||||
global->setReservedSlot(GlobalAppSlotModuleDynamicImportHook, args[0]);
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
FinishDynamicModuleImport(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 3) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"finishDynamicModuleImport", "0", "s");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[1].isString()) {
|
||||
return ReportArgumentTypeError(cx, args[1], "String");
|
||||
}
|
||||
|
||||
if (!args[2].isObject() || !args[2].toObject().is<PromiseObject>()) {
|
||||
return ReportArgumentTypeError(cx, args[2], "PromiseObject");
|
||||
}
|
||||
|
||||
RootedString specifier(cx, args[1].toString());
|
||||
Rooted<PromiseObject*> promise(cx, &args[2].toObject().as<PromiseObject>());
|
||||
|
||||
return js::FinishDynamicModuleImport(cx, args[0], specifier, promise);
|
||||
}
|
||||
|
||||
static bool
|
||||
AbortDynamicModuleImport(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 4) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"abortDynamicModuleImport", "0", "s");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[1].isString()) {
|
||||
return ReportArgumentTypeError(cx, args[1], "String");
|
||||
}
|
||||
|
||||
if (!args[2].isObject() || !args[2].toObject().is<PromiseObject>()) {
|
||||
return ReportArgumentTypeError(cx, args[2], "PromiseObject");
|
||||
}
|
||||
|
||||
if (!args[3].isObject() || !args[3].toObject().is<ErrorObject>()) {
|
||||
return ReportArgumentTypeError(cx, args[3], "ErrorObject");
|
||||
}
|
||||
|
||||
RootedString specifier(cx, args[1].toString());
|
||||
Rooted<PromiseObject*> promise(cx, &args[2].toObject().as<PromiseObject>());
|
||||
Rooted<ErrorObject*> error(cx, &args[3].toObject().as<ErrorObject>());
|
||||
|
||||
Rooted<Value> value(cx, ObjectValue(*error));
|
||||
cx->setPendingException(value);
|
||||
return js::FinishDynamicModuleImport(cx, args[0], specifier, promise);
|
||||
}
|
||||
|
||||
static bool
|
||||
ShellModuleDynamicImportHook(JSContext* cx, HandleValue referencingPrivate, HandleString specifier,
|
||||
HandleObject promise)
|
||||
{
|
||||
Handle<GlobalObject*> global = cx->global();
|
||||
RootedValue hookValue(cx, global->getReservedSlot(GlobalAppSlotModuleDynamicImportHook));
|
||||
if (hookValue.isUndefined()) {
|
||||
JS_ReportErrorASCII(cx, "Module resolve hook not set");
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(hookValue.toObject().is<JSFunction>());
|
||||
|
||||
JS::AutoValueArray<3> args(cx);
|
||||
args[0].set(referencingPrivate);
|
||||
args[1].setString(specifier);
|
||||
args[2].setObject(*promise);
|
||||
|
||||
RootedValue result(cx);
|
||||
if (!JS_CallFunctionValue(cx, nullptr, hookValue, args, &result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetModuleLoadPath(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
|
@ -5984,7 +6117,7 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
|
|||
" Parses source text as a module and returns a Module object."),
|
||||
|
||||
JS_FN_HELP("setModuleResolveHook", SetModuleResolveHook, 1, 0,
|
||||
"setModuleResolveHook(function(module, specifier) {})",
|
||||
"setModuleResolveHook(function(referrer, specifier))",
|
||||
" Set the HostResolveImportedModule hook to |function|.\n"
|
||||
" This hook is used to look up a previously loaded module object. It should\n"
|
||||
" be implemented by the module loader."),
|
||||
|
|
@ -5997,6 +6130,28 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
|
|||
"getModulePrivate(scriptObject)",
|
||||
" Get the private value associated with a module object.\n"),
|
||||
|
||||
JS_FN_HELP("setModuleMetadataHook", SetModuleMetadataHook, 1, 0,
|
||||
"setModuleMetadataHook(function(module) {})",
|
||||
" Set the HostPopulateImportMeta hook to |function|.\n"
|
||||
" This hook is used to create the metadata object returned by import.meta for\n"
|
||||
" a module. It should be implemented by the module loader."),
|
||||
|
||||
JS_FN_HELP("setModuleDynamicImportHook", SetModuleDynamicImportHook, 1, 0,
|
||||
"setModuleDynamicImportHook(function(referrer, specifier, promise))",
|
||||
" Set the HostImportModuleDynamically hook to |function|.\n"
|
||||
" This hook is used to dynamically import a module. It should\n"
|
||||
" be implemented by the module loader."),
|
||||
|
||||
JS_FN_HELP("finishDynamicModuleImport", FinishDynamicModuleImport, 3, 0,
|
||||
"finishDynamicModuleImport(referrer, specifier, promise)",
|
||||
" The module loader's dynamic import hook should call this when the module has"
|
||||
" been loaded successfully."),
|
||||
|
||||
JS_FN_HELP("abortDynamicModuleImport", AbortDynamicModuleImport, 4, 0,
|
||||
"abortDynamicModuleImport(referrer, specifier, promise, error)",
|
||||
" The module loader's dynamic import hook should call this when the module "
|
||||
" import has failed."),
|
||||
|
||||
JS_FN_HELP("getModuleLoadPath", GetModuleLoadPath, 0, 0,
|
||||
"getModuleLoadPath()",
|
||||
" Return any --module-load-path argument passed to the shell. Used by the\n"
|
||||
|
|
@ -8054,7 +8209,8 @@ main(int argc, char** argv, char** envp)
|
|||
|
||||
js::SetPreserveWrapperCallback(cx, DummyPreserveWrapperCallback);
|
||||
|
||||
JS::SetModuleResolveHook(cx->runtime(), CallModuleResolveHook);
|
||||
JS::SetModuleResolveHook(cx->runtime(), ShellModuleResolveHook);
|
||||
JS::SetModuleDynamicImportHook(cx, ShellModuleDynamicImportHook);
|
||||
JS::SetModuleMetadataHook(cx, ShellModuleMetadataHook);
|
||||
|
||||
result = Shell(cx, &op, envp);
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@
|
|||
macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \
|
||||
macro(get, get, "get") \
|
||||
macro(getInternals, getInternals, "getInternals") \
|
||||
macro(GetModuleNamespace, GetModuleNamespace, "GetModuleNamespace") \
|
||||
macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
|
||||
macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \
|
||||
macro(getPrefix, getPrefix, "get ") \
|
||||
|
|
|
|||
|
|
@ -3083,6 +3083,23 @@ js::GetModuleObjectForScript(JSScript* script)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Value
|
||||
js::FindScriptOrModulePrivateForScript(JSScript* script)
|
||||
{
|
||||
while (script) {
|
||||
ScriptSourceObject* sso = &script->scriptSourceUnwrap();
|
||||
Value value = sso->getPrivate();
|
||||
if (!value.isUndefined()) {
|
||||
return value;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(sso->introductionScript() != script);
|
||||
script = sso->introductionScript();
|
||||
}
|
||||
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetThisValueForDebuggerMaybeOptimizedOut(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc,
|
||||
MutableHandleValue res)
|
||||
|
|
|
|||
|
|
@ -1075,7 +1075,11 @@ CreateObjectsForEnvironmentChain(JSContext* cx, AutoObjectVector& chain,
|
|||
HandleObject terminatingEnv,
|
||||
MutableHandleObject envObj);
|
||||
|
||||
ModuleObject* GetModuleObjectForScript(JSScript* script);
|
||||
ModuleObject*
|
||||
GetModuleObjectForScript(JSScript* script);
|
||||
|
||||
Value
|
||||
FindScriptOrModulePrivateForScript(JSScript* script);
|
||||
|
||||
ModuleEnvironmentObject* GetModuleEnvironmentForScript(JSScript* script);
|
||||
|
||||
|
|
|
|||
|
|
@ -4201,6 +4201,22 @@ CASE(JSOP_IMPORTMETA)
|
|||
}
|
||||
END_CASE(JSOP_IMPORTMETA)
|
||||
|
||||
CASE(JSOP_DYNAMIC_IMPORT)
|
||||
{
|
||||
ReservedRooted<Value> referencingPrivate(&rootValue0);
|
||||
referencingPrivate = FindScriptOrModulePrivateForScript(script);
|
||||
|
||||
ReservedRooted<Value> specifier(&rootValue1);
|
||||
POP_COPY_TO(specifier);
|
||||
|
||||
JSObject* promise = StartDynamicModuleImport(cx, referencingPrivate, specifier);
|
||||
if (!promise)
|
||||
goto error;
|
||||
|
||||
PUSH_OBJECT(*promise);
|
||||
}
|
||||
END_CASE(JSOP_DYNAMIC_IMPORT)
|
||||
|
||||
CASE(JSOP_SUPERFUN)
|
||||
{
|
||||
ReservedRooted<JSObject*> superEnvFunc(&rootObject0, &GetSuperEnvFunction(cx, REGS));
|
||||
|
|
|
|||
|
|
@ -2345,13 +2345,23 @@
|
|||
* Operands:
|
||||
* Stack: => import.meta
|
||||
*/ \
|
||||
macro(JSOP_IMPORTMETA, 233, "importmeta", NULL, 1, 0, 1, JOF_BYTE)
|
||||
macro(JSOP_IMPORTMETA, 233, "importmeta", NULL, 1, 0, 1, JOF_BYTE) \
|
||||
/*
|
||||
* Dynamic import of the module specified by the string value on the top of
|
||||
* the stack.
|
||||
*
|
||||
* Category: Variables and Scopes
|
||||
* Type: Modules
|
||||
* Operands:
|
||||
* Stack: arg => rval
|
||||
*/ \
|
||||
macro(JSOP_DYNAMIC_IMPORT, 234, "call-import", NULL, 1, 1, 1, JOF_BYTE)
|
||||
|
||||
/*
|
||||
* In certain circumstances it may be useful to "pad out" the opcode space to
|
||||
* a power of two. Use this macro to do so.
|
||||
*/
|
||||
#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
|
||||
macro(234) \
|
||||
macro(235) \
|
||||
macro(236) \
|
||||
macro(237) \
|
||||
|
|
|
|||
|
|
@ -244,7 +244,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||
js::StackFormat::Default :
|
||||
js::StackFormat::SpiderMonkey),
|
||||
moduleResolveHook(),
|
||||
moduleMetadataHook()
|
||||
moduleMetadataHook(),
|
||||
moduleDynamicImportHook()
|
||||
{
|
||||
setGCStoreBufferPtr(&gc.storeBuffer);
|
||||
|
||||
|
|
|
|||
|
|
@ -1300,6 +1300,10 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
// A hook that implements the abstract operations
|
||||
// HostGetImportMetaProperties and HostFinalizeImportMeta.
|
||||
JS::ModuleMetadataHook moduleMetadataHook;
|
||||
|
||||
// A hook that implements the abstract operation
|
||||
// HostImportModuleDynamically.
|
||||
JS::ModuleDynamicImportHook moduleDynamicImportHook;
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
|
|
|||
|
|
@ -1999,15 +1999,9 @@ intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc, Value* vp)
|
|||
RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
|
||||
RootedString specifier(cx, args[1].toString());
|
||||
|
||||
JS::ModuleResolveHook moduleResolveHook = cx->runtime()->moduleResolveHook;
|
||||
if (!moduleResolveHook) {
|
||||
JS_ReportErrorASCII(cx, "Module resolve hook not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject result(cx);
|
||||
RootedValue referencingPrivate(cx, JS::GetModulePrivate(module));
|
||||
result = moduleResolveHook(cx, referencingPrivate, specifier);
|
||||
RootedObject result(cx, CallModuleResolveHook(cx, referencingPrivate, specifier));
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -151,8 +151,8 @@ AssertScopeMatchesEnvironment(Scope* scope, JSObject* originalEnv)
|
|||
break;
|
||||
|
||||
case ScopeKind::Module:
|
||||
MOZ_ASSERT(env->as<ModuleEnvironmentObject>().module().script() ==
|
||||
si.scope()->as<ModuleScope>().script());
|
||||
MOZ_ASSERT(&env->as<ModuleEnvironmentObject>().module() ==
|
||||
si.scope()->as<ModuleScope>().module());
|
||||
env = &env->as<ModuleEnvironmentObject>().enclosingEnvironment();
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue