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-17 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       85176 :   PROFILE(isolate, CodeCreateEvent(CodeEventListener::BUILTIN_TAG,
      36             :                                    AbstractCode::cast(code), name));
      37             : }
      38             : 
      39       85176 : AssemblerOptions BuiltinAssemblerOptions(Isolate* isolate,
      40             :                                          int32_t builtin_index) {
      41       85176 :   AssemblerOptions options = AssemblerOptions::Default(isolate);
      42       85176 :   CHECK(!options.isolate_independent_code);
      43       85176 :   CHECK(!options.use_pc_relative_calls_and_jumps);
      44       85176 :   CHECK(!options.collect_win64_unwind_info);
      45             : 
      46       85176 :   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      170352 :       !code_range.is_empty() &&
      55       85176 :       std::ceil(static_cast<float>(code_range.size() / MB)) <=
      56             :           kMaxPCRelativeCodeRangeInMB;
      57             : 
      58       85176 :   options.isolate_independent_code = true;
      59       85176 :   options.use_pc_relative_calls_and_jumps = pc_relative_calls_fit_in_code_range;
      60       85176 :   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       85176 : 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      170352 :                       ExternalAssemblerBuffer(buffer, kBufferSize));
      74             :   DCHECK(!masm.has_frame());
      75             :   {
      76       85176 :     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       85176 :     masm.Move(kJavaScriptCallCodeStartRegister, Smi::zero());
      80             :     masm.Call(kJavaScriptCallCodeStartRegister);
      81             :   }
      82       85176 :   CodeDesc desc;
      83             :   masm.GetCode(isolate, &desc);
      84             :   Handle<Code> code = isolate->factory()->NewCode(
      85      170352 :       desc, Code::BUILTIN, masm.CodeObject(), builtin_index);
      86      170352 :   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             :     static constexpr int kJSEntryHandlerCount = 1;
     114             :     handler_table_offset =
     115         168 :         HandlerTable::EmitReturnTableStart(&masm, kJSEntryHandlerCount);
     116             :     HandlerTable::EmitReturnEntry(
     117         168 :         &masm, 0, isolate->builtins()->js_entry_handler_offset());
     118             :   }
     119             : 
     120        3920 :   CodeDesc desc;
     121             :   masm.GetCode(isolate, &desc, MacroAssembler::kNoSafepointTable,
     122        3920 :                handler_table_offset);
     123             : 
     124             :   static constexpr bool kIsNotTurbofanned = false;
     125             :   static constexpr int kStackSlots = 0;
     126             : 
     127             :   Handle<Code> code = isolate->factory()->NewCode(
     128             :       desc, Code::BUILTIN, masm.CodeObject(), builtin_index,
     129             :       MaybeHandle<ByteArray>(), DeoptimizationData::Empty(isolate), kMovable,
     130       11760 :       kIsNotTurbofanned, kStackSlots);
     131             : #if defined(V8_OS_WIN_X64)
     132             :   isolate->SetBuiltinUnwindData(builtin_index, masm.GetUnwindInfo());
     133             : #endif
     134             :   PostBuildProfileAndTracing(isolate, *code, s_name);
     135        3920 :   return *code;
     136             : }
     137             : 
     138       15568 : Code BuildAdaptor(Isolate* isolate, int32_t builtin_index,
     139             :                   Address builtin_address,
     140             :                   Builtins::ExitFrameType exit_frame_type, const char* name) {
     141             :   HandleScope scope(isolate);
     142             :   // Canonicalize handles, so that we can share constant pool entries pointing
     143             :   // to code targets without dereferencing their handles.
     144       31136 :   CanonicalHandleScope canonical(isolate);
     145             :   constexpr int kBufferSize = 32 * KB;
     146             :   byte buffer[kBufferSize];
     147       31136 :   MacroAssembler masm(isolate, BuiltinAssemblerOptions(isolate, builtin_index),
     148             :                       CodeObjectRequired::kYes,
     149       46704 :                       ExternalAssemblerBuffer(buffer, kBufferSize));
     150             :   masm.set_builtin_index(builtin_index);
     151             :   DCHECK(!masm.has_frame());
     152       15568 :   Builtins::Generate_Adaptor(&masm, builtin_address, exit_frame_type);
     153       15568 :   CodeDesc desc;
     154             :   masm.GetCode(isolate, &desc);
     155             :   Handle<Code> code = isolate->factory()->NewCode(
     156       31136 :       desc, Code::BUILTIN, masm.CodeObject(), builtin_index);
     157             :   PostBuildProfileAndTracing(isolate, *code, name);
     158       15568 :   return *code;
     159             : }
     160             : 
     161             : // Builder for builtins implemented in TurboFan with JS linkage.
     162       19208 : Code BuildWithCodeStubAssemblerJS(Isolate* isolate, int32_t builtin_index,
     163             :                                   CodeAssemblerGenerator generator, int argc,
     164             :                                   const char* name) {
     165             :   HandleScope scope(isolate);
     166             :   // Canonicalize handles, so that we can share constant pool entries pointing
     167             :   // to code targets without dereferencing their handles.
     168       38416 :   CanonicalHandleScope canonical(isolate);
     169             : 
     170             :   SegmentSize segment_size = isolate->serializer_enabled()
     171             :                                  ? SegmentSize::kLarge
     172       19208 :                                  : SegmentSize::kDefault;
     173       38416 :   Zone zone(isolate->allocator(), ZONE_NAME, segment_size);
     174             :   const int argc_with_recv =
     175       19208 :       (argc == SharedFunctionInfo::kDontAdaptArgumentsSentinel) ? 0 : argc + 1;
     176             :   compiler::CodeAssemblerState state(
     177             :       isolate, &zone, argc_with_recv, Code::BUILTIN, name,
     178       38416 :       PoisoningMitigationLevel::kDontPoison, builtin_index);
     179       19208 :   generator(&state);
     180             :   Handle<Code> code = compiler::CodeAssembler::GenerateCode(
     181       19208 :       &state, BuiltinAssemblerOptions(isolate, builtin_index));
     182             :   PostBuildProfileAndTracing(isolate, *code, name);
     183       19208 :   return *code;
     184             : }
     185             : 
     186             : // Builder for builtins implemented in TurboFan with CallStub linkage.
     187       19936 : Code BuildWithCodeStubAssemblerCS(Isolate* isolate, int32_t builtin_index,
     188             :                                   CodeAssemblerGenerator generator,
     189             :                                   CallDescriptors::Key interface_descriptor,
     190             :                                   const char* name) {
     191             :   HandleScope scope(isolate);
     192             :   // Canonicalize handles, so that we can share constant pool entries pointing
     193             :   // to code targets without dereferencing their handles.
     194       39872 :   CanonicalHandleScope canonical(isolate);
     195             :   SegmentSize segment_size = isolate->serializer_enabled()
     196             :                                  ? SegmentSize::kLarge
     197       19936 :                                  : SegmentSize::kDefault;
     198       39872 :   Zone zone(isolate->allocator(), ZONE_NAME, segment_size);
     199             :   // The interface descriptor with given key must be initialized at this point
     200             :   // and this construction just queries the details from the descriptors table.
     201             :   CallInterfaceDescriptor descriptor(interface_descriptor);
     202             :   // Ensure descriptor is already initialized.
     203             :   DCHECK_LE(0, descriptor.GetRegisterParameterCount());
     204             :   compiler::CodeAssemblerState state(
     205             :       isolate, &zone, descriptor, Code::BUILTIN, name,
     206       39872 :       PoisoningMitigationLevel::kDontPoison, builtin_index);
     207       19936 :   generator(&state);
     208             :   Handle<Code> code = compiler::CodeAssembler::GenerateCode(
     209       19936 :       &state, BuiltinAssemblerOptions(isolate, builtin_index));
     210             :   PostBuildProfileAndTracing(isolate, *code, name);
     211       19936 :   return *code;
     212             : }
     213             : 
     214             : }  // anonymous namespace
     215             : 
     216             : // static
     217           0 : void SetupIsolateDelegate::AddBuiltin(Builtins* builtins, int index,
     218             :                                       Code code) {
     219             :   DCHECK_EQ(index, code->builtin_index());
     220      170352 :   builtins->set_builtin(index, code);
     221           0 : }
     222             : 
     223             : // static
     224          56 : void SetupIsolateDelegate::PopulateWithPlaceholders(Isolate* isolate) {
     225             :   // Fill the builtins list with placeholders. References to these placeholder
     226             :   // builtins are eventually replaced by the actual builtins. This is to
     227             :   // support circular references between builtins.
     228             :   Builtins* builtins = isolate->builtins();
     229             :   HandleScope scope(isolate);
     230      170408 :   for (int i = 0; i < Builtins::builtin_count; i++) {
     231       85176 :     Handle<Code> placeholder = BuildPlaceholder(isolate, i);
     232             :     AddBuiltin(builtins, i, *placeholder);
     233             :   }
     234          56 : }
     235             : 
     236             : // static
     237          56 : void SetupIsolateDelegate::ReplacePlaceholders(Isolate* isolate) {
     238             :   // Replace references from all code objects to placeholders.
     239             :   Builtins* builtins = isolate->builtins();
     240             :   DisallowHeapAllocation no_gc;
     241         112 :   CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
     242             :   static const int kRelocMask =
     243             :       RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
     244             :       RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
     245             :       RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET);
     246         112 :   HeapIterator iterator(isolate->heap());
     247      574280 :   for (HeapObject obj = iterator.next(); !obj.is_null();
     248             :        obj = iterator.next()) {
     249      574224 :     if (!obj->IsCode()) continue;
     250             :     Code code = Code::cast(obj);
     251             :     bool flush_icache = false;
     252      570192 :     for (RelocIterator it(code, kRelocMask); !it.done(); it.next()) {
     253             :       RelocInfo* rinfo = it.rinfo();
     254      399840 :       if (RelocInfo::IsCodeTargetMode(rinfo->rmode())) {
     255      399840 :         Code target = Code::GetCodeFromTargetAddress(rinfo->target_address());
     256             :         DCHECK_IMPLIES(RelocInfo::IsRelativeCodeTarget(rinfo->rmode()),
     257             :                        Builtins::IsIsolateIndependent(target->builtin_index()));
     258      399840 :         if (!target->is_builtin()) continue;
     259      399840 :         Code new_target = builtins->builtin(target->builtin_index());
     260             :         rinfo->set_target_address(new_target->raw_instruction_start(),
     261      399840 :                                   UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
     262             :       } else {
     263             :         DCHECK(RelocInfo::IsEmbeddedObject(rinfo->rmode()));
     264             :         Object object = rinfo->target_object();
     265           0 :         if (!object->IsCode()) continue;
     266             :         Code target = Code::cast(object);
     267           0 :         if (!target->is_builtin()) continue;
     268           0 :         Code new_target = builtins->builtin(target->builtin_index());
     269             :         rinfo->set_target_object(isolate->heap(), new_target,
     270             :                                  UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
     271             :       }
     272             :       flush_icache = true;
     273             :     }
     274      170352 :     if (flush_icache) {
     275       73416 :       FlushInstructionCache(code->raw_instruction_start(),
     276             :                             code->raw_instruction_size());
     277             :     }
     278             :   }
     279          56 : }
     280             : 
     281             : namespace {
     282             : 
     283       26544 : Code GenerateBytecodeHandler(Isolate* isolate, int builtin_index,
     284             :                              const char* name,
     285             :                              interpreter::OperandScale operand_scale,
     286             :                              interpreter::Bytecode bytecode) {
     287             :   DCHECK(interpreter::Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
     288             : 
     289             :   Handle<Code> code = interpreter::GenerateBytecodeHandler(
     290             :       isolate, bytecode, operand_scale, builtin_index,
     291       26544 :       BuiltinAssemblerOptions(isolate, builtin_index));
     292             : 
     293             :   PostBuildProfileAndTracing(isolate, *code, name);
     294             : 
     295       26544 :   return *code;
     296             : }
     297             : 
     298             : }  // namespace
     299             : 
     300             : // static
     301          56 : void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
     302             :   Builtins* builtins = isolate->builtins();
     303             :   DCHECK(!builtins->initialized_);
     304             : 
     305          56 :   PopulateWithPlaceholders(isolate);
     306             : 
     307             :   // Create a scope for the handles in the builtins.
     308             :   HandleScope scope(isolate);
     309             : 
     310             :   int index = 0;
     311             :   Code code;
     312             : #define BUILD_CPP(Name)                                              \
     313             :   code = BuildAdaptor(isolate, index, FUNCTION_ADDR(Builtin_##Name), \
     314             :                       Builtins::BUILTIN_EXIT, #Name);                \
     315             :   AddBuiltin(builtins, index++, code);
     316             : #define BUILD_API(Name)                                              \
     317             :   code = BuildAdaptor(isolate, index, FUNCTION_ADDR(Builtin_##Name), \
     318             :                       Builtins::EXIT, #Name);                        \
     319             :   AddBuiltin(builtins, index++, code);
     320             : #define BUILD_TFJ(Name, Argc, ...)                              \
     321             :   code = BuildWithCodeStubAssemblerJS(                          \
     322             :       isolate, index, &Builtins::Generate_##Name, Argc, #Name); \
     323             :   AddBuiltin(builtins, index++, code);
     324             : #define BUILD_TFC(Name, InterfaceDescriptor)                      \
     325             :   /* Return size is from the provided CallInterfaceDescriptor. */ \
     326             :   code = BuildWithCodeStubAssemblerCS(                            \
     327             :       isolate, index, &Builtins::Generate_##Name,                 \
     328             :       CallDescriptors::InterfaceDescriptor, #Name);               \
     329             :   AddBuiltin(builtins, index++, code);
     330             : #define BUILD_TFS(Name, ...)                                                   \
     331             :   /* Return size for generic TF builtins (stub linkage) is always 1. */        \
     332             :   code =                                                                       \
     333             :       BuildWithCodeStubAssemblerCS(isolate, index, &Builtins::Generate_##Name, \
     334             :                                    CallDescriptors::Name, #Name);              \
     335             :   AddBuiltin(builtins, index++, code);
     336             : #define BUILD_TFH(Name, InterfaceDescriptor)              \
     337             :   /* Return size for IC builtins/handlers is always 1. */ \
     338             :   code = BuildWithCodeStubAssemblerCS(                    \
     339             :       isolate, index, &Builtins::Generate_##Name,         \
     340             :       CallDescriptors::InterfaceDescriptor, #Name);       \
     341             :   AddBuiltin(builtins, index++, code);
     342             : 
     343             : #define BUILD_BCH(Name, OperandScale, Bytecode)                         \
     344             :   code = GenerateBytecodeHandler(isolate, index, Builtins::name(index), \
     345             :                                  OperandScale, Bytecode);               \
     346             :   AddBuiltin(builtins, index++, code);
     347             : 
     348             : #define BUILD_ASM(Name, InterfaceDescriptor)                                \
     349             :   code = BuildWithMacroAssembler(isolate, index, Builtins::Generate_##Name, \
     350             :                                  #Name);                                    \
     351             :   AddBuiltin(builtins, index++, code);
     352             : 
     353       85176 :   BUILTIN_LIST(BUILD_CPP, BUILD_API, BUILD_TFJ, BUILD_TFC, BUILD_TFS, BUILD_TFH,
     354             :                BUILD_BCH, BUILD_ASM);
     355             : 
     356             : #undef BUILD_CPP
     357             : #undef BUILD_API
     358             : #undef BUILD_TFJ
     359             : #undef BUILD_TFC
     360             : #undef BUILD_TFS
     361             : #undef BUILD_TFH
     362             : #undef BUILD_BCH
     363             : #undef BUILD_ASM
     364             :   CHECK_EQ(Builtins::builtin_count, index);
     365             : 
     366          56 :   ReplacePlaceholders(isolate);
     367             : 
     368             : #define SET_PROMISE_REJECTION_PREDICTION(Name) \
     369             :   builtins->builtin(Builtins::k##Name)->set_is_promise_rejection(true);
     370             : 
     371          56 :   BUILTIN_PROMISE_REJECTION_PREDICTION_LIST(SET_PROMISE_REJECTION_PREDICTION)
     372             : #undef SET_PROMISE_REJECTION_PREDICTION
     373             : 
     374             : #define SET_EXCEPTION_CAUGHT_PREDICTION(Name) \
     375             :   builtins->builtin(Builtins::k##Name)->set_is_exception_caught(true);
     376             : 
     377          56 :   BUILTIN_EXCEPTION_CAUGHT_PREDICTION_LIST(SET_EXCEPTION_CAUGHT_PREDICTION)
     378             : #undef SET_EXCEPTION_CAUGHT_PREDICTION
     379             : 
     380             :   builtins->MarkInitialized();
     381          56 : }
     382             : 
     383             : }  // namespace internal
     384       59456 : }  // namespace v8

Generated by: LCOV version 1.10