From cd718536ec8ca83a1619a78f4839ff2c8cb932c1 Mon Sep 17 00:00:00 2001 From: Georg Neis Date: Wed, 15 Jul 2020 16:55:51 +0200 Subject: [PATCH] [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 Commit-Queue: Georg Neis Cr-Commit-Position: refs/heads/master@{#68875} --- src/compiler/heap-refs.h | 4 + src/compiler/js-context-specialization.cc | 58 ++++++++++ src/compiler/js-context-specialization.h | 5 +- src/compiler/js-generic-lowering.cc | 4 + src/compiler/js-heap-broker.cc | 45 +++++++- src/compiler/js-intrinsic-lowering.cc | 7 ++ src/compiler/js-intrinsic-lowering.h | 1 + src/compiler/js-operator.cc | 8 ++ src/compiler/js-operator.h | 2 + src/compiler/opcodes.h | 1 + src/compiler/operator-properties.cc | 2 + .../serializer-for-background-compilation.cc | 14 +++ src/compiler/typer.cc | 2 + src/compiler/verifier.cc | 4 + src/execution/isolate.cc | 7 +- src/execution/isolate.h | 2 +- src/objects/source-text-module.cc | 7 +- src/objects/source-text-module.h | 2 +- src/runtime/runtime-module.cc | 3 +- test/cctest/test-api.cc | 104 +++++++++++++++++- test/mjsunit/modules-import-meta-turbo.mjs | 47 ++++++++ .../modules-skip-import-meta-export.mjs | 3 + 22 files changed, 320 insertions(+), 12 deletions(-) create mode 100644 test/mjsunit/modules-import-meta-turbo.mjs create mode 100644 test/mjsunit/modules-skip-import-meta-export.mjs diff --git a/src/compiler/heap-refs.h b/src/compiler/heap-refs.h index ef0da29a05..209d2ee4e5 100644 --- a/src/compiler/heap-refs.h +++ b/src/compiler/heap-refs.h @@ -135,6 +135,7 @@ class V8_EXPORT_PRIVATE ObjectRef { #undef HEAP_AS_METHOD_DECL bool IsNullOrUndefined() const; + bool IsTheHole() const; bool BooleanValue() const; Maybe 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 GetCell(int cell_index) const; + ObjectRef import_meta() const; }; class TemplateObjectDescriptionRef : public HeapObjectRef { diff --git a/src/compiler/js-context-specialization.cc b/src/compiler/js-context-specialization.cc index c64b61746b..21f6c887c0 100644 --- a/src/compiler/js-context-specialization.cc +++ b/src/compiler/js-context-specialization.cc @@ -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 GetModuleContext(JSHeapBroker* broker, Node* node, + Maybe maybe_context) { + size_t depth = std::numeric_limits::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(); +} + +Reduction JSContextSpecialization::ReduceJSGetImportMeta(Node* node) { + base::Optional 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(); diff --git a/src/compiler/js-context-specialization.h b/src/compiler/js-context-specialization.h index 14a72a70b5..f74bd5b6de 100644 --- a/src/compiler/js-context-specialization.h +++ b/src/compiler/js-context-specialization.h @@ -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); diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index c00c6471ae..0950248087 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -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. } diff --git a/src/compiler/js-heap-broker.cc b/src/compiler/js-heap-broker.cc index c44edc82cd..45f301359d 100644 --- a/src/compiler/js-heap-broker.cc +++ b/src/compiler/js-heap-broker.cc @@ -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 imports_; ZoneVector exports_; + ObjectData* import_meta_; }; SourceTextModuleData::SourceTextModuleData(JSHeapBroker* broker, @@ -1867,7 +1869,8 @@ SourceTextModuleData::SourceTextModuleData(JSHeapBroker* broker, Handle 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 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 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, bool check_type) : broker_(broker) { diff --git a/src/compiler/js-intrinsic-lowering.cc b/src/compiler/js-intrinsic-lowering.cc index 604cd20f5e..044c63a199 100644 --- a/src/compiler/js-intrinsic-lowering.cc +++ b/src/compiler/js-intrinsic-lowering.cc @@ -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); diff --git a/src/compiler/js-intrinsic-lowering.h b/src/compiler/js-intrinsic-lowering.h index 2331446c12..3deeb5685e 100644 --- a/src/compiler/js-intrinsic-lowering.h +++ b/src/compiler/js-intrinsic-lowering.h @@ -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); diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc index 67133a9bc6..206c8cebea 100644 --- a/src/compiler/js-operator.cc +++ b/src/compiler/js-operator.cc @@ -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>( // -- IrOpcode::kJSStoreModule, // opcode diff --git a/src/compiler/js-operator.h b/src/compiler/js-operator.h index 422a675d31..1df5326ae4 100644 --- a/src/compiler/js-operator.h +++ b/src/compiler/js-operator.h @@ -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(); diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 3358830e74..f041164abd 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -217,6 +217,7 @@ V(JSStoreMessage) \ V(JSLoadModule) \ V(JSStoreModule) \ + V(JSGetImportMeta) \ V(JSGeneratorStore) \ V(JSGeneratorRestoreContinuation) \ V(JSGeneratorRestoreContext) \ diff --git a/src/compiler/operator-properties.cc b/src/compiler/operator-properties.cc index bf0f724a99..c7851dd263 100644 --- a/src/compiler/operator-properties.cc +++ b/src/compiler/operator-properties.cc @@ -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: diff --git a/src/compiler/serializer-for-background-compilation.cc b/src/compiler/serializer-for-background-compilation.cc index 1275a3ecde..c800fac489 100644 --- a/src/compiler/serializer-for-background-compilation.cc +++ b/src/compiler/serializer-for-background-compilation.cc @@ -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; } diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 5e42e23f5e..3eefd5429d 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -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) { diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index 1a0995c066..aa516cc475 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -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; diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc index 7b0beeb3ad..d4f49a0f4b 100644 --- a/src/execution/isolate.cc +++ b/src/execution/isolate.cc @@ -4065,7 +4065,7 @@ void Isolate::SetHostImportModuleDynamicallyCallback( host_import_module_dynamically_callback_ = callback; } -Handle Isolate::RunHostInitializeImportMetaObjectCallback( +MaybeHandle Isolate::RunHostInitializeImportMetaObjectCallback( Handle module) { CHECK(module->import_meta().IsTheHole(this)); Handle import_meta = factory()->NewJSObjectWithNullProto(); @@ -4075,7 +4075,10 @@ Handle Isolate::RunHostInitializeImportMetaObjectCallback( host_initialize_import_meta_object_callback_( api_context, Utils::ToLocal(Handle::cast(module)), v8::Local::Cast(v8::Utils::ToLocal(import_meta))); - CHECK(!has_scheduled_exception()); + if (has_scheduled_exception()) { + PromoteScheduledException(); + return {}; + } } return import_meta; } diff --git a/src/execution/isolate.h b/src/execution/isolate.h index 4b7dcb38a5..af9af65032 100644 --- a/src/execution/isolate.h +++ b/src/execution/isolate.h @@ -1435,7 +1435,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { void SetHostInitializeImportMetaObjectCallback( HostInitializeImportMetaObjectCallback callback); - Handle RunHostInitializeImportMetaObjectCallback( + MaybeHandle RunHostInitializeImportMetaObjectCallback( Handle module); void RegisterEmbeddedFileWriter(EmbeddedFileWriterInterface* writer) { diff --git a/src/objects/source-text-module.cc b/src/objects/source-text-module.cc index a47d472dd2..bffe6b6061 100644 --- a/src/objects/source-text-module.cc +++ b/src/objects/source-text-module.cc @@ -582,11 +582,14 @@ Handle SourceTextModule::GetModuleNamespace( return Module::GetModuleNamespace(isolate, requested_module); } -Handle SourceTextModule::GetImportMeta( +MaybeHandle SourceTextModule::GetImportMeta( Isolate* isolate, Handle module) { Handle 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::cast(import_meta); diff --git a/src/objects/source-text-module.h b/src/objects/source-text-module.h index 9197081254..f7ebf3f28f 100644 --- a/src/objects/source-text-module.h +++ b/src/objects/source-text-module.h @@ -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 GetImportMeta( + V8_EXPORT_PRIVATE static MaybeHandle GetImportMeta( Isolate* isolate, Handle module); using BodyDescriptor = diff --git a/src/runtime/runtime-module.cc b/src/runtime/runtime-module.cc index ecc9ad534e..dd15f64be5 100644 --- a/src/runtime/runtime-module.cc +++ b/src/runtime/runtime-module.cc @@ -41,7 +41,8 @@ RUNTIME_FUNCTION(Runtime_GetImportMetaObject) { HandleScope scope(isolate); DCHECK_EQ(0, args.length()); Handle module(isolate->context().module(), isolate); - return *SourceTextModule::GetImportMeta(isolate, module); + RETURN_RESULT_OR_FAILURE(isolate, + SourceTextModule::GetImportMeta(isolate, module)); } } // namespace internal diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index e97c7e74f1..78a7c8ce4b 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -25856,9 +25856,11 @@ TEST(ImportMeta) { v8::ScriptCompiler::Source source(source_text, origin); Local module = v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); - i::Handle meta = i::SourceTextModule::GetImportMeta( - i_isolate, - i::Handle::cast(v8::Utils::OpenHandle(*module))); + i::Handle meta = + i::SourceTextModule::GetImportMeta( + i_isolate, + i::Handle::cast(v8::Utils::OpenHandle(*module))) + .ToHandleChecked(); Local meta_obj = Local::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, + Local module, + Local 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 url = v8_str("www.google.com"); + Local source_text = + v8_str("export default function() { return import.meta }"); + v8::ScriptOrigin origin(url, Local(), Local(), + Local(), Local(), + Local(), Local(), + Local(), True(isolate)); + v8::ScriptCompiler::Source source(source_text, origin); + Local module = + v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); + module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback) + .ToChecked(); + + Local result = module->Evaluate(context.local()).ToLocalChecked(); + if (i::FLAG_harmony_top_level_await) { + auto promise = Local::Cast(result); + CHECK_EQ(promise->State(), v8::Promise::kFulfilled); + } + + Local ns = module->GetModuleNamespace().As(); + Local 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 url = v8_str("www.google.com"); + Local source_text = v8_str(R"javascript( + export default function() { + try { + import.meta; + } catch { + return true; + } + return false; + } + )javascript"); + v8::ScriptOrigin origin(url, Local(), Local(), + Local(), Local(), + Local(), Local(), + Local(), True(isolate)); + v8::ScriptCompiler::Source source(source_text, origin); + Local module = + v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); + module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback) + .ToChecked(); + + Local result = module->Evaluate(context.local()).ToLocalChecked(); + if (i::FLAG_harmony_top_level_await) { + auto promise = Local::Cast(result); + CHECK_EQ(promise->State(), v8::Promise::kFulfilled); + } + + Local ns = module->GetModuleNamespace().As(); + Local 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(); diff --git a/test/mjsunit/modules-import-meta-turbo.mjs b/test/mjsunit/modules-import-meta-turbo.mjs new file mode 100644 index 0000000000..c54e940ab6 --- /dev/null +++ b/test/mjsunit/modules-import-meta-turbo.mjs @@ -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); diff --git a/test/mjsunit/modules-skip-import-meta-export.mjs b/test/mjsunit/modules-skip-import-meta-export.mjs new file mode 100644 index 0000000000..5d111ace69 --- /dev/null +++ b/test/mjsunit/modules-skip-import-meta-export.mjs @@ -0,0 +1,3 @@ +export function getImportMeta() { + return import.meta; +}