[turbofan] Optimize import.meta
Make JSContextSpecialization constant-fold import.meta loads if the meta object has already been created. Most of this CL was contributed by Gus Caplan. This is a verbatim copy of CL https://chromium-review.googlesource.com/c/v8/v8/+/2170982 which could not be landed due to the wrong email address being used. TBR=verwaest@chromium.org TBR=gsathya@chromium.org Bug: v8:7044 Change-Id: Ief45f3082dc756265904ff500305d32717071e81 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2299375 Reviewed-by: Georg Neis <neis@chromium.org> Commit-Queue: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#68875}
This commit is contained in:
parent
e72702454a
commit
cd718536ec
@ -135,6 +135,7 @@ class V8_EXPORT_PRIVATE ObjectRef {
|
||||
#undef HEAP_AS_METHOD_DECL
|
||||
|
||||
bool IsNullOrUndefined() const;
|
||||
bool IsTheHole() const;
|
||||
|
||||
bool BooleanValue() const;
|
||||
Maybe<double> OddballToNumber() const;
|
||||
@ -379,6 +380,8 @@ class ContextRef : public HeapObjectRef {
|
||||
int index, SerializationPolicy policy =
|
||||
SerializationPolicy::kAssumeSerialized) const;
|
||||
|
||||
SourceTextModuleRef GetModule(SerializationPolicy policy) const;
|
||||
|
||||
// We only serialize the ScopeInfo if certain Promise
|
||||
// builtins are called.
|
||||
void SerializeScopeInfo();
|
||||
@ -860,6 +863,7 @@ class SourceTextModuleRef : public HeapObjectRef {
|
||||
void Serialize();
|
||||
|
||||
base::Optional<CellRef> GetCell(int cell_index) const;
|
||||
ObjectRef import_meta() const;
|
||||
};
|
||||
|
||||
class TemplateObjectDescriptionRef : public HeapObjectRef {
|
||||
|
@ -25,6 +25,8 @@ Reduction JSContextSpecialization::Reduce(Node* node) {
|
||||
return ReduceJSLoadContext(node);
|
||||
case IrOpcode::kJSStoreContext:
|
||||
return ReduceJSStoreContext(node);
|
||||
case IrOpcode::kJSGetImportMeta:
|
||||
return ReduceJSGetImportMeta(node);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -217,6 +219,62 @@ Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
|
||||
return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth);
|
||||
}
|
||||
|
||||
base::Optional<ContextRef> GetModuleContext(JSHeapBroker* broker, Node* node,
|
||||
Maybe<OuterContext> maybe_context) {
|
||||
size_t depth = std::numeric_limits<size_t>::max();
|
||||
Node* context = NodeProperties::GetOuterContext(node, &depth);
|
||||
|
||||
auto find_context = [](ContextRef c) {
|
||||
while (c.map().instance_type() != MODULE_CONTEXT_TYPE) {
|
||||
size_t depth = 1;
|
||||
c = c.previous(&depth);
|
||||
CHECK_EQ(depth, 0);
|
||||
}
|
||||
return c;
|
||||
};
|
||||
|
||||
switch (context->opcode()) {
|
||||
case IrOpcode::kHeapConstant: {
|
||||
HeapObjectRef object(broker, HeapConstantOf(context->op()));
|
||||
if (object.IsContext()) {
|
||||
return find_context(object.AsContext());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kParameter: {
|
||||
OuterContext outer;
|
||||
if (maybe_context.To(&outer) && IsContextParameter(context)) {
|
||||
return find_context(ContextRef(broker, outer.context));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return base::Optional<ContextRef>();
|
||||
}
|
||||
|
||||
Reduction JSContextSpecialization::ReduceJSGetImportMeta(Node* node) {
|
||||
base::Optional<ContextRef> maybe_context =
|
||||
GetModuleContext(broker(), node, outer());
|
||||
if (!maybe_context.has_value()) return NoChange();
|
||||
|
||||
ContextRef context = maybe_context.value();
|
||||
SourceTextModuleRef module =
|
||||
context.get(Context::EXTENSION_INDEX).value().AsSourceTextModule();
|
||||
ObjectRef import_meta = module.import_meta();
|
||||
if (import_meta.IsJSObject()) {
|
||||
Node* import_meta_const = jsgraph()->Constant(import_meta);
|
||||
ReplaceWithValue(node, import_meta_const);
|
||||
return Changed(import_meta_const);
|
||||
} else {
|
||||
DCHECK(import_meta.IsTheHole());
|
||||
// The import.meta object has not yet been created. Let JSGenericLowering
|
||||
// replace the operator with a runtime call.
|
||||
return NoChange();
|
||||
}
|
||||
}
|
||||
|
||||
Isolate* JSContextSpecialization::isolate() const {
|
||||
return jsgraph()->isolate();
|
||||
|
@ -28,7 +28,9 @@ struct OuterContext {
|
||||
|
||||
// Specializes a given JSGraph to a given context, potentially constant folding
|
||||
// some {LoadContext} nodes or strength reducing some {StoreContext} nodes.
|
||||
// Additionally, constant-folds the function parameter if {closure} is given.
|
||||
// Additionally, constant-folds the function parameter if {closure} is given,
|
||||
// and constant-folds import.meta loads if the corresponding object already
|
||||
// exists.
|
||||
//
|
||||
// The context can be the incoming function context or any outer context
|
||||
// thereof, as indicated by {outer}'s {distance}.
|
||||
@ -53,6 +55,7 @@ class V8_EXPORT_PRIVATE JSContextSpecialization final : public AdvancedReducer {
|
||||
Reduction ReduceParameter(Node* node);
|
||||
Reduction ReduceJSLoadContext(Node* node);
|
||||
Reduction ReduceJSStoreContext(Node* node);
|
||||
Reduction ReduceJSGetImportMeta(Node* node);
|
||||
|
||||
Reduction SimplifyJSStoreContext(Node* node, Node* new_context,
|
||||
size_t new_depth);
|
||||
|
@ -1176,6 +1176,10 @@ void JSGenericLowering::LowerJSStoreModule(Node* node) {
|
||||
UNREACHABLE(); // Eliminated in typed lowering.
|
||||
}
|
||||
|
||||
void JSGenericLowering::LowerJSGetImportMeta(Node* node) {
|
||||
ReplaceWithRuntimeCall(node, Runtime::kGetImportMetaObject);
|
||||
}
|
||||
|
||||
void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
|
||||
UNREACHABLE(); // Eliminated in typed lowering.
|
||||
}
|
||||
|
@ -1855,11 +1855,13 @@ class SourceTextModuleData : public HeapObjectData {
|
||||
void Serialize(JSHeapBroker* broker);
|
||||
|
||||
CellData* GetCell(JSHeapBroker* broker, int cell_index) const;
|
||||
ObjectData* GetImportMeta(JSHeapBroker* broker) const;
|
||||
|
||||
private:
|
||||
bool serialized_ = false;
|
||||
ZoneVector<CellData*> imports_;
|
||||
ZoneVector<CellData*> exports_;
|
||||
ObjectData* import_meta_;
|
||||
};
|
||||
|
||||
SourceTextModuleData::SourceTextModuleData(JSHeapBroker* broker,
|
||||
@ -1867,7 +1869,8 @@ SourceTextModuleData::SourceTextModuleData(JSHeapBroker* broker,
|
||||
Handle<SourceTextModule> object)
|
||||
: HeapObjectData(broker, storage, object),
|
||||
imports_(broker->zone()),
|
||||
exports_(broker->zone()) {}
|
||||
exports_(broker->zone()),
|
||||
import_meta_(nullptr) {}
|
||||
|
||||
CellData* SourceTextModuleData::GetCell(JSHeapBroker* broker,
|
||||
int cell_index) const {
|
||||
@ -1892,6 +1895,11 @@ CellData* SourceTextModuleData::GetCell(JSHeapBroker* broker,
|
||||
return cell;
|
||||
}
|
||||
|
||||
ObjectData* SourceTextModuleData::GetImportMeta(JSHeapBroker* broker) const {
|
||||
CHECK(serialized_);
|
||||
return import_meta_;
|
||||
}
|
||||
|
||||
void SourceTextModuleData::Serialize(JSHeapBroker* broker) {
|
||||
if (serialized_) return;
|
||||
serialized_ = true;
|
||||
@ -1919,6 +1927,10 @@ void SourceTextModuleData::Serialize(JSHeapBroker* broker) {
|
||||
exports_.push_back(broker->GetOrCreateData(exports->get(i))->AsCell());
|
||||
}
|
||||
TRACE(broker, "Copied " << exports_.size() << " exports");
|
||||
|
||||
DCHECK_NULL(import_meta_);
|
||||
import_meta_ = broker->GetOrCreateData(module->import_meta());
|
||||
TRACE(broker, "Copied import_meta");
|
||||
}
|
||||
|
||||
class CellData : public HeapObjectData {
|
||||
@ -2384,6 +2396,18 @@ base::Optional<ObjectRef> ContextRef::get(int index,
|
||||
return base::nullopt;
|
||||
}
|
||||
|
||||
SourceTextModuleRef ContextRef::GetModule(SerializationPolicy policy) const {
|
||||
ContextRef current = *this;
|
||||
while (current.map().instance_type() != MODULE_CONTEXT_TYPE) {
|
||||
size_t depth = 1;
|
||||
current = current.previous(&depth, policy);
|
||||
CHECK_EQ(depth, 0);
|
||||
}
|
||||
return current.get(Context::EXTENSION_INDEX, policy)
|
||||
.value()
|
||||
.AsSourceTextModule();
|
||||
}
|
||||
|
||||
JSHeapBroker::JSHeapBroker(
|
||||
Isolate* isolate, Zone* broker_zone, bool tracing_enabled,
|
||||
bool is_concurrent_inlining, bool is_native_context_independent,
|
||||
@ -3811,6 +3835,11 @@ bool ObjectRef::IsNullOrUndefined() const {
|
||||
return type == OddballType::kNull || type == OddballType::kUndefined;
|
||||
}
|
||||
|
||||
bool ObjectRef::IsTheHole() const {
|
||||
return IsHeapObject() &&
|
||||
AsHeapObject().map().oddball_type() == OddballType::kHole;
|
||||
}
|
||||
|
||||
bool ObjectRef::BooleanValue() const {
|
||||
if (data_->should_access_heap()) {
|
||||
AllowHandleDereferenceIf allow_handle_dereference(data()->kind(),
|
||||
@ -3932,6 +3961,20 @@ base::Optional<CellRef> SourceTextModuleRef::GetCell(int cell_index) const {
|
||||
return CellRef(broker(), cell);
|
||||
}
|
||||
|
||||
ObjectRef SourceTextModuleRef::import_meta() const {
|
||||
if (data_->should_access_heap()) {
|
||||
DCHECK(data_->kind() != ObjectDataKind::kUnserializedReadOnlyHeapObject);
|
||||
AllowHandleAllocationIf allow_handle_allocation(data()->kind(),
|
||||
broker()->mode());
|
||||
AllowHandleDereferenceIf allow_handle_dereference(data()->kind(),
|
||||
broker()->mode());
|
||||
return ObjectRef(broker(),
|
||||
handle(object()->import_meta(), broker()->isolate()));
|
||||
}
|
||||
return ObjectRef(broker(),
|
||||
data()->AsSourceTextModule()->GetImportMeta(broker()));
|
||||
}
|
||||
|
||||
ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object,
|
||||
bool check_type)
|
||||
: broker_(broker) {
|
||||
|
@ -88,6 +88,8 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
|
||||
return ReduceCall(node);
|
||||
case Runtime::kInlineIncBlockCounter:
|
||||
return ReduceIncBlockCounter(node);
|
||||
case Runtime::kInlineGetImportMetaObject:
|
||||
return ReduceGetImportMetaObject(node);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -350,6 +352,11 @@ Reduction JSIntrinsicLowering::ReduceIncBlockCounter(Node* node) {
|
||||
kDoesNotNeedFrameState);
|
||||
}
|
||||
|
||||
Reduction JSIntrinsicLowering::ReduceGetImportMetaObject(Node* node) {
|
||||
NodeProperties::ChangeOp(node, javascript()->GetImportMeta());
|
||||
return Changed(node);
|
||||
}
|
||||
|
||||
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
|
||||
Node* b) {
|
||||
RelaxControls(node);
|
||||
|
@ -65,6 +65,7 @@ class V8_EXPORT_PRIVATE JSIntrinsicLowering final
|
||||
Reduction ReduceToString(Node* node);
|
||||
Reduction ReduceCall(Node* node);
|
||||
Reduction ReduceIncBlockCounter(Node* node);
|
||||
Reduction ReduceGetImportMetaObject(Node* node);
|
||||
|
||||
Reduction Change(Node* node, const Operator* op);
|
||||
Reduction Change(Node* node, const Operator* op, Node* a, Node* b);
|
||||
|
@ -1115,6 +1115,14 @@ const Operator* JSOperatorBuilder::LoadModule(int32_t cell_index) {
|
||||
cell_index); // parameter
|
||||
}
|
||||
|
||||
const Operator* JSOperatorBuilder::GetImportMeta() {
|
||||
return new (zone()) Operator( // --
|
||||
IrOpcode::kJSGetImportMeta, // opcode
|
||||
Operator::kNoProperties, // flags
|
||||
"JSGetImportMeta", // name
|
||||
0, 1, 1, 1, 1, 2); // counts
|
||||
}
|
||||
|
||||
const Operator* JSOperatorBuilder::StoreModule(int32_t cell_index) {
|
||||
return zone()->New<Operator1<int32_t>>( // --
|
||||
IrOpcode::kJSStoreModule, // opcode
|
||||
|
@ -954,6 +954,8 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
|
||||
const Operator* LoadModule(int32_t cell_index);
|
||||
const Operator* StoreModule(int32_t cell_index);
|
||||
|
||||
const Operator* GetImportMeta();
|
||||
|
||||
const Operator* HasInPrototypeChain();
|
||||
const Operator* InstanceOf(const FeedbackSource& feedback);
|
||||
const Operator* OrdinaryHasInstance();
|
||||
|
@ -217,6 +217,7 @@
|
||||
V(JSStoreMessage) \
|
||||
V(JSLoadModule) \
|
||||
V(JSStoreModule) \
|
||||
V(JSGetImportMeta) \
|
||||
V(JSGeneratorStore) \
|
||||
V(JSGeneratorRestoreContinuation) \
|
||||
V(JSGeneratorRestoreContext) \
|
||||
|
@ -74,6 +74,7 @@ bool OperatorProperties::NeedsExactContext(const Operator* op) {
|
||||
case IrOpcode::kJSDebugger:
|
||||
case IrOpcode::kJSDeleteProperty:
|
||||
case IrOpcode::kJSGeneratorStore:
|
||||
case IrOpcode::kJSGetImportMeta:
|
||||
case IrOpcode::kJSHasProperty:
|
||||
case IrOpcode::kJSHasContextExtension:
|
||||
case IrOpcode::kJSLoadContext:
|
||||
@ -240,6 +241,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
|
||||
case IrOpcode::kJSPerformPromiseThen:
|
||||
case IrOpcode::kJSObjectIsArray:
|
||||
case IrOpcode::kJSRegExpTest:
|
||||
case IrOpcode::kJSGetImportMeta:
|
||||
|
||||
// Iterator protocol operations
|
||||
case IrOpcode::kJSGetIterator:
|
||||
|
@ -1475,6 +1475,20 @@ void SerializerForBackgroundCompilation::VisitInvokeIntrinsic(
|
||||
Builtins::kCopyDataProperties));
|
||||
break;
|
||||
}
|
||||
case Runtime::kInlineGetImportMetaObject: {
|
||||
Hints const& context_hints = environment()->current_context_hints();
|
||||
for (auto x : context_hints.constants()) {
|
||||
ContextRef(broker(), x)
|
||||
.GetModule(SerializationPolicy::kSerializeIfNeeded)
|
||||
.Serialize();
|
||||
}
|
||||
for (auto x : context_hints.virtual_contexts()) {
|
||||
ContextRef(broker(), x.context)
|
||||
.GetModule(SerializationPolicy::kSerializeIfNeeded)
|
||||
.Serialize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
|
@ -1857,6 +1857,8 @@ Type Typer::Visitor::TypeJSLoadModule(Node* node) { return Type::Any(); }
|
||||
|
||||
Type Typer::Visitor::TypeJSStoreModule(Node* node) { UNREACHABLE(); }
|
||||
|
||||
Type Typer::Visitor::TypeJSGetImportMeta(Node* node) { return Type::Any(); }
|
||||
|
||||
Type Typer::Visitor::TypeJSGeneratorStore(Node* node) { UNREACHABLE(); }
|
||||
|
||||
Type Typer::Visitor::TypeJSGeneratorRestoreContinuation(Node* node) {
|
||||
|
@ -820,6 +820,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
|
||||
CheckNotTyped(node);
|
||||
break;
|
||||
|
||||
case IrOpcode::kJSGetImportMeta:
|
||||
CheckTypeIs(node, Type::Any());
|
||||
break;
|
||||
|
||||
case IrOpcode::kJSGeneratorStore:
|
||||
CheckNotTyped(node);
|
||||
break;
|
||||
|
@ -4065,7 +4065,7 @@ void Isolate::SetHostImportModuleDynamicallyCallback(
|
||||
host_import_module_dynamically_callback_ = callback;
|
||||
}
|
||||
|
||||
Handle<JSObject> Isolate::RunHostInitializeImportMetaObjectCallback(
|
||||
MaybeHandle<JSObject> Isolate::RunHostInitializeImportMetaObjectCallback(
|
||||
Handle<SourceTextModule> module) {
|
||||
CHECK(module->import_meta().IsTheHole(this));
|
||||
Handle<JSObject> import_meta = factory()->NewJSObjectWithNullProto();
|
||||
@ -4075,7 +4075,10 @@ Handle<JSObject> Isolate::RunHostInitializeImportMetaObjectCallback(
|
||||
host_initialize_import_meta_object_callback_(
|
||||
api_context, Utils::ToLocal(Handle<Module>::cast(module)),
|
||||
v8::Local<v8::Object>::Cast(v8::Utils::ToLocal(import_meta)));
|
||||
CHECK(!has_scheduled_exception());
|
||||
if (has_scheduled_exception()) {
|
||||
PromoteScheduledException();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return import_meta;
|
||||
}
|
||||
|
@ -1435,7 +1435,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
||||
|
||||
void SetHostInitializeImportMetaObjectCallback(
|
||||
HostInitializeImportMetaObjectCallback callback);
|
||||
Handle<JSObject> RunHostInitializeImportMetaObjectCallback(
|
||||
MaybeHandle<JSObject> RunHostInitializeImportMetaObjectCallback(
|
||||
Handle<SourceTextModule> module);
|
||||
|
||||
void RegisterEmbeddedFileWriter(EmbeddedFileWriterInterface* writer) {
|
||||
|
@ -582,11 +582,14 @@ Handle<JSModuleNamespace> SourceTextModule::GetModuleNamespace(
|
||||
return Module::GetModuleNamespace(isolate, requested_module);
|
||||
}
|
||||
|
||||
Handle<JSObject> SourceTextModule::GetImportMeta(
|
||||
MaybeHandle<JSObject> SourceTextModule::GetImportMeta(
|
||||
Isolate* isolate, Handle<SourceTextModule> module) {
|
||||
Handle<HeapObject> import_meta(module->import_meta(), isolate);
|
||||
if (import_meta->IsTheHole(isolate)) {
|
||||
import_meta = isolate->RunHostInitializeImportMetaObjectCallback(module);
|
||||
if (!isolate->RunHostInitializeImportMetaObjectCallback(module).ToHandle(
|
||||
&import_meta)) {
|
||||
return {};
|
||||
}
|
||||
module->set_import_meta(*import_meta);
|
||||
}
|
||||
return Handle<JSObject>::cast(import_meta);
|
||||
|
@ -62,7 +62,7 @@ class SourceTextModule
|
||||
|
||||
// Get the import.meta object of [module]. If it doesn't exist yet, it is
|
||||
// created and passed to the embedder callback for initialization.
|
||||
V8_EXPORT_PRIVATE static Handle<JSObject> GetImportMeta(
|
||||
V8_EXPORT_PRIVATE static MaybeHandle<JSObject> GetImportMeta(
|
||||
Isolate* isolate, Handle<SourceTextModule> module);
|
||||
|
||||
using BodyDescriptor =
|
||||
|
@ -41,7 +41,8 @@ RUNTIME_FUNCTION(Runtime_GetImportMetaObject) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(0, args.length());
|
||||
Handle<SourceTextModule> module(isolate->context().module(), isolate);
|
||||
return *SourceTextModule::GetImportMeta(isolate, module);
|
||||
RETURN_RESULT_OR_FAILURE(isolate,
|
||||
SourceTextModule::GetImportMeta(isolate, module));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -25856,9 +25856,11 @@ TEST(ImportMeta) {
|
||||
v8::ScriptCompiler::Source source(source_text, origin);
|
||||
Local<Module> module =
|
||||
v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
||||
i::Handle<i::JSObject> meta = i::SourceTextModule::GetImportMeta(
|
||||
i_isolate,
|
||||
i::Handle<i::SourceTextModule>::cast(v8::Utils::OpenHandle(*module)));
|
||||
i::Handle<i::JSObject> meta =
|
||||
i::SourceTextModule::GetImportMeta(
|
||||
i_isolate,
|
||||
i::Handle<i::SourceTextModule>::cast(v8::Utils::OpenHandle(*module)))
|
||||
.ToHandleChecked();
|
||||
Local<Object> meta_obj = Local<Object>::Cast(v8::Utils::ToLocal(meta));
|
||||
CHECK(meta_obj->Get(context.local(), v8_str("foo"))
|
||||
.ToLocalChecked()
|
||||
@ -25880,6 +25882,102 @@ TEST(ImportMeta) {
|
||||
}
|
||||
}
|
||||
|
||||
void HostInitializeImportMetaObjectCallbackThrow(Local<Context> context,
|
||||
Local<Module> module,
|
||||
Local<Object> meta) {
|
||||
CcTest::isolate()->ThrowException(v8_num(42));
|
||||
}
|
||||
|
||||
TEST(ImportMetaThrowUnhandled) {
|
||||
i::FLAG_harmony_dynamic_import = true;
|
||||
i::FLAG_harmony_import_meta = true;
|
||||
LocalContext context;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
isolate->SetHostInitializeImportMetaObjectCallback(
|
||||
HostInitializeImportMetaObjectCallbackThrow);
|
||||
|
||||
Local<String> url = v8_str("www.google.com");
|
||||
Local<String> source_text =
|
||||
v8_str("export default function() { return import.meta }");
|
||||
v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
|
||||
Local<v8::Boolean>(), Local<v8::Integer>(),
|
||||
Local<v8::Value>(), Local<v8::Boolean>(),
|
||||
Local<v8::Boolean>(), True(isolate));
|
||||
v8::ScriptCompiler::Source source(source_text, origin);
|
||||
Local<Module> module =
|
||||
v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
||||
module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
|
||||
.ToChecked();
|
||||
|
||||
Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
|
||||
if (i::FLAG_harmony_top_level_await) {
|
||||
auto promise = Local<v8::Promise>::Cast(result);
|
||||
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
|
||||
}
|
||||
|
||||
Local<Object> ns = module->GetModuleNamespace().As<Object>();
|
||||
Local<Value> closure =
|
||||
ns->Get(context.local(), v8_str("default")).ToLocalChecked();
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
CHECK(Function::Cast(*closure)
|
||||
->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
|
||||
.IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
CHECK(try_catch.Exception()->StrictEquals(v8_num(42)));
|
||||
}
|
||||
|
||||
TEST(ImportMetaThrowHandled) {
|
||||
i::FLAG_harmony_dynamic_import = true;
|
||||
i::FLAG_harmony_import_meta = true;
|
||||
LocalContext context;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
isolate->SetHostInitializeImportMetaObjectCallback(
|
||||
HostInitializeImportMetaObjectCallbackThrow);
|
||||
|
||||
Local<String> url = v8_str("www.google.com");
|
||||
Local<String> source_text = v8_str(R"javascript(
|
||||
export default function() {
|
||||
try {
|
||||
import.meta;
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
)javascript");
|
||||
v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
|
||||
Local<v8::Boolean>(), Local<v8::Integer>(),
|
||||
Local<v8::Value>(), Local<v8::Boolean>(),
|
||||
Local<v8::Boolean>(), True(isolate));
|
||||
v8::ScriptCompiler::Source source(source_text, origin);
|
||||
Local<Module> module =
|
||||
v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
||||
module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
|
||||
.ToChecked();
|
||||
|
||||
Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
|
||||
if (i::FLAG_harmony_top_level_await) {
|
||||
auto promise = Local<v8::Promise>::Cast(result);
|
||||
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
|
||||
}
|
||||
|
||||
Local<Object> ns = module->GetModuleNamespace().As<Object>();
|
||||
Local<Value> closure =
|
||||
ns->Get(context.local(), v8_str("default")).ToLocalChecked();
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
CHECK(Function::Cast(*closure)
|
||||
->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
|
||||
.ToLocalChecked()
|
||||
->IsTrue());
|
||||
CHECK(!try_catch.HasCaught());
|
||||
}
|
||||
|
||||
TEST(GetModuleNamespace) {
|
||||
LocalContext context;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
|
47
test/mjsunit/modules-import-meta-turbo.mjs
Normal file
47
test/mjsunit/modules-import-meta-turbo.mjs
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
// Flags: --allow-natives-syntax --opt
|
||||
|
||||
import { getImportMeta } from 'modules-skip-import-meta-export.mjs';
|
||||
|
||||
function foo() {
|
||||
return import.meta;
|
||||
}
|
||||
%PrepareFunctionForOptimization(foo);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
// Optimize when import.meta hasn't been created yet.
|
||||
assertEquals('object', typeof foo());
|
||||
assertEquals(import.meta, foo());
|
||||
assertOptimized(foo);
|
||||
|
||||
function bar() {
|
||||
return import.meta;
|
||||
}
|
||||
%PrepareFunctionForOptimization(bar);
|
||||
// Optimize when import.meta already exists.
|
||||
%OptimizeFunctionOnNextCall(bar);
|
||||
assertEquals(import.meta, bar());
|
||||
assertOptimized(bar);
|
||||
|
||||
%PrepareFunctionForOptimization(getImportMeta);
|
||||
%OptimizeFunctionOnNextCall(getImportMeta);
|
||||
assertEquals('object', typeof getImportMeta());
|
||||
assertOptimized(getImportMeta);
|
||||
assertNotEquals(import.meta, getImportMeta());
|
||||
assertOptimized(getImportMeta);
|
||||
|
||||
|
||||
function baz() {
|
||||
return getImportMeta();
|
||||
}
|
||||
|
||||
// Test inlined (from another module) import.meta accesses.
|
||||
%PrepareFunctionForOptimization(baz);
|
||||
baz();
|
||||
%OptimizeFunctionOnNextCall(baz);
|
||||
assertEquals('object', typeof baz());
|
||||
assertNotEquals(import.meta, baz());
|
||||
assertEquals(baz(), getImportMeta());
|
||||
assertOptimized(baz);
|
3
test/mjsunit/modules-skip-import-meta-export.mjs
Normal file
3
test/mjsunit/modules-skip-import-meta-export.mjs
Normal file
@ -0,0 +1,3 @@
|
||||
export function getImportMeta() {
|
||||
return import.meta;
|
||||
}
|
Loading…
Reference in New Issue
Block a user