• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CodeStubDescriptor(CodeStub * stub)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 
CodeStubDescriptor(Isolate * isolate,uint32_t stub_key)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 
Initialize(Address deoptimization_handler,int hint_stack_parameter_count,StubFunctionMode function_mode)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 
Initialize(Register stack_parameter_count,Address deoptimization_handler,int hint_stack_parameter_count,StubFunctionMode function_mode)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 
FindCodeInCache(Code ** code_out)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 
RecordCodeGeneration(Handle<Code> code)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 
DeleteStubFromCacheForTesting()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 
GenerateCode()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 
GetCode()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 
GetMajorKey(const Code * code_stub)180 CodeStub::Major CodeStub::GetMajorKey(const Code* code_stub) {
181   return MajorKeyFromKey(code_stub->stub_key());
182 }
183 
MajorName(CodeStub::Major major_key)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 
PrintBaseName(std::ostream & os) const198 void CodeStub::PrintBaseName(std::ostream& os) const {  // NOLINT
199   os << MajorName(MajorKey());
200 }
201 
202 
PrintName(std::ostream & os) const203 void CodeStub::PrintName(std::ostream& os) const {  // NOLINT
204   PrintBaseName(os);
205   PrintState(os);
206 }
207 
208 
Dispatch(Isolate * isolate,uint32_t key,void ** value_out,DispatchedCall call)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 
GenerateHandlerTable(MacroAssembler * masm)228 int PlatformCodeStub::GenerateHandlerTable(MacroAssembler* masm) { return 0; }
229 
InitializeDescriptorDispatchedCall(CodeStub * stub,void ** value_out)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 
InitializeDescriptor(Isolate * isolate,uint32_t key,CodeStubDescriptor * desc)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 
GetCodeDispatchCall(CodeStub * stub,void ** value_out)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 
GetCode(Isolate * isolate,uint32_t key)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 
GenerateCode()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 
TF_STUB(ElementsTransitionAndStoreStub,CodeStubAssembler)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.
TF_STUB(KeyedLoadSloppyArgumentsStub,CodeStubAssembler)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.
TF_STUB(KeyedStoreSloppyArgumentsStub,CodeStubAssembler)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.
TF_STUB(StoreInterceptorStub,CodeStubAssembler)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.
TF_STUB(LoadIndexedInterceptorStub,CodeStubAssembler)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 
GenerateHandlerTable(MacroAssembler * masm)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.
TF_STUB(StoreSlowElementStub,CodeStubAssembler)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 
TF_STUB(StoreInArrayLiteralSlowStub,CodeStubAssembler)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 
TF_STUB(StoreFastElementStub,CodeStubAssembler)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
GenerateAheadOfTime(Isolate * isolate)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 
EntryHookTrampoline(intptr_t function,intptr_t stack_pointer,Isolate * isolate)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 
GenerateStubsAheadOfTime(Isolate * isolate)461 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
462   StoreFastElementStub::GenerateAheadOfTime(isolate);
463 }
464 
465 }  // namespace internal
466 }  // namespace v8
467