LCOV - code coverage report
Current view: top level - src/builtins - setup-builtins-internal.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 104 110 94.5 %
Date: 2019-01-20 Functions: 13 14 92.9 %

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

Generated by: LCOV version 1.10