LCOV - code coverage report
Current view: top level - src/builtins - setup-builtins-internal.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 86 91 94.5 %
Date: 2019-04-18 Functions: 11 12 91.7 %

          Line data    Source code
       1             : // Copyright 2017 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/setup-isolate.h"
       6             : 
       7             : #include "src/assembler-inl.h"
       8             : #include "src/builtins/builtins.h"
       9             : #include "src/code-events.h"
      10             : #include "src/compiler/code-assembler.h"
      11             : #include "src/handles-inl.h"
      12             : #include "src/heap/heap-inl.h"  // For MemoryAllocator::code_range.
      13             : #include "src/interface-descriptors.h"
      14             : #include "src/interpreter/bytecodes.h"
      15             : #include "src/interpreter/interpreter-generator.h"
      16             : #include "src/interpreter/interpreter.h"
      17             : #include "src/isolate.h"
      18             : #include "src/macro-assembler.h"
      19             : #include "src/objects-inl.h"
      20             : #include "src/objects/shared-function-info.h"
      21             : #include "src/objects/smi.h"
      22             : 
      23             : namespace v8 {
      24             : namespace internal {
      25             : 
      26             : // Forward declarations for C++ builtins.
      27             : #define FORWARD_DECLARE(Name) \
      28             :   Address Builtin_##Name(int argc, Address* args, Isolate* isolate);
      29             : BUILTIN_LIST_C(FORWARD_DECLARE)
      30             : #undef FORWARD_DECLARE
      31             : 
      32             : namespace {
      33             : 
      34             : void PostBuildProfileAndTracing(Isolate* isolate, Code code, const char* name) {
      35       85232 :   PROFILE(isolate, CodeCreateEvent(CodeEventListener::BUILTIN_TAG,
      36             :                                    AbstractCode::cast(code), name));
      37             : }
      38             : 
      39       85232 : AssemblerOptions BuiltinAssemblerOptions(Isolate* isolate,
      40             :                                          int32_t builtin_index) {
      41       85232 :   AssemblerOptions options = AssemblerOptions::Default(isolate);
      42       85232 :   CHECK(!options.isolate_independent_code);
      43       85232 :   CHECK(!options.use_pc_relative_calls_and_jumps);
      44       85232 :   CHECK(!options.collect_win64_unwind_info);
      45             : 
      46       85232 :   if (!isolate->IsGeneratingEmbeddedBuiltins() ||
      47             :       !Builtins::IsIsolateIndependent(builtin_index)) {
      48             :     return options;
      49             :   }
      50             : 
      51             :   const base::AddressRegion& code_range =
      52             :       isolate->heap()->memory_allocator()->code_range();
      53             :   bool pc_relative_calls_fit_in_code_range =
      54      170464 :       !code_range.is_empty() &&
      55       85232 :       std::ceil(static_cast<float>(code_range.size() / MB)) <=
      56             :           kMaxPCRelativeCodeRangeInMB;
      57             : 
      58       85232 :   options.isolate_independent_code = true;
      59       85232 :   options.use_pc_relative_calls_and_jumps = pc_relative_calls_fit_in_code_range;
      60       85232 :   options.collect_win64_unwind_info = true;
      61             : 
      62             :   return options;
      63             : }
      64             : 
      65             : typedef void (*MacroAssemblerGenerator)(MacroAssembler*);
      66             : typedef void (*CodeAssemblerGenerator)(compiler::CodeAssemblerState*);
      67             : 
      68       85232 : Handle<Code> BuildPlaceholder(Isolate* isolate, int32_t builtin_index) {
      69             :   HandleScope scope(isolate);
      70             :   constexpr int kBufferSize = 1 * KB;
      71             :   byte buffer[kBufferSize];
      72             :   MacroAssembler masm(isolate, CodeObjectRequired::kYes,
      73      170464 :                       ExternalAssemblerBuffer(buffer, kBufferSize));
      74             :   DCHECK(!masm.has_frame());
      75             :   {
      76       85232 :     FrameScope scope(&masm, StackFrame::NONE);
      77             :     // The contents of placeholder don't matter, as long as they don't create
      78             :     // embedded constants or external references.
      79       85232 :     masm.Move(kJavaScriptCallCodeStartRegister, Smi::zero());
      80             :     masm.Call(kJavaScriptCallCodeStartRegister);
      81             :   }
      82       85232 :   CodeDesc desc;
      83             :   masm.GetCode(isolate, &desc);
      84             :   Handle<Code> code = isolate->factory()->NewCode(
      85      170464 :       desc, Code::BUILTIN, masm.CodeObject(), builtin_index);
      86      170464 :   return scope.CloseAndEscape(code);
      87             : }
      88             : 
      89        3920 : Code BuildWithMacroAssembler(Isolate* isolate, int32_t builtin_index,
      90             :                              MacroAssemblerGenerator generator,
      91             :                              const char* s_name) {
      92             :   HandleScope scope(isolate);
      93             :   // Canonicalize handles, so that we can share constant pool entries pointing
      94             :   // to code targets without dereferencing their handles.
      95        7840 :   CanonicalHandleScope canonical(isolate);
      96             :   constexpr int kBufferSize = 32 * KB;
      97             :   byte buffer[kBufferSize];
      98             : 
      99        7840 :   MacroAssembler masm(isolate, BuiltinAssemblerOptions(isolate, builtin_index),
     100             :                       CodeObjectRequired::kYes,
     101       11760 :                       ExternalAssemblerBuffer(buffer, kBufferSize));
     102             :   masm.set_builtin_index(builtin_index);
     103             :   DCHECK(!masm.has_frame());
     104        3920 :   generator(&masm);
     105             : 
     106             :   int handler_table_offset = 0;
     107             : 
     108             :   // JSEntry builtins are a special case and need to generate a handler table.
     109             :   DCHECK_EQ(Builtins::KindOf(Builtins::kJSEntry), Builtins::ASM);
     110             :   DCHECK_EQ(Builtins::KindOf(Builtins::kJSConstructEntry), Builtins::ASM);
     111             :   DCHECK_EQ(Builtins::KindOf(Builtins::kJSRunMicrotasksEntry), Builtins::ASM);
     112        3920 :   if (Builtins::IsJSEntryVariant(builtin_index)) {
     113         168 :     handler_table_offset = HandlerTable::EmitReturnTableStart(&masm);
     114             :     HandlerTable::EmitReturnEntry(
     115         168 :         &masm, 0, isolate->builtins()->js_entry_handler_offset());
     116             :   }
     117             : 
     118        3920 :   CodeDesc desc;
     119             :   masm.GetCode(isolate, &desc, MacroAssembler::kNoSafepointTable,
     120        3920 :                handler_table_offset);
     121             : 
     122             :   static constexpr bool kIsNotTurbofanned = false;
     123             :   static constexpr int kStackSlots = 0;
     124             : 
     125             :   Handle<Code> code = isolate->factory()->NewCode(
     126             :       desc, Code::BUILTIN, masm.CodeObject(), builtin_index,
     127             :       MaybeHandle<ByteArray>(), DeoptimizationData::Empty(isolate), kMovable,
     128       11760 :       kIsNotTurbofanned, kStackSlots);
     129             : #if defined(V8_OS_WIN_X64)
     130             :   isolate->SetBuiltinUnwindData(builtin_index, masm.GetUnwindInfo());
     131             : #endif
     132             :   PostBuildProfileAndTracing(isolate, *code, s_name);
     133        3920 :   return *code;
     134             : }
     135             : 
     136       15568 : Code BuildAdaptor(Isolate* isolate, int32_t builtin_index,
     137             :                   Address builtin_address,
     138             :                   Builtins::ExitFrameType exit_frame_type, const char* name) {
     139             :   HandleScope scope(isolate);
     140             :   // Canonicalize handles, so that we can share constant pool entries pointing
     141             :   // to code targets without dereferencing their handles.
     142       31136 :   CanonicalHandleScope canonical(isolate);
     143             :   constexpr int kBufferSize = 32 * KB;
     144             :   byte buffer[kBufferSize];
     145       31136 :   MacroAssembler masm(isolate, BuiltinAssemblerOptions(isolate, builtin_index),
     146             :                       CodeObjectRequired::kYes,
     147       46704 :                       ExternalAssemblerBuffer(buffer, kBufferSize));
     148             :   masm.set_builtin_index(builtin_index);
     149             :   DCHECK(!masm.has_frame());
     150       15568 :   Builtins::Generate_Adaptor(&masm, builtin_address, exit_frame_type);
     151       15568 :   CodeDesc desc;
     152             :   masm.GetCode(isolate, &desc);
     153             :   Handle<Code> code = isolate->factory()->NewCode(
     154       31136 :       desc, Code::BUILTIN, masm.CodeObject(), builtin_index);
     155             :   PostBuildProfileAndTracing(isolate, *code, name);
     156       15568 :   return *code;
     157             : }
     158             : 
     159             : // Builder for builtins implemented in TurboFan with JS linkage.
     160       19208 : Code BuildWithCodeStubAssemblerJS(Isolate* isolate, int32_t builtin_index,
     161             :                                   CodeAssemblerGenerator generator, int argc,
     162             :                                   const char* name) {
     163             :   HandleScope scope(isolate);
     164             :   // Canonicalize handles, so that we can share constant pool entries pointing
     165             :   // to code targets without dereferencing their handles.
     166       38416 :   CanonicalHandleScope canonical(isolate);
     167             : 
     168             :   SegmentSize segment_size = isolate->serializer_enabled()
     169             :                                  ? SegmentSize::kLarge
     170       19208 :                                  : SegmentSize::kDefault;
     171       38416 :   Zone zone(isolate->allocator(), ZONE_NAME, segment_size);
     172             :   const int argc_with_recv =
     173       19208 :       (argc == SharedFunctionInfo::kDontAdaptArgumentsSentinel) ? 0 : argc + 1;
     174             :   compiler::CodeAssemblerState state(
     175             :       isolate, &zone, argc_with_recv, Code::BUILTIN, name,
     176       38416 :       PoisoningMitigationLevel::kDontPoison, builtin_index);
     177       19208 :   generator(&state);
     178             :   Handle<Code> code = compiler::CodeAssembler::GenerateCode(
     179       19208 :       &state, BuiltinAssemblerOptions(isolate, builtin_index));
     180             :   PostBuildProfileAndTracing(isolate, *code, name);
     181       19208 :   return *code;
     182             : }
     183             : 
     184             : // Builder for builtins implemented in TurboFan with CallStub linkage.
     185       19992 : Code BuildWithCodeStubAssemblerCS(Isolate* isolate, int32_t builtin_index,
     186             :                                   CodeAssemblerGenerator generator,
     187             :                                   CallDescriptors::Key interface_descriptor,
     188             :                                   const char* name) {
     189             :   HandleScope scope(isolate);
     190             :   // Canonicalize handles, so that we can share constant pool entries pointing
     191             :   // to code targets without dereferencing their handles.
     192       39984 :   CanonicalHandleScope canonical(isolate);
     193             :   SegmentSize segment_size = isolate->serializer_enabled()
     194             :                                  ? SegmentSize::kLarge
     195       19992 :                                  : SegmentSize::kDefault;
     196       39984 :   Zone zone(isolate->allocator(), ZONE_NAME, segment_size);
     197             :   // The interface descriptor with given key must be initialized at this point
     198             :   // and this construction just queries the details from the descriptors table.
     199             :   CallInterfaceDescriptor descriptor(interface_descriptor);
     200             :   // Ensure descriptor is already initialized.
     201             :   DCHECK_LE(0, descriptor.GetRegisterParameterCount());
     202             :   compiler::CodeAssemblerState state(
     203             :       isolate, &zone, descriptor, Code::BUILTIN, name,
     204       39984 :       PoisoningMitigationLevel::kDontPoison, builtin_index);
     205       19992 :   generator(&state);
     206             :   Handle<Code> code = compiler::CodeAssembler::GenerateCode(
     207       19992 :       &state, BuiltinAssemblerOptions(isolate, builtin_index));
     208             :   PostBuildProfileAndTracing(isolate, *code, name);
     209       19992 :   return *code;
     210             : }
     211             : 
     212             : }  // anonymous namespace
     213             : 
     214             : // static
     215           0 : void SetupIsolateDelegate::AddBuiltin(Builtins* builtins, int index,
     216             :                                       Code code) {
     217             :   DCHECK_EQ(index, code->builtin_index());
     218      170464 :   builtins->set_builtin(index, code);
     219           0 : }
     220             : 
     221             : // static
     222          56 : void SetupIsolateDelegate::PopulateWithPlaceholders(Isolate* isolate) {
     223             :   // Fill the builtins list with placeholders. References to these placeholder
     224             :   // builtins are eventually replaced by the actual builtins. This is to
     225             :   // support circular references between builtins.
     226             :   Builtins* builtins = isolate->builtins();
     227             :   HandleScope scope(isolate);
     228      170520 :   for (int i = 0; i < Builtins::builtin_count; i++) {
     229       85232 :     Handle<Code> placeholder = BuildPlaceholder(isolate, i);
     230             :     AddBuiltin(builtins, i, *placeholder);
     231             :   }
     232          56 : }
     233             : 
     234             : // static
     235          56 : void SetupIsolateDelegate::ReplacePlaceholders(Isolate* isolate) {
     236             :   // Replace references from all code objects to placeholders.
     237             :   Builtins* builtins = isolate->builtins();
     238             :   DisallowHeapAllocation no_gc;
     239         112 :   CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
     240             :   static const int kRelocMask =
     241             :       RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
     242             :       RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
     243             :       RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET);
     244         112 :   HeapIterator iterator(isolate->heap());
     245      574672 :   for (HeapObject obj = iterator.next(); !obj.is_null();
     246             :        obj = iterator.next()) {
     247      574616 :     if (!obj->IsCode()) continue;
     248             :     Code code = Code::cast(obj);
     249             :     bool flush_icache = false;
     250      567952 :     for (RelocIterator it(code, kRelocMask); !it.done(); it.next()) {
     251             :       RelocInfo* rinfo = it.rinfo();
     252      397488 :       if (RelocInfo::IsCodeTargetMode(rinfo->rmode())) {
     253      397488 :         Code target = Code::GetCodeFromTargetAddress(rinfo->target_address());
     254             :         DCHECK_IMPLIES(RelocInfo::IsRelativeCodeTarget(rinfo->rmode()),
     255             :                        Builtins::IsIsolateIndependent(target->builtin_index()));
     256      397488 :         if (!target->is_builtin()) continue;
     257      397488 :         Code new_target = builtins->builtin(target->builtin_index());
     258             :         rinfo->set_target_address(new_target->raw_instruction_start(),
     259      397488 :                                   UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
     260             :       } else {
     261             :         DCHECK(RelocInfo::IsEmbeddedObject(rinfo->rmode()));
     262             :         Object object = rinfo->target_object();
     263           0 :         if (!object->IsCode()) continue;
     264             :         Code target = Code::cast(object);
     265           0 :         if (!target->is_builtin()) continue;
     266           0 :         Code new_target = builtins->builtin(target->builtin_index());
     267             :         rinfo->set_target_object(isolate->heap(), new_target,
     268             :                                  UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
     269             :       }
     270             :       flush_icache = true;
     271             :     }
     272      170464 :     if (flush_icache) {
     273       73416 :       FlushInstructionCache(code->raw_instruction_start(),
     274             :                             code->raw_instruction_size());
     275             :     }
     276             :   }
     277          56 : }
     278             : 
     279             : namespace {
     280             : 
     281       26544 : Code GenerateBytecodeHandler(Isolate* isolate, int builtin_index,
     282             :                              const char* name,
     283             :                              interpreter::OperandScale operand_scale,
     284             :                              interpreter::Bytecode bytecode) {
     285             :   DCHECK(interpreter::Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
     286             : 
     287             :   Handle<Code> code = interpreter::GenerateBytecodeHandler(
     288             :       isolate, bytecode, operand_scale, builtin_index,
     289       26544 :       BuiltinAssemblerOptions(isolate, builtin_index));
     290             : 
     291             :   PostBuildProfileAndTracing(isolate, *code, name);
     292             : 
     293       26544 :   return *code;
     294             : }
     295             : 
     296             : }  // namespace
     297             : 
     298             : // static
     299          56 : void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
     300             :   Builtins* builtins = isolate->builtins();
     301             :   DCHECK(!builtins->initialized_);
     302             : 
     303          56 :   PopulateWithPlaceholders(isolate);
     304             : 
     305             :   // Create a scope for the handles in the builtins.
     306             :   HandleScope scope(isolate);
     307             : 
     308             :   int index = 0;
     309             :   Code code;
     310             : #define BUILD_CPP(Name)                                              \
     311             :   code = BuildAdaptor(isolate, index, FUNCTION_ADDR(Builtin_##Name), \
     312             :                       Builtins::BUILTIN_EXIT, #Name);                \
     313             :   AddBuiltin(builtins, index++, code);
     314             : #define BUILD_API(Name)                                              \
     315             :   code = BuildAdaptor(isolate, index, FUNCTION_ADDR(Builtin_##Name), \
     316             :                       Builtins::EXIT, #Name);                        \
     317             :   AddBuiltin(builtins, index++, code);
     318             : #define BUILD_TFJ(Name, Argc, ...)                              \
     319             :   code = BuildWithCodeStubAssemblerJS(                          \
     320             :       isolate, index, &Builtins::Generate_##Name, Argc, #Name); \
     321             :   AddBuiltin(builtins, index++, code);
     322             : #define BUILD_TFC(Name, InterfaceDescriptor)                      \
     323             :   /* Return size is from the provided CallInterfaceDescriptor. */ \
     324             :   code = BuildWithCodeStubAssemblerCS(                            \
     325             :       isolate, index, &Builtins::Generate_##Name,                 \
     326             :       CallDescriptors::InterfaceDescriptor, #Name);               \
     327             :   AddBuiltin(builtins, index++, code);
     328             : #define BUILD_TFS(Name, ...)                                                   \
     329             :   /* Return size for generic TF builtins (stub linkage) is always 1. */        \
     330             :   code =                                                                       \
     331             :       BuildWithCodeStubAssemblerCS(isolate, index, &Builtins::Generate_##Name, \
     332             :                                    CallDescriptors::Name, #Name);              \
     333             :   AddBuiltin(builtins, index++, code);
     334             : #define BUILD_TFH(Name, InterfaceDescriptor)              \
     335             :   /* Return size for IC builtins/handlers is always 1. */ \
     336             :   code = BuildWithCodeStubAssemblerCS(                    \
     337             :       isolate, index, &Builtins::Generate_##Name,         \
     338             :       CallDescriptors::InterfaceDescriptor, #Name);       \
     339             :   AddBuiltin(builtins, index++, code);
     340             : 
     341             : #define BUILD_BCH(Name, OperandScale, Bytecode)                         \
     342             :   code = GenerateBytecodeHandler(isolate, index, Builtins::name(index), \
     343             :                                  OperandScale, Bytecode);               \
     344             :   AddBuiltin(builtins, index++, code);
     345             : 
     346             : #define BUILD_ASM(Name, InterfaceDescriptor)                                \
     347             :   code = BuildWithMacroAssembler(isolate, index, Builtins::Generate_##Name, \
     348             :                                  #Name);                                    \
     349             :   AddBuiltin(builtins, index++, code);
     350             : 
     351       85232 :   BUILTIN_LIST(BUILD_CPP, BUILD_API, BUILD_TFJ, BUILD_TFC, BUILD_TFS, BUILD_TFH,
     352             :                BUILD_BCH, BUILD_ASM);
     353             : 
     354             : #undef BUILD_CPP
     355             : #undef BUILD_API
     356             : #undef BUILD_TFJ
     357             : #undef BUILD_TFC
     358             : #undef BUILD_TFS
     359             : #undef BUILD_TFH
     360             : #undef BUILD_BCH
     361             : #undef BUILD_ASM
     362             :   CHECK_EQ(Builtins::builtin_count, index);
     363             : 
     364          56 :   ReplacePlaceholders(isolate);
     365             : 
     366             : #define SET_PROMISE_REJECTION_PREDICTION(Name) \
     367             :   builtins->builtin(Builtins::k##Name)->set_is_promise_rejection(true);
     368             : 
     369          56 :   BUILTIN_PROMISE_REJECTION_PREDICTION_LIST(SET_PROMISE_REJECTION_PREDICTION)
     370             : #undef SET_PROMISE_REJECTION_PREDICTION
     371             : 
     372             : #define SET_EXCEPTION_CAUGHT_PREDICTION(Name) \
     373             :   builtins->builtin(Builtins::k##Name)->set_is_exception_caught(true);
     374             : 
     375          56 :   BUILTIN_EXCEPTION_CAUGHT_PREDICTION_LIST(SET_EXCEPTION_CAUGHT_PREDICTION)
     376             : #undef SET_EXCEPTION_CAUGHT_PREDICTION
     377             : 
     378             :   builtins->MarkInitialized();
     379          56 : }
     380             : 
     381             : }  // namespace internal
     382       59480 : }  // namespace v8

Generated by: LCOV version 1.10