Home | History | Annotate | Download | only in src
      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/code-stubs.h"
      6 
      7 #include <sstream>
      8 
      9 #include "src/arguments.h"
     10 #include "src/assembler-inl.h"
     11 #include "src/ast/ast.h"
     12 #include "src/bootstrapper.h"
     13 #include "src/code-factory.h"
     14 #include "src/code-stub-assembler.h"
     15 #include "src/code-stubs-utils.h"
     16 #include "src/code-tracer.h"
     17 #include "src/counters.h"
     18 #include "src/gdb-jit.h"
     19 #include "src/heap/heap-inl.h"
     20 #include "src/ic/ic-stats.h"
     21 #include "src/ic/ic.h"
     22 #include "src/macro-assembler.h"
     23 #include "src/objects-inl.h"
     24 #include "src/objects/hash-table-inl.h"
     25 #include "src/tracing/tracing-category-observer.h"
     26 
     27 namespace v8 {
     28 namespace internal {
     29 
     30 using compiler::CodeAssemblerState;
     31 
     32 CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
     33     : isolate_(stub->isolate()),
     34       call_descriptor_(stub->GetCallInterfaceDescriptor()),
     35       stack_parameter_count_(no_reg),
     36       hint_stack_parameter_count_(-1),
     37       function_mode_(NOT_JS_FUNCTION_STUB_MODE),
     38       deoptimization_handler_(kNullAddress),
     39       miss_handler_(),
     40       has_miss_handler_(false) {}
     41 
     42 CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
     43     : isolate_(isolate),
     44       stack_parameter_count_(no_reg),
     45       hint_stack_parameter_count_(-1),
     46       function_mode_(NOT_JS_FUNCTION_STUB_MODE),
     47       deoptimization_handler_(kNullAddress),
     48       miss_handler_(),
     49       has_miss_handler_(false) {
     50   CodeStub::InitializeDescriptor(isolate, stub_key, this);
     51 }
     52 
     53 
     54 void CodeStubDescriptor::Initialize(Address deoptimization_handler,
     55                                     int hint_stack_parameter_count,
     56                                     StubFunctionMode function_mode) {
     57   deoptimization_handler_ = deoptimization_handler;
     58   hint_stack_parameter_count_ = hint_stack_parameter_count;
     59   function_mode_ = function_mode;
     60 }
     61 
     62 
     63 void CodeStubDescriptor::Initialize(Register stack_parameter_count,
     64                                     Address deoptimization_handler,
     65                                     int hint_stack_parameter_count,
     66                                     StubFunctionMode function_mode) {
     67   Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
     68   stack_parameter_count_ = stack_parameter_count;
     69 }
     70 
     71 
     72 bool CodeStub::FindCodeInCache(Code** code_out) {
     73   SimpleNumberDictionary* stubs = isolate()->heap()->code_stubs();
     74   int index = stubs->FindEntry(isolate(), GetKey());
     75   if (index != SimpleNumberDictionary::kNotFound) {
     76     *code_out = Code::cast(stubs->ValueAt(index));
     77     return true;
     78   }
     79   return false;
     80 }
     81 
     82 
     83 void CodeStub::RecordCodeGeneration(Handle<Code> code) {
     84   std::ostringstream os;
     85   os << *this;
     86   PROFILE(isolate(),
     87           CodeCreateEvent(CodeEventListener::STUB_TAG,
     88                           AbstractCode::cast(*code), os.str().c_str()));
     89   Counters* counters = isolate()->counters();
     90   counters->total_stubs_code_size()->Increment(code->raw_instruction_size());
     91 #ifdef DEBUG
     92   code->VerifyEmbeddedObjects(isolate());
     93 #endif
     94 }
     95 
     96 
     97 void CodeStub::DeleteStubFromCacheForTesting() {
     98   Heap* heap = isolate_->heap();
     99   Handle<SimpleNumberDictionary> dict(heap->code_stubs(), isolate());
    100   int entry = dict->FindEntry(isolate(), GetKey());
    101   DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
    102   dict = SimpleNumberDictionary::DeleteEntry(isolate(), dict, entry);
    103   heap->SetRootCodeStubs(*dict);
    104 }
    105 
    106 Handle<Code> PlatformCodeStub::GenerateCode() {
    107   Factory* factory = isolate()->factory();
    108 
    109   // Generate the new code.
    110   // TODO(yangguo): remove this once we can serialize IC stubs.
    111   AssemblerOptions options = AssemblerOptions::Default(isolate(), true);
    112   MacroAssembler masm(isolate(), options, nullptr, 256,
    113                       CodeObjectRequired::kYes);
    114 
    115   {
    116     // Update the static counter each time a new code stub is generated.
    117     isolate()->counters()->code_stubs()->Increment();
    118 
    119     // Generate the code for the stub.
    120     NoCurrentFrameScope scope(&masm);
    121     Generate(&masm);
    122   }
    123 
    124   // Generate the handler table.
    125   int handler_table_offset = GenerateHandlerTable(&masm);
    126 
    127   // Create the code object.
    128   CodeDesc desc;
    129   masm.GetCode(isolate(), &desc);
    130   // Copy the generated code into a heap object.
    131   Handle<Code> new_object = factory->NewCode(
    132       desc, Code::STUB, masm.CodeObject(), Builtins::kNoBuiltinId,
    133       MaybeHandle<ByteArray>(), DeoptimizationData::Empty(isolate()),
    134       NeedsImmovableCode(), GetKey(), false, 0, 0, handler_table_offset);
    135   return new_object;
    136 }
    137 
    138 
    139 Handle<Code> CodeStub::GetCode() {
    140   Heap* heap = isolate()->heap();
    141   Code* code;
    142   if (FindCodeInCache(&code)) {
    143     DCHECK(code->is_stub());
    144     return handle(code, isolate_);
    145   }
    146 
    147   {
    148     HandleScope scope(isolate());
    149     // Canonicalize handles, so that we can share constant pool entries pointing
    150     // to code targets without dereferencing their handles.
    151     CanonicalHandleScope canonical(isolate());
    152 
    153     Handle<Code> new_object = GenerateCode();
    154     DCHECK_EQ(GetKey(), new_object->stub_key());
    155     RecordCodeGeneration(new_object);
    156 
    157 #ifdef ENABLE_DISASSEMBLER
    158     if (FLAG_print_code_stubs) {
    159       CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
    160       OFStream os(trace_scope.file());
    161       std::ostringstream name;
    162       name << *this;
    163       new_object->Disassemble(name.str().c_str(), os);
    164       os << "\n";
    165     }
    166 #endif
    167 
    168     // Update the dictionary and the root in Heap.
    169     Handle<SimpleNumberDictionary> dict = SimpleNumberDictionary::Set(
    170         isolate(), handle(heap->code_stubs(), isolate_), GetKey(), new_object);
    171     heap->SetRootCodeStubs(*dict);
    172     code = *new_object;
    173   }
    174 
    175   Activate(code);
    176   DCHECK(!NeedsImmovableCode() || Heap::IsImmovable(code));
    177   return Handle<Code>(code, isolate());
    178 }
    179 
    180 CodeStub::Major CodeStub::GetMajorKey(const Code* code_stub) {
    181   return MajorKeyFromKey(code_stub->stub_key());
    182 }
    183 
    184 const char* CodeStub::MajorName(CodeStub::Major major_key) {
    185   switch (major_key) {
    186 #define DEF_CASE(name) case name: return #name "Stub";
    187     CODE_STUB_LIST(DEF_CASE)
    188 #undef DEF_CASE
    189     case NoCache:
    190       return "<NoCache>Stub";
    191     case NUMBER_OF_IDS:
    192       UNREACHABLE();
    193   }
    194   return nullptr;
    195 }
    196 
    197 
    198 void CodeStub::PrintBaseName(std::ostream& os) const {  // NOLINT
    199   os << MajorName(MajorKey());
    200 }
    201 
    202 
    203 void CodeStub::PrintName(std::ostream& os) const {  // NOLINT
    204   PrintBaseName(os);
    205   PrintState(os);
    206 }
    207 
    208 
    209 void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
    210                         DispatchedCall call) {
    211   switch (MajorKeyFromKey(key)) {
    212 #define DEF_CASE(NAME)             \
    213   case NAME: {                     \
    214     NAME##Stub stub(key, isolate); \
    215     CodeStub* pstub = &stub;       \
    216     call(pstub, value_out);        \
    217     break;                         \
    218   }
    219     CODE_STUB_LIST(DEF_CASE)
    220 #undef DEF_CASE
    221     case NUMBER_OF_IDS:
    222     case NoCache:
    223       UNREACHABLE();
    224       break;
    225   }
    226 }
    227 
    228 int PlatformCodeStub::GenerateHandlerTable(MacroAssembler* masm) { return 0; }
    229 
    230 static void InitializeDescriptorDispatchedCall(CodeStub* stub,
    231                                                void** value_out) {
    232   CodeStubDescriptor* descriptor_out =
    233       reinterpret_cast<CodeStubDescriptor*>(value_out);
    234   descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
    235 }
    236 
    237 
    238 void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
    239                                     CodeStubDescriptor* desc) {
    240   void** value_out = reinterpret_cast<void**>(desc);
    241   Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
    242 }
    243 
    244 
    245 void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
    246   Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
    247   *code_out = stub->GetCode();
    248 }
    249 
    250 
    251 MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
    252   HandleScope scope(isolate);
    253   Handle<Code> code;
    254   void** value_out = reinterpret_cast<void**>(&code);
    255   Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
    256   return scope.CloseAndEscape(code);
    257 }
    258 
    259 Handle<Code> TurboFanCodeStub::GenerateCode() {
    260   const char* name = CodeStub::MajorName(MajorKey());
    261   Zone zone(isolate()->allocator(), ZONE_NAME);
    262   CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor());
    263   compiler::CodeAssemblerState state(
    264       isolate(), &zone, descriptor, Code::STUB, name,
    265       PoisoningMitigationLevel::kDontPoison, GetKey());
    266   GenerateAssembly(&state);
    267   return compiler::CodeAssembler::GenerateCode(
    268       &state, AssemblerOptions::Default(isolate()));
    269 }
    270 
    271 TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) {
    272   Node* receiver = Parameter(Descriptor::kReceiver);
    273   Node* key = Parameter(Descriptor::kName);
    274   Node* value = Parameter(Descriptor::kValue);
    275   Node* map = Parameter(Descriptor::kMap);
    276   Node* slot = Parameter(Descriptor::kSlot);
    277   Node* vector = Parameter(Descriptor::kVector);
    278   Node* context = Parameter(Descriptor::kContext);
    279 
    280   Comment(
    281       "ElementsTransitionAndStoreStub: from_kind=%s, to_kind=%s,"
    282       " is_jsarray=%d, store_mode=%d",
    283       ElementsKindToString(stub->from_kind()),
    284       ElementsKindToString(stub->to_kind()), stub->is_jsarray(),
    285       stub->store_mode());
    286 
    287   Label miss(this);
    288 
    289   if (FLAG_trace_elements_transitions) {
    290     // Tracing elements transitions is the job of the runtime.
    291     Goto(&miss);
    292   } else {
    293     TransitionElementsKind(receiver, map, stub->from_kind(), stub->to_kind(),
    294                            stub->is_jsarray(), &miss);
    295     EmitElementStore(receiver, key, value, stub->is_jsarray(), stub->to_kind(),
    296                      stub->store_mode(), &miss, context);
    297     Return(value);
    298   }
    299 
    300   BIND(&miss);
    301   {
    302     Comment("Miss");
    303     TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
    304                     receiver, key, value, map, slot, vector);
    305   }
    306 }
    307 
    308 // TODO(ishell): move to builtins-handler-gen.
    309 TF_STUB(KeyedLoadSloppyArgumentsStub, CodeStubAssembler) {
    310   Node* receiver = Parameter(Descriptor::kReceiver);
    311   Node* key = Parameter(Descriptor::kName);
    312   Node* slot = Parameter(Descriptor::kSlot);
    313   Node* vector = Parameter(Descriptor::kVector);
    314   Node* context = Parameter(Descriptor::kContext);
    315 
    316   Label miss(this);
    317 
    318   Node* result = LoadKeyedSloppyArguments(receiver, key, &miss);
    319   Return(result);
    320 
    321   BIND(&miss);
    322   {
    323     Comment("Miss");
    324     TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
    325                     vector);
    326   }
    327 }
    328 
    329 // TODO(ishell): move to builtins-handler-gen.
    330 TF_STUB(KeyedStoreSloppyArgumentsStub, CodeStubAssembler) {
    331   Node* receiver = Parameter(Descriptor::kReceiver);
    332   Node* key = Parameter(Descriptor::kName);
    333   Node* value = Parameter(Descriptor::kValue);
    334   Node* slot = Parameter(Descriptor::kSlot);
    335   Node* vector = Parameter(Descriptor::kVector);
    336   Node* context = Parameter(Descriptor::kContext);
    337 
    338   Label miss(this);
    339 
    340   StoreKeyedSloppyArguments(receiver, key, value, &miss);
    341   Return(value);
    342 
    343   BIND(&miss);
    344   {
    345     Comment("Miss");
    346     TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
    347                     receiver, key);
    348   }
    349 }
    350 
    351 // TODO(ishell): move to builtins-handler-gen.
    352 TF_STUB(StoreInterceptorStub, CodeStubAssembler) {
    353   Node* receiver = Parameter(Descriptor::kReceiver);
    354   Node* name = Parameter(Descriptor::kName);
    355   Node* value = Parameter(Descriptor::kValue);
    356   Node* slot = Parameter(Descriptor::kSlot);
    357   Node* vector = Parameter(Descriptor::kVector);
    358   Node* context = Parameter(Descriptor::kContext);
    359   TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, value, slot,
    360                   vector, receiver, name);
    361 }
    362 
    363 // TODO(ishell): move to builtins-handler-gen.
    364 TF_STUB(LoadIndexedInterceptorStub, CodeStubAssembler) {
    365   Node* receiver = Parameter(Descriptor::kReceiver);
    366   Node* key = Parameter(Descriptor::kName);
    367   Node* slot = Parameter(Descriptor::kSlot);
    368   Node* vector = Parameter(Descriptor::kVector);
    369   Node* context = Parameter(Descriptor::kContext);
    370 
    371   Label if_keyispositivesmi(this), if_keyisinvalid(this);
    372   Branch(TaggedIsPositiveSmi(key), &if_keyispositivesmi, &if_keyisinvalid);
    373   BIND(&if_keyispositivesmi);
    374   TailCallRuntime(Runtime::kLoadElementWithInterceptor, context, receiver, key);
    375 
    376   BIND(&if_keyisinvalid);
    377   TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
    378                   vector);
    379 }
    380 
    381 int JSEntryStub::GenerateHandlerTable(MacroAssembler* masm) {
    382   int handler_table_offset = HandlerTable::EmitReturnTableStart(masm, 1);
    383   HandlerTable::EmitReturnEntry(masm, 0, handler_offset_);
    384   return handler_table_offset;
    385 }
    386 
    387 // TODO(ishell): move to builtins-handler-gen.
    388 TF_STUB(StoreSlowElementStub, CodeStubAssembler) {
    389   Node* receiver = Parameter(Descriptor::kReceiver);
    390   Node* name = Parameter(Descriptor::kName);
    391   Node* value = Parameter(Descriptor::kValue);
    392   Node* slot = Parameter(Descriptor::kSlot);
    393   Node* vector = Parameter(Descriptor::kVector);
    394   Node* context = Parameter(Descriptor::kContext);
    395 
    396   TailCallRuntime(Runtime::kKeyedStoreIC_Slow, context, value, slot, vector,
    397                   receiver, name);
    398 }
    399 
    400 TF_STUB(StoreInArrayLiteralSlowStub, CodeStubAssembler) {
    401   Node* array = Parameter(Descriptor::kReceiver);
    402   Node* index = Parameter(Descriptor::kName);
    403   Node* value = Parameter(Descriptor::kValue);
    404   Node* context = Parameter(Descriptor::kContext);
    405   TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, context, value, array,
    406                   index);
    407 }
    408 
    409 TF_STUB(StoreFastElementStub, CodeStubAssembler) {
    410   Comment("StoreFastElementStub: js_array=%d, elements_kind=%s, store_mode=%d",
    411           stub->is_js_array(), ElementsKindToString(stub->elements_kind()),
    412           stub->store_mode());
    413 
    414   Node* receiver = Parameter(Descriptor::kReceiver);
    415   Node* key = Parameter(Descriptor::kName);
    416   Node* value = Parameter(Descriptor::kValue);
    417   Node* slot = Parameter(Descriptor::kSlot);
    418   Node* vector = Parameter(Descriptor::kVector);
    419   Node* context = Parameter(Descriptor::kContext);
    420 
    421   Label miss(this);
    422 
    423   EmitElementStore(receiver, key, value, stub->is_js_array(),
    424                    stub->elements_kind(), stub->store_mode(), &miss, context);
    425   Return(value);
    426 
    427   BIND(&miss);
    428   {
    429     Comment("Miss");
    430     TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
    431                     receiver, key);
    432   }
    433 }
    434 
    435 // static
    436 void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
    437   if (FLAG_minimal) return;
    438   StoreFastElementStub(isolate, false, HOLEY_ELEMENTS, STANDARD_STORE)
    439       .GetCode();
    440   StoreFastElementStub(isolate, false, HOLEY_ELEMENTS,
    441                        STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
    442       .GetCode();
    443   for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
    444     ElementsKind kind = static_cast<ElementsKind>(i);
    445     StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
    446     StoreFastElementStub(isolate, true, kind,
    447                          STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
    448         .GetCode();
    449   }
    450 }
    451 
    452 
    453 void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
    454                                                intptr_t stack_pointer,
    455                                                Isolate* isolate) {
    456   FunctionEntryHook entry_hook = isolate->function_entry_hook();
    457   DCHECK_NOT_NULL(entry_hook);
    458   entry_hook(function, stack_pointer);
    459 }
    460 
    461 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
    462   StoreFastElementStub::GenerateAheadOfTime(isolate);
    463 }
    464 
    465 }  // namespace internal
    466 }  // namespace v8
    467