Home | History | Annotate | Download | only in builtins
      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 #include "src/api.h"
      7 #include "src/code-events.h"
      8 #include "src/compiler/code-assembler.h"
      9 #include "src/ic/ic-state.h"
     10 #include "src/interface-descriptors.h"
     11 #include "src/isolate.h"
     12 #include "src/macro-assembler.h"
     13 #include "src/objects-inl.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 // Forward declarations for C++ builtins.
     19 #define FORWARD_DECLARE(Name) \
     20   Object* Builtin_##Name(int argc, Object** args, Isolate* isolate);
     21 BUILTIN_LIST_C(FORWARD_DECLARE)
     22 
     23 Builtins::Builtins() : initialized_(false) {
     24   memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
     25 }
     26 
     27 Builtins::~Builtins() {}
     28 
     29 namespace {
     30 void PostBuildProfileAndTracing(Isolate* isolate, Code* code,
     31                                 const char* name) {
     32   PROFILE(isolate, CodeCreateEvent(CodeEventListener::BUILTIN_TAG,
     33                                    AbstractCode::cast(code), name));
     34 #ifdef ENABLE_DISASSEMBLER
     35   if (FLAG_print_builtin_code) {
     36     CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
     37     OFStream os(trace_scope.file());
     38     os << "Builtin: " << name << "\n";
     39     code->Disassemble(name, os);
     40     os << "\n";
     41   }
     42 #endif
     43 }
     44 
     45 typedef void (*MacroAssemblerGenerator)(MacroAssembler*);
     46 typedef void (*CodeAssemblerGenerator)(compiler::CodeAssemblerState*);
     47 
     48 Code* BuildWithMacroAssembler(Isolate* isolate,
     49                               MacroAssemblerGenerator generator,
     50                               Code::Flags flags, const char* s_name) {
     51   HandleScope scope(isolate);
     52   const size_t buffer_size = 32 * KB;
     53   byte buffer[buffer_size];  // NOLINT(runtime/arrays)
     54   MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
     55   DCHECK(!masm.has_frame());
     56   generator(&masm);
     57   CodeDesc desc;
     58   masm.GetCode(&desc);
     59   Handle<Code> code =
     60       isolate->factory()->NewCode(desc, flags, masm.CodeObject());
     61   PostBuildProfileAndTracing(isolate, *code, s_name);
     62   return *code;
     63 }
     64 
     65 Code* BuildAdaptor(Isolate* isolate, Address builtin_address,
     66                    Builtins::ExitFrameType exit_frame_type, Code::Flags flags,
     67                    const char* name) {
     68   HandleScope scope(isolate);
     69   const size_t buffer_size = 32 * KB;
     70   byte buffer[buffer_size];  // NOLINT(runtime/arrays)
     71   MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
     72   DCHECK(!masm.has_frame());
     73   Builtins::Generate_Adaptor(&masm, builtin_address, exit_frame_type);
     74   CodeDesc desc;
     75   masm.GetCode(&desc);
     76   Handle<Code> code =
     77       isolate->factory()->NewCode(desc, flags, masm.CodeObject());
     78   PostBuildProfileAndTracing(isolate, *code, name);
     79   return *code;
     80 }
     81 
     82 // Builder for builtins implemented in TurboFan with JS linkage.
     83 Code* BuildWithCodeStubAssemblerJS(Isolate* isolate,
     84                                    CodeAssemblerGenerator generator, int argc,
     85                                    Code::Flags flags, const char* name) {
     86   HandleScope scope(isolate);
     87   Zone zone(isolate->allocator(), ZONE_NAME);
     88   const int argc_with_recv =
     89       (argc == SharedFunctionInfo::kDontAdaptArgumentsSentinel) ? 0 : argc + 1;
     90   compiler::CodeAssemblerState state(isolate, &zone, argc_with_recv, flags,
     91                                      name);
     92   generator(&state);
     93   Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state);
     94   PostBuildProfileAndTracing(isolate, *code, name);
     95   return *code;
     96 }
     97 
     98 // Builder for builtins implemented in TurboFan with CallStub linkage.
     99 Code* BuildWithCodeStubAssemblerCS(Isolate* isolate,
    100                                    CodeAssemblerGenerator generator,
    101                                    CallDescriptors::Key interface_descriptor,
    102                                    Code::Flags flags, const char* name,
    103                                    int result_size) {
    104   HandleScope scope(isolate);
    105   Zone zone(isolate->allocator(), ZONE_NAME);
    106   // The interface descriptor with given key must be initialized at this point
    107   // and this construction just queries the details from the descriptors table.
    108   CallInterfaceDescriptor descriptor(isolate, interface_descriptor);
    109   // Ensure descriptor is already initialized.
    110   DCHECK_LE(0, descriptor.GetRegisterParameterCount());
    111   compiler::CodeAssemblerState state(isolate, &zone, descriptor, flags, name,
    112                                      result_size);
    113   generator(&state);
    114   Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state);
    115   PostBuildProfileAndTracing(isolate, *code, name);
    116   return *code;
    117 }
    118 }  // anonymous namespace
    119 
    120 void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
    121   DCHECK(!initialized_);
    122 
    123   // Create a scope for the handles in the builtins.
    124   HandleScope scope(isolate);
    125 
    126   if (create_heap_objects) {
    127     int index = 0;
    128     const Code::Flags kBuiltinFlags = Code::ComputeFlags(Code::BUILTIN);
    129     Code* code;
    130 #define BUILD_CPP(Name)                                                     \
    131   code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), BUILTIN_EXIT, \
    132                       kBuiltinFlags, #Name);                                \
    133   builtins_[index++] = code;
    134 #define BUILD_API(Name)                                             \
    135   code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), EXIT, \
    136                       kBuiltinFlags, #Name);                        \
    137   builtins_[index++] = code;
    138 #define BUILD_TFJ(Name, Argc)                                          \
    139   code = BuildWithCodeStubAssemblerJS(isolate, &Generate_##Name, Argc, \
    140                                       kBuiltinFlags, #Name);           \
    141   builtins_[index++] = code;
    142 #define BUILD_TFS(Name, Kind, Extra, InterfaceDescriptor, result_size) \
    143   { InterfaceDescriptor##Descriptor descriptor(isolate); }             \
    144   code = BuildWithCodeStubAssemblerCS(                                 \
    145       isolate, &Generate_##Name, CallDescriptors::InterfaceDescriptor, \
    146       Code::ComputeFlags(Code::Kind, Extra), #Name, result_size);      \
    147   builtins_[index++] = code;
    148 #define BUILD_ASM(Name)                                                        \
    149   code =                                                                       \
    150       BuildWithMacroAssembler(isolate, Generate_##Name, kBuiltinFlags, #Name); \
    151   builtins_[index++] = code;
    152 #define BUILD_ASH(Name, Kind, Extra)                                           \
    153   code = BuildWithMacroAssembler(                                              \
    154       isolate, Generate_##Name, Code::ComputeFlags(Code::Kind, Extra), #Name); \
    155   builtins_[index++] = code;
    156 
    157     BUILTIN_LIST(BUILD_CPP, BUILD_API, BUILD_TFJ, BUILD_TFS, BUILD_ASM,
    158                  BUILD_ASH, BUILD_ASM);
    159 
    160 #undef BUILD_CPP
    161 #undef BUILD_API
    162 #undef BUILD_TFJ
    163 #undef BUILD_TFS
    164 #undef BUILD_ASM
    165 #undef BUILD_ASH
    166     CHECK_EQ(builtin_count, index);
    167     for (int i = 0; i < builtin_count; i++) {
    168       Code::cast(builtins_[i])->set_builtin_index(i);
    169     }
    170   }
    171 
    172   // Mark as initialized.
    173   initialized_ = true;
    174 }
    175 
    176 void Builtins::TearDown() { initialized_ = false; }
    177 
    178 void Builtins::IterateBuiltins(ObjectVisitor* v) {
    179   v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
    180 }
    181 
    182 const char* Builtins::Lookup(byte* pc) {
    183   // may be called during initialization (disassembler!)
    184   if (initialized_) {
    185     for (int i = 0; i < builtin_count; i++) {
    186       Code* entry = Code::cast(builtins_[i]);
    187       if (entry->contains(pc)) return name(i);
    188     }
    189   }
    190   return NULL;
    191 }
    192 
    193 // static
    194 const char* Builtins::name(int index) {
    195   switch (index) {
    196 #define CASE(Name, ...) \
    197   case k##Name:         \
    198     return #Name;
    199     BUILTIN_LIST_ALL(CASE)
    200 #undef CASE
    201     default:
    202       UNREACHABLE();
    203       break;
    204   }
    205   return "";
    206 }
    207 
    208 // static
    209 Address Builtins::CppEntryOf(int index) {
    210   DCHECK(0 <= index && index < builtin_count);
    211   switch (index) {
    212 #define CASE(Name, ...) \
    213   case k##Name:         \
    214     return FUNCTION_ADDR(Builtin_##Name);
    215     BUILTIN_LIST_C(CASE)
    216 #undef CASE
    217     default:
    218       return nullptr;
    219   }
    220   UNREACHABLE();
    221 }
    222 
    223 // static
    224 bool Builtins::IsCpp(int index) {
    225   DCHECK(0 <= index && index < builtin_count);
    226   switch (index) {
    227 #define CASE(Name, ...) \
    228   case k##Name:         \
    229     return true;
    230 #define BUILTIN_LIST_CPP(V)                                       \
    231   BUILTIN_LIST(V, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \
    232                IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
    233     BUILTIN_LIST_CPP(CASE)
    234 #undef BUILTIN_LIST_CPP
    235 #undef CASE
    236     default:
    237       return false;
    238   }
    239   UNREACHABLE();
    240 }
    241 
    242 // static
    243 bool Builtins::IsApi(int index) {
    244   DCHECK(0 <= index && index < builtin_count);
    245   switch (index) {
    246 #define CASE(Name, ...) \
    247   case k##Name:         \
    248     return true;
    249 #define BUILTIN_LIST_API(V)                                       \
    250   BUILTIN_LIST(IGNORE_BUILTIN, V, IGNORE_BUILTIN, IGNORE_BUILTIN, \
    251                IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
    252     BUILTIN_LIST_API(CASE);
    253 #undef BUILTIN_LIST_API
    254 #undef CASE
    255     default:
    256       return false;
    257   }
    258   UNREACHABLE();
    259 }
    260 
    261 // static
    262 bool Builtins::HasCppImplementation(int index) {
    263   DCHECK(0 <= index && index < builtin_count);
    264   switch (index) {
    265 #define CASE(Name, ...) \
    266   case k##Name:         \
    267     return true;
    268     BUILTIN_LIST_C(CASE)
    269 #undef CASE
    270     default:
    271       return false;
    272   }
    273   UNREACHABLE();
    274 }
    275 
    276 #define DEFINE_BUILTIN_ACCESSOR(Name, ...)                                    \
    277   Handle<Code> Builtins::Name() {                                             \
    278     Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \
    279     return Handle<Code>(code_address);                                        \
    280   }
    281 BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR)
    282 #undef DEFINE_BUILTIN_ACCESSOR
    283 
    284 // static
    285 bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
    286                                     Handle<JSObject> target_global_proxy) {
    287   if (FLAG_allow_unsafe_function_constructor) return true;
    288   HandleScopeImplementer* impl = isolate->handle_scope_implementer();
    289   Handle<Context> responsible_context =
    290       impl->MicrotaskContextIsLastEnteredContext() ? impl->MicrotaskContext()
    291                                                    : impl->LastEnteredContext();
    292   // TODO(jochen): Remove this.
    293   if (responsible_context.is_null()) {
    294     return true;
    295   }
    296   if (*responsible_context == target->context()) return true;
    297   return isolate->MayAccess(responsible_context, target_global_proxy);
    298 }
    299 
    300 }  // namespace internal
    301 }  // namespace v8
    302