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