LCOV - code coverage report
Current view: top level - src/builtins - builtins.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 77 107 72.0 %
Date: 2019-01-20 Functions: 27 32 84.4 %

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

Generated by: LCOV version 1.10