1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "api.h" 31 #include "arguments.h" 32 #include "ast.h" 33 #include "code-stubs.h" 34 #include "cpu-profiler.h" 35 #include "gdb-jit.h" 36 #include "ic-inl.h" 37 #include "stub-cache.h" 38 #include "vm-state-inl.h" 39 40 namespace v8 { 41 namespace internal { 42 43 // ----------------------------------------------------------------------- 44 // StubCache implementation. 45 46 47 StubCache::StubCache(Isolate* isolate) 48 : isolate_(isolate) { } 49 50 51 void StubCache::Initialize() { 52 ASSERT(IsPowerOf2(kPrimaryTableSize)); 53 ASSERT(IsPowerOf2(kSecondaryTableSize)); 54 Clear(); 55 } 56 57 58 Code* StubCache::Set(Name* name, Map* map, Code* code) { 59 // Get the flags from the code. 60 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); 61 62 // Validate that the name does not move on scavenge, and that we 63 // can use identity checks instead of structural equality checks. 64 ASSERT(!heap()->InNewSpace(name)); 65 ASSERT(name->IsUniqueName()); 66 67 // The state bits are not important to the hash function because 68 // the stub cache only contains monomorphic stubs. Make sure that 69 // the bits are the least significant so they will be the ones 70 // masked out. 71 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC); 72 STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1); 73 74 // Make sure that the code type is not included in the hash. 75 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); 76 77 // Compute the primary entry. 78 int primary_offset = PrimaryOffset(name, flags, map); 79 Entry* primary = entry(primary_, primary_offset); 80 Code* old_code = primary->value; 81 82 // If the primary entry has useful data in it, we retire it to the 83 // secondary cache before overwriting it. 84 if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) { 85 Map* old_map = primary->map; 86 Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags()); 87 int seed = PrimaryOffset(primary->key, old_flags, old_map); 88 int secondary_offset = SecondaryOffset(primary->key, old_flags, seed); 89 Entry* secondary = entry(secondary_, secondary_offset); 90 *secondary = *primary; 91 } 92 93 // Update primary cache. 94 primary->key = name; 95 primary->value = code; 96 primary->map = map; 97 isolate()->counters()->megamorphic_stub_cache_updates()->Increment(); 98 return code; 99 } 100 101 102 Handle<Code> StubCache::FindIC(Handle<Name> name, 103 Handle<Map> stub_holder, 104 Code::Kind kind, 105 ExtraICState extra_state, 106 InlineCacheHolderFlag cache_holder) { 107 Code::Flags flags = Code::ComputeMonomorphicFlags( 108 kind, extra_state, cache_holder); 109 Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_); 110 if (probe->IsCode()) return Handle<Code>::cast(probe); 111 return Handle<Code>::null(); 112 } 113 114 115 Handle<Code> StubCache::FindHandler(Handle<Name> name, 116 Handle<Map> stub_holder, 117 Code::Kind kind, 118 InlineCacheHolderFlag cache_holder) { 119 Code::Flags flags = Code::ComputeMonomorphicFlags( 120 Code::HANDLER, kNoExtraICState, cache_holder, Code::NORMAL, kind); 121 122 Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_); 123 if (probe->IsCode()) return Handle<Code>::cast(probe); 124 return Handle<Code>::null(); 125 } 126 127 128 Handle<Code> StubCache::ComputeMonomorphicIC( 129 Handle<Name> name, 130 Handle<Type> type, 131 Handle<Code> handler, 132 ExtraICState extra_ic_state) { 133 Code::Kind kind = handler->handler_kind(); 134 InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type); 135 136 Handle<Map> stub_holder; 137 Handle<Code> ic; 138 // There are multiple string maps that all use the same prototype. That 139 // prototype cannot hold multiple handlers, one for each of the string maps, 140 // for a single name. Hence, turn off caching of the IC. 141 bool can_be_cached = !type->Is(Type::String()); 142 if (can_be_cached) { 143 stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate()); 144 ic = FindIC(name, stub_holder, kind, extra_ic_state, flag); 145 if (!ic.is_null()) return ic; 146 } 147 148 if (kind == Code::LOAD_IC) { 149 LoadStubCompiler ic_compiler(isolate(), flag); 150 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); 151 } else if (kind == Code::KEYED_LOAD_IC) { 152 KeyedLoadStubCompiler ic_compiler(isolate(), flag); 153 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); 154 } else if (kind == Code::STORE_IC) { 155 StoreStubCompiler ic_compiler(isolate(), extra_ic_state); 156 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); 157 } else { 158 ASSERT(kind == Code::KEYED_STORE_IC); 159 ASSERT(STANDARD_STORE == 160 KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state)); 161 KeyedStoreStubCompiler ic_compiler(isolate(), extra_ic_state); 162 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); 163 } 164 165 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic); 166 return ic; 167 } 168 169 170 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name, 171 Handle<Type> type) { 172 InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type); 173 Handle<Map> stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate()); 174 // If no dictionary mode objects are present in the prototype chain, the load 175 // nonexistent IC stub can be shared for all names for a given map and we use 176 // the empty string for the map cache in that case. If there are dictionary 177 // mode objects involved, we need to do negative lookups in the stub and 178 // therefore the stub will be specific to the name. 179 Handle<Map> current_map = stub_holder; 180 Handle<Name> cache_name = current_map->is_dictionary_map() 181 ? name : Handle<Name>::cast(isolate()->factory()->empty_string()); 182 Handle<Object> next(current_map->prototype(), isolate()); 183 Handle<JSObject> last = Handle<JSObject>::null(); 184 while (!next->IsNull()) { 185 last = Handle<JSObject>::cast(next); 186 next = handle(current_map->prototype(), isolate()); 187 current_map = handle(Handle<HeapObject>::cast(next)->map()); 188 if (current_map->is_dictionary_map()) cache_name = name; 189 } 190 191 // Compile the stub that is either shared for all names or 192 // name specific if there are global objects involved. 193 Handle<Code> handler = FindHandler( 194 cache_name, stub_holder, Code::LOAD_IC, flag); 195 if (!handler.is_null()) return handler; 196 197 LoadStubCompiler compiler(isolate_, flag); 198 handler = compiler.CompileLoadNonexistent(type, last, cache_name); 199 Map::UpdateCodeCache(stub_holder, cache_name, handler); 200 return handler; 201 } 202 203 204 Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) { 205 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC); 206 Handle<Name> name = 207 isolate()->factory()->KeyedLoadElementMonomorphic_string(); 208 209 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); 210 if (probe->IsCode()) return Handle<Code>::cast(probe); 211 212 KeyedLoadStubCompiler compiler(isolate()); 213 Handle<Code> code = compiler.CompileLoadElement(receiver_map); 214 215 Map::UpdateCodeCache(receiver_map, name, code); 216 return code; 217 } 218 219 220 Handle<Code> StubCache::ComputeKeyedStoreElement( 221 Handle<Map> receiver_map, 222 StrictModeFlag strict_mode, 223 KeyedAccessStoreMode store_mode) { 224 ExtraICState extra_state = 225 KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode); 226 Code::Flags flags = Code::ComputeMonomorphicFlags( 227 Code::KEYED_STORE_IC, extra_state); 228 229 ASSERT(store_mode == STANDARD_STORE || 230 store_mode == STORE_AND_GROW_NO_TRANSITION || 231 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || 232 store_mode == STORE_NO_TRANSITION_HANDLE_COW); 233 234 Handle<String> name = 235 isolate()->factory()->KeyedStoreElementMonomorphic_string(); 236 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); 237 if (probe->IsCode()) return Handle<Code>::cast(probe); 238 239 KeyedStoreStubCompiler compiler(isolate(), extra_state); 240 Handle<Code> code = compiler.CompileStoreElement(receiver_map); 241 242 Map::UpdateCodeCache(receiver_map, name, code); 243 ASSERT(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state()) 244 == store_mode); 245 return code; 246 } 247 248 249 #define CALL_LOGGER_TAG(kind, type) \ 250 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type) 251 252 Handle<Code> StubCache::ComputeCallConstant(int argc, 253 Code::Kind kind, 254 ExtraICState extra_state, 255 Handle<Name> name, 256 Handle<Object> object, 257 Handle<JSObject> holder, 258 Handle<JSFunction> function) { 259 // Compute the check type and the map. 260 InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object); 261 Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder( 262 isolate_, *object, cache_holder)); 263 264 // Compute check type based on receiver/holder. 265 CheckType check = RECEIVER_MAP_CHECK; 266 if (object->IsString()) { 267 check = STRING_CHECK; 268 } else if (object->IsSymbol()) { 269 check = SYMBOL_CHECK; 270 } else if (object->IsNumber()) { 271 check = NUMBER_CHECK; 272 } else if (object->IsBoolean()) { 273 check = BOOLEAN_CHECK; 274 } 275 276 if (check != RECEIVER_MAP_CHECK && 277 !function->IsBuiltin() && 278 function->shared()->is_classic_mode()) { 279 // Calling non-strict non-builtins with a value as the receiver 280 // requires boxing. 281 return Handle<Code>::null(); 282 } 283 284 Code::Flags flags = Code::ComputeMonomorphicFlags( 285 kind, extra_state, cache_holder, Code::FAST, argc); 286 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), 287 isolate_); 288 if (probe->IsCode()) return Handle<Code>::cast(probe); 289 290 CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); 291 Handle<Code> code = 292 compiler.CompileCallConstant(object, holder, name, check, function); 293 code->set_check_type(check); 294 ASSERT(flags == code->flags()); 295 PROFILE(isolate_, 296 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); 297 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); 298 299 if (CallStubCompiler::CanBeCached(function)) { 300 HeapObject::UpdateMapCodeCache(stub_holder, name, code); 301 } 302 return code; 303 } 304 305 306 Handle<Code> StubCache::ComputeCallField(int argc, 307 Code::Kind kind, 308 ExtraICState extra_state, 309 Handle<Name> name, 310 Handle<Object> object, 311 Handle<JSObject> holder, 312 PropertyIndex index) { 313 // Compute the check type and the map. 314 InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object); 315 Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder( 316 isolate_, *object, cache_holder)); 317 318 // TODO(1233596): We cannot do receiver map check for non-JS objects 319 // because they may be represented as immediates without a 320 // map. Instead, we check against the map in the holder. 321 if (object->IsNumber() || object->IsSymbol() || 322 object->IsBoolean() || object->IsString()) { 323 object = holder; 324 } 325 326 Code::Flags flags = Code::ComputeMonomorphicFlags( 327 kind, extra_state, cache_holder, Code::FAST, argc); 328 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), 329 isolate_); 330 if (probe->IsCode()) return Handle<Code>::cast(probe); 331 332 CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); 333 Handle<Code> code = 334 compiler.CompileCallField(Handle<JSObject>::cast(object), 335 holder, index, name); 336 ASSERT(flags == code->flags()); 337 PROFILE(isolate_, 338 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); 339 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); 340 HeapObject::UpdateMapCodeCache(stub_holder, name, code); 341 return code; 342 } 343 344 345 Handle<Code> StubCache::ComputeCallInterceptor(int argc, 346 Code::Kind kind, 347 ExtraICState extra_state, 348 Handle<Name> name, 349 Handle<Object> object, 350 Handle<JSObject> holder) { 351 // Compute the check type and the map. 352 InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object); 353 Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder( 354 isolate_, *object, cache_holder)); 355 356 // TODO(1233596): We cannot do receiver map check for non-JS objects 357 // because they may be represented as immediates without a 358 // map. Instead, we check against the map in the holder. 359 if (object->IsNumber() || object->IsSymbol() || 360 object->IsBoolean() || object->IsString()) { 361 object = holder; 362 } 363 364 Code::Flags flags = Code::ComputeMonomorphicFlags( 365 kind, extra_state, cache_holder, Code::FAST, argc); 366 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), 367 isolate_); 368 if (probe->IsCode()) return Handle<Code>::cast(probe); 369 370 CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder); 371 Handle<Code> code = 372 compiler.CompileCallInterceptor(Handle<JSObject>::cast(object), 373 holder, name); 374 ASSERT(flags == code->flags()); 375 PROFILE(isolate(), 376 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); 377 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); 378 HeapObject::UpdateMapCodeCache(stub_holder, name, code); 379 return code; 380 } 381 382 383 Handle<Code> StubCache::ComputeCallGlobal(int argc, 384 Code::Kind kind, 385 ExtraICState extra_state, 386 Handle<Name> name, 387 Handle<JSObject> receiver, 388 Handle<GlobalObject> holder, 389 Handle<PropertyCell> cell, 390 Handle<JSFunction> function) { 391 Code::Flags flags = Code::ComputeMonomorphicFlags( 392 kind, extra_state, OWN_MAP, Code::NORMAL, argc); 393 Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), 394 isolate_); 395 if (probe->IsCode()) return Handle<Code>::cast(probe); 396 397 CallStubCompiler compiler(isolate(), argc, kind, extra_state); 398 Handle<Code> code = 399 compiler.CompileCallGlobal(receiver, holder, cell, function, name); 400 ASSERT(flags == code->flags()); 401 PROFILE(isolate(), 402 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); 403 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); 404 if (CallStubCompiler::CanBeCached(function)) { 405 HeapObject::UpdateMapCodeCache(receiver, name, code); 406 } 407 return code; 408 } 409 410 411 static void FillCache(Isolate* isolate, Handle<Code> code) { 412 Handle<UnseededNumberDictionary> dictionary = 413 UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(), 414 code->flags(), 415 code); 416 isolate->heap()->public_set_non_monomorphic_cache(*dictionary); 417 } 418 419 420 Code* StubCache::FindCallInitialize(int argc, 421 RelocInfo::Mode mode, 422 Code::Kind kind) { 423 ExtraICState extra_state = 424 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) | 425 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT 426 ? CONTEXTUAL : NOT_CONTEXTUAL); 427 Code::Flags flags = 428 Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc); 429 UnseededNumberDictionary* dictionary = 430 isolate()->heap()->non_monomorphic_cache(); 431 int entry = dictionary->FindEntry(isolate(), flags); 432 ASSERT(entry != -1); 433 Object* code = dictionary->ValueAt(entry); 434 // This might be called during the marking phase of the collector 435 // hence the unchecked cast. 436 return reinterpret_cast<Code*>(code); 437 } 438 439 440 Handle<Code> StubCache::ComputeCallInitialize(int argc, 441 RelocInfo::Mode mode, 442 Code::Kind kind) { 443 ExtraICState extra_state = 444 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) | 445 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT 446 ? CONTEXTUAL : NOT_CONTEXTUAL); 447 Code::Flags flags = 448 Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc); 449 Handle<UnseededNumberDictionary> cache = 450 isolate_->factory()->non_monomorphic_cache(); 451 int entry = cache->FindEntry(isolate_, flags); 452 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 453 454 StubCompiler compiler(isolate_); 455 Handle<Code> code = compiler.CompileCallInitialize(flags); 456 FillCache(isolate_, code); 457 return code; 458 } 459 460 461 Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) { 462 return ComputeCallInitialize(argc, mode, Code::CALL_IC); 463 } 464 465 466 Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) { 467 return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET, 468 Code::KEYED_CALL_IC); 469 } 470 471 472 Handle<Code> StubCache::ComputeCallPreMonomorphic( 473 int argc, 474 Code::Kind kind, 475 ExtraICState extra_state) { 476 Code::Flags flags = 477 Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, Code::NORMAL, argc); 478 Handle<UnseededNumberDictionary> cache = 479 isolate_->factory()->non_monomorphic_cache(); 480 int entry = cache->FindEntry(isolate_, flags); 481 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 482 483 StubCompiler compiler(isolate_); 484 Handle<Code> code = compiler.CompileCallPreMonomorphic(flags); 485 FillCache(isolate_, code); 486 return code; 487 } 488 489 490 Handle<Code> StubCache::ComputeCallNormal(int argc, 491 Code::Kind kind, 492 ExtraICState extra_state) { 493 Code::Flags flags = 494 Code::ComputeFlags(kind, MONOMORPHIC, extra_state, Code::NORMAL, argc); 495 Handle<UnseededNumberDictionary> cache = 496 isolate_->factory()->non_monomorphic_cache(); 497 int entry = cache->FindEntry(isolate_, flags); 498 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 499 500 StubCompiler compiler(isolate_); 501 Handle<Code> code = compiler.CompileCallNormal(flags); 502 FillCache(isolate_, code); 503 return code; 504 } 505 506 507 Handle<Code> StubCache::ComputeCallArguments(int argc) { 508 Code::Flags flags = 509 Code::ComputeFlags(Code::KEYED_CALL_IC, MEGAMORPHIC, 510 kNoExtraICState, Code::NORMAL, argc); 511 Handle<UnseededNumberDictionary> cache = 512 isolate_->factory()->non_monomorphic_cache(); 513 int entry = cache->FindEntry(isolate_, flags); 514 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 515 516 StubCompiler compiler(isolate_); 517 Handle<Code> code = compiler.CompileCallArguments(flags); 518 FillCache(isolate_, code); 519 return code; 520 } 521 522 523 Handle<Code> StubCache::ComputeCallMegamorphic( 524 int argc, 525 Code::Kind kind, 526 ExtraICState extra_state) { 527 Code::Flags flags = 528 Code::ComputeFlags(kind, MEGAMORPHIC, extra_state, 529 Code::NORMAL, argc); 530 Handle<UnseededNumberDictionary> cache = 531 isolate_->factory()->non_monomorphic_cache(); 532 int entry = cache->FindEntry(isolate_, flags); 533 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 534 535 StubCompiler compiler(isolate_); 536 Handle<Code> code = compiler.CompileCallMegamorphic(flags); 537 FillCache(isolate_, code); 538 return code; 539 } 540 541 542 Handle<Code> StubCache::ComputeCallMiss(int argc, 543 Code::Kind kind, 544 ExtraICState extra_state) { 545 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs 546 // and monomorphic stubs are not mixed up together in the stub cache. 547 Code::Flags flags = 548 Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state, 549 Code::NORMAL, argc, OWN_MAP); 550 Handle<UnseededNumberDictionary> cache = 551 isolate_->factory()->non_monomorphic_cache(); 552 int entry = cache->FindEntry(isolate_, flags); 553 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 554 555 StubCompiler compiler(isolate_); 556 Handle<Code> code = compiler.CompileCallMiss(flags); 557 FillCache(isolate_, code); 558 return code; 559 } 560 561 562 Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map, 563 CompareNilICStub& stub) { 564 Handle<String> name(isolate_->heap()->empty_string()); 565 if (!receiver_map->is_shared()) { 566 Handle<Code> cached_ic = FindIC(name, receiver_map, Code::COMPARE_NIL_IC, 567 stub.GetExtraICState()); 568 if (!cached_ic.is_null()) return cached_ic; 569 } 570 571 Handle<Code> ic = stub.GetCodeCopyFromTemplate(isolate_); 572 ic->ReplaceNthObject(1, isolate_->heap()->meta_map(), *receiver_map); 573 574 if (!receiver_map->is_shared()) { 575 Map::UpdateCodeCache(receiver_map, name, ic); 576 } 577 578 return ic; 579 } 580 581 582 // TODO(verwaest): Change this method so it takes in a TypeHandleList. 583 Handle<Code> StubCache::ComputeLoadElementPolymorphic( 584 MapHandleList* receiver_maps) { 585 Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC); 586 Handle<PolymorphicCodeCache> cache = 587 isolate_->factory()->polymorphic_code_cache(); 588 Handle<Object> probe = cache->Lookup(receiver_maps, flags); 589 if (probe->IsCode()) return Handle<Code>::cast(probe); 590 591 TypeHandleList types(receiver_maps->length()); 592 for (int i = 0; i < receiver_maps->length(); i++) { 593 types.Add(handle(Type::Class(receiver_maps->at(i)), isolate())); 594 } 595 CodeHandleList handlers(receiver_maps->length()); 596 KeyedLoadStubCompiler compiler(isolate_); 597 compiler.CompileElementHandlers(receiver_maps, &handlers); 598 Handle<Code> code = compiler.CompilePolymorphicIC( 599 &types, &handlers, factory()->empty_string(), Code::NORMAL, ELEMENT); 600 601 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); 602 603 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code); 604 return code; 605 } 606 607 608 Handle<Code> StubCache::ComputePolymorphicIC( 609 TypeHandleList* types, 610 CodeHandleList* handlers, 611 int number_of_valid_types, 612 Handle<Name> name, 613 ExtraICState extra_ic_state) { 614 615 Handle<Code> handler = handlers->at(0); 616 Code::Kind kind = handler->handler_kind(); 617 Code::StubType type = number_of_valid_types == 1 ? handler->type() 618 : Code::NORMAL; 619 if (kind == Code::LOAD_IC) { 620 LoadStubCompiler ic_compiler(isolate_); 621 return ic_compiler.CompilePolymorphicIC( 622 types, handlers, name, type, PROPERTY); 623 } else { 624 ASSERT(kind == Code::STORE_IC); 625 StrictModeFlag strict_mode = StoreIC::GetStrictMode(extra_ic_state); 626 StoreStubCompiler ic_compiler(isolate_, strict_mode); 627 return ic_compiler.CompilePolymorphicIC( 628 types, handlers, name, type, PROPERTY); 629 } 630 } 631 632 633 Handle<Code> StubCache::ComputeStoreElementPolymorphic( 634 MapHandleList* receiver_maps, 635 KeyedAccessStoreMode store_mode, 636 StrictModeFlag strict_mode) { 637 ASSERT(store_mode == STANDARD_STORE || 638 store_mode == STORE_AND_GROW_NO_TRANSITION || 639 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || 640 store_mode == STORE_NO_TRANSITION_HANDLE_COW); 641 Handle<PolymorphicCodeCache> cache = 642 isolate_->factory()->polymorphic_code_cache(); 643 ExtraICState extra_state = KeyedStoreIC::ComputeExtraICState( 644 strict_mode, store_mode); 645 Code::Flags flags = 646 Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state); 647 Handle<Object> probe = cache->Lookup(receiver_maps, flags); 648 if (probe->IsCode()) return Handle<Code>::cast(probe); 649 650 KeyedStoreStubCompiler compiler(isolate_, extra_state); 651 Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps); 652 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code); 653 return code; 654 } 655 656 657 #ifdef ENABLE_DEBUGGER_SUPPORT 658 Handle<Code> StubCache::ComputeCallDebugBreak(int argc, 659 Code::Kind kind) { 660 // Extra IC state is irrelevant for debug break ICs. They jump to 661 // the actual call ic to carry out the work. 662 Code::Flags flags = 663 Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_BREAK, 664 Code::NORMAL, argc); 665 Handle<UnseededNumberDictionary> cache = 666 isolate_->factory()->non_monomorphic_cache(); 667 int entry = cache->FindEntry(isolate_, flags); 668 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 669 670 StubCompiler compiler(isolate_); 671 Handle<Code> code = compiler.CompileCallDebugBreak(flags); 672 FillCache(isolate_, code); 673 return code; 674 } 675 676 677 Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc, 678 Code::Kind kind) { 679 // Extra IC state is irrelevant for debug break ICs. They jump to 680 // the actual call ic to carry out the work. 681 Code::Flags flags = 682 Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_PREPARE_STEP_IN, 683 Code::NORMAL, argc); 684 Handle<UnseededNumberDictionary> cache = 685 isolate_->factory()->non_monomorphic_cache(); 686 int entry = cache->FindEntry(isolate_, flags); 687 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 688 689 StubCompiler compiler(isolate_); 690 Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags); 691 FillCache(isolate_, code); 692 return code; 693 } 694 #endif 695 696 697 void StubCache::Clear() { 698 Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal); 699 for (int i = 0; i < kPrimaryTableSize; i++) { 700 primary_[i].key = heap()->empty_string(); 701 primary_[i].map = NULL; 702 primary_[i].value = empty; 703 } 704 for (int j = 0; j < kSecondaryTableSize; j++) { 705 secondary_[j].key = heap()->empty_string(); 706 secondary_[j].map = NULL; 707 secondary_[j].value = empty; 708 } 709 } 710 711 712 void StubCache::CollectMatchingMaps(SmallMapList* types, 713 Handle<Name> name, 714 Code::Flags flags, 715 Handle<Context> native_context, 716 Zone* zone) { 717 for (int i = 0; i < kPrimaryTableSize; i++) { 718 if (primary_[i].key == *name) { 719 Map* map = primary_[i].map; 720 // Map can be NULL, if the stub is constant function call 721 // with a primitive receiver. 722 if (map == NULL) continue; 723 724 int offset = PrimaryOffset(*name, flags, map); 725 if (entry(primary_, offset) == &primary_[i] && 726 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) { 727 types->AddMapIfMissing(Handle<Map>(map), zone); 728 } 729 } 730 } 731 732 for (int i = 0; i < kSecondaryTableSize; i++) { 733 if (secondary_[i].key == *name) { 734 Map* map = secondary_[i].map; 735 // Map can be NULL, if the stub is constant function call 736 // with a primitive receiver. 737 if (map == NULL) continue; 738 739 // Lookup in primary table and skip duplicates. 740 int primary_offset = PrimaryOffset(*name, flags, map); 741 742 // Lookup in secondary table and add matches. 743 int offset = SecondaryOffset(*name, flags, primary_offset); 744 if (entry(secondary_, offset) == &secondary_[i] && 745 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) { 746 types->AddMapIfMissing(Handle<Map>(map), zone); 747 } 748 } 749 } 750 } 751 752 753 // ------------------------------------------------------------------------ 754 // StubCompiler implementation. 755 756 757 RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) { 758 JSObject* recv = JSObject::cast(args[0]); 759 ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[1]); 760 Address setter_address = v8::ToCData<Address>(callback->setter()); 761 v8::AccessorSetterCallback fun = 762 FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address); 763 ASSERT(fun != NULL); 764 ASSERT(callback->IsCompatibleReceiver(recv)); 765 Handle<Name> name = args.at<Name>(2); 766 Handle<Object> value = args.at<Object>(3); 767 HandleScope scope(isolate); 768 769 // TODO(rossberg): Support symbols in the API. 770 if (name->IsSymbol()) return *value; 771 Handle<String> str = Handle<String>::cast(name); 772 773 LOG(isolate, ApiNamedPropertyAccess("store", recv, *name)); 774 PropertyCallbackArguments 775 custom_args(isolate, callback->data(), recv, recv); 776 custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value)); 777 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 778 return *value; 779 } 780 781 782 /** 783 * Attempts to load a property with an interceptor (which must be present), 784 * but doesn't search the prototype chain. 785 * 786 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't 787 * provide any value for the given name. 788 */ 789 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) { 790 ASSERT(args.length() == StubCache::kInterceptorArgsLength); 791 Handle<Name> name_handle = 792 args.at<Name>(StubCache::kInterceptorArgsNameIndex); 793 Handle<InterceptorInfo> interceptor_info = 794 args.at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex); 795 796 // TODO(rossberg): Support symbols in the API. 797 if (name_handle->IsSymbol()) 798 return isolate->heap()->no_interceptor_result_sentinel(); 799 Handle<String> name = Handle<String>::cast(name_handle); 800 801 Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); 802 v8::NamedPropertyGetterCallback getter = 803 FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address); 804 ASSERT(getter != NULL); 805 806 Handle<JSObject> receiver = 807 args.at<JSObject>(StubCache::kInterceptorArgsThisIndex); 808 Handle<JSObject> holder = 809 args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex); 810 PropertyCallbackArguments callback_args( 811 isolate, interceptor_info->data(), *receiver, *holder); 812 { 813 // Use the interceptor getter. 814 HandleScope scope(isolate); 815 v8::Handle<v8::Value> r = 816 callback_args.Call(getter, v8::Utils::ToLocal(name)); 817 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 818 if (!r.IsEmpty()) { 819 Handle<Object> result = v8::Utils::OpenHandle(*r); 820 result->VerifyApiCallResultType(); 821 return *v8::Utils::OpenHandle(*r); 822 } 823 } 824 825 return isolate->heap()->no_interceptor_result_sentinel(); 826 } 827 828 829 static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) { 830 // If the load is non-contextual, just return the undefined result. 831 // Note that both keyed and non-keyed loads may end up here, so we 832 // can't use either LoadIC or KeyedLoadIC constructors. 833 HandleScope scope(isolate); 834 IC ic(IC::NO_EXTRA_FRAME, isolate); 835 ASSERT(ic.IsLoadStub()); 836 if (!ic.SlowIsUndeclaredGlobal()) return isolate->heap()->undefined_value(); 837 838 // Throw a reference error. 839 Handle<Name> name_handle(name); 840 Handle<Object> error = 841 isolate->factory()->NewReferenceError("not_defined", 842 HandleVector(&name_handle, 1)); 843 return isolate->Throw(*error); 844 } 845 846 847 static Handle<Object> LoadWithInterceptor(Arguments* args, 848 PropertyAttributes* attrs) { 849 ASSERT(args->length() == StubCache::kInterceptorArgsLength); 850 Handle<Name> name_handle = 851 args->at<Name>(StubCache::kInterceptorArgsNameIndex); 852 Handle<InterceptorInfo> interceptor_info = 853 args->at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex); 854 Handle<JSObject> receiver_handle = 855 args->at<JSObject>(StubCache::kInterceptorArgsThisIndex); 856 Handle<JSObject> holder_handle = 857 args->at<JSObject>(StubCache::kInterceptorArgsHolderIndex); 858 859 Isolate* isolate = receiver_handle->GetIsolate(); 860 861 // TODO(rossberg): Support symbols in the API. 862 if (name_handle->IsSymbol()) { 863 return JSObject::GetPropertyPostInterceptor( 864 holder_handle, receiver_handle, name_handle, attrs); 865 } 866 Handle<String> name = Handle<String>::cast(name_handle); 867 868 Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); 869 v8::NamedPropertyGetterCallback getter = 870 FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address); 871 ASSERT(getter != NULL); 872 873 PropertyCallbackArguments callback_args(isolate, 874 interceptor_info->data(), 875 *receiver_handle, 876 *holder_handle); 877 { 878 HandleScope scope(isolate); 879 // Use the interceptor getter. 880 v8::Handle<v8::Value> r = 881 callback_args.Call(getter, v8::Utils::ToLocal(name)); 882 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); 883 if (!r.IsEmpty()) { 884 *attrs = NONE; 885 Handle<Object> result = v8::Utils::OpenHandle(*r); 886 result->VerifyApiCallResultType(); 887 return scope.CloseAndEscape(result); 888 } 889 } 890 891 Handle<Object> result = JSObject::GetPropertyPostInterceptor( 892 holder_handle, receiver_handle, name_handle, attrs); 893 return result; 894 } 895 896 897 /** 898 * Loads a property with an interceptor performing post interceptor 899 * lookup if interceptor failed. 900 */ 901 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) { 902 PropertyAttributes attr = NONE; 903 HandleScope scope(isolate); 904 Handle<Object> result = LoadWithInterceptor(&args, &attr); 905 RETURN_IF_EMPTY_HANDLE(isolate, result); 906 907 // If the property is present, return it. 908 if (attr != ABSENT) return *result; 909 return ThrowReferenceError(isolate, Name::cast(args[0])); 910 } 911 912 913 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) { 914 PropertyAttributes attr; 915 HandleScope scope(isolate); 916 Handle<Object> result = LoadWithInterceptor(&args, &attr); 917 RETURN_IF_EMPTY_HANDLE(isolate, result); 918 // This is call IC. In this case, we simply return the undefined result which 919 // will lead to an exception when trying to invoke the result as a 920 // function. 921 return *result; 922 } 923 924 925 RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) { 926 HandleScope scope(isolate); 927 ASSERT(args.length() == 3); 928 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); 929 Handle<JSObject> receiver = args.at<JSObject>(0); 930 Handle<Name> name = args.at<Name>(1); 931 Handle<Object> value = args.at<Object>(2); 932 ASSERT(receiver->HasNamedInterceptor()); 933 PropertyAttributes attr = NONE; 934 Handle<Object> result = JSObject::SetPropertyWithInterceptor( 935 receiver, name, value, attr, ic.strict_mode()); 936 RETURN_IF_EMPTY_HANDLE(isolate, result); 937 return *result; 938 } 939 940 941 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) { 942 JSObject* receiver = JSObject::cast(args[0]); 943 ASSERT(args.smi_at(1) >= 0); 944 uint32_t index = args.smi_at(1); 945 return receiver->GetElementWithInterceptor(receiver, index); 946 } 947 948 949 Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) { 950 int argc = Code::ExtractArgumentsCountFromFlags(flags); 951 Code::Kind kind = Code::ExtractKindFromFlags(flags); 952 ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); 953 if (kind == Code::CALL_IC) { 954 CallIC::GenerateInitialize(masm(), argc, extra_state); 955 } else { 956 KeyedCallIC::GenerateInitialize(masm(), argc); 957 } 958 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize"); 959 isolate()->counters()->call_initialize_stubs()->Increment(); 960 PROFILE(isolate(), 961 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG), 962 *code, code->arguments_count())); 963 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code)); 964 return code; 965 } 966 967 968 Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) { 969 int argc = Code::ExtractArgumentsCountFromFlags(flags); 970 // The code of the PreMonomorphic stub is the same as the code 971 // of the Initialized stub. They just differ on the code object flags. 972 Code::Kind kind = Code::ExtractKindFromFlags(flags); 973 ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); 974 if (kind == Code::CALL_IC) { 975 CallIC::GenerateInitialize(masm(), argc, extra_state); 976 } else { 977 KeyedCallIC::GenerateInitialize(masm(), argc); 978 } 979 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic"); 980 isolate()->counters()->call_premonomorphic_stubs()->Increment(); 981 PROFILE(isolate(), 982 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG), 983 *code, code->arguments_count())); 984 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code)); 985 return code; 986 } 987 988 989 Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) { 990 int argc = Code::ExtractArgumentsCountFromFlags(flags); 991 Code::Kind kind = Code::ExtractKindFromFlags(flags); 992 if (kind == Code::CALL_IC) { 993 // Call normal is always with a explict receiver. 994 ASSERT(!CallIC::Contextual::decode( 995 Code::ExtractExtraICStateFromFlags(flags))); 996 CallIC::GenerateNormal(masm(), argc); 997 } else { 998 KeyedCallIC::GenerateNormal(masm(), argc); 999 } 1000 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal"); 1001 isolate()->counters()->call_normal_stubs()->Increment(); 1002 PROFILE(isolate(), 1003 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG), 1004 *code, code->arguments_count())); 1005 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code)); 1006 return code; 1007 } 1008 1009 1010 Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) { 1011 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1012 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1013 ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); 1014 if (kind == Code::CALL_IC) { 1015 CallIC::GenerateMegamorphic(masm(), argc, extra_state); 1016 } else { 1017 KeyedCallIC::GenerateMegamorphic(masm(), argc); 1018 } 1019 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic"); 1020 isolate()->counters()->call_megamorphic_stubs()->Increment(); 1021 PROFILE(isolate(), 1022 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG), 1023 *code, code->arguments_count())); 1024 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code)); 1025 return code; 1026 } 1027 1028 1029 Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) { 1030 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1031 KeyedCallIC::GenerateNonStrictArguments(masm(), argc); 1032 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments"); 1033 PROFILE(isolate(), 1034 CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags), 1035 CALL_MEGAMORPHIC_TAG), 1036 *code, code->arguments_count())); 1037 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code)); 1038 return code; 1039 } 1040 1041 1042 Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) { 1043 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1044 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1045 ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); 1046 if (kind == Code::CALL_IC) { 1047 CallIC::GenerateMiss(masm(), argc, extra_state); 1048 } else { 1049 KeyedCallIC::GenerateMiss(masm(), argc); 1050 } 1051 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss"); 1052 isolate()->counters()->call_megamorphic_stubs()->Increment(); 1053 PROFILE(isolate(), 1054 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG), 1055 *code, code->arguments_count())); 1056 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code)); 1057 return code; 1058 } 1059 1060 1061 #ifdef ENABLE_DEBUGGER_SUPPORT 1062 Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) { 1063 Debug::GenerateCallICDebugBreak(masm()); 1064 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak"); 1065 PROFILE(isolate(), 1066 CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags), 1067 CALL_DEBUG_BREAK_TAG), 1068 *code, code->arguments_count())); 1069 return code; 1070 } 1071 1072 1073 Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) { 1074 // Use the same code for the the step in preparations as we do for the 1075 // miss case. 1076 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1077 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1078 if (kind == Code::CALL_IC) { 1079 // For the debugger extra ic state is irrelevant. 1080 CallIC::GenerateMiss(masm(), argc, kNoExtraICState); 1081 } else { 1082 KeyedCallIC::GenerateMiss(masm(), argc); 1083 } 1084 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn"); 1085 PROFILE(isolate(), 1086 CodeCreateEvent( 1087 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG), 1088 *code, 1089 code->arguments_count())); 1090 return code; 1091 } 1092 #endif // ENABLE_DEBUGGER_SUPPORT 1093 1094 #undef CALL_LOGGER_TAG 1095 1096 1097 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags, 1098 const char* name) { 1099 // Create code object in the heap. 1100 CodeDesc desc; 1101 masm_.GetCode(&desc); 1102 Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject()); 1103 if (code->has_major_key()) { 1104 code->set_major_key(CodeStub::NoCache); 1105 } 1106 #ifdef ENABLE_DISASSEMBLER 1107 if (FLAG_print_code_stubs) code->Disassemble(name); 1108 #endif 1109 return code; 1110 } 1111 1112 1113 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags, 1114 Handle<Name> name) { 1115 return (FLAG_print_code_stubs && !name.is_null() && name->IsString()) 1116 ? GetCodeWithFlags(flags, *Handle<String>::cast(name)->ToCString()) 1117 : GetCodeWithFlags(flags, NULL); 1118 } 1119 1120 1121 void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder, 1122 Handle<Name> name, 1123 LookupResult* lookup) { 1124 holder->LocalLookupRealNamedProperty(*name, lookup); 1125 if (lookup->IsFound()) return; 1126 if (holder->GetPrototype()->IsNull()) return; 1127 holder->GetPrototype()->Lookup(*name, lookup); 1128 } 1129 1130 1131 #define __ ACCESS_MASM(masm()) 1132 1133 1134 CallKind CallStubCompiler::call_kind() { 1135 return CallICBase::Contextual::decode(extra_state()) 1136 ? CALL_AS_FUNCTION 1137 : CALL_AS_METHOD; 1138 } 1139 1140 1141 void CallStubCompiler::HandlerFrontendFooter(Label* miss) { 1142 __ bind(miss); 1143 GenerateMissBranch(); 1144 } 1145 1146 1147 void CallStubCompiler::GenerateJumpFunctionIgnoreReceiver( 1148 Handle<JSFunction> function) { 1149 ParameterCount expected(function); 1150 __ InvokeFunction(function, expected, arguments(), 1151 JUMP_FUNCTION, NullCallWrapper(), call_kind()); 1152 } 1153 1154 1155 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, 1156 Handle<JSFunction> function) { 1157 PatchGlobalProxy(object); 1158 GenerateJumpFunctionIgnoreReceiver(function); 1159 } 1160 1161 1162 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, 1163 Register actual_closure, 1164 Handle<JSFunction> function) { 1165 PatchGlobalProxy(object); 1166 ParameterCount expected(function); 1167 __ InvokeFunction(actual_closure, expected, arguments(), 1168 JUMP_FUNCTION, NullCallWrapper(), call_kind()); 1169 } 1170 1171 1172 Handle<Code> CallStubCompiler::CompileCallConstant( 1173 Handle<Object> object, 1174 Handle<JSObject> holder, 1175 Handle<Name> name, 1176 CheckType check, 1177 Handle<JSFunction> function) { 1178 if (HasCustomCallGenerator(function)) { 1179 Handle<Code> code = CompileCustomCall(object, holder, 1180 Handle<Cell>::null(), 1181 function, Handle<String>::cast(name), 1182 Code::FAST); 1183 // A null handle means bail out to the regular compiler code below. 1184 if (!code.is_null()) return code; 1185 } 1186 1187 Label miss; 1188 HandlerFrontendHeader(object, holder, name, check, &miss); 1189 GenerateJumpFunction(object, function); 1190 HandlerFrontendFooter(&miss); 1191 1192 // Return the generated code. 1193 return GetCode(function); 1194 } 1195 1196 1197 Register LoadStubCompiler::HandlerFrontendHeader( 1198 Handle<Type> type, 1199 Register object_reg, 1200 Handle<JSObject> holder, 1201 Handle<Name> name, 1202 Label* miss) { 1203 PrototypeCheckType check_type = CHECK_ALL_MAPS; 1204 int function_index = -1; 1205 if (type->Is(Type::String())) { 1206 function_index = Context::STRING_FUNCTION_INDEX; 1207 } else if (type->Is(Type::Symbol())) { 1208 function_index = Context::SYMBOL_FUNCTION_INDEX; 1209 } else if (type->Is(Type::Number())) { 1210 function_index = Context::NUMBER_FUNCTION_INDEX; 1211 } else if (type->Is(Type::Boolean())) { 1212 // Booleans use the generic oddball map, so an additional check is needed to 1213 // ensure the receiver is really a boolean. 1214 GenerateBooleanCheck(object_reg, miss); 1215 function_index = Context::BOOLEAN_FUNCTION_INDEX; 1216 } else { 1217 check_type = SKIP_RECEIVER; 1218 } 1219 1220 if (check_type == CHECK_ALL_MAPS) { 1221 GenerateDirectLoadGlobalFunctionPrototype( 1222 masm(), function_index, scratch1(), miss); 1223 Object* function = isolate()->native_context()->get(function_index); 1224 Object* prototype = JSFunction::cast(function)->instance_prototype(); 1225 type = IC::CurrentTypeOf(handle(prototype, isolate()), isolate()); 1226 object_reg = scratch1(); 1227 } 1228 1229 // Check that the maps starting from the prototype haven't changed. 1230 return CheckPrototypes( 1231 type, object_reg, holder, scratch1(), scratch2(), scratch3(), 1232 name, miss, check_type); 1233 } 1234 1235 1236 // HandlerFrontend for store uses the name register. It has to be restored 1237 // before a miss. 1238 Register StoreStubCompiler::HandlerFrontendHeader( 1239 Handle<Type> type, 1240 Register object_reg, 1241 Handle<JSObject> holder, 1242 Handle<Name> name, 1243 Label* miss) { 1244 return CheckPrototypes(type, object_reg, holder, this->name(), 1245 scratch1(), scratch2(), name, miss, SKIP_RECEIVER); 1246 } 1247 1248 1249 bool BaseLoadStoreStubCompiler::IncludesNumberType(TypeHandleList* types) { 1250 for (int i = 0; i < types->length(); ++i) { 1251 if (types->at(i)->Is(Type::Number())) return true; 1252 } 1253 return false; 1254 } 1255 1256 1257 Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<Type> type, 1258 Register object_reg, 1259 Handle<JSObject> holder, 1260 Handle<Name> name) { 1261 Label miss; 1262 1263 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); 1264 1265 HandlerFrontendFooter(name, &miss); 1266 1267 return reg; 1268 } 1269 1270 1271 void LoadStubCompiler::NonexistentHandlerFrontend(Handle<Type> type, 1272 Handle<JSObject> last, 1273 Handle<Name> name) { 1274 Label miss; 1275 1276 Register holder; 1277 Handle<Map> last_map; 1278 if (last.is_null()) { 1279 holder = receiver(); 1280 last_map = IC::TypeToMap(*type, isolate()); 1281 // If |type| has null as its prototype, |last| is Handle<JSObject>::null(). 1282 ASSERT(last_map->prototype() == isolate()->heap()->null_value()); 1283 } else { 1284 holder = HandlerFrontendHeader(type, receiver(), last, name, &miss); 1285 last_map = handle(last->map()); 1286 } 1287 1288 if (last_map->is_dictionary_map() && 1289 !last_map->IsJSGlobalObjectMap() && 1290 !last_map->IsJSGlobalProxyMap()) { 1291 if (!name->IsUniqueName()) { 1292 ASSERT(name->IsString()); 1293 name = factory()->InternalizeString(Handle<String>::cast(name)); 1294 } 1295 ASSERT(last.is_null() || 1296 last->property_dictionary()->FindEntry(*name) == 1297 NameDictionary::kNotFound); 1298 GenerateDictionaryNegativeLookup(masm(), &miss, holder, name, 1299 scratch2(), scratch3()); 1300 } 1301 1302 // If the last object in the prototype chain is a global object, 1303 // check that the global property cell is empty. 1304 if (last_map->IsJSGlobalObjectMap()) { 1305 Handle<JSGlobalObject> global = last.is_null() 1306 ? Handle<JSGlobalObject>::cast(type->AsConstant()) 1307 : Handle<JSGlobalObject>::cast(last); 1308 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); 1309 } 1310 1311 HandlerFrontendFooter(name, &miss); 1312 } 1313 1314 1315 Handle<Code> LoadStubCompiler::CompileLoadField( 1316 Handle<Type> type, 1317 Handle<JSObject> holder, 1318 Handle<Name> name, 1319 PropertyIndex field, 1320 Representation representation) { 1321 Label miss; 1322 1323 Register reg = HandlerFrontendHeader(type, receiver(), holder, name, &miss); 1324 1325 GenerateLoadField(reg, holder, field, representation); 1326 1327 __ bind(&miss); 1328 TailCallBuiltin(masm(), MissBuiltin(kind())); 1329 1330 // Return the generated code. 1331 return GetCode(kind(), Code::FAST, name); 1332 } 1333 1334 1335 Handle<Code> LoadStubCompiler::CompileLoadConstant( 1336 Handle<Type> type, 1337 Handle<JSObject> holder, 1338 Handle<Name> name, 1339 Handle<Object> value) { 1340 HandlerFrontend(type, receiver(), holder, name); 1341 GenerateLoadConstant(value); 1342 1343 // Return the generated code. 1344 return GetCode(kind(), Code::FAST, name); 1345 } 1346 1347 1348 Handle<Code> LoadStubCompiler::CompileLoadCallback( 1349 Handle<Type> type, 1350 Handle<JSObject> holder, 1351 Handle<Name> name, 1352 Handle<ExecutableAccessorInfo> callback) { 1353 Register reg = CallbackHandlerFrontend( 1354 type, receiver(), holder, name, callback); 1355 GenerateLoadCallback(reg, callback); 1356 1357 // Return the generated code. 1358 return GetCode(kind(), Code::FAST, name); 1359 } 1360 1361 1362 Handle<Code> LoadStubCompiler::CompileLoadCallback( 1363 Handle<Type> type, 1364 Handle<JSObject> holder, 1365 Handle<Name> name, 1366 const CallOptimization& call_optimization) { 1367 ASSERT(call_optimization.is_simple_api_call()); 1368 Handle<JSFunction> callback = call_optimization.constant_function(); 1369 CallbackHandlerFrontend(type, receiver(), holder, name, callback); 1370 GenerateLoadCallback(call_optimization); 1371 1372 // Return the generated code. 1373 return GetCode(kind(), Code::FAST, name); 1374 } 1375 1376 1377 Handle<Code> LoadStubCompiler::CompileLoadInterceptor( 1378 Handle<Type> type, 1379 Handle<JSObject> holder, 1380 Handle<Name> name) { 1381 LookupResult lookup(isolate()); 1382 LookupPostInterceptor(holder, name, &lookup); 1383 1384 Register reg = HandlerFrontend(type, receiver(), holder, name); 1385 // TODO(368): Compile in the whole chain: all the interceptors in 1386 // prototypes and ultimate answer. 1387 GenerateLoadInterceptor(reg, type, holder, &lookup, name); 1388 1389 // Return the generated code. 1390 return GetCode(kind(), Code::FAST, name); 1391 } 1392 1393 1394 void LoadStubCompiler::GenerateLoadPostInterceptor( 1395 Register interceptor_reg, 1396 Handle<JSObject> interceptor_holder, 1397 Handle<Name> name, 1398 LookupResult* lookup) { 1399 Handle<JSObject> holder(lookup->holder()); 1400 if (lookup->IsField()) { 1401 PropertyIndex field = lookup->GetFieldIndex(); 1402 if (interceptor_holder.is_identical_to(holder)) { 1403 GenerateLoadField( 1404 interceptor_reg, holder, field, lookup->representation()); 1405 } else { 1406 // We found FIELD property in prototype chain of interceptor's holder. 1407 // Retrieve a field from field's holder. 1408 Register reg = HandlerFrontend( 1409 IC::CurrentTypeOf(interceptor_holder, isolate()), 1410 interceptor_reg, holder, name); 1411 GenerateLoadField( 1412 reg, holder, field, lookup->representation()); 1413 } 1414 } else { 1415 // We found CALLBACKS property in prototype chain of interceptor's 1416 // holder. 1417 ASSERT(lookup->type() == CALLBACKS); 1418 Handle<ExecutableAccessorInfo> callback( 1419 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); 1420 ASSERT(callback->getter() != NULL); 1421 1422 Register reg = CallbackHandlerFrontend( 1423 IC::CurrentTypeOf(interceptor_holder, isolate()), 1424 interceptor_reg, holder, name, callback); 1425 GenerateLoadCallback(reg, callback); 1426 } 1427 } 1428 1429 1430 Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC( 1431 Handle<Type> type, 1432 Handle<Code> handler, 1433 Handle<Name> name) { 1434 TypeHandleList types(1); 1435 CodeHandleList handlers(1); 1436 types.Add(type); 1437 handlers.Add(handler); 1438 Code::StubType stub_type = handler->type(); 1439 return CompilePolymorphicIC(&types, &handlers, name, stub_type, PROPERTY); 1440 } 1441 1442 1443 Handle<Code> LoadStubCompiler::CompileLoadViaGetter( 1444 Handle<Type> type, 1445 Handle<JSObject> holder, 1446 Handle<Name> name, 1447 Handle<JSFunction> getter) { 1448 HandlerFrontend(type, receiver(), holder, name); 1449 GenerateLoadViaGetter(masm(), receiver(), getter); 1450 1451 // Return the generated code. 1452 return GetCode(kind(), Code::FAST, name); 1453 } 1454 1455 1456 Handle<Code> StoreStubCompiler::CompileStoreTransition( 1457 Handle<JSObject> object, 1458 LookupResult* lookup, 1459 Handle<Map> transition, 1460 Handle<Name> name) { 1461 Label miss, slow; 1462 1463 // Ensure no transitions to deprecated maps are followed. 1464 __ CheckMapDeprecated(transition, scratch1(), &miss); 1465 1466 // Check that we are allowed to write this. 1467 if (object->GetPrototype()->IsJSObject()) { 1468 Handle<JSObject> holder; 1469 // holder == object indicates that no property was found. 1470 if (lookup->holder() != *object) { 1471 holder = Handle<JSObject>(lookup->holder()); 1472 } else { 1473 // Find the top object. 1474 holder = object; 1475 do { 1476 holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype())); 1477 } while (holder->GetPrototype()->IsJSObject()); 1478 } 1479 1480 Register holder_reg = HandlerFrontendHeader( 1481 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name, &miss); 1482 1483 // If no property was found, and the holder (the last object in the 1484 // prototype chain) is in slow mode, we need to do a negative lookup on the 1485 // holder. 1486 if (lookup->holder() == *object) { 1487 GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss); 1488 } 1489 } 1490 1491 GenerateStoreTransition(masm(), 1492 object, 1493 lookup, 1494 transition, 1495 name, 1496 receiver(), this->name(), value(), 1497 scratch1(), scratch2(), scratch3(), 1498 &miss, 1499 &slow); 1500 1501 // Handle store cache miss. 1502 GenerateRestoreName(masm(), &miss, name); 1503 TailCallBuiltin(masm(), MissBuiltin(kind())); 1504 1505 GenerateRestoreName(masm(), &slow, name); 1506 TailCallBuiltin(masm(), SlowBuiltin(kind())); 1507 1508 // Return the generated code. 1509 return GetCode(kind(), Code::FAST, name); 1510 } 1511 1512 1513 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object, 1514 LookupResult* lookup, 1515 Handle<Name> name) { 1516 Label miss; 1517 1518 HandlerFrontendHeader(IC::CurrentTypeOf(object, isolate()), 1519 receiver(), object, name, &miss); 1520 1521 // Generate store field code. 1522 GenerateStoreField(masm(), 1523 object, 1524 lookup, 1525 receiver(), this->name(), value(), scratch1(), scratch2(), 1526 &miss); 1527 1528 // Handle store cache miss. 1529 __ bind(&miss); 1530 TailCallBuiltin(masm(), MissBuiltin(kind())); 1531 1532 // Return the generated code. 1533 return GetCode(kind(), Code::FAST, name); 1534 } 1535 1536 1537 Handle<Code> StoreStubCompiler::CompileStoreViaSetter( 1538 Handle<JSObject> object, 1539 Handle<JSObject> holder, 1540 Handle<Name> name, 1541 Handle<JSFunction> setter) { 1542 HandlerFrontend(IC::CurrentTypeOf(object, isolate()), 1543 receiver(), holder, name); 1544 GenerateStoreViaSetter(masm(), setter); 1545 1546 return GetCode(kind(), Code::FAST, name); 1547 } 1548 1549 1550 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( 1551 Handle<Map> receiver_map) { 1552 ElementsKind elements_kind = receiver_map->elements_kind(); 1553 if (receiver_map->has_fast_elements() || 1554 receiver_map->has_external_array_elements()) { 1555 Handle<Code> stub = KeyedLoadFastElementStub( 1556 receiver_map->instance_type() == JS_ARRAY_TYPE, 1557 elements_kind).GetCode(isolate()); 1558 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); 1559 } else { 1560 Handle<Code> stub = FLAG_compiled_keyed_dictionary_loads 1561 ? KeyedLoadDictionaryElementStub().GetCode(isolate()) 1562 : KeyedLoadDictionaryElementPlatformStub().GetCode(isolate()); 1563 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); 1564 } 1565 1566 TailCallBuiltin(masm(), Builtins::kKeyedLoadIC_Miss); 1567 1568 // Return the generated code. 1569 return GetICCode(kind(), Code::NORMAL, factory()->empty_string()); 1570 } 1571 1572 1573 Handle<Code> KeyedStoreStubCompiler::CompileStoreElement( 1574 Handle<Map> receiver_map) { 1575 ElementsKind elements_kind = receiver_map->elements_kind(); 1576 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; 1577 Handle<Code> stub; 1578 if (receiver_map->has_fast_elements() || 1579 receiver_map->has_external_array_elements()) { 1580 stub = KeyedStoreFastElementStub( 1581 is_jsarray, 1582 elements_kind, 1583 store_mode()).GetCode(isolate()); 1584 } else { 1585 stub = KeyedStoreElementStub(is_jsarray, 1586 elements_kind, 1587 store_mode()).GetCode(isolate()); 1588 } 1589 1590 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); 1591 1592 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); 1593 1594 // Return the generated code. 1595 return GetICCode(kind(), Code::NORMAL, factory()->empty_string()); 1596 } 1597 1598 1599 #undef __ 1600 1601 1602 void StubCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) { 1603 Handle<Code> code(masm->isolate()->builtins()->builtin(name)); 1604 GenerateTailCall(masm, code); 1605 } 1606 1607 1608 void BaseLoadStoreStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) { 1609 #ifdef ENABLE_GDB_JIT_INTERFACE 1610 GDBJITInterface::CodeTag tag; 1611 if (kind_ == Code::LOAD_IC) { 1612 tag = GDBJITInterface::LOAD_IC; 1613 } else if (kind_ == Code::KEYED_LOAD_IC) { 1614 tag = GDBJITInterface::KEYED_LOAD_IC; 1615 } else if (kind_ == Code::STORE_IC) { 1616 tag = GDBJITInterface::STORE_IC; 1617 } else { 1618 tag = GDBJITInterface::KEYED_STORE_IC; 1619 } 1620 GDBJIT(AddCode(tag, *name, *code)); 1621 #endif 1622 } 1623 1624 1625 void BaseLoadStoreStubCompiler::InitializeRegisters() { 1626 if (kind_ == Code::LOAD_IC) { 1627 registers_ = LoadStubCompiler::registers(); 1628 } else if (kind_ == Code::KEYED_LOAD_IC) { 1629 registers_ = KeyedLoadStubCompiler::registers(); 1630 } else if (kind_ == Code::STORE_IC) { 1631 registers_ = StoreStubCompiler::registers(); 1632 } else { 1633 registers_ = KeyedStoreStubCompiler::registers(); 1634 } 1635 } 1636 1637 1638 Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind, 1639 Code::StubType type, 1640 Handle<Name> name, 1641 InlineCacheState state) { 1642 Code::Flags flags = Code::ComputeFlags(kind, state, extra_state(), type); 1643 Handle<Code> code = GetCodeWithFlags(flags, name); 1644 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); 1645 JitEvent(name, code); 1646 return code; 1647 } 1648 1649 1650 Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind, 1651 Code::StubType type, 1652 Handle<Name> name) { 1653 Code::Flags flags = Code::ComputeFlags( 1654 Code::HANDLER, MONOMORPHIC, extra_state(), type, kind, cache_holder_); 1655 Handle<Code> code = GetCodeWithFlags(flags, name); 1656 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); 1657 JitEvent(name, code); 1658 return code; 1659 } 1660 1661 1662 void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps, 1663 CodeHandleList* handlers) { 1664 for (int i = 0; i < receiver_maps->length(); ++i) { 1665 Handle<Map> receiver_map = receiver_maps->at(i); 1666 Handle<Code> cached_stub; 1667 1668 if ((receiver_map->instance_type() & kNotStringTag) == 0) { 1669 cached_stub = isolate()->builtins()->KeyedLoadIC_String(); 1670 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { 1671 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow(); 1672 } else { 1673 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; 1674 ElementsKind elements_kind = receiver_map->elements_kind(); 1675 1676 if (IsFastElementsKind(elements_kind) || 1677 IsExternalArrayElementsKind(elements_kind)) { 1678 cached_stub = 1679 KeyedLoadFastElementStub(is_js_array, 1680 elements_kind).GetCode(isolate()); 1681 } else { 1682 ASSERT(elements_kind == DICTIONARY_ELEMENTS); 1683 cached_stub = KeyedLoadDictionaryElementStub().GetCode(isolate()); 1684 } 1685 } 1686 1687 handlers->Add(cached_stub); 1688 } 1689 } 1690 1691 1692 Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic( 1693 MapHandleList* receiver_maps) { 1694 // Collect MONOMORPHIC stubs for all |receiver_maps|. 1695 CodeHandleList handlers(receiver_maps->length()); 1696 MapHandleList transitioned_maps(receiver_maps->length()); 1697 for (int i = 0; i < receiver_maps->length(); ++i) { 1698 Handle<Map> receiver_map(receiver_maps->at(i)); 1699 Handle<Code> cached_stub; 1700 Handle<Map> transitioned_map = 1701 receiver_map->FindTransitionedMap(receiver_maps); 1702 1703 // TODO(mvstanton): The code below is doing pessimistic elements 1704 // transitions. I would like to stop doing that and rely on Allocation Site 1705 // Tracking to do a better job of ensuring the data types are what they need 1706 // to be. Not all the elements are in place yet, pessimistic elements 1707 // transitions are still important for performance. 1708 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; 1709 ElementsKind elements_kind = receiver_map->elements_kind(); 1710 if (!transitioned_map.is_null()) { 1711 cached_stub = ElementsTransitionAndStoreStub( 1712 elements_kind, 1713 transitioned_map->elements_kind(), 1714 is_js_array, 1715 store_mode()).GetCode(isolate()); 1716 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { 1717 cached_stub = isolate()->builtins()->KeyedStoreIC_Slow(); 1718 } else { 1719 if (receiver_map->has_fast_elements() || 1720 receiver_map->has_external_array_elements()) { 1721 cached_stub = KeyedStoreFastElementStub( 1722 is_js_array, 1723 elements_kind, 1724 store_mode()).GetCode(isolate()); 1725 } else { 1726 cached_stub = KeyedStoreElementStub( 1727 is_js_array, 1728 elements_kind, 1729 store_mode()).GetCode(isolate()); 1730 } 1731 } 1732 ASSERT(!cached_stub.is_null()); 1733 handlers.Add(cached_stub); 1734 transitioned_maps.Add(transitioned_map); 1735 } 1736 Handle<Code> code = 1737 CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps); 1738 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); 1739 PROFILE(isolate(), 1740 CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0)); 1741 return code; 1742 } 1743 1744 1745 void KeyedStoreStubCompiler::GenerateStoreDictionaryElement( 1746 MacroAssembler* masm) { 1747 KeyedStoreIC::GenerateSlow(masm); 1748 } 1749 1750 1751 CallStubCompiler::CallStubCompiler(Isolate* isolate, 1752 int argc, 1753 Code::Kind kind, 1754 ExtraICState extra_state, 1755 InlineCacheHolderFlag cache_holder) 1756 : StubCompiler(isolate, extra_state), 1757 arguments_(argc), 1758 kind_(kind), 1759 cache_holder_(cache_holder) { 1760 } 1761 1762 1763 bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) { 1764 if (function->shared()->HasBuiltinFunctionId()) { 1765 BuiltinFunctionId id = function->shared()->builtin_function_id(); 1766 #define CALL_GENERATOR_CASE(name) if (id == k##name) return true; 1767 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE) 1768 #undef CALL_GENERATOR_CASE 1769 } 1770 1771 CallOptimization optimization(function); 1772 return optimization.is_simple_api_call(); 1773 } 1774 1775 1776 bool CallStubCompiler::CanBeCached(Handle<JSFunction> function) { 1777 if (function->shared()->HasBuiltinFunctionId()) { 1778 BuiltinFunctionId id = function->shared()->builtin_function_id(); 1779 #define CALL_GENERATOR_CASE(name) if (id == k##name) return false; 1780 SITE_SPECIFIC_CALL_GENERATORS(CALL_GENERATOR_CASE) 1781 #undef CALL_GENERATOR_CASE 1782 } 1783 1784 return true; 1785 } 1786 1787 1788 Handle<Code> CallStubCompiler::CompileCustomCall( 1789 Handle<Object> object, 1790 Handle<JSObject> holder, 1791 Handle<Cell> cell, 1792 Handle<JSFunction> function, 1793 Handle<String> fname, 1794 Code::StubType type) { 1795 ASSERT(HasCustomCallGenerator(function)); 1796 1797 if (function->shared()->HasBuiltinFunctionId()) { 1798 BuiltinFunctionId id = function->shared()->builtin_function_id(); 1799 #define CALL_GENERATOR_CASE(name) \ 1800 if (id == k##name) { \ 1801 return CallStubCompiler::Compile##name##Call(object, \ 1802 holder, \ 1803 cell, \ 1804 function, \ 1805 fname, \ 1806 type); \ 1807 } 1808 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE) 1809 #undef CALL_GENERATOR_CASE 1810 } 1811 CallOptimization optimization(function); 1812 ASSERT(optimization.is_simple_api_call()); 1813 return CompileFastApiCall(optimization, 1814 object, 1815 holder, 1816 cell, 1817 function, 1818 fname); 1819 } 1820 1821 1822 Handle<Code> CallStubCompiler::GetCode(Code::StubType type, 1823 Handle<Name> name) { 1824 int argc = arguments_.immediate(); 1825 Code::Flags flags = Code::ComputeMonomorphicFlags( 1826 kind_, extra_state(), cache_holder_, type, argc); 1827 return GetCodeWithFlags(flags, name); 1828 } 1829 1830 1831 Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) { 1832 Handle<String> function_name; 1833 if (function->shared()->name()->IsString()) { 1834 function_name = Handle<String>(String::cast(function->shared()->name())); 1835 } 1836 return GetCode(Code::FAST, function_name); 1837 } 1838 1839 1840 CallOptimization::CallOptimization(LookupResult* lookup) { 1841 if (lookup->IsFound() && 1842 lookup->IsCacheable() && 1843 lookup->IsConstantFunction()) { 1844 // We only optimize constant function calls. 1845 Initialize(Handle<JSFunction>(lookup->GetConstantFunction())); 1846 } else { 1847 Initialize(Handle<JSFunction>::null()); 1848 } 1849 } 1850 1851 1852 CallOptimization::CallOptimization(Handle<JSFunction> function) { 1853 Initialize(function); 1854 } 1855 1856 1857 int CallOptimization::GetPrototypeDepthOfExpectedType( 1858 Handle<JSObject> object, 1859 Handle<JSObject> holder) const { 1860 ASSERT(is_simple_api_call()); 1861 if (expected_receiver_type_.is_null()) return 0; 1862 int depth = 0; 1863 while (!object.is_identical_to(holder)) { 1864 if (expected_receiver_type_->IsTemplateFor(object->map())) return depth; 1865 object = Handle<JSObject>(JSObject::cast(object->GetPrototype())); 1866 if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth; 1867 ++depth; 1868 } 1869 if (expected_receiver_type_->IsTemplateFor(holder->map())) return depth; 1870 return kInvalidProtoDepth; 1871 } 1872 1873 1874 void CallOptimization::Initialize(Handle<JSFunction> function) { 1875 constant_function_ = Handle<JSFunction>::null(); 1876 is_simple_api_call_ = false; 1877 expected_receiver_type_ = Handle<FunctionTemplateInfo>::null(); 1878 api_call_info_ = Handle<CallHandlerInfo>::null(); 1879 1880 if (function.is_null() || !function->is_compiled()) return; 1881 1882 constant_function_ = function; 1883 AnalyzePossibleApiFunction(function); 1884 } 1885 1886 1887 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) { 1888 if (!function->shared()->IsApiFunction()) return; 1889 Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data()); 1890 1891 // Require a C++ callback. 1892 if (info->call_code()->IsUndefined()) return; 1893 api_call_info_ = 1894 Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code())); 1895 1896 // Accept signatures that either have no restrictions at all or 1897 // only have restrictions on the receiver. 1898 if (!info->signature()->IsUndefined()) { 1899 Handle<SignatureInfo> signature = 1900 Handle<SignatureInfo>(SignatureInfo::cast(info->signature())); 1901 if (!signature->args()->IsUndefined()) return; 1902 if (!signature->receiver()->IsUndefined()) { 1903 expected_receiver_type_ = 1904 Handle<FunctionTemplateInfo>( 1905 FunctionTemplateInfo::cast(signature->receiver())); 1906 } 1907 } 1908 1909 is_simple_api_call_ = true; 1910 } 1911 1912 1913 } } // namespace v8::internal 1914