1 // Copyright 2014 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/ic/handler-compiler.h" 6 7 #include "src/field-type.h" 8 #include "src/ic/call-optimization.h" 9 #include "src/ic/handler-configuration-inl.h" 10 #include "src/ic/ic-inl.h" 11 #include "src/ic/ic.h" 12 #include "src/isolate-inl.h" 13 14 namespace v8 { 15 namespace internal { 16 17 Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name, 18 Handle<Map> stub_holder, 19 Code::Kind kind, 20 CacheHolderFlag cache_holder) { 21 Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder); 22 Code* code = stub_holder->LookupInCodeCache(*name, flags); 23 if (code == nullptr) return Handle<Code>(); 24 return handle(code); 25 } 26 27 28 Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent( 29 Handle<Name> name, Handle<Map> receiver_map) { 30 Isolate* isolate = name->GetIsolate(); 31 if (receiver_map->prototype()->IsNull(isolate)) { 32 // TODO(jkummerow/verwaest): If there is no prototype and the property 33 // is nonexistent, introduce a builtin to handle this (fast properties 34 // -> return undefined, dictionary properties -> do negative lookup). 35 return Handle<Code>(); 36 } 37 CacheHolderFlag flag; 38 Handle<Map> stub_holder_map = 39 IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag); 40 41 // If no dictionary mode objects are present in the prototype chain, the load 42 // nonexistent IC stub can be shared for all names for a given map and we use 43 // the empty string for the map cache in that case. If there are dictionary 44 // mode objects involved, we need to do negative lookups in the stub and 45 // therefore the stub will be specific to the name. 46 Handle<Name> cache_name = 47 receiver_map->is_dictionary_map() 48 ? name 49 : Handle<Name>::cast(isolate->factory()->nonexistent_symbol()); 50 Handle<Map> current_map = stub_holder_map; 51 Handle<JSObject> last(JSObject::cast(receiver_map->prototype())); 52 while (true) { 53 if (current_map->is_dictionary_map()) cache_name = name; 54 if (current_map->prototype()->IsNull(isolate)) break; 55 if (name->IsPrivate()) { 56 // TODO(verwaest): Use nonexistent_private_symbol. 57 cache_name = name; 58 if (!current_map->has_hidden_prototype()) break; 59 } 60 61 last = handle(JSObject::cast(current_map->prototype())); 62 current_map = handle(last->map()); 63 } 64 // Compile the stub that is either shared for all names or 65 // name specific if there are global objects involved. 66 Handle<Code> handler = PropertyHandlerCompiler::Find( 67 cache_name, stub_holder_map, Code::LOAD_IC, flag); 68 if (!handler.is_null()) { 69 TRACE_HANDLER_STATS(isolate, LoadIC_HandlerCacheHit_NonExistent); 70 return handler; 71 } 72 73 TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent); 74 NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag); 75 handler = compiler.CompileLoadNonexistent(cache_name); 76 Map::UpdateCodeCache(stub_holder_map, cache_name, handler); 77 return handler; 78 } 79 80 81 Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind, 82 Handle<Name> name) { 83 Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder()); 84 Handle<Code> code = GetCodeWithFlags(flags, name); 85 PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG, 86 AbstractCode::cast(*code), *name)); 87 #ifdef DEBUG 88 code->VerifyEmbeddedObjects(); 89 #endif 90 return code; 91 } 92 93 94 #define __ ACCESS_MASM(masm()) 95 96 97 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, 98 Handle<Name> name, 99 Label* miss, 100 ReturnHolder return_what) { 101 if (map()->IsPrimitiveMap() || map()->IsJSGlobalProxyMap()) { 102 // If the receiver is a global proxy and if we get to this point then 103 // the compile-time (current) native context has access to global proxy's 104 // native context. Since access rights revocation is not supported at all, 105 // we can generate a check that an execution-time native context is either 106 // the same as compile-time native context or has the same access token. 107 Handle<Context> native_context = isolate()->native_context(); 108 Handle<WeakCell> weak_cell(native_context->self_weak_cell(), isolate()); 109 110 bool compare_native_contexts_only = map()->IsPrimitiveMap(); 111 GenerateAccessCheck(weak_cell, scratch1(), scratch2(), miss, 112 compare_native_contexts_only); 113 } 114 115 // Check that the maps starting from the prototype haven't changed. 116 return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name, 117 miss, return_what); 118 } 119 120 121 // Frontend for store uses the name register. It has to be restored before a 122 // miss. 123 Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg, 124 Handle<Name> name, 125 Label* miss, 126 ReturnHolder return_what) { 127 if (map()->IsJSGlobalProxyMap()) { 128 Handle<Context> native_context = isolate()->native_context(); 129 Handle<WeakCell> weak_cell(native_context->self_weak_cell(), isolate()); 130 GenerateAccessCheck(weak_cell, scratch1(), scratch2(), miss, false); 131 } 132 133 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, 134 miss, return_what); 135 } 136 137 138 Register PropertyHandlerCompiler::Frontend(Handle<Name> name) { 139 Label miss; 140 if (IC::ShouldPushPopSlotAndVector(kind())) { 141 PushVectorAndSlot(); 142 } 143 Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER); 144 FrontendFooter(name, &miss); 145 // The footer consumes the vector and slot from the stack if miss occurs. 146 if (IC::ShouldPushPopSlotAndVector(kind())) { 147 DiscardVectorAndSlot(); 148 } 149 return reg; 150 } 151 152 153 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name, 154 Label* miss, 155 Register scratch1, 156 Register scratch2) { 157 Register holder_reg; 158 Handle<Map> last_map; 159 if (holder().is_null()) { 160 holder_reg = receiver(); 161 last_map = map(); 162 // If |type| has null as its prototype, |holder()| is 163 // Handle<JSObject>::null(). 164 DCHECK(last_map->prototype() == isolate()->heap()->null_value()); 165 } else { 166 last_map = handle(holder()->map()); 167 // This condition matches the branches below. 168 bool need_holder = 169 last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap(); 170 holder_reg = 171 FrontendHeader(receiver(), name, miss, 172 need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING); 173 } 174 175 if (last_map->is_dictionary_map()) { 176 if (last_map->IsJSGlobalObjectMap()) { 177 Handle<JSGlobalObject> global = 178 holder().is_null() 179 ? Handle<JSGlobalObject>::cast(isolate()->global_object()) 180 : Handle<JSGlobalObject>::cast(holder()); 181 GenerateCheckPropertyCell(masm(), global, name, scratch1, miss); 182 } else { 183 if (!name->IsUniqueName()) { 184 DCHECK(name->IsString()); 185 name = factory()->InternalizeString(Handle<String>::cast(name)); 186 } 187 DCHECK(holder().is_null() || 188 holder()->property_dictionary()->FindEntry(name) == 189 NameDictionary::kNotFound); 190 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1, 191 scratch2); 192 } 193 } 194 } 195 196 197 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name, 198 FieldIndex field) { 199 Register reg = Frontend(name); 200 __ Move(receiver(), reg); 201 LoadFieldStub stub(isolate(), field); 202 GenerateTailCall(masm(), stub.GetCode()); 203 return GetCode(kind(), name); 204 } 205 206 207 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name, 208 int constant_index) { 209 Register reg = Frontend(name); 210 __ Move(receiver(), reg); 211 LoadConstantStub stub(isolate(), constant_index); 212 GenerateTailCall(masm(), stub.GetCode()); 213 return GetCode(kind(), name); 214 } 215 216 217 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( 218 Handle<Name> name) { 219 Label miss; 220 if (IC::ShouldPushPopSlotAndVector(kind())) { 221 DCHECK(kind() == Code::LOAD_IC); 222 PushVectorAndSlot(); 223 } 224 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3()); 225 if (IC::ShouldPushPopSlotAndVector(kind())) { 226 DiscardVectorAndSlot(); 227 } 228 GenerateLoadConstant(isolate()->factory()->undefined_value()); 229 FrontendFooter(name, &miss); 230 return GetCode(kind(), name); 231 } 232 233 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( 234 Handle<Name> name, Handle<AccessorInfo> callback, Handle<Code> slow_stub) { 235 if (V8_UNLIKELY(FLAG_runtime_stats)) { 236 GenerateTailCall(masm(), slow_stub); 237 } 238 Register reg = Frontend(name); 239 GenerateLoadCallback(reg, callback); 240 return GetCode(kind(), name); 241 } 242 243 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( 244 Handle<Name> name, const CallOptimization& call_optimization, 245 int accessor_index, Handle<Code> slow_stub) { 246 DCHECK(call_optimization.is_simple_api_call()); 247 if (V8_UNLIKELY(FLAG_runtime_stats)) { 248 GenerateTailCall(masm(), slow_stub); 249 } 250 Register holder = Frontend(name); 251 GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(), 252 scratch2(), false, no_reg, holder, accessor_index); 253 return GetCode(kind(), name); 254 } 255 256 257 void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) { 258 if (IC::ShouldPushPopSlotAndVector(kind())) { 259 if (holder_reg.is(receiver())) { 260 PushVectorAndSlot(); 261 } else { 262 DCHECK(holder_reg.is(scratch1())); 263 PushVectorAndSlot(scratch2(), scratch3()); 264 } 265 } 266 } 267 268 269 void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg, 270 PopMode mode) { 271 if (IC::ShouldPushPopSlotAndVector(kind())) { 272 if (mode == DISCARD) { 273 DiscardVectorAndSlot(); 274 } else { 275 if (holder_reg.is(receiver())) { 276 PopVectorAndSlot(); 277 } else { 278 DCHECK(holder_reg.is(scratch1())); 279 PopVectorAndSlot(scratch2(), scratch3()); 280 } 281 } 282 } 283 } 284 285 286 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor( 287 LookupIterator* it) { 288 // So far the most popular follow ups for interceptor loads are DATA and 289 // AccessorInfo, so inline only them. Other cases may be added 290 // later. 291 bool inline_followup = false; 292 switch (it->state()) { 293 case LookupIterator::TRANSITION: 294 UNREACHABLE(); 295 case LookupIterator::ACCESS_CHECK: 296 case LookupIterator::INTERCEPTOR: 297 case LookupIterator::JSPROXY: 298 case LookupIterator::NOT_FOUND: 299 case LookupIterator::INTEGER_INDEXED_EXOTIC: 300 break; 301 case LookupIterator::DATA: 302 inline_followup = 303 it->property_details().type() == DATA && !it->is_dictionary_holder(); 304 break; 305 case LookupIterator::ACCESSOR: { 306 Handle<Object> accessors = it->GetAccessors(); 307 if (accessors->IsAccessorInfo()) { 308 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); 309 inline_followup = 310 info->getter() != NULL && 311 AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map()); 312 } else if (accessors->IsAccessorPair()) { 313 Handle<JSObject> property_holder(it->GetHolder<JSObject>()); 314 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), 315 isolate()); 316 if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) { 317 break; 318 } 319 if (!property_holder->HasFastProperties()) break; 320 CallOptimization call_optimization(getter); 321 Handle<Map> receiver_map = map(); 322 inline_followup = call_optimization.is_simple_api_call() && 323 call_optimization.IsCompatibleReceiverMap( 324 receiver_map, property_holder); 325 } 326 } 327 } 328 329 Label miss; 330 InterceptorVectorSlotPush(receiver()); 331 bool lost_holder_register = false; 332 auto holder_orig = holder(); 333 // non masking interceptors must check the entire chain, so temporarily reset 334 // the holder to be that last element for the FrontendHeader call. 335 if (holder()->GetNamedInterceptor()->non_masking()) { 336 DCHECK(!inline_followup); 337 JSObject* last = *holder(); 338 PrototypeIterator iter(isolate(), last); 339 while (!iter.IsAtEnd()) { 340 lost_holder_register = true; 341 // Casting to JSObject is fine here. The LookupIterator makes sure to 342 // look behind non-masking interceptors during the original lookup, and 343 // we wouldn't try to compile a handler if there was a Proxy anywhere. 344 last = iter.GetCurrent<JSObject>(); 345 iter.Advance(); 346 } 347 auto last_handle = handle(last); 348 set_holder(last_handle); 349 } 350 Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER); 351 // Reset the holder so further calculations are correct. 352 set_holder(holder_orig); 353 if (lost_holder_register) { 354 if (*it->GetReceiver() == *holder()) { 355 reg = receiver(); 356 } else { 357 // Reload lost holder register. 358 auto cell = isolate()->factory()->NewWeakCell(holder()); 359 __ LoadWeakValue(reg, cell, &miss); 360 } 361 } 362 FrontendFooter(it->name(), &miss); 363 InterceptorVectorSlotPop(reg); 364 if (inline_followup) { 365 // TODO(368): Compile in the whole chain: all the interceptors in 366 // prototypes and ultimate answer. 367 GenerateLoadInterceptorWithFollowup(it, reg); 368 } else { 369 GenerateLoadInterceptor(reg); 370 } 371 return GetCode(kind(), it->name()); 372 } 373 374 void NamedLoadHandlerCompiler::GenerateLoadCallback( 375 Register reg, Handle<AccessorInfo> callback) { 376 DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister())); 377 __ Move(ApiGetterDescriptor::HolderRegister(), reg); 378 // The callback is alive if this instruction is executed, 379 // so the weak cell is not cleared and points to data. 380 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback); 381 __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell); 382 383 CallApiGetterStub stub(isolate()); 384 __ TailCallStub(&stub); 385 } 386 387 void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor( 388 LookupIterator* it, Register interceptor_reg) { 389 Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>()); 390 391 Handle<Map> holder_map(holder()->map()); 392 set_map(holder_map); 393 set_holder(real_named_property_holder); 394 395 Label miss; 396 InterceptorVectorSlotPush(interceptor_reg); 397 Register reg = 398 FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER); 399 FrontendFooter(it->name(), &miss); 400 // We discard the vector and slot now because we don't miss below this point. 401 InterceptorVectorSlotPop(reg, DISCARD); 402 403 switch (it->state()) { 404 case LookupIterator::ACCESS_CHECK: 405 case LookupIterator::INTERCEPTOR: 406 case LookupIterator::JSPROXY: 407 case LookupIterator::NOT_FOUND: 408 case LookupIterator::INTEGER_INDEXED_EXOTIC: 409 case LookupIterator::TRANSITION: 410 UNREACHABLE(); 411 case LookupIterator::DATA: { 412 DCHECK_EQ(DATA, it->property_details().type()); 413 __ Move(receiver(), reg); 414 LoadFieldStub stub(isolate(), it->GetFieldIndex()); 415 GenerateTailCall(masm(), stub.GetCode()); 416 break; 417 } 418 case LookupIterator::ACCESSOR: 419 if (it->GetAccessors()->IsAccessorInfo()) { 420 Handle<AccessorInfo> info = 421 Handle<AccessorInfo>::cast(it->GetAccessors()); 422 DCHECK_NOT_NULL(info->getter()); 423 GenerateLoadCallback(reg, info); 424 } else { 425 Handle<Object> function = handle( 426 AccessorPair::cast(*it->GetAccessors())->getter(), isolate()); 427 CallOptimization call_optimization(function); 428 GenerateApiAccessorCall(masm(), call_optimization, holder_map, 429 receiver(), scratch2(), false, no_reg, reg, 430 it->GetAccessorIndex()); 431 } 432 } 433 } 434 435 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter( 436 Handle<Name> name, int accessor_index, int expected_arguments) { 437 Register holder = Frontend(name); 438 GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index, 439 expected_arguments, scratch2()); 440 return GetCode(kind(), name); 441 } 442 443 444 // TODO(verwaest): Cleanup. holder() is actually the receiver. 445 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition( 446 Handle<Map> transition, Handle<Name> name) { 447 Label miss; 448 449 // Ensure that the StoreTransitionStub we are going to call has the same 450 // number of stack arguments. This means that we don't have to adapt them 451 // if we decide to call the transition or miss stub. 452 STATIC_ASSERT(Descriptor::kStackArgumentsCount == 453 StoreTransitionDescriptor::kStackArgumentsCount); 454 STATIC_ASSERT(Descriptor::kStackArgumentsCount == 0 || 455 Descriptor::kStackArgumentsCount == 3); 456 STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kValue == 457 StoreTransitionDescriptor::kParameterCount - 458 StoreTransitionDescriptor::kValue); 459 STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kSlot == 460 StoreTransitionDescriptor::kParameterCount - 461 StoreTransitionDescriptor::kSlot); 462 STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kVector == 463 StoreTransitionDescriptor::kParameterCount - 464 StoreTransitionDescriptor::kVector); 465 466 if (Descriptor::kPassLastArgsOnStack) { 467 __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue); 468 } 469 470 bool need_save_restore = IC::ShouldPushPopSlotAndVector(kind()); 471 if (need_save_restore) { 472 PushVectorAndSlot(); 473 } 474 475 // Check that we are allowed to write this. 476 bool is_nonexistent = holder()->map() == transition->GetBackPointer(); 477 if (is_nonexistent) { 478 // Find the top object. 479 Handle<JSObject> last; 480 PrototypeIterator::WhereToEnd end = 481 name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN 482 : PrototypeIterator::END_AT_NULL; 483 PrototypeIterator iter(isolate(), holder(), kStartAtPrototype, end); 484 while (!iter.IsAtEnd()) { 485 last = PrototypeIterator::GetCurrent<JSObject>(iter); 486 iter.Advance(); 487 } 488 if (!last.is_null()) set_holder(last); 489 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2()); 490 } else { 491 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); 492 DCHECK(holder()->HasFastProperties()); 493 } 494 495 int descriptor = transition->LastAdded(); 496 Handle<DescriptorArray> descriptors(transition->instance_descriptors()); 497 PropertyDetails details = descriptors->GetDetails(descriptor); 498 Representation representation = details.representation(); 499 DCHECK(!representation.IsNone()); 500 501 // Stub is never generated for objects that require access checks. 502 DCHECK(!transition->is_access_check_needed()); 503 504 // Call to respective StoreTransitionStub. 505 Register map_reg = StoreTransitionDescriptor::MapRegister(); 506 507 if (details.type() == DATA_CONSTANT) { 508 DCHECK(descriptors->GetValue(descriptor)->IsJSFunction()); 509 GenerateRestoreMap(transition, map_reg, scratch1(), &miss); 510 GenerateConstantCheck(map_reg, descriptor, value(), scratch1(), &miss); 511 if (need_save_restore) { 512 PopVectorAndSlot(); 513 } 514 GenerateRestoreName(name); 515 StoreMapStub stub(isolate()); 516 GenerateTailCall(masm(), stub.GetCode()); 517 518 } else { 519 if (representation.IsHeapObject()) { 520 GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(), 521 &miss); 522 } 523 StoreTransitionStub::StoreMode store_mode = 524 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0 525 ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue 526 : StoreTransitionStub::StoreMapAndValue; 527 GenerateRestoreMap(transition, map_reg, scratch1(), &miss); 528 if (need_save_restore) { 529 PopVectorAndSlot(); 530 } 531 // We need to pass name on the stack. 532 PopReturnAddress(this->name()); 533 __ Push(name); 534 PushReturnAddress(this->name()); 535 536 FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor); 537 __ Move(StoreNamedTransitionDescriptor::FieldOffsetRegister(), 538 Smi::FromInt(index.index() << kPointerSizeLog2)); 539 540 StoreTransitionStub stub(isolate(), index.is_inobject(), representation, 541 store_mode); 542 GenerateTailCall(masm(), stub.GetCode()); 543 } 544 545 __ bind(&miss); 546 if (need_save_restore) { 547 PopVectorAndSlot(); 548 } 549 GenerateRestoreName(name); 550 TailCallBuiltin(masm(), MissBuiltin(kind())); 551 552 return GetCode(kind(), name); 553 } 554 555 bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks( 556 FieldType* field_type) const { 557 return field_type->IsClass(); 558 } 559 560 561 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) { 562 Label miss; 563 DCHECK(it->representation().IsHeapObject()); 564 565 FieldType* field_type = *it->GetFieldType(); 566 bool need_save_restore = false; 567 if (RequiresFieldTypeChecks(field_type)) { 568 need_save_restore = IC::ShouldPushPopSlotAndVector(kind()); 569 if (Descriptor::kPassLastArgsOnStack) { 570 __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue); 571 } 572 if (need_save_restore) PushVectorAndSlot(); 573 GenerateFieldTypeChecks(field_type, value(), &miss); 574 if (need_save_restore) PopVectorAndSlot(); 575 } 576 577 StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation()); 578 GenerateTailCall(masm(), stub.GetCode()); 579 580 __ bind(&miss); 581 if (need_save_restore) PopVectorAndSlot(); 582 TailCallBuiltin(masm(), MissBuiltin(kind())); 583 return GetCode(kind(), it->name()); 584 } 585 586 587 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter( 588 Handle<JSObject> object, Handle<Name> name, int accessor_index, 589 int expected_arguments) { 590 Register holder = Frontend(name); 591 GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index, 592 expected_arguments, scratch2()); 593 594 return GetCode(kind(), name); 595 } 596 597 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( 598 Handle<JSObject> object, Handle<Name> name, 599 const CallOptimization& call_optimization, int accessor_index, 600 Handle<Code> slow_stub) { 601 if (V8_UNLIKELY(FLAG_runtime_stats)) { 602 GenerateTailCall(masm(), slow_stub); 603 } 604 Register holder = Frontend(name); 605 if (Descriptor::kPassLastArgsOnStack) { 606 __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue); 607 } 608 GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()), 609 receiver(), scratch2(), true, value(), holder, 610 accessor_index); 611 return GetCode(kind(), name); 612 } 613 614 615 #undef __ 616 617 // static 618 Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler( 619 Handle<Map> receiver_map, Isolate* isolate) { 620 if (receiver_map->has_indexed_interceptor() && 621 !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(isolate) && 622 !receiver_map->GetIndexedInterceptor()->non_masking()) { 623 TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedInterceptorStub); 624 return LoadIndexedInterceptorStub(isolate).GetCode(); 625 } 626 if (receiver_map->IsStringMap()) { 627 TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub); 628 return LoadIndexedStringStub(isolate).GetCode(); 629 } 630 InstanceType instance_type = receiver_map->instance_type(); 631 if (instance_type < FIRST_JS_RECEIVER_TYPE) { 632 TRACE_HANDLER_STATS(isolate, KeyedLoadIC_SlowStub); 633 return isolate->builtins()->KeyedLoadIC_Slow(); 634 } 635 636 ElementsKind elements_kind = receiver_map->elements_kind(); 637 if (IsSloppyArgumentsElements(elements_kind)) { 638 TRACE_HANDLER_STATS(isolate, KeyedLoadIC_KeyedLoadSloppyArgumentsStub); 639 return KeyedLoadSloppyArgumentsStub(isolate).GetCode(); 640 } 641 bool is_js_array = instance_type == JS_ARRAY_TYPE; 642 if (elements_kind == DICTIONARY_ELEMENTS) { 643 if (FLAG_tf_load_ic_stub) { 644 TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH); 645 return LoadHandler::LoadElement(isolate, elements_kind, false, 646 is_js_array); 647 } 648 TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadDictionaryElementStub); 649 return LoadDictionaryElementStub(isolate).GetCode(); 650 } 651 DCHECK(IsFastElementsKind(elements_kind) || 652 IsFixedTypedArrayElementsKind(elements_kind)); 653 // TODO(jkummerow): Use IsHoleyElementsKind(elements_kind). 654 bool convert_hole_to_undefined = 655 is_js_array && elements_kind == FAST_HOLEY_ELEMENTS && 656 *receiver_map == isolate->get_initial_js_array_map(elements_kind); 657 if (FLAG_tf_load_ic_stub) { 658 TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH); 659 return LoadHandler::LoadElement(isolate, elements_kind, 660 convert_hole_to_undefined, is_js_array); 661 } else { 662 TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadFastElementStub); 663 return LoadFastElementStub(isolate, is_js_array, elements_kind, 664 convert_hole_to_undefined) 665 .GetCode(); 666 } 667 } 668 669 void ElementHandlerCompiler::CompileElementHandlers( 670 MapHandleList* receiver_maps, List<Handle<Object>>* handlers) { 671 for (int i = 0; i < receiver_maps->length(); ++i) { 672 handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate())); 673 } 674 } 675 } // namespace internal 676 } // namespace v8 677