LCOV - code coverage report
Current view: top level - src/asmjs - asm-js.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 136 145 93.8 %
Date: 2019-02-19 Functions: 16 17 94.1 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/asmjs/asm-js.h"
       6             : 
       7             : #include "src/asmjs/asm-names.h"
       8             : #include "src/asmjs/asm-parser.h"
       9             : #include "src/assert-scope.h"
      10             : #include "src/ast/ast.h"
      11             : #include "src/base/optional.h"
      12             : #include "src/base/platform/elapsed-timer.h"
      13             : #include "src/compiler.h"
      14             : #include "src/counters.h"
      15             : #include "src/execution.h"
      16             : #include "src/handles.h"
      17             : #include "src/heap/factory.h"
      18             : #include "src/isolate.h"
      19             : #include "src/message-template.h"
      20             : #include "src/objects-inl.h"
      21             : #include "src/objects/heap-number-inl.h"
      22             : #include "src/parsing/parse-info.h"
      23             : #include "src/parsing/scanner-character-streams.h"
      24             : #include "src/parsing/scanner.h"
      25             : #include "src/unoptimized-compilation-info.h"
      26             : 
      27             : #include "src/wasm/wasm-engine.h"
      28             : #include "src/wasm/wasm-js.h"
      29             : #include "src/wasm/wasm-limits.h"
      30             : #include "src/wasm/wasm-module-builder.h"
      31             : #include "src/wasm/wasm-objects-inl.h"
      32             : #include "src/wasm/wasm-result.h"
      33             : 
      34             : namespace v8 {
      35             : namespace internal {
      36             : 
      37             : const char* const AsmJs::kSingleFunctionName = "__single_function__";
      38             : 
      39             : namespace {
      40             : 
      41        4853 : Handle<Object> StdlibMathMember(Isolate* isolate, Handle<JSReceiver> stdlib,
      42             :                                 Handle<Name> name) {
      43             :   Handle<Name> math_name(
      44        4853 :       isolate->factory()->InternalizeOneByteString(StaticCharVector("Math")));
      45        4853 :   Handle<Object> math = JSReceiver::GetDataProperty(stdlib, math_name);
      46        9710 :   if (!math->IsJSReceiver()) return isolate->factory()->undefined_value();
      47        4849 :   Handle<JSReceiver> math_receiver = Handle<JSReceiver>::cast(math);
      48        4849 :   Handle<Object> value = JSReceiver::GetDataProperty(math_receiver, name);
      49        4849 :   return value;
      50             : }
      51             : 
      52        2143 : bool AreStdlibMembersValid(Isolate* isolate, Handle<JSReceiver> stdlib,
      53             :                            wasm::AsmJsParser::StdlibSet members,
      54             :                            bool* is_typed_array) {
      55        2143 :   if (members.contains(wasm::AsmJsParser::StandardMember::kInfinity)) {
      56             :     members.Remove(wasm::AsmJsParser::StandardMember::kInfinity);
      57             :     Handle<Name> name = isolate->factory()->Infinity_string();
      58           8 :     Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);
      59          32 :     if (!value->IsNumber() || !std::isinf(value->Number())) return false;
      60             :   }
      61        2143 :   if (members.contains(wasm::AsmJsParser::StandardMember::kNaN)) {
      62             :     members.Remove(wasm::AsmJsParser::StandardMember::kNaN);
      63             :     Handle<Name> name = isolate->factory()->NaN_string();
      64          16 :     Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);
      65          32 :     if (!value->IsNaN()) return false;
      66             :   }
      67             : #define STDLIB_MATH_FUNC(fname, FName, ignore1, ignore2)                   \
      68             :   if (members.contains(wasm::AsmJsParser::StandardMember::kMath##FName)) { \
      69             :     members.Remove(wasm::AsmJsParser::StandardMember::kMath##FName);       \
      70             :     Handle<Name> name(isolate->factory()->InternalizeOneByteString(        \
      71             :         StaticCharVector(#fname)));                                        \
      72             :     Handle<Object> value = StdlibMathMember(isolate, stdlib, name);        \
      73             :     if (!value->IsJSFunction()) return false;                              \
      74             :     SharedFunctionInfo shared = Handle<JSFunction>::cast(value)->shared(); \
      75             :     if (!shared->HasBuiltinId() ||                                         \
      76             :         shared->builtin_id() != Builtins::kMath##FName) {                  \
      77             :       return false;                                                        \
      78             :     }                                                                      \
      79             :     DCHECK_EQ(shared->GetCode(),                                           \
      80             :               isolate->builtins()->builtin(Builtins::kMath##FName));       \
      81             :   }
      82       64582 :   STDLIB_MATH_FUNCTION_LIST(STDLIB_MATH_FUNC)
      83             : #undef STDLIB_MATH_FUNC
      84             : #define STDLIB_MATH_CONST(cname, const_value)                               \
      85             :   if (members.contains(wasm::AsmJsParser::StandardMember::kMath##cname)) {  \
      86             :     members.Remove(wasm::AsmJsParser::StandardMember::kMath##cname);        \
      87             :     Handle<Name> name(isolate->factory()->InternalizeOneByteString(         \
      88             :         StaticCharVector(#cname)));                                         \
      89             :     Handle<Object> value = StdlibMathMember(isolate, stdlib, name);         \
      90             :     if (!value->IsNumber() || value->Number() != const_value) return false; \
      91             :   }
      92       17524 :   STDLIB_MATH_VALUE_LIST(STDLIB_MATH_CONST)
      93             : #undef STDLIB_MATH_CONST
      94             : #define STDLIB_ARRAY_TYPE(fname, FName)                                \
      95             :   if (members.contains(wasm::AsmJsParser::StandardMember::k##FName)) { \
      96             :     members.Remove(wasm::AsmJsParser::StandardMember::k##FName);       \
      97             :     *is_typed_array = true;                                            \
      98             :     Handle<Name> name(isolate->factory()->InternalizeOneByteString(    \
      99             :         StaticCharVector(#FName)));                                    \
     100             :     Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);  \
     101             :     if (!value->IsJSFunction()) return false;                          \
     102             :     Handle<JSFunction> func = Handle<JSFunction>::cast(value);         \
     103             :     if (!func.is_identical_to(isolate->fname())) return false;         \
     104             :   }
     105        2801 :   STDLIB_ARRAY_TYPE(int8_array_fun, Int8Array)
     106        3091 :   STDLIB_ARRAY_TYPE(uint8_array_fun, Uint8Array)
     107        2741 :   STDLIB_ARRAY_TYPE(int16_array_fun, Int16Array)
     108        2621 :   STDLIB_ARRAY_TYPE(uint16_array_fun, Uint16Array)
     109        7101 :   STDLIB_ARRAY_TYPE(int32_array_fun, Int32Array)
     110        2761 :   STDLIB_ARRAY_TYPE(uint32_array_fun, Uint32Array)
     111        2901 :   STDLIB_ARRAY_TYPE(float32_array_fun, Float32Array)
     112        2699 :   STDLIB_ARRAY_TYPE(float64_array_fun, Float64Array)
     113             : #undef STDLIB_ARRAY_TYPE
     114             :   // All members accounted for.
     115             :   DCHECK(members.empty());
     116             :   return true;
     117             : }
     118             : 
     119         171 : void Report(Handle<Script> script, int position, Vector<const char> text,
     120             :             MessageTemplate message_template,
     121             :             v8::Isolate::MessageErrorLevel level) {
     122             :   Isolate* isolate = script->GetIsolate();
     123         171 :   MessageLocation location(script, position, position);
     124         171 :   Handle<String> text_object = isolate->factory()->InternalizeUtf8String(text);
     125             :   Handle<JSMessageObject> message = MessageHandler::MakeMessageObject(
     126             :       isolate, message_template, &location, text_object,
     127         171 :       Handle<FixedArray>::null());
     128         171 :   message->set_error_level(level);
     129         171 :   MessageHandler::ReportMessage(isolate, &location, message);
     130         171 : }
     131             : 
     132             : // Hook to report successful execution of {AsmJs::CompileAsmViaWasm} phase.
     133        2439 : void ReportCompilationSuccess(Handle<Script> script, int position,
     134             :                               double translate_time, double compile_time,
     135             :                               size_t module_size) {
     136        4878 :   if (FLAG_suppress_asm_messages || !FLAG_trace_asm_time) return;
     137             :   EmbeddedVector<char, 100> text;
     138             :   int length = SNPrintF(
     139             :       text, "success, asm->wasm: %0.3f ms, compile: %0.3f ms, %" PRIuS " bytes",
     140           0 :       translate_time, compile_time, module_size);
     141           0 :   CHECK_NE(-1, length);
     142           0 :   text.Truncate(length);
     143             :   Report(script, position, text, MessageTemplate::kAsmJsCompiled,
     144           0 :          v8::Isolate::kMessageInfo);
     145             : }
     146             : 
     147             : // Hook to report failed execution of {AsmJs::CompileAsmViaWasm} phase.
     148             : void ReportCompilationFailure(ParseInfo* parse_info, int position,
     149             :                               const char* reason) {
     150        1248 :   if (FLAG_suppress_asm_messages) return;
     151             :   parse_info->pending_error_handler()->ReportWarningAt(
     152        1248 :       position, position, MessageTemplate::kAsmJsInvalid, reason);
     153             : }
     154             : 
     155             : // Hook to report successful execution of {AsmJs::InstantiateAsmWasm} phase.
     156        4791 : void ReportInstantiationSuccess(Handle<Script> script, int position,
     157             :                                 double instantiate_time) {
     158        9582 :   if (FLAG_suppress_asm_messages || !FLAG_trace_asm_time) return;
     159             :   EmbeddedVector<char, 50> text;
     160           0 :   int length = SNPrintF(text, "success, %0.3f ms", instantiate_time);
     161           0 :   CHECK_NE(-1, length);
     162           0 :   text.Truncate(length);
     163             :   Report(script, position, text, MessageTemplate::kAsmJsInstantiated,
     164           0 :          v8::Isolate::kMessageInfo);
     165             : }
     166             : 
     167             : // Hook to report failed execution of {AsmJs::InstantiateAsmWasm} phase.
     168         171 : void ReportInstantiationFailure(Handle<Script> script, int position,
     169             :                                 const char* reason) {
     170         171 :   if (FLAG_suppress_asm_messages) return;
     171         171 :   Vector<const char> text = CStrVector(reason);
     172             :   Report(script, position, text, MessageTemplate::kAsmJsLinkingFailed,
     173         171 :          v8::Isolate::kMessageWarning);
     174             : }
     175             : 
     176             : }  // namespace
     177             : 
     178             : // The compilation of asm.js modules is split into two distinct steps:
     179             : //  [1] ExecuteJobImpl: The asm.js module source is parsed, validated, and
     180             : //      translated to a valid WebAssembly module. The result are two vectors
     181             : //      representing the encoded module as well as encoded source position
     182             : //      information and a StdlibSet bit set.
     183             : //  [2] FinalizeJobImpl: The module is handed to WebAssembly which decodes it
     184             : //      into an internal representation and eventually compiles it to machine
     185             : //      code.
     186        7441 : class AsmJsCompilationJob final : public UnoptimizedCompilationJob {
     187             :  public:
     188        7442 :   explicit AsmJsCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal,
     189             :                                AccountingAllocator* allocator)
     190             :       : UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info,
     191             :                                   &compilation_info_),
     192             :         allocator_(allocator),
     193             :         zone_(allocator, ZONE_NAME),
     194             :         compilation_info_(&zone_, parse_info, literal),
     195             :         module_(nullptr),
     196             :         asm_offsets_(nullptr),
     197             :         translate_time_(0),
     198             :         compile_time_(0),
     199             :         module_source_size_(0),
     200             :         translate_time_micro_(0),
     201        7442 :         translate_zone_size_(0) {}
     202             : 
     203             :  protected:
     204             :   Status ExecuteJobImpl() final;
     205             :   Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
     206             :                          Isolate* isolate) final;
     207             : 
     208             :  private:
     209             :   void RecordHistograms(Isolate* isolate);
     210             : 
     211             :   AccountingAllocator* allocator_;
     212             :   Zone zone_;
     213             :   UnoptimizedCompilationInfo compilation_info_;
     214             :   wasm::ZoneBuffer* module_;
     215             :   wasm::ZoneBuffer* asm_offsets_;
     216             :   wasm::AsmJsParser::StdlibSet stdlib_uses_;
     217             : 
     218             :   double translate_time_;   // Time (milliseconds) taken to execute step [1].
     219             :   double compile_time_;     // Time (milliseconds) taken to execute step [2].
     220             :   int module_source_size_;  // Module source size in bytes.
     221             :   int64_t translate_time_micro_;  // Time (microseconds) taken to translate.
     222             :   size_t translate_zone_size_;
     223             : 
     224             :   DISALLOW_COPY_AND_ASSIGN(AsmJsCompilationJob);
     225             : };
     226             : 
     227        3721 : UnoptimizedCompilationJob::Status AsmJsCompilationJob::ExecuteJobImpl() {
     228             :   // Step 1: Translate asm.js module to WebAssembly module.
     229       23540 :   size_t compile_zone_start = compilation_info()->zone()->allocation_size();
     230             :   base::ElapsedTimer translate_timer;
     231             :   translate_timer.Start();
     232             : 
     233        3721 :   Zone* compile_zone = compilation_info()->zone();
     234        3721 :   Zone translate_zone(allocator_, ZONE_NAME);
     235             : 
     236             :   Utf16CharacterStream* stream = parse_info()->character_stream();
     237             :   base::Optional<AllowHandleDereference> allow_deref;
     238        3721 :   if (stream->can_access_heap()) {
     239             :     allow_deref.emplace();
     240             :   }
     241        3721 :   stream->Seek(compilation_info()->literal()->start_position());
     242        3721 :   wasm::AsmJsParser parser(&translate_zone, stack_limit(), stream);
     243        3717 :   if (!parser.Run()) {
     244        1248 :     if (!FLAG_suppress_asm_messages) {
     245             :       ReportCompilationFailure(parse_info(), parser.failure_location(),
     246        1248 :                                parser.failure_message());
     247             :     }
     248             :     return FAILED;
     249             :   }
     250        2470 :   module_ = new (compile_zone) wasm::ZoneBuffer(compile_zone);
     251        2470 :   parser.module_builder()->WriteTo(*module_);
     252        2469 :   asm_offsets_ = new (compile_zone) wasm::ZoneBuffer(compile_zone);
     253        2469 :   parser.module_builder()->WriteAsmJsOffsetTable(*asm_offsets_);
     254        2469 :   stdlib_uses_ = *parser.stdlib_uses();
     255             : 
     256             :   size_t compile_zone_size =
     257        4938 :       compilation_info()->zone()->allocation_size() - compile_zone_start;
     258        2469 :   translate_zone_size_ = translate_zone.allocation_size();
     259        2470 :   translate_time_ = translate_timer.Elapsed().InMillisecondsF();
     260        2470 :   translate_time_micro_ = translate_timer.Elapsed().InMicroseconds();
     261        4939 :   module_source_size_ = compilation_info()->literal()->end_position() -
     262        4938 :                         compilation_info()->literal()->start_position();
     263        2469 :   if (FLAG_trace_asm_parser) {
     264             :     PrintF(
     265             :         "[asm.js translation successful: time=%0.3fms, "
     266             :         "translate_zone=%" PRIuS "KB, compile_zone+=%" PRIuS "KB]\n",
     267           0 :         translate_time_, translate_zone_size_ / KB, compile_zone_size / KB);
     268             :   }
     269        3721 :   return SUCCEEDED;
     270             : }
     271             : 
     272        2439 : UnoptimizedCompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl(
     273             :     Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
     274             :   // Step 2: Compile and decode the WebAssembly module.
     275             :   base::ElapsedTimer compile_timer;
     276             :   compile_timer.Start();
     277             : 
     278             :   Handle<HeapNumber> uses_bitset =
     279        2439 :       isolate->factory()->NewHeapNumberFromBits(stdlib_uses_.ToIntegral());
     280             : 
     281             :   // The result is a compiled module and serialized standard library uses.
     282             :   wasm::ErrorThrower thrower(isolate, "AsmJs::Compile");
     283             :   Handle<AsmWasmData> result =
     284             :       isolate->wasm_engine()
     285             :           ->SyncCompileTranslatedAsmJs(
     286             :               isolate, &thrower,
     287             :               wasm::ModuleWireBytes(module_->begin(), module_->end()),
     288             :               Vector<const byte>(asm_offsets_->begin(), asm_offsets_->size()),
     289        9756 :               uses_bitset)
     290        4878 :           .ToHandleChecked();
     291             :   DCHECK(!thrower.error());
     292        2439 :   compile_time_ = compile_timer.Elapsed().InMillisecondsF();
     293             : 
     294        7317 :   compilation_info()->SetAsmWasmData(result);
     295             : 
     296        2439 :   RecordHistograms(isolate);
     297             :   ReportCompilationSuccess(parse_info()->script(),
     298        2439 :                            compilation_info()->literal()->position(),
     299        9756 :                            translate_time_, compile_time_, module_->size());
     300        2439 :   return SUCCEEDED;
     301             : }
     302             : 
     303        2439 : void AsmJsCompilationJob::RecordHistograms(Isolate* isolate) {
     304             :   Counters* counters = isolate->counters();
     305             :   counters->asm_wasm_translation_time()->AddSample(
     306        2439 :       static_cast<int>(translate_time_micro_));
     307             :   counters->asm_wasm_translation_peak_memory_bytes()->AddSample(
     308        2439 :       static_cast<int>(translate_zone_size_));
     309        2439 :   counters->asm_module_size_bytes()->AddSample(module_source_size_);
     310             :   // translation_throughput is not exact (assumes MB == 1000000). But that is ok
     311             :   // since the metric is stored in buckets that lose some precision anyways.
     312             :   int translation_throughput =
     313        2439 :       translate_time_micro_ != 0
     314        2439 :           ? static_cast<int>(static_cast<int64_t>(module_source_size_) /
     315             :                              translate_time_micro_)
     316        4878 :           : 0;
     317             :   counters->asm_wasm_translation_throughput()->AddSample(
     318        2439 :       translation_throughput);
     319        2439 : }
     320             : 
     321        3721 : UnoptimizedCompilationJob* AsmJs::NewCompilationJob(
     322             :     ParseInfo* parse_info, FunctionLiteral* literal,
     323             :     AccountingAllocator* allocator) {
     324        3721 :   return new AsmJsCompilationJob(parse_info, literal, allocator);
     325             : }
     326             : 
     327             : namespace {
     328        1324 : inline bool IsValidAsmjsMemorySize(size_t size) {
     329             :   // Enforce asm.js spec minimum size.
     330        1324 :   if (size < (1u << 12u)) return false;
     331             :   // Enforce engine-limited and flag-limited maximum allocation size.
     332        1269 :   if (size > wasm::max_mem_pages() * uint64_t{wasm::kWasmPageSize}) {
     333             :     return false;
     334             :   }
     335             :   // Enforce power-of-2 sizes for 2^12 - 2^24.
     336        1261 :   if (size < (1u << 24u)) {
     337        1154 :     uint32_t size32 = static_cast<uint32_t>(size);
     338        1154 :     return base::bits::IsPowerOfTwo(size32);
     339             :   }
     340             :   // Enforce multiple of 2^24 for sizes >= 2^24
     341         107 :   if ((size % (1u << 24u)) != 0) return false;
     342             :   // All checks passed!
     343          98 :   return true;
     344             : }
     345             : }  // namespace
     346             : 
     347        4962 : MaybeHandle<Object> AsmJs::InstantiateAsmWasm(Isolate* isolate,
     348             :                                               Handle<SharedFunctionInfo> shared,
     349             :                                               Handle<AsmWasmData> wasm_data,
     350             :                                               Handle<JSReceiver> stdlib,
     351             :                                               Handle<JSReceiver> foreign,
     352             :                                               Handle<JSArrayBuffer> memory) {
     353             :   base::ElapsedTimer instantiate_timer;
     354             :   instantiate_timer.Start();
     355        9924 :   Handle<HeapNumber> uses_bitset(wasm_data->uses_bitset(), isolate);
     356        9924 :   Handle<Script> script(Script::cast(shared->script()), isolate);
     357             : 
     358             :   // Allocate the WasmModuleObject.
     359             :   Handle<WasmModuleObject> module =
     360             :       isolate->wasm_engine()->FinalizeTranslatedAsmJs(isolate, wasm_data,
     361        4962 :                                                       script);
     362             : 
     363             :   // TODO(mstarzinger): The position currently points to the module definition
     364             :   // but should instead point to the instantiation site (more intuitive).
     365        4962 :   int position = shared->StartPosition();
     366             : 
     367             :   // Check that all used stdlib members are valid.
     368        4962 :   bool stdlib_use_of_typed_array_present = false;
     369             :   wasm::AsmJsParser::StdlibSet stdlib_uses =
     370             :       wasm::AsmJsParser::StdlibSet::FromIntegral(uses_bitset->value_as_bits());
     371        4962 :   if (!stdlib_uses.empty()) {  // No checking needed if no uses.
     372        2159 :     if (stdlib.is_null()) {
     373          16 :       ReportInstantiationFailure(script, position, "Requires standard library");
     374          16 :       return MaybeHandle<Object>();
     375             :     }
     376        2143 :     if (!AreStdlibMembersValid(isolate, stdlib, stdlib_uses,
     377        2143 :                                &stdlib_use_of_typed_array_present)) {
     378          12 :       ReportInstantiationFailure(script, position, "Unexpected stdlib member");
     379          12 :       return MaybeHandle<Object>();
     380             :     }
     381             :   }
     382             : 
     383             :   // Check that a valid heap buffer is provided if required.
     384        4934 :   if (stdlib_use_of_typed_array_present) {
     385        1336 :     if (memory.is_null()) {
     386          12 :       ReportInstantiationFailure(script, position, "Requires heap buffer");
     387          12 :       return MaybeHandle<Object>();
     388             :     }
     389             :     memory->set_is_growable(false);
     390             :     size_t size = memory->byte_length();
     391             :     // Check the asm.js heap size against the valid limits.
     392        1324 :     if (!IsValidAsmjsMemorySize(size)) {
     393          84 :       ReportInstantiationFailure(script, position, "Invalid heap size");
     394          84 :       return MaybeHandle<Object>();
     395             :     }
     396             :   } else {
     397             :     memory = Handle<JSArrayBuffer>::null();
     398             :   }
     399             : 
     400             :   wasm::ErrorThrower thrower(isolate, "AsmJs::Instantiate");
     401             :   MaybeHandle<Object> maybe_module_object =
     402             :       isolate->wasm_engine()->SyncInstantiate(isolate, &thrower, module,
     403        4838 :                                               foreign, memory);
     404        4838 :   if (maybe_module_object.is_null()) {
     405             :     // An exception caused by the module start function will be set as pending
     406             :     // and bypass the {ErrorThrower}, this happens in case of a stack overflow.
     407          47 :     if (isolate->has_pending_exception()) isolate->clear_pending_exception();
     408          47 :     if (thrower.error()) {
     409             :       ScopedVector<char> error_reason(100);
     410          43 :       SNPrintF(error_reason, "Internal wasm failure: %s", thrower.error_msg());
     411          43 :       ReportInstantiationFailure(script, position, error_reason.start());
     412             :     } else {
     413           4 :       ReportInstantiationFailure(script, position, "Internal wasm failure");
     414             :     }
     415          47 :     thrower.Reset();  // Ensure exceptions do not propagate.
     416          47 :     return MaybeHandle<Object>();
     417             :   }
     418             :   DCHECK(!thrower.error());
     419        4791 :   Handle<Object> module_object = maybe_module_object.ToHandleChecked();
     420             : 
     421             :   ReportInstantiationSuccess(script, position,
     422        4791 :                              instantiate_timer.Elapsed().InMillisecondsF());
     423             : 
     424             :   Handle<Name> single_function_name(
     425        4791 :       isolate->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName));
     426             :   MaybeHandle<Object> single_function =
     427        4791 :       Object::GetProperty(isolate, module_object, single_function_name);
     428       14373 :   if (!single_function.is_null() &&
     429        9582 :       !single_function.ToHandleChecked()->IsUndefined(isolate)) {
     430         256 :     return single_function;
     431             :   }
     432             : 
     433             :   Handle<String> exports_name =
     434        4535 :       isolate->factory()->InternalizeUtf8String("exports");
     435        4535 :   return Object::GetProperty(isolate, module_object, exports_name);
     436             : }
     437             : 
     438             : }  // namespace internal
     439      178779 : }  // namespace v8

Generated by: LCOV version 1.10