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