LCOV - code coverage report
Current view: top level - src/builtins - builtins.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 76 106 71.7 %
Date: 2019-04-19 Functions: 26 31 83.9 %

          Line data    Source code
       1             : // Copyright 2012 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/builtins/builtins.h"
       6             : 
       7             : #include "src/api-inl.h"
       8             : #include "src/assembler-inl.h"
       9             : #include "src/builtins/builtins-descriptors.h"
      10             : #include "src/callable.h"
      11             : #include "src/code-tracer.h"
      12             : #include "src/isolate.h"
      13             : #include "src/macro-assembler.h"
      14             : #include "src/objects-inl.h"
      15             : #include "src/objects/fixed-array.h"
      16             : #include "src/ostreams.h"
      17             : #include "src/snapshot/embedded-data.h"
      18             : #include "src/visitors.h"
      19             : 
      20             : namespace v8 {
      21             : namespace internal {
      22             : 
      23             : // Forward declarations for C++ builtins.
      24             : #define FORWARD_DECLARE(Name) \
      25             :   Address Builtin_##Name(int argc, Address* args, Isolate* isolate);
      26             : BUILTIN_LIST_C(FORWARD_DECLARE)
      27             : #undef FORWARD_DECLARE
      28             : 
      29             : namespace {
      30             : 
      31             : // TODO(jgruber): Pack in CallDescriptors::Key.
      32             : struct BuiltinMetadata {
      33             :   const char* name;
      34             :   Builtins::Kind kind;
      35             :   // For CPP and API builtins it's cpp_entry address and for TFJ it's a
      36             :   // parameter count.
      37             :   Address cpp_entry_or_parameter_count;
      38             : };
      39             : 
      40             : #define DECL_CPP(Name, ...) \
      41             :   {#Name, Builtins::CPP, FUNCTION_ADDR(Builtin_##Name)},
      42             : #define DECL_API(Name, ...) \
      43             :   {#Name, Builtins::API, FUNCTION_ADDR(Builtin_##Name)},
      44             : #define DECL_TFJ(Name, Count, ...) \
      45             :   {#Name, Builtins::TFJ, static_cast<Address>(Count)},
      46             : #define DECL_TFC(Name, ...) {#Name, Builtins::TFC, kNullAddress},
      47             : #define DECL_TFS(Name, ...) {#Name, Builtins::TFS, kNullAddress},
      48             : #define DECL_TFH(Name, ...) {#Name, Builtins::TFH, kNullAddress},
      49             : #define DECL_BCH(Name, ...) {#Name, Builtins::BCH, kNullAddress},
      50             : #define DECL_ASM(Name, ...) {#Name, Builtins::ASM, kNullAddress},
      51             : const BuiltinMetadata builtin_metadata[] = {
      52             :   BUILTIN_LIST(DECL_CPP, DECL_API, DECL_TFJ, DECL_TFC, DECL_TFS, DECL_TFH,
      53             :                DECL_BCH, DECL_ASM)
      54             : };
      55             : #undef DECL_CPP
      56             : #undef DECL_API
      57             : #undef DECL_TFJ
      58             : #undef DECL_TFC
      59             : #undef DECL_TFS
      60             : #undef DECL_TFH
      61             : #undef DECL_BCH
      62             : #undef DECL_ASM
      63             : 
      64             : }  // namespace
      65             : 
      66        9580 : BailoutId Builtins::GetContinuationBailoutId(Name name) {
      67             :   DCHECK(Builtins::KindOf(name) == TFJ || Builtins::KindOf(name) == TFC);
      68        9580 :   return BailoutId(BailoutId::kFirstBuiltinContinuationId + name);
      69             : }
      70             : 
      71        2254 : Builtins::Name Builtins::GetBuiltinFromBailoutId(BailoutId id) {
      72        2254 :   int builtin_index = id.ToInt() - BailoutId::kFirstBuiltinContinuationId;
      73             :   DCHECK(Builtins::KindOf(builtin_index) == TFJ ||
      74             :          Builtins::KindOf(builtin_index) == TFC);
      75        2254 :   return static_cast<Name>(builtin_index);
      76             : }
      77             : 
      78       62427 : void Builtins::TearDown() { initialized_ = false; }
      79             : 
      80           0 : const char* Builtins::Lookup(Address pc) {
      81             :   // Off-heap pc's can be looked up through binary search.
      82             :   if (FLAG_embedded_builtins) {
      83           0 :     Code maybe_builtin = InstructionStream::TryLookupCode(isolate_, pc);
      84           0 :     if (!maybe_builtin.is_null()) return name(maybe_builtin->builtin_index());
      85             :   }
      86             : 
      87             :   // May be called during initialization (disassembler).
      88           0 :   if (initialized_) {
      89           0 :     for (int i = 0; i < builtin_count; i++) {
      90           0 :       if (isolate_->heap()->builtin(i)->contains(pc)) return name(i);
      91             :     }
      92             :   }
      93             :   return nullptr;
      94             : }
      95             : 
      96        3532 : Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
      97        3532 :   switch (hint) {
      98             :     case ToPrimitiveHint::kDefault:
      99             :       return builtin_handle(kNonPrimitiveToPrimitive_Default);
     100             :     case ToPrimitiveHint::kNumber:
     101             :       return builtin_handle(kNonPrimitiveToPrimitive_Number);
     102             :     case ToPrimitiveHint::kString:
     103             :       return builtin_handle(kNonPrimitiveToPrimitive_String);
     104             :   }
     105           0 :   UNREACHABLE();
     106             : }
     107             : 
     108         280 : Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
     109         280 :   switch (hint) {
     110             :     case OrdinaryToPrimitiveHint::kNumber:
     111             :       return builtin_handle(kOrdinaryToPrimitive_Number);
     112             :     case OrdinaryToPrimitiveHint::kString:
     113             :       return builtin_handle(kOrdinaryToPrimitive_String);
     114             :   }
     115           0 :   UNREACHABLE();
     116             : }
     117             : 
     118      255696 : void Builtins::set_builtin(int index, Code builtin) {
     119      511392 :   isolate_->heap()->set_builtin(index, builtin);
     120      255696 : }
     121             : 
     122   108299806 : Code Builtins::builtin(int index) { return isolate_->heap()->builtin(index); }
     123             : 
     124    28692450 : Handle<Code> Builtins::builtin_handle(int index) {
     125             :   DCHECK(IsBuiltinId(index));
     126             :   return Handle<Code>(
     127    62762310 :       reinterpret_cast<Address*>(isolate_->heap()->builtin_address(index)));
     128             : }
     129             : 
     130             : // static
     131        6529 : int Builtins::GetStackParameterCount(Name name) {
     132             :   DCHECK(Builtins::KindOf(name) == TFJ);
     133        6529 :   return static_cast<int>(builtin_metadata[name].cpp_entry_or_parameter_count);
     134             : }
     135             : 
     136             : // static
     137     2686267 : Callable Builtins::CallableFor(Isolate* isolate, Name name) {
     138             :   Handle<Code> code = isolate->builtins()->builtin_handle(name);
     139             :   CallDescriptors::Key key;
     140     2686263 :   switch (name) {
     141             : // This macro is deliberately crafted so as to emit very little code,
     142             : // in order to keep binary size of this function under control.
     143             : #define CASE_OTHER(Name, ...)                          \
     144             :   case k##Name: {                                      \
     145             :     key = Builtin_##Name##_InterfaceDescriptor::key(); \
     146             :     break;                                             \
     147             :   }
     148          56 :     BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, CASE_OTHER,
     149             :                  CASE_OTHER, CASE_OTHER, IGNORE_BUILTIN, CASE_OTHER)
     150             : #undef CASE_OTHER
     151             :     default:
     152             :       Builtins::Kind kind = Builtins::KindOf(name);
     153             :       DCHECK_NE(BCH, kind);
     154       54929 :       if (kind == TFJ || kind == CPP) {
     155             :         return Callable(code, JSTrampolineDescriptor{});
     156             :       }
     157           0 :       UNREACHABLE();
     158             :   }
     159             :   CallInterfaceDescriptor descriptor(key);
     160             :   return Callable(code, descriptor);
     161             : }
     162             : 
     163             : // static
     164   379715701 : const char* Builtins::name(int index) {
     165             :   DCHECK(IsBuiltinId(index));
     166   379715701 :   return builtin_metadata[index].name;
     167             : }
     168             : 
     169           0 : void Builtins::PrintBuiltinCode() {
     170             :   DCHECK(FLAG_print_builtin_code);
     171             : #ifdef ENABLE_DISASSEMBLER
     172             :   for (int i = 0; i < builtin_count; i++) {
     173             :     const char* builtin_name = name(i);
     174             :     Handle<Code> code = builtin_handle(i);
     175             :     if (PassesFilter(CStrVector(builtin_name),
     176             :                      CStrVector(FLAG_print_builtin_code_filter))) {
     177             :       CodeTracer::Scope trace_scope(isolate_->GetCodeTracer());
     178             :       OFStream os(trace_scope.file());
     179             :       code->Disassemble(builtin_name, os);
     180             :       os << "\n";
     181             :     }
     182             :   }
     183             : #endif
     184           0 : }
     185             : 
     186           0 : void Builtins::PrintBuiltinSize() {
     187             :   DCHECK(FLAG_print_builtin_size);
     188           0 :   for (int i = 0; i < builtin_count; i++) {
     189             :     const char* builtin_name = name(i);
     190           0 :     const char* kind = KindNameOf(i);
     191           0 :     Code code = builtin(i);
     192             :     PrintF(stdout, "%s Builtin, %s, %d\n", kind, builtin_name,
     193           0 :            code->InstructionSize());
     194             :   }
     195           0 : }
     196             : 
     197             : // static
     198        2918 : Address Builtins::CppEntryOf(int index) {
     199             :   DCHECK(Builtins::HasCppImplementation(index));
     200        2918 :   return builtin_metadata[index].cpp_entry_or_parameter_count;
     201             : }
     202             : 
     203             : // static
     204           0 : bool Builtins::IsBuiltin(const Code code) {
     205           0 :   return Builtins::IsBuiltinId(code->builtin_index());
     206             : }
     207             : 
     208     9919194 : bool Builtins::IsBuiltinHandle(Handle<HeapObject> maybe_code,
     209             :                                int* index) const {
     210     9919194 :   Heap* heap = isolate_->heap();
     211             :   Address handle_location = maybe_code.address();
     212     9919194 :   Address start = heap->builtin_address(0);
     213     9919197 :   Address end = heap->builtin_address(Builtins::builtin_count);
     214     9919199 :   if (handle_location >= end) return false;
     215     9862224 :   if (handle_location < start) return false;
     216     9832366 :   *index = static_cast<int>(handle_location - start) >> kSystemPointerSizeLog2;
     217             :   DCHECK(Builtins::IsBuiltinId(*index));
     218     9832366 :   return true;
     219             : }
     220             : 
     221             : // static
     222     1277450 : bool Builtins::IsIsolateIndependentBuiltin(const Code code) {
     223             :   if (FLAG_embedded_builtins) {
     224             :     const int builtin_index = code->builtin_index();
     225     1277450 :     return Builtins::IsBuiltinId(builtin_index) &&
     226             :            Builtins::IsIsolateIndependent(builtin_index);
     227             :   } else {
     228             :     return false;
     229             :   }
     230             : }
     231             : 
     232             : // static
     233      208320 : bool Builtins::IsWasmRuntimeStub(int index) {
     234             :   DCHECK(IsBuiltinId(index));
     235      208320 :   switch (index) {
     236             : #define CASE_TRAP(Name) case kThrowWasm##Name:
     237             : #define CASE(Name) case k##Name:
     238             :     WASM_RUNTIME_STUB_LIST(CASE, CASE_TRAP)
     239             : #undef CASE_TRAP
     240             : #undef CASE
     241             :     return true;
     242             :     default:
     243      203672 :       return false;
     244             :   }
     245             :   UNREACHABLE();
     246             : }
     247             : 
     248             : // static
     249       62473 : void Builtins::UpdateBuiltinEntryTable(Isolate* isolate) {
     250             :   Heap* heap = isolate->heap();
     251             :   Address* builtin_entry_table = isolate->builtin_entry_table();
     252   190132959 :   for (int i = 0; i < builtin_count; i++) {
     253   190070517 :     builtin_entry_table[i] = heap->builtin(i)->InstructionStart();
     254             :   }
     255       62442 : }
     256             : 
     257             : namespace {
     258             : 
     259       85288 : class OffHeapTrampolineGenerator {
     260             :  public:
     261       85288 :   explicit OffHeapTrampolineGenerator(Isolate* isolate)
     262             :       : isolate_(isolate),
     263             :         masm_(isolate, CodeObjectRequired::kYes,
     264      170576 :               ExternalAssemblerBuffer(buffer_, kBufferSize)) {}
     265             : 
     266       85288 :   CodeDesc Generate(Address off_heap_entry) {
     267             :     // Generate replacement code that simply tail-calls the off-heap code.
     268             :     DCHECK(!masm_.has_frame());
     269             :     {
     270      170576 :       FrameScope scope(&masm_, StackFrame::NONE);
     271       85288 :       masm_.JumpToInstructionStream(off_heap_entry);
     272             :     }
     273             : 
     274       85288 :     CodeDesc desc;
     275       85288 :     masm_.GetCode(isolate_, &desc);
     276       85288 :     return desc;
     277             :   }
     278             : 
     279             :   Handle<HeapObject> CodeObject() { return masm_.CodeObject(); }
     280             : 
     281             :  private:
     282             :   Isolate* isolate_;
     283             :   // Enough to fit the single jmp.
     284             :   static constexpr int kBufferSize = 256;
     285             :   byte buffer_[kBufferSize];
     286             :   MacroAssembler masm_;
     287             : };
     288             : 
     289             : constexpr int OffHeapTrampolineGenerator::kBufferSize;
     290             : 
     291             : }  // namespace
     292             : 
     293             : // static
     294       85232 : Handle<Code> Builtins::GenerateOffHeapTrampolineFor(Isolate* isolate,
     295             :                                                     Address off_heap_entry) {
     296             :   DCHECK_NOT_NULL(isolate->embedded_blob());
     297             :   DCHECK_NE(0, isolate->embedded_blob_size());
     298             : 
     299       85232 :   OffHeapTrampolineGenerator generator(isolate);
     300       85232 :   CodeDesc desc = generator.Generate(off_heap_entry);
     301             : 
     302             :   return isolate->factory()->NewCode(desc, Code::BUILTIN,
     303      255696 :                                      generator.CodeObject());
     304             : }
     305             : 
     306             : // static
     307          56 : Handle<ByteArray> Builtins::GenerateOffHeapTrampolineRelocInfo(
     308             :     Isolate* isolate) {
     309          56 :   OffHeapTrampolineGenerator generator(isolate);
     310             :   // Generate a jump to a dummy address as we're not actually interested in the
     311             :   // generated instruction stream.
     312          56 :   CodeDesc desc = generator.Generate(kNullAddress);
     313             : 
     314             :   Handle<ByteArray> reloc_info = isolate->factory()->NewByteArray(
     315          56 :       desc.reloc_size, AllocationType::kReadOnly);
     316             :   Code::CopyRelocInfoToByteArray(*reloc_info, desc);
     317             : 
     318         112 :   return reloc_info;
     319             : }
     320             : 
     321             : // static
     322    22851025 : Builtins::Kind Builtins::KindOf(int index) {
     323             :   DCHECK(IsBuiltinId(index));
     324    22917663 :   return builtin_metadata[index].kind;
     325             : }
     326             : 
     327             : // static
     328           0 : const char* Builtins::KindNameOf(int index) {
     329             :   Kind kind = Builtins::KindOf(index);
     330             :   // clang-format off
     331           0 :   switch (kind) {
     332             :     case CPP: return "CPP";
     333           0 :     case API: return "API";
     334           0 :     case TFJ: return "TFJ";
     335           0 :     case TFC: return "TFC";
     336           0 :     case TFS: return "TFS";
     337           0 :     case TFH: return "TFH";
     338           0 :     case BCH: return "BCH";
     339           0 :     case ASM: return "ASM";
     340             :   }
     341             :   // clang-format on
     342           0 :   UNREACHABLE();
     343             : }
     344             : 
     345             : // static
     346        5404 : bool Builtins::IsCpp(int index) { return Builtins::KindOf(index) == CPP; }
     347             : 
     348             : // static
     349        9007 : bool Builtins::HasCppImplementation(int index) {
     350             :   Kind kind = Builtins::KindOf(index);
     351        9007 :   return (kind == CPP || kind == API);
     352             : }
     353             : 
     354             : // static
     355     1090603 : bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
     356             :                                     Handle<JSObject> target_global_proxy) {
     357     1090603 :   if (FLAG_allow_unsafe_function_constructor) return true;
     358             :   HandleScopeImplementer* impl = isolate->handle_scope_implementer();
     359     1090387 :   Handle<Context> responsible_context = impl->LastEnteredOrMicrotaskContext();
     360             :   // TODO(jochen): Remove this.
     361     1090387 :   if (responsible_context.is_null()) {
     362             :     return true;
     363             :   }
     364     1090387 :   if (*responsible_context == target->context()) return true;
     365         263 :   return isolate->MayAccess(responsible_context, target_global_proxy);
     366             : }
     367             : 
     368        1816 : Builtins::Name ExampleBuiltinForTorqueFunctionPointerType(
     369             :     size_t function_pointer_type_id) {
     370        1816 :   switch (function_pointer_type_id) {
     371             : #define FUNCTION_POINTER_ID_CASE(id, name) \
     372             :   case id:                                 \
     373             :     return Builtins::k##name;
     374         504 :     TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(FUNCTION_POINTER_ID_CASE)
     375             : #undef FUNCTION_POINTER_ID_CASE
     376             :     default:
     377           0 :       UNREACHABLE();
     378             :   }
     379             : }
     380             : 
     381             : }  // namespace internal
     382      122036 : }  // namespace v8

Generated by: LCOV version 1.10