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 ASSERT(isolate == Isolate::Current()); 50 } 51 52 53 void StubCache::Initialize() { 54 ASSERT(IsPowerOf2(kPrimaryTableSize)); 55 ASSERT(IsPowerOf2(kSecondaryTableSize)); 56 Clear(); 57 } 58 59 60 Code* StubCache::Set(Name* name, Map* map, Code* code) { 61 // Get the flags from the code. 62 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); 63 64 // Validate that the name does not move on scavenge, and that we 65 // can use identity checks instead of structural equality checks. 66 ASSERT(!heap()->InNewSpace(name)); 67 ASSERT(name->IsUniqueName()); 68 69 // The state bits are not important to the hash function because 70 // the stub cache only contains monomorphic stubs. Make sure that 71 // the bits are the least significant so they will be the ones 72 // masked out. 73 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC); 74 STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1); 75 76 // Make sure that the code type is not included in the hash. 77 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); 78 79 // Compute the primary entry. 80 int primary_offset = PrimaryOffset(name, flags, map); 81 Entry* primary = entry(primary_, primary_offset); 82 Code* old_code = primary->value; 83 84 // If the primary entry has useful data in it, we retire it to the 85 // secondary cache before overwriting it. 86 if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) { 87 Map* old_map = primary->map; 88 Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags()); 89 int seed = PrimaryOffset(primary->key, old_flags, old_map); 90 int secondary_offset = SecondaryOffset(primary->key, old_flags, seed); 91 Entry* secondary = entry(secondary_, secondary_offset); 92 *secondary = *primary; 93 } 94 95 // Update primary cache. 96 primary->key = name; 97 primary->value = code; 98 primary->map = map; 99 isolate()->counters()->megamorphic_stub_cache_updates()->Increment(); 100 return code; 101 } 102 103 104 Handle<JSObject> StubCache::StubHolder(Handle<JSObject> receiver, 105 Handle<JSObject> holder) { 106 InlineCacheHolderFlag cache_holder = 107 IC::GetCodeCacheForObject(*receiver, *holder); 108 return Handle<JSObject>(IC::GetCodeCacheHolder( 109 isolate_, *receiver, cache_holder)); 110 } 111 112 113 Handle<Code> StubCache::FindIC(Handle<Name> name, 114 Handle<Map> stub_holder_map, 115 Code::Kind kind, 116 Code::StubType type, 117 Code::ExtraICState extra_state) { 118 Code::Flags flags = Code::ComputeMonomorphicFlags(kind, extra_state, type); 119 Handle<Object> probe(stub_holder_map->FindInCodeCache(*name, flags), 120 isolate_); 121 if (probe->IsCode()) return Handle<Code>::cast(probe); 122 return Handle<Code>::null(); 123 } 124 125 126 Handle<Code> StubCache::FindIC(Handle<Name> name, 127 Handle<JSObject> stub_holder, 128 Code::Kind kind, 129 Code::StubType type, 130 Code::ExtraICState extra_ic_state) { 131 return FindIC(name, Handle<Map>(stub_holder->map()), kind, 132 type, extra_ic_state); 133 } 134 135 136 Handle<Code> StubCache::FindLoadHandler(Handle<Name> name, 137 Handle<JSObject> receiver, 138 Handle<JSObject> stub_holder, 139 Code::Kind kind, 140 Code::StubType type) { 141 Code::ExtraICState extra_ic_state = Code::ComputeExtraICState( 142 receiver.is_identical_to(stub_holder) ? Code::OWN_STUB 143 : Code::PROTOTYPE_STUB); 144 ASSERT(type != Code::NORMAL); 145 Code::Flags flags = Code::ComputeMonomorphicFlags( 146 Code::STUB, extra_ic_state, type, kind); 147 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), 148 isolate_); 149 if (probe->IsCode()) return Handle<Code>::cast(probe); 150 return Handle<Code>::null(); 151 } 152 153 154 Handle<Code> StubCache::FindStoreHandler(Handle<Name> name, 155 Handle<JSObject> receiver, 156 Code::Kind kind, 157 Code::StubType type, 158 StrictModeFlag strict_mode) { 159 Code::ExtraICState extra_ic_state = Code::ComputeExtraICState( 160 STANDARD_STORE, strict_mode); 161 ASSERT(type != Code::NORMAL); 162 Code::Flags flags = Code::ComputeMonomorphicFlags( 163 Code::STUB, extra_ic_state, type, kind); 164 Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), 165 isolate_); 166 if (probe->IsCode()) return Handle<Code>::cast(probe); 167 return Handle<Code>::null(); 168 } 169 170 171 Handle<Code> StubCache::ComputeMonomorphicLoadIC(Handle<JSObject> receiver, 172 Handle<Code> handler, 173 Handle<Name> name) { 174 Handle<Code> ic = FindIC(name, receiver, Code::LOAD_IC, handler->type()); 175 if (!ic.is_null()) return ic; 176 177 LoadStubCompiler ic_compiler(isolate()); 178 ic = ic_compiler.CompileMonomorphicIC( 179 Handle<Map>(receiver->map()), handler, name); 180 181 JSObject::UpdateMapCodeCache(receiver, name, ic); 182 return ic; 183 } 184 185 186 Handle<Code> StubCache::ComputeMonomorphicKeyedLoadIC(Handle<JSObject> receiver, 187 Handle<Code> handler, 188 Handle<Name> name) { 189 Handle<Code> ic = FindIC( 190 name, receiver, Code::KEYED_LOAD_IC, handler->type()); 191 if (!ic.is_null()) return ic; 192 193 KeyedLoadStubCompiler ic_compiler(isolate()); 194 ic = ic_compiler.CompileMonomorphicIC( 195 Handle<Map>(receiver->map()), handler, name); 196 197 JSObject::UpdateMapCodeCache(receiver, name, ic); 198 return ic; 199 } 200 201 202 Handle<Code> StubCache::ComputeMonomorphicStoreIC(Handle<JSObject> receiver, 203 Handle<Code> handler, 204 Handle<Name> name, 205 StrictModeFlag strict_mode) { 206 Handle<Code> ic = FindIC( 207 name, receiver, Code::STORE_IC, handler->type(), strict_mode); 208 if (!ic.is_null()) return ic; 209 210 StoreStubCompiler ic_compiler(isolate(), strict_mode); 211 ic = ic_compiler.CompileMonomorphicIC( 212 Handle<Map>(receiver->map()), handler, name); 213 214 JSObject::UpdateMapCodeCache(receiver, name, ic); 215 return ic; 216 } 217 218 219 Handle<Code> StubCache::ComputeMonomorphicKeyedStoreIC( 220 Handle<JSObject> receiver, 221 Handle<Code> handler, 222 Handle<Name> name, 223 StrictModeFlag strict_mode) { 224 Handle<Code> ic = FindIC( 225 name, receiver, Code::KEYED_STORE_IC, handler->type(), strict_mode); 226 if (!ic.is_null()) return ic; 227 228 KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE); 229 ic = ic_compiler.CompileMonomorphicIC( 230 Handle<Map>(receiver->map()), handler, name); 231 232 JSObject::UpdateMapCodeCache(receiver, name, ic); 233 return ic; 234 } 235 236 237 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name, 238 Handle<JSObject> receiver) { 239 // If no global objects are present in the prototype chain, the load 240 // nonexistent IC stub can be shared for all names for a given map 241 // and we use the empty string for the map cache in that case. If 242 // there are global objects involved, we need to check global 243 // property cells in the stub and therefore the stub will be 244 // specific to the name. 245 Handle<Name> cache_name = factory()->empty_string(); 246 Handle<JSObject> current; 247 Handle<Object> next = receiver; 248 Handle<GlobalObject> global; 249 do { 250 current = Handle<JSObject>::cast(next); 251 next = Handle<Object>(current->GetPrototype(), isolate_); 252 if (current->IsGlobalObject()) { 253 global = Handle<GlobalObject>::cast(current); 254 cache_name = name; 255 } else if (!current->HasFastProperties()) { 256 cache_name = name; 257 } 258 } while (!next->IsNull()); 259 260 // Compile the stub that is either shared for all names or 261 // name specific if there are global objects involved. 262 Handle<Code> handler = FindLoadHandler( 263 cache_name, receiver, receiver, Code::LOAD_IC, Code::NONEXISTENT); 264 if (!handler.is_null()) return handler; 265 266 LoadStubCompiler compiler(isolate_); 267 handler = 268 compiler.CompileLoadNonexistent(receiver, current, cache_name, global); 269 JSObject::UpdateMapCodeCache(receiver, cache_name, handler); 270 return handler; 271 } 272 273 274 Handle<Code> StubCache::ComputeLoadField(Handle<Name> name, 275 Handle<JSObject> receiver, 276 Handle<JSObject> holder, 277 PropertyIndex field, 278 Representation representation) { 279 if (receiver.is_identical_to(holder)) { 280 LoadFieldStub stub(field.is_inobject(holder), 281 field.translate(holder), 282 representation); 283 return stub.GetCode(isolate()); 284 } 285 286 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 287 Handle<Code> stub = FindLoadHandler( 288 name, receiver, stub_holder, Code::LOAD_IC, Code::FIELD); 289 if (!stub.is_null()) return stub; 290 291 LoadStubCompiler compiler(isolate_); 292 Handle<Code> handler = 293 compiler.CompileLoadField(receiver, holder, name, field, representation); 294 JSObject::UpdateMapCodeCache(stub_holder, name, handler); 295 return handler; 296 } 297 298 299 Handle<Code> StubCache::ComputeLoadCallback( 300 Handle<Name> name, 301 Handle<JSObject> receiver, 302 Handle<JSObject> holder, 303 Handle<ExecutableAccessorInfo> callback) { 304 ASSERT(v8::ToCData<Address>(callback->getter()) != 0); 305 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 306 Handle<Code> stub = FindLoadHandler( 307 name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS); 308 if (!stub.is_null()) return stub; 309 310 LoadStubCompiler compiler(isolate_); 311 Handle<Code> handler = 312 compiler.CompileLoadCallback(receiver, holder, name, callback); 313 JSObject::UpdateMapCodeCache(stub_holder, name, handler); 314 return handler; 315 } 316 317 318 Handle<Code> StubCache::ComputeLoadViaGetter(Handle<Name> name, 319 Handle<JSObject> receiver, 320 Handle<JSObject> holder, 321 Handle<JSFunction> getter) { 322 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 323 Handle<Code> stub = FindLoadHandler( 324 name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS); 325 if (!stub.is_null()) return stub; 326 327 LoadStubCompiler compiler(isolate_); 328 Handle<Code> handler = 329 compiler.CompileLoadViaGetter(receiver, holder, name, getter); 330 JSObject::UpdateMapCodeCache(stub_holder, name, handler); 331 return handler; 332 } 333 334 335 Handle<Code> StubCache::ComputeLoadConstant(Handle<Name> name, 336 Handle<JSObject> receiver, 337 Handle<JSObject> holder, 338 Handle<Object> value) { 339 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 340 Handle<Code> handler = FindLoadHandler( 341 name, receiver, stub_holder, Code::LOAD_IC, Code::CONSTANT); 342 if (!handler.is_null()) return handler; 343 344 LoadStubCompiler compiler(isolate_); 345 handler = compiler.CompileLoadConstant(receiver, holder, name, value); 346 JSObject::UpdateMapCodeCache(stub_holder, name, handler); 347 348 return handler; 349 } 350 351 352 Handle<Code> StubCache::ComputeLoadInterceptor(Handle<Name> name, 353 Handle<JSObject> receiver, 354 Handle<JSObject> holder) { 355 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 356 Handle<Code> stub = FindLoadHandler( 357 name, receiver, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR); 358 if (!stub.is_null()) return stub; 359 360 LoadStubCompiler compiler(isolate_); 361 Handle<Code> handler = 362 compiler.CompileLoadInterceptor(receiver, holder, name); 363 JSObject::UpdateMapCodeCache(stub_holder, name, handler); 364 return handler; 365 } 366 367 368 Handle<Code> StubCache::ComputeLoadNormal(Handle<Name> name, 369 Handle<JSObject> receiver) { 370 return isolate_->builtins()->LoadIC_Normal(); 371 } 372 373 374 Handle<Code> StubCache::ComputeLoadGlobal(Handle<Name> name, 375 Handle<JSObject> receiver, 376 Handle<GlobalObject> holder, 377 Handle<PropertyCell> cell, 378 bool is_dont_delete) { 379 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 380 Handle<Code> stub = FindIC(name, stub_holder, Code::LOAD_IC, Code::NORMAL); 381 if (!stub.is_null()) return stub; 382 383 LoadStubCompiler compiler(isolate_); 384 Handle<Code> ic = 385 compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete); 386 JSObject::UpdateMapCodeCache(stub_holder, name, ic); 387 return ic; 388 } 389 390 391 Handle<Code> StubCache::ComputeKeyedLoadField(Handle<Name> name, 392 Handle<JSObject> receiver, 393 Handle<JSObject> holder, 394 PropertyIndex field, 395 Representation representation) { 396 if (receiver.is_identical_to(holder)) { 397 // TODO(titzer): this should use an HObjectAccess 398 KeyedLoadFieldStub stub(field.is_inobject(holder), 399 field.translate(holder), 400 representation); 401 return stub.GetCode(isolate()); 402 } 403 404 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 405 Handle<Code> stub = FindLoadHandler( 406 name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD); 407 if (!stub.is_null()) return stub; 408 409 KeyedLoadStubCompiler compiler(isolate_); 410 Handle<Code> handler = 411 compiler.CompileLoadField(receiver, holder, name, field, representation); 412 JSObject::UpdateMapCodeCache(stub_holder, name, handler); 413 return handler; 414 } 415 416 417 Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<Name> name, 418 Handle<JSObject> receiver, 419 Handle<JSObject> holder, 420 Handle<Object> value) { 421 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 422 Handle<Code> handler = FindLoadHandler( 423 name, receiver, stub_holder, Code::KEYED_LOAD_IC, 424 Code::CONSTANT); 425 if (!handler.is_null()) return handler; 426 427 KeyedLoadStubCompiler compiler(isolate_); 428 handler = compiler.CompileLoadConstant(receiver, holder, name, value); 429 JSObject::UpdateMapCodeCache(stub_holder, name, handler); 430 return handler; 431 } 432 433 434 Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<Name> name, 435 Handle<JSObject> receiver, 436 Handle<JSObject> holder) { 437 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 438 Handle<Code> stub = FindLoadHandler( 439 name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR); 440 if (!stub.is_null()) return stub; 441 442 KeyedLoadStubCompiler compiler(isolate_); 443 Handle<Code> handler = 444 compiler.CompileLoadInterceptor(receiver, holder, name); 445 JSObject::UpdateMapCodeCache(stub_holder, name, handler); 446 return handler; 447 } 448 449 450 Handle<Code> StubCache::ComputeKeyedLoadCallback( 451 Handle<Name> name, 452 Handle<JSObject> receiver, 453 Handle<JSObject> holder, 454 Handle<ExecutableAccessorInfo> callback) { 455 Handle<JSObject> stub_holder = StubHolder(receiver, holder); 456 Handle<Code> stub = FindLoadHandler( 457 name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS); 458 if (!stub.is_null()) return stub; 459 460 KeyedLoadStubCompiler compiler(isolate_); 461 Handle<Code> handler = 462 compiler.CompileLoadCallback(receiver, holder, name, callback); 463 JSObject::UpdateMapCodeCache(stub_holder, name, handler); 464 return handler; 465 } 466 467 468 Handle<Code> StubCache::ComputeStoreField(Handle<Name> name, 469 Handle<JSObject> receiver, 470 LookupResult* lookup, 471 StrictModeFlag strict_mode) { 472 Handle<Code> stub = FindStoreHandler( 473 name, receiver, Code::STORE_IC, Code::FIELD, strict_mode); 474 if (!stub.is_null()) return stub; 475 476 StoreStubCompiler compiler(isolate_, strict_mode); 477 Handle<Code> handler = compiler.CompileStoreField(receiver, lookup, name); 478 JSObject::UpdateMapCodeCache(receiver, name, handler); 479 return handler; 480 } 481 482 483 Handle<Code> StubCache::ComputeStoreTransition(Handle<Name> name, 484 Handle<JSObject> receiver, 485 LookupResult* lookup, 486 Handle<Map> transition, 487 StrictModeFlag strict_mode) { 488 Handle<Code> stub = FindStoreHandler( 489 name, receiver, Code::STORE_IC, Code::MAP_TRANSITION, strict_mode); 490 if (!stub.is_null()) return stub; 491 492 StoreStubCompiler compiler(isolate_, strict_mode); 493 Handle<Code> handler = 494 compiler.CompileStoreTransition(receiver, lookup, transition, name); 495 JSObject::UpdateMapCodeCache(receiver, name, handler); 496 return handler; 497 } 498 499 500 Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) { 501 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC); 502 Handle<Name> name = 503 isolate()->factory()->KeyedLoadElementMonomorphic_string(); 504 505 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); 506 if (probe->IsCode()) return Handle<Code>::cast(probe); 507 508 KeyedLoadStubCompiler compiler(isolate()); 509 Handle<Code> code = compiler.CompileLoadElement(receiver_map); 510 511 Map::UpdateCodeCache(receiver_map, name, code); 512 return code; 513 } 514 515 516 Handle<Code> StubCache::ComputeKeyedStoreElement( 517 Handle<Map> receiver_map, 518 StrictModeFlag strict_mode, 519 KeyedAccessStoreMode store_mode) { 520 Code::ExtraICState extra_state = 521 Code::ComputeExtraICState(store_mode, strict_mode); 522 Code::Flags flags = Code::ComputeMonomorphicFlags( 523 Code::KEYED_STORE_IC, extra_state); 524 525 ASSERT(store_mode == STANDARD_STORE || 526 store_mode == STORE_AND_GROW_NO_TRANSITION || 527 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || 528 store_mode == STORE_NO_TRANSITION_HANDLE_COW); 529 530 Handle<String> name = 531 isolate()->factory()->KeyedStoreElementMonomorphic_string(); 532 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); 533 if (probe->IsCode()) return Handle<Code>::cast(probe); 534 535 KeyedStoreStubCompiler compiler(isolate(), strict_mode, store_mode); 536 Handle<Code> code = compiler.CompileStoreElement(receiver_map); 537 538 Map::UpdateCodeCache(receiver_map, name, code); 539 ASSERT(Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == store_mode); 540 return code; 541 } 542 543 544 Handle<Code> StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) { 545 return (strict_mode == kStrictMode) 546 ? isolate_->builtins()->Builtins::StoreIC_Normal_Strict() 547 : isolate_->builtins()->Builtins::StoreIC_Normal(); 548 } 549 550 551 Handle<Code> StubCache::ComputeStoreGlobal(Handle<Name> name, 552 Handle<GlobalObject> receiver, 553 Handle<PropertyCell> cell, 554 Handle<Object> value, 555 StrictModeFlag strict_mode) { 556 Isolate* isolate = cell->GetIsolate(); 557 Handle<Type> union_type(PropertyCell::UpdateType(cell, value), isolate); 558 bool is_constant = union_type->IsConstant(); 559 StoreGlobalStub stub(strict_mode, is_constant); 560 561 Handle<Code> code = FindIC( 562 name, Handle<JSObject>::cast(receiver), 563 Code::STORE_IC, Code::NORMAL, stub.GetExtraICState()); 564 if (!code.is_null()) return code; 565 566 // Replace the placeholder cell and global object map with the actual global 567 // cell and receiver map. 568 Handle<Map> meta_map(isolate_->heap()->meta_map()); 569 Handle<Object> receiver_map(receiver->map(), isolate_); 570 code = stub.GetCodeCopyFromTemplate(isolate_); 571 code->ReplaceNthObject(1, *meta_map, *receiver_map); 572 Handle<Map> cell_map(isolate_->heap()->global_property_cell_map()); 573 code->ReplaceNthObject(1, *cell_map, *cell); 574 575 JSObject::UpdateMapCodeCache(receiver, name, code); 576 577 return code; 578 } 579 580 581 Handle<Code> StubCache::ComputeStoreCallback( 582 Handle<Name> name, 583 Handle<JSObject> receiver, 584 Handle<JSObject> holder, 585 Handle<ExecutableAccessorInfo> callback, 586 StrictModeFlag strict_mode) { 587 ASSERT(v8::ToCData<Address>(callback->setter()) != 0); 588 Handle<Code> stub = FindStoreHandler( 589 name, receiver, Code::STORE_IC, Code::CALLBACKS, strict_mode); 590 if (!stub.is_null()) return stub; 591 592 StoreStubCompiler compiler(isolate_, strict_mode); 593 Handle<Code> handler = compiler.CompileStoreCallback( 594 receiver, holder, name, callback); 595 JSObject::UpdateMapCodeCache(receiver, name, handler); 596 return handler; 597 } 598 599 600 Handle<Code> StubCache::ComputeStoreViaSetter(Handle<Name> name, 601 Handle<JSObject> receiver, 602 Handle<JSObject> holder, 603 Handle<JSFunction> setter, 604 StrictModeFlag strict_mode) { 605 Handle<Code> stub = FindStoreHandler( 606 name, receiver, Code::STORE_IC, Code::CALLBACKS, strict_mode); 607 if (!stub.is_null()) return stub; 608 609 StoreStubCompiler compiler(isolate_, strict_mode); 610 Handle<Code> handler = compiler.CompileStoreViaSetter( 611 receiver, holder, name, setter); 612 JSObject::UpdateMapCodeCache(receiver, name, handler); 613 return handler; 614 } 615 616 617 Handle<Code> StubCache::ComputeStoreInterceptor(Handle<Name> name, 618 Handle<JSObject> receiver, 619 StrictModeFlag strict_mode) { 620 Handle<Code> stub = FindStoreHandler( 621 name, receiver, Code::STORE_IC, Code::INTERCEPTOR, strict_mode); 622 if (!stub.is_null()) return stub; 623 624 StoreStubCompiler compiler(isolate_, strict_mode); 625 Handle<Code> handler = compiler.CompileStoreInterceptor(receiver, name); 626 JSObject::UpdateMapCodeCache(receiver, name, handler); 627 return handler; 628 } 629 630 631 Handle<Code> StubCache::ComputeKeyedStoreField(Handle<Name> name, 632 Handle<JSObject> receiver, 633 LookupResult* lookup, 634 StrictModeFlag strict_mode) { 635 Handle<Code> stub = FindStoreHandler( 636 name, receiver, Code::KEYED_STORE_IC, Code::FIELD, strict_mode); 637 if (!stub.is_null()) return stub; 638 639 KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE); 640 Handle<Code> handler = compiler.CompileStoreField(receiver, lookup, name); 641 JSObject::UpdateMapCodeCache(receiver, name, handler); 642 return handler; 643 } 644 645 646 Handle<Code> StubCache::ComputeKeyedStoreTransition( 647 Handle<Name> name, 648 Handle<JSObject> receiver, 649 LookupResult* lookup, 650 Handle<Map> transition, 651 StrictModeFlag strict_mode) { 652 Handle<Code> stub = FindStoreHandler( 653 name, receiver, Code::KEYED_STORE_IC, Code::MAP_TRANSITION, strict_mode); 654 if (!stub.is_null()) return stub; 655 656 KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE); 657 Handle<Code> handler = 658 compiler.CompileStoreTransition(receiver, lookup, transition, name); 659 JSObject::UpdateMapCodeCache(receiver, name, handler); 660 return handler; 661 } 662 663 664 #define CALL_LOGGER_TAG(kind, type) \ 665 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type) 666 667 Handle<Code> StubCache::ComputeCallConstant(int argc, 668 Code::Kind kind, 669 Code::ExtraICState extra_state, 670 Handle<Name> name, 671 Handle<Object> object, 672 Handle<JSObject> holder, 673 Handle<JSFunction> function) { 674 // Compute the check type and the map. 675 InlineCacheHolderFlag cache_holder = 676 IC::GetCodeCacheForObject(*object, *holder); 677 Handle<JSObject> stub_holder(IC::GetCodeCacheHolder( 678 isolate_, *object, cache_holder)); 679 680 // Compute check type based on receiver/holder. 681 CheckType check = RECEIVER_MAP_CHECK; 682 if (object->IsString()) { 683 check = STRING_CHECK; 684 } else if (object->IsSymbol()) { 685 check = SYMBOL_CHECK; 686 } else if (object->IsNumber()) { 687 check = NUMBER_CHECK; 688 } else if (object->IsBoolean()) { 689 check = BOOLEAN_CHECK; 690 } 691 692 if (check != RECEIVER_MAP_CHECK && 693 !function->IsBuiltin() && 694 function->shared()->is_classic_mode()) { 695 // Calling non-strict non-builtins with a value as the receiver 696 // requires boxing. 697 return Handle<Code>::null(); 698 } 699 700 Code::Flags flags = Code::ComputeMonomorphicFlags( 701 kind, extra_state, Code::CONSTANT, argc, cache_holder); 702 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), 703 isolate_); 704 if (probe->IsCode()) return Handle<Code>::cast(probe); 705 706 CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); 707 Handle<Code> code = 708 compiler.CompileCallConstant(object, holder, name, check, function); 709 code->set_check_type(check); 710 ASSERT(flags == code->flags()); 711 PROFILE(isolate_, 712 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); 713 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); 714 715 if (CallStubCompiler::CanBeCached(function)) { 716 JSObject::UpdateMapCodeCache(stub_holder, name, code); 717 } 718 return code; 719 } 720 721 722 Handle<Code> StubCache::ComputeCallField(int argc, 723 Code::Kind kind, 724 Code::ExtraICState extra_state, 725 Handle<Name> name, 726 Handle<Object> object, 727 Handle<JSObject> holder, 728 PropertyIndex index) { 729 // Compute the check type and the map. 730 InlineCacheHolderFlag cache_holder = 731 IC::GetCodeCacheForObject(*object, *holder); 732 Handle<JSObject> stub_holder(IC::GetCodeCacheHolder( 733 isolate_, *object, cache_holder)); 734 735 // TODO(1233596): We cannot do receiver map check for non-JS objects 736 // because they may be represented as immediates without a 737 // map. Instead, we check against the map in the holder. 738 if (object->IsNumber() || object->IsSymbol() || 739 object->IsBoolean() || object->IsString()) { 740 object = holder; 741 } 742 743 Code::Flags flags = Code::ComputeMonomorphicFlags( 744 kind, extra_state, Code::FIELD, argc, cache_holder); 745 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), 746 isolate_); 747 if (probe->IsCode()) return Handle<Code>::cast(probe); 748 749 CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); 750 Handle<Code> code = 751 compiler.CompileCallField(Handle<JSObject>::cast(object), 752 holder, index, name); 753 ASSERT(flags == code->flags()); 754 PROFILE(isolate_, 755 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); 756 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); 757 JSObject::UpdateMapCodeCache(stub_holder, name, code); 758 return code; 759 } 760 761 762 Handle<Code> StubCache::ComputeCallInterceptor(int argc, 763 Code::Kind kind, 764 Code::ExtraICState extra_state, 765 Handle<Name> name, 766 Handle<Object> object, 767 Handle<JSObject> holder) { 768 // Compute the check type and the map. 769 InlineCacheHolderFlag cache_holder = 770 IC::GetCodeCacheForObject(*object, *holder); 771 Handle<JSObject> stub_holder(IC::GetCodeCacheHolder( 772 isolate_, *object, cache_holder)); 773 774 // TODO(1233596): We cannot do receiver map check for non-JS objects 775 // because they may be represented as immediates without a 776 // map. Instead, we check against the map in the holder. 777 if (object->IsNumber() || object->IsSymbol() || 778 object->IsBoolean() || object->IsString()) { 779 object = holder; 780 } 781 782 Code::Flags flags = Code::ComputeMonomorphicFlags( 783 kind, extra_state, Code::INTERCEPTOR, argc, cache_holder); 784 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), 785 isolate_); 786 if (probe->IsCode()) return Handle<Code>::cast(probe); 787 788 CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder); 789 Handle<Code> code = 790 compiler.CompileCallInterceptor(Handle<JSObject>::cast(object), 791 holder, name); 792 ASSERT(flags == code->flags()); 793 PROFILE(isolate(), 794 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); 795 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); 796 JSObject::UpdateMapCodeCache(stub_holder, name, code); 797 return code; 798 } 799 800 801 Handle<Code> StubCache::ComputeCallGlobal(int argc, 802 Code::Kind kind, 803 Code::ExtraICState extra_state, 804 Handle<Name> name, 805 Handle<JSObject> receiver, 806 Handle<GlobalObject> holder, 807 Handle<PropertyCell> cell, 808 Handle<JSFunction> function) { 809 InlineCacheHolderFlag cache_holder = 810 IC::GetCodeCacheForObject(*receiver, *holder); 811 Handle<JSObject> stub_holder(IC::GetCodeCacheHolder( 812 isolate_, *receiver, cache_holder)); 813 Code::Flags flags = Code::ComputeMonomorphicFlags( 814 kind, extra_state, Code::NORMAL, argc, cache_holder); 815 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), 816 isolate_); 817 if (probe->IsCode()) return Handle<Code>::cast(probe); 818 819 CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder); 820 Handle<Code> code = 821 compiler.CompileCallGlobal(receiver, holder, cell, function, name); 822 ASSERT(flags == code->flags()); 823 PROFILE(isolate(), 824 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); 825 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); 826 if (CallStubCompiler::CanBeCached(function)) { 827 JSObject::UpdateMapCodeCache(stub_holder, name, code); 828 } 829 return code; 830 } 831 832 833 static void FillCache(Isolate* isolate, Handle<Code> code) { 834 Handle<UnseededNumberDictionary> dictionary = 835 UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(), 836 code->flags(), 837 code); 838 isolate->heap()->public_set_non_monomorphic_cache(*dictionary); 839 } 840 841 842 Code* StubCache::FindCallInitialize(int argc, 843 RelocInfo::Mode mode, 844 Code::Kind kind) { 845 Code::ExtraICState extra_state = 846 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) | 847 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT); 848 Code::Flags flags = 849 Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc); 850 UnseededNumberDictionary* dictionary = 851 isolate()->heap()->non_monomorphic_cache(); 852 int entry = dictionary->FindEntry(isolate(), flags); 853 ASSERT(entry != -1); 854 Object* code = dictionary->ValueAt(entry); 855 // This might be called during the marking phase of the collector 856 // hence the unchecked cast. 857 return reinterpret_cast<Code*>(code); 858 } 859 860 861 Handle<Code> StubCache::ComputeCallInitialize(int argc, 862 RelocInfo::Mode mode, 863 Code::Kind kind) { 864 Code::ExtraICState extra_state = 865 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) | 866 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT); 867 Code::Flags flags = 868 Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc); 869 Handle<UnseededNumberDictionary> cache = 870 isolate_->factory()->non_monomorphic_cache(); 871 int entry = cache->FindEntry(isolate_, flags); 872 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 873 874 StubCompiler compiler(isolate_); 875 Handle<Code> code = compiler.CompileCallInitialize(flags); 876 FillCache(isolate_, code); 877 return code; 878 } 879 880 881 Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) { 882 return ComputeCallInitialize(argc, mode, Code::CALL_IC); 883 } 884 885 886 Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) { 887 return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET, 888 Code::KEYED_CALL_IC); 889 } 890 891 892 Handle<Code> StubCache::ComputeCallPreMonomorphic( 893 int argc, 894 Code::Kind kind, 895 Code::ExtraICState extra_state) { 896 Code::Flags flags = 897 Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, Code::NORMAL, argc); 898 Handle<UnseededNumberDictionary> cache = 899 isolate_->factory()->non_monomorphic_cache(); 900 int entry = cache->FindEntry(isolate_, flags); 901 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 902 903 StubCompiler compiler(isolate_); 904 Handle<Code> code = compiler.CompileCallPreMonomorphic(flags); 905 FillCache(isolate_, code); 906 return code; 907 } 908 909 910 Handle<Code> StubCache::ComputeCallNormal(int argc, 911 Code::Kind kind, 912 Code::ExtraICState extra_state) { 913 Code::Flags flags = 914 Code::ComputeFlags(kind, MONOMORPHIC, extra_state, Code::NORMAL, argc); 915 Handle<UnseededNumberDictionary> cache = 916 isolate_->factory()->non_monomorphic_cache(); 917 int entry = cache->FindEntry(isolate_, flags); 918 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 919 920 StubCompiler compiler(isolate_); 921 Handle<Code> code = compiler.CompileCallNormal(flags); 922 FillCache(isolate_, code); 923 return code; 924 } 925 926 927 Handle<Code> StubCache::ComputeCallArguments(int argc) { 928 Code::Flags flags = 929 Code::ComputeFlags(Code::KEYED_CALL_IC, MEGAMORPHIC, 930 Code::kNoExtraICState, Code::NORMAL, argc); 931 Handle<UnseededNumberDictionary> cache = 932 isolate_->factory()->non_monomorphic_cache(); 933 int entry = cache->FindEntry(isolate_, flags); 934 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 935 936 StubCompiler compiler(isolate_); 937 Handle<Code> code = compiler.CompileCallArguments(flags); 938 FillCache(isolate_, code); 939 return code; 940 } 941 942 943 Handle<Code> StubCache::ComputeCallMegamorphic( 944 int argc, 945 Code::Kind kind, 946 Code::ExtraICState extra_state) { 947 Code::Flags flags = 948 Code::ComputeFlags(kind, MEGAMORPHIC, extra_state, 949 Code::NORMAL, argc); 950 Handle<UnseededNumberDictionary> cache = 951 isolate_->factory()->non_monomorphic_cache(); 952 int entry = cache->FindEntry(isolate_, flags); 953 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 954 955 StubCompiler compiler(isolate_); 956 Handle<Code> code = compiler.CompileCallMegamorphic(flags); 957 FillCache(isolate_, code); 958 return code; 959 } 960 961 962 Handle<Code> StubCache::ComputeCallMiss(int argc, 963 Code::Kind kind, 964 Code::ExtraICState extra_state) { 965 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs 966 // and monomorphic stubs are not mixed up together in the stub cache. 967 Code::Flags flags = 968 Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state, 969 Code::NORMAL, argc, OWN_MAP); 970 Handle<UnseededNumberDictionary> cache = 971 isolate_->factory()->non_monomorphic_cache(); 972 int entry = cache->FindEntry(isolate_, flags); 973 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 974 975 StubCompiler compiler(isolate_); 976 Handle<Code> code = compiler.CompileCallMiss(flags); 977 FillCache(isolate_, code); 978 return code; 979 } 980 981 982 Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map, 983 CompareNilICStub& stub) { 984 Handle<String> name(isolate_->heap()->empty_string()); 985 if (!receiver_map->is_shared()) { 986 Handle<Code> cached_ic = FindIC(name, receiver_map, Code::COMPARE_NIL_IC, 987 Code::NORMAL, stub.GetExtraICState()); 988 if (!cached_ic.is_null()) return cached_ic; 989 } 990 991 Handle<Code> ic = stub.GetCodeCopyFromTemplate(isolate_); 992 ic->ReplaceNthObject(1, isolate_->heap()->meta_map(), *receiver_map); 993 994 if (!receiver_map->is_shared()) { 995 Map::UpdateCodeCache(receiver_map, name, ic); 996 } 997 998 return ic; 999 } 1000 1001 1002 Handle<Code> StubCache::ComputeLoadElementPolymorphic( 1003 MapHandleList* receiver_maps) { 1004 Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC); 1005 Handle<PolymorphicCodeCache> cache = 1006 isolate_->factory()->polymorphic_code_cache(); 1007 Handle<Object> probe = cache->Lookup(receiver_maps, flags); 1008 if (probe->IsCode()) return Handle<Code>::cast(probe); 1009 1010 CodeHandleList handlers(receiver_maps->length()); 1011 KeyedLoadStubCompiler compiler(isolate_); 1012 compiler.CompileElementHandlers(receiver_maps, &handlers); 1013 Handle<Code> code = compiler.CompilePolymorphicIC( 1014 receiver_maps, &handlers, factory()->empty_string(), 1015 Code::NORMAL, ELEMENT); 1016 1017 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); 1018 1019 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code); 1020 return code; 1021 } 1022 1023 1024 Handle<Code> StubCache::ComputePolymorphicLoadIC(MapHandleList* receiver_maps, 1025 CodeHandleList* handlers, 1026 int number_of_valid_maps, 1027 Handle<Name> name) { 1028 LoadStubCompiler ic_compiler(isolate_); 1029 Code::StubType type = number_of_valid_maps == 1 ? handlers->at(0)->type() 1030 : Code::NORMAL; 1031 Handle<Code> ic = ic_compiler.CompilePolymorphicIC( 1032 receiver_maps, handlers, name, type, PROPERTY); 1033 return ic; 1034 } 1035 1036 1037 Handle<Code> StubCache::ComputePolymorphicStoreIC(MapHandleList* receiver_maps, 1038 CodeHandleList* handlers, 1039 int number_of_valid_maps, 1040 Handle<Name> name, 1041 StrictModeFlag strict_mode) { 1042 StoreStubCompiler ic_compiler(isolate_, strict_mode); 1043 Code::StubType type = number_of_valid_maps == 1 ? handlers->at(0)->type() 1044 : Code::NORMAL; 1045 Handle<Code> ic = ic_compiler.CompilePolymorphicIC( 1046 receiver_maps, handlers, name, type, PROPERTY); 1047 return ic; 1048 } 1049 1050 1051 Handle<Code> StubCache::ComputeStoreElementPolymorphic( 1052 MapHandleList* receiver_maps, 1053 KeyedAccessStoreMode store_mode, 1054 StrictModeFlag strict_mode) { 1055 ASSERT(store_mode == STANDARD_STORE || 1056 store_mode == STORE_AND_GROW_NO_TRANSITION || 1057 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || 1058 store_mode == STORE_NO_TRANSITION_HANDLE_COW); 1059 Handle<PolymorphicCodeCache> cache = 1060 isolate_->factory()->polymorphic_code_cache(); 1061 Code::ExtraICState extra_state = Code::ComputeExtraICState(store_mode, 1062 strict_mode); 1063 Code::Flags flags = 1064 Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state); 1065 Handle<Object> probe = cache->Lookup(receiver_maps, flags); 1066 if (probe->IsCode()) return Handle<Code>::cast(probe); 1067 1068 KeyedStoreStubCompiler compiler(isolate_, strict_mode, store_mode); 1069 Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps); 1070 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code); 1071 return code; 1072 } 1073 1074 1075 #ifdef ENABLE_DEBUGGER_SUPPORT 1076 Handle<Code> StubCache::ComputeCallDebugBreak(int argc, 1077 Code::Kind kind) { 1078 // Extra IC state is irrelevant for debug break ICs. They jump to 1079 // the actual call ic to carry out the work. 1080 Code::Flags flags = 1081 Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_BREAK, 1082 Code::NORMAL, argc); 1083 Handle<UnseededNumberDictionary> cache = 1084 isolate_->factory()->non_monomorphic_cache(); 1085 int entry = cache->FindEntry(isolate_, flags); 1086 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 1087 1088 StubCompiler compiler(isolate_); 1089 Handle<Code> code = compiler.CompileCallDebugBreak(flags); 1090 FillCache(isolate_, code); 1091 return code; 1092 } 1093 1094 1095 Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc, 1096 Code::Kind kind) { 1097 // Extra IC state is irrelevant for debug break ICs. They jump to 1098 // the actual call ic to carry out the work. 1099 Code::Flags flags = 1100 Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_PREPARE_STEP_IN, 1101 Code::NORMAL, argc); 1102 Handle<UnseededNumberDictionary> cache = 1103 isolate_->factory()->non_monomorphic_cache(); 1104 int entry = cache->FindEntry(isolate_, flags); 1105 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); 1106 1107 StubCompiler compiler(isolate_); 1108 Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags); 1109 FillCache(isolate_, code); 1110 return code; 1111 } 1112 #endif 1113 1114 1115 void StubCache::Clear() { 1116 Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal); 1117 for (int i = 0; i < kPrimaryTableSize; i++) { 1118 primary_[i].key = heap()->empty_string(); 1119 primary_[i].map = NULL; 1120 primary_[i].value = empty; 1121 } 1122 for (int j = 0; j < kSecondaryTableSize; j++) { 1123 secondary_[j].key = heap()->empty_string(); 1124 secondary_[j].map = NULL; 1125 secondary_[j].value = empty; 1126 } 1127 } 1128 1129 1130 void StubCache::CollectMatchingMaps(SmallMapList* types, 1131 Handle<Name> name, 1132 Code::Flags flags, 1133 Handle<Context> native_context, 1134 Zone* zone) { 1135 for (int i = 0; i < kPrimaryTableSize; i++) { 1136 if (primary_[i].key == *name) { 1137 Map* map = primary_[i].map; 1138 // Map can be NULL, if the stub is constant function call 1139 // with a primitive receiver. 1140 if (map == NULL) continue; 1141 1142 int offset = PrimaryOffset(*name, flags, map); 1143 if (entry(primary_, offset) == &primary_[i] && 1144 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) { 1145 types->AddMapIfMissing(Handle<Map>(map), zone); 1146 } 1147 } 1148 } 1149 1150 for (int i = 0; i < kSecondaryTableSize; i++) { 1151 if (secondary_[i].key == *name) { 1152 Map* map = secondary_[i].map; 1153 // Map can be NULL, if the stub is constant function call 1154 // with a primitive receiver. 1155 if (map == NULL) continue; 1156 1157 // Lookup in primary table and skip duplicates. 1158 int primary_offset = PrimaryOffset(*name, flags, map); 1159 1160 // Lookup in secondary table and add matches. 1161 int offset = SecondaryOffset(*name, flags, primary_offset); 1162 if (entry(secondary_, offset) == &secondary_[i] && 1163 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) { 1164 types->AddMapIfMissing(Handle<Map>(map), zone); 1165 } 1166 } 1167 } 1168 } 1169 1170 1171 // ------------------------------------------------------------------------ 1172 // StubCompiler implementation. 1173 1174 1175 RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) { 1176 JSObject* recv = JSObject::cast(args[0]); 1177 ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[1]); 1178 Address setter_address = v8::ToCData<Address>(callback->setter()); 1179 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address); 1180 ASSERT(fun != NULL); 1181 ASSERT(callback->IsCompatibleReceiver(recv)); 1182 Handle<Name> name = args.at<Name>(2); 1183 Handle<Object> value = args.at<Object>(3); 1184 HandleScope scope(isolate); 1185 1186 // TODO(rossberg): Support symbols in the API. 1187 if (name->IsSymbol()) return *value; 1188 Handle<String> str = Handle<String>::cast(name); 1189 1190 LOG(isolate, ApiNamedPropertyAccess("store", recv, *name)); 1191 PropertyCallbackArguments 1192 custom_args(isolate, callback->data(), recv, recv); 1193 custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value)); 1194 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1195 return *value; 1196 } 1197 1198 1199 static const int kAccessorInfoOffsetInInterceptorArgs = 2; 1200 1201 1202 /** 1203 * Attempts to load a property with an interceptor (which must be present), 1204 * but doesn't search the prototype chain. 1205 * 1206 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't 1207 * provide any value for the given name. 1208 */ 1209 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) { 1210 typedef PropertyCallbackArguments PCA; 1211 static const int kArgsOffset = kAccessorInfoOffsetInInterceptorArgs; 1212 Handle<Name> name_handle = args.at<Name>(0); 1213 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1); 1214 ASSERT(kArgsOffset == 2); 1215 // No ReturnValue in interceptors. 1216 ASSERT_EQ(kArgsOffset + PCA::kArgsLength - 2, args.length()); 1217 1218 // TODO(rossberg): Support symbols in the API. 1219 if (name_handle->IsSymbol()) 1220 return isolate->heap()->no_interceptor_result_sentinel(); 1221 Handle<String> name = Handle<String>::cast(name_handle); 1222 1223 Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); 1224 v8::NamedPropertyGetter getter = 1225 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address); 1226 ASSERT(getter != NULL); 1227 1228 Handle<JSObject> receiver = 1229 args.at<JSObject>(kArgsOffset - PCA::kThisIndex); 1230 Handle<JSObject> holder = 1231 args.at<JSObject>(kArgsOffset - PCA::kHolderIndex); 1232 PropertyCallbackArguments callback_args(isolate, 1233 interceptor_info->data(), 1234 *receiver, 1235 *holder); 1236 { 1237 // Use the interceptor getter. 1238 HandleScope scope(isolate); 1239 v8::Handle<v8::Value> r = 1240 callback_args.Call(getter, v8::Utils::ToLocal(name)); 1241 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1242 if (!r.IsEmpty()) { 1243 Handle<Object> result = v8::Utils::OpenHandle(*r); 1244 result->VerifyApiCallResultType(); 1245 return *v8::Utils::OpenHandle(*r); 1246 } 1247 } 1248 1249 return isolate->heap()->no_interceptor_result_sentinel(); 1250 } 1251 1252 1253 static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) { 1254 // If the load is non-contextual, just return the undefined result. 1255 // Note that both keyed and non-keyed loads may end up here, so we 1256 // can't use either LoadIC or KeyedLoadIC constructors. 1257 IC ic(IC::NO_EXTRA_FRAME, isolate); 1258 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub()); 1259 if (!ic.SlowIsUndeclaredGlobal()) return HEAP->undefined_value(); 1260 1261 // Throw a reference error. 1262 HandleScope scope(isolate); 1263 Handle<Name> name_handle(name); 1264 Handle<Object> error = 1265 isolate->factory()->NewReferenceError("not_defined", 1266 HandleVector(&name_handle, 1)); 1267 return isolate->Throw(*error); 1268 } 1269 1270 1271 static MaybeObject* LoadWithInterceptor(Arguments* args, 1272 PropertyAttributes* attrs) { 1273 typedef PropertyCallbackArguments PCA; 1274 static const int kArgsOffset = kAccessorInfoOffsetInInterceptorArgs; 1275 Handle<Name> name_handle = args->at<Name>(0); 1276 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1); 1277 ASSERT(kArgsOffset == 2); 1278 // No ReturnValue in interceptors. 1279 ASSERT_EQ(kArgsOffset + PCA::kArgsLength - 2, args->length()); 1280 Handle<JSObject> receiver_handle = 1281 args->at<JSObject>(kArgsOffset - PCA::kThisIndex); 1282 Handle<JSObject> holder_handle = 1283 args->at<JSObject>(kArgsOffset - PCA::kHolderIndex); 1284 1285 Isolate* isolate = receiver_handle->GetIsolate(); 1286 1287 // TODO(rossberg): Support symbols in the API. 1288 if (name_handle->IsSymbol()) 1289 return holder_handle->GetPropertyPostInterceptor( 1290 *receiver_handle, *name_handle, attrs); 1291 Handle<String> name = Handle<String>::cast(name_handle); 1292 1293 Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); 1294 v8::NamedPropertyGetter getter = 1295 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address); 1296 ASSERT(getter != NULL); 1297 1298 PropertyCallbackArguments callback_args(isolate, 1299 interceptor_info->data(), 1300 *receiver_handle, 1301 *holder_handle); 1302 { 1303 // Use the interceptor getter. 1304 HandleScope scope(isolate); 1305 v8::Handle<v8::Value> r = 1306 callback_args.Call(getter, v8::Utils::ToLocal(name)); 1307 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1308 if (!r.IsEmpty()) { 1309 *attrs = NONE; 1310 Handle<Object> result = v8::Utils::OpenHandle(*r); 1311 result->VerifyApiCallResultType(); 1312 return *result; 1313 } 1314 } 1315 1316 MaybeObject* result = holder_handle->GetPropertyPostInterceptor( 1317 *receiver_handle, 1318 *name_handle, 1319 attrs); 1320 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1321 return result; 1322 } 1323 1324 1325 /** 1326 * Loads a property with an interceptor performing post interceptor 1327 * lookup if interceptor failed. 1328 */ 1329 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) { 1330 PropertyAttributes attr = NONE; 1331 Object* result; 1332 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr); 1333 if (!maybe_result->ToObject(&result)) return maybe_result; 1334 } 1335 1336 // If the property is present, return it. 1337 if (attr != ABSENT) return result; 1338 return ThrowReferenceError(isolate, Name::cast(args[0])); 1339 } 1340 1341 1342 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) { 1343 PropertyAttributes attr; 1344 MaybeObject* result = LoadWithInterceptor(&args, &attr); 1345 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1346 // This is call IC. In this case, we simply return the undefined result which 1347 // will lead to an exception when trying to invoke the result as a 1348 // function. 1349 return result; 1350 } 1351 1352 1353 RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) { 1354 ASSERT(args.length() == 4); 1355 JSObject* recv = JSObject::cast(args[0]); 1356 Name* name = Name::cast(args[1]); 1357 Object* value = args[2]; 1358 ASSERT(args.smi_at(3) == kStrictMode || args.smi_at(3) == kNonStrictMode); 1359 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3)); 1360 ASSERT(recv->HasNamedInterceptor()); 1361 PropertyAttributes attr = NONE; 1362 MaybeObject* result = recv->SetPropertyWithInterceptor( 1363 name, value, attr, strict_mode); 1364 return result; 1365 } 1366 1367 1368 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) { 1369 JSObject* receiver = JSObject::cast(args[0]); 1370 ASSERT(args.smi_at(1) >= 0); 1371 uint32_t index = args.smi_at(1); 1372 return receiver->GetElementWithInterceptor(receiver, index); 1373 } 1374 1375 1376 Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) { 1377 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1378 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1379 Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); 1380 if (kind == Code::CALL_IC) { 1381 CallIC::GenerateInitialize(masm(), argc, extra_state); 1382 } else { 1383 KeyedCallIC::GenerateInitialize(masm(), argc); 1384 } 1385 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize"); 1386 isolate()->counters()->call_initialize_stubs()->Increment(); 1387 PROFILE(isolate(), 1388 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG), 1389 *code, code->arguments_count())); 1390 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code)); 1391 return code; 1392 } 1393 1394 1395 Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) { 1396 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1397 // The code of the PreMonomorphic stub is the same as the code 1398 // of the Initialized stub. They just differ on the code object flags. 1399 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1400 Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); 1401 if (kind == Code::CALL_IC) { 1402 CallIC::GenerateInitialize(masm(), argc, extra_state); 1403 } else { 1404 KeyedCallIC::GenerateInitialize(masm(), argc); 1405 } 1406 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic"); 1407 isolate()->counters()->call_premonomorphic_stubs()->Increment(); 1408 PROFILE(isolate(), 1409 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG), 1410 *code, code->arguments_count())); 1411 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code)); 1412 return code; 1413 } 1414 1415 1416 Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) { 1417 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1418 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1419 if (kind == Code::CALL_IC) { 1420 // Call normal is always with a explict receiver. 1421 ASSERT(!CallIC::Contextual::decode( 1422 Code::ExtractExtraICStateFromFlags(flags))); 1423 CallIC::GenerateNormal(masm(), argc); 1424 } else { 1425 KeyedCallIC::GenerateNormal(masm(), argc); 1426 } 1427 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal"); 1428 isolate()->counters()->call_normal_stubs()->Increment(); 1429 PROFILE(isolate(), 1430 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG), 1431 *code, code->arguments_count())); 1432 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code)); 1433 return code; 1434 } 1435 1436 1437 Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) { 1438 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1439 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1440 Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); 1441 if (kind == Code::CALL_IC) { 1442 CallIC::GenerateMegamorphic(masm(), argc, extra_state); 1443 } else { 1444 KeyedCallIC::GenerateMegamorphic(masm(), argc); 1445 } 1446 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic"); 1447 isolate()->counters()->call_megamorphic_stubs()->Increment(); 1448 PROFILE(isolate(), 1449 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG), 1450 *code, code->arguments_count())); 1451 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code)); 1452 return code; 1453 } 1454 1455 1456 Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) { 1457 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1458 KeyedCallIC::GenerateNonStrictArguments(masm(), argc); 1459 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments"); 1460 PROFILE(isolate(), 1461 CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags), 1462 CALL_MEGAMORPHIC_TAG), 1463 *code, code->arguments_count())); 1464 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code)); 1465 return code; 1466 } 1467 1468 1469 Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) { 1470 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1471 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1472 Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); 1473 if (kind == Code::CALL_IC) { 1474 CallIC::GenerateMiss(masm(), argc, extra_state); 1475 } else { 1476 KeyedCallIC::GenerateMiss(masm(), argc); 1477 } 1478 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss"); 1479 isolate()->counters()->call_megamorphic_stubs()->Increment(); 1480 PROFILE(isolate(), 1481 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG), 1482 *code, code->arguments_count())); 1483 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code)); 1484 return code; 1485 } 1486 1487 1488 #ifdef ENABLE_DEBUGGER_SUPPORT 1489 Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) { 1490 Debug::GenerateCallICDebugBreak(masm()); 1491 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak"); 1492 PROFILE(isolate(), 1493 CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags), 1494 CALL_DEBUG_BREAK_TAG), 1495 *code, code->arguments_count())); 1496 return code; 1497 } 1498 1499 1500 Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) { 1501 // Use the same code for the the step in preparations as we do for the 1502 // miss case. 1503 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1504 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1505 if (kind == Code::CALL_IC) { 1506 // For the debugger extra ic state is irrelevant. 1507 CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState); 1508 } else { 1509 KeyedCallIC::GenerateMiss(masm(), argc); 1510 } 1511 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn"); 1512 PROFILE(isolate(), 1513 CodeCreateEvent( 1514 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG), 1515 *code, 1516 code->arguments_count())); 1517 return code; 1518 } 1519 #endif // ENABLE_DEBUGGER_SUPPORT 1520 1521 #undef CALL_LOGGER_TAG 1522 1523 1524 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags, 1525 const char* name) { 1526 // Create code object in the heap. 1527 CodeDesc desc; 1528 masm_.GetCode(&desc); 1529 Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject()); 1530 #ifdef ENABLE_DISASSEMBLER 1531 if (FLAG_print_code_stubs) code->Disassemble(name); 1532 #endif 1533 return code; 1534 } 1535 1536 1537 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags, 1538 Handle<Name> name) { 1539 return (FLAG_print_code_stubs && !name.is_null() && name->IsString()) 1540 ? GetCodeWithFlags(flags, *Handle<String>::cast(name)->ToCString()) 1541 : GetCodeWithFlags(flags, NULL); 1542 } 1543 1544 1545 void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder, 1546 Handle<Name> name, 1547 LookupResult* lookup) { 1548 holder->LocalLookupRealNamedProperty(*name, lookup); 1549 if (lookup->IsFound()) return; 1550 if (holder->GetPrototype()->IsNull()) return; 1551 holder->GetPrototype()->Lookup(*name, lookup); 1552 } 1553 1554 1555 #define __ ACCESS_MASM(masm()) 1556 1557 1558 Register BaseLoadStubCompiler::HandlerFrontendHeader( 1559 Handle<JSObject> object, 1560 Register object_reg, 1561 Handle<JSObject> holder, 1562 Handle<Name> name, 1563 Label* miss) { 1564 return CheckPrototypes(object, object_reg, holder, 1565 scratch1(), scratch2(), scratch3(), 1566 name, miss, SKIP_RECEIVER); 1567 } 1568 1569 1570 // HandlerFrontend for store uses the name register. It has to be restored 1571 // before a miss. 1572 Register BaseStoreStubCompiler::HandlerFrontendHeader( 1573 Handle<JSObject> object, 1574 Register object_reg, 1575 Handle<JSObject> holder, 1576 Handle<Name> name, 1577 Label* miss) { 1578 return CheckPrototypes(object, object_reg, holder, 1579 this->name(), scratch1(), scratch2(), 1580 name, miss, SKIP_RECEIVER); 1581 } 1582 1583 1584 Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<JSObject> object, 1585 Register object_reg, 1586 Handle<JSObject> holder, 1587 Handle<Name> name, 1588 Label* success) { 1589 Label miss; 1590 1591 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss); 1592 1593 HandlerFrontendFooter(name, success, &miss); 1594 return reg; 1595 } 1596 1597 1598 Handle<Code> BaseLoadStubCompiler::CompileLoadField( 1599 Handle<JSObject> object, 1600 Handle<JSObject> holder, 1601 Handle<Name> name, 1602 PropertyIndex field, 1603 Representation representation) { 1604 Label miss; 1605 1606 Register reg = HandlerFrontendHeader(object, receiver(), holder, name, &miss); 1607 1608 GenerateLoadField(reg, holder, field, representation); 1609 1610 __ bind(&miss); 1611 TailCallBuiltin(masm(), MissBuiltin(kind())); 1612 1613 // Return the generated code. 1614 return GetCode(kind(), Code::FIELD, name); 1615 } 1616 1617 1618 Handle<Code> BaseLoadStubCompiler::CompileLoadConstant( 1619 Handle<JSObject> object, 1620 Handle<JSObject> holder, 1621 Handle<Name> name, 1622 Handle<Object> value) { 1623 Label success; 1624 HandlerFrontend(object, receiver(), holder, name, &success); 1625 __ bind(&success); 1626 GenerateLoadConstant(value); 1627 1628 // Return the generated code. 1629 return GetCode(kind(), Code::CONSTANT, name); 1630 } 1631 1632 1633 Handle<Code> BaseLoadStubCompiler::CompileLoadCallback( 1634 Handle<JSObject> object, 1635 Handle<JSObject> holder, 1636 Handle<Name> name, 1637 Handle<ExecutableAccessorInfo> callback) { 1638 Label success; 1639 1640 Register reg = CallbackHandlerFrontend( 1641 object, receiver(), holder, name, &success, callback); 1642 __ bind(&success); 1643 GenerateLoadCallback(reg, callback); 1644 1645 // Return the generated code. 1646 return GetCode(kind(), Code::CALLBACKS, name); 1647 } 1648 1649 1650 Handle<Code> BaseLoadStubCompiler::CompileLoadInterceptor( 1651 Handle<JSObject> object, 1652 Handle<JSObject> holder, 1653 Handle<Name> name) { 1654 Label success; 1655 1656 LookupResult lookup(isolate()); 1657 LookupPostInterceptor(holder, name, &lookup); 1658 1659 Register reg = HandlerFrontend(object, receiver(), holder, name, &success); 1660 __ bind(&success); 1661 // TODO(368): Compile in the whole chain: all the interceptors in 1662 // prototypes and ultimate answer. 1663 GenerateLoadInterceptor(reg, object, holder, &lookup, name); 1664 1665 // Return the generated code. 1666 return GetCode(kind(), Code::INTERCEPTOR, name); 1667 } 1668 1669 1670 void BaseLoadStubCompiler::GenerateLoadPostInterceptor( 1671 Register interceptor_reg, 1672 Handle<JSObject> interceptor_holder, 1673 Handle<Name> name, 1674 LookupResult* lookup) { 1675 Label success; 1676 Handle<JSObject> holder(lookup->holder()); 1677 if (lookup->IsField()) { 1678 PropertyIndex field = lookup->GetFieldIndex(); 1679 if (interceptor_holder.is_identical_to(holder)) { 1680 GenerateLoadField( 1681 interceptor_reg, holder, field, lookup->representation()); 1682 } else { 1683 // We found FIELD property in prototype chain of interceptor's holder. 1684 // Retrieve a field from field's holder. 1685 Register reg = HandlerFrontend( 1686 interceptor_holder, interceptor_reg, holder, name, &success); 1687 __ bind(&success); 1688 GenerateLoadField( 1689 reg, holder, field, lookup->representation()); 1690 } 1691 } else { 1692 // We found CALLBACKS property in prototype chain of interceptor's 1693 // holder. 1694 ASSERT(lookup->type() == CALLBACKS); 1695 Handle<ExecutableAccessorInfo> callback( 1696 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); 1697 ASSERT(callback->getter() != NULL); 1698 1699 Register reg = CallbackHandlerFrontend( 1700 interceptor_holder, interceptor_reg, holder, name, &success, callback); 1701 __ bind(&success); 1702 GenerateLoadCallback(reg, callback); 1703 } 1704 } 1705 1706 1707 Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC( 1708 Handle<Map> receiver_map, 1709 Handle<Code> handler, 1710 Handle<Name> name) { 1711 MapHandleList receiver_maps(1); 1712 receiver_maps.Add(receiver_map); 1713 CodeHandleList handlers(1); 1714 handlers.Add(handler); 1715 Code::StubType type = handler->type(); 1716 return CompilePolymorphicIC(&receiver_maps, &handlers, name, type, PROPERTY); 1717 } 1718 1719 1720 Handle<Code> LoadStubCompiler::CompileLoadViaGetter( 1721 Handle<JSObject> object, 1722 Handle<JSObject> holder, 1723 Handle<Name> name, 1724 Handle<JSFunction> getter) { 1725 Label success; 1726 HandlerFrontend(object, receiver(), holder, name, &success); 1727 1728 __ bind(&success); 1729 GenerateLoadViaGetter(masm(), getter); 1730 1731 // Return the generated code. 1732 return GetCode(kind(), Code::CALLBACKS, name); 1733 } 1734 1735 1736 Handle<Code> BaseStoreStubCompiler::CompileStoreTransition( 1737 Handle<JSObject> object, 1738 LookupResult* lookup, 1739 Handle<Map> transition, 1740 Handle<Name> name) { 1741 Label miss, slow; 1742 1743 // Ensure no transitions to deprecated maps are followed. 1744 __ CheckMapDeprecated(transition, scratch1(), &miss); 1745 1746 // Check that we are allowed to write this. 1747 if (object->GetPrototype()->IsJSObject()) { 1748 Handle<JSObject> holder; 1749 // holder == object indicates that no property was found. 1750 if (lookup->holder() != *object) { 1751 holder = Handle<JSObject>(lookup->holder()); 1752 } else { 1753 // Find the top object. 1754 holder = object; 1755 do { 1756 holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype())); 1757 } while (holder->GetPrototype()->IsJSObject()); 1758 } 1759 1760 Register holder_reg = 1761 HandlerFrontendHeader(object, receiver(), holder, name, &miss); 1762 1763 // If no property was found, and the holder (the last object in the 1764 // prototype chain) is in slow mode, we need to do a negative lookup on the 1765 // holder. 1766 if (lookup->holder() == *object) { 1767 GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss); 1768 } 1769 } 1770 1771 GenerateStoreTransition(masm(), 1772 object, 1773 lookup, 1774 transition, 1775 name, 1776 receiver(), this->name(), value(), 1777 scratch1(), scratch2(), scratch3(), 1778 &miss, 1779 &slow); 1780 1781 // Handle store cache miss. 1782 GenerateRestoreName(masm(), &miss, name); 1783 TailCallBuiltin(masm(), MissBuiltin(kind())); 1784 1785 GenerateRestoreName(masm(), &slow, name); 1786 TailCallBuiltin(masm(), SlowBuiltin(kind())); 1787 1788 // Return the generated code. 1789 return GetCode(kind(), Code::MAP_TRANSITION, name); 1790 } 1791 1792 1793 Handle<Code> BaseStoreStubCompiler::CompileStoreField(Handle<JSObject> object, 1794 LookupResult* lookup, 1795 Handle<Name> name) { 1796 Label miss; 1797 1798 HandlerFrontendHeader(object, receiver(), object, name, &miss); 1799 1800 // Generate store field code. 1801 GenerateStoreField(masm(), 1802 object, 1803 lookup, 1804 receiver(), this->name(), value(), scratch1(), scratch2(), 1805 &miss); 1806 1807 // Handle store cache miss. 1808 __ bind(&miss); 1809 TailCallBuiltin(masm(), MissBuiltin(kind())); 1810 1811 // Return the generated code. 1812 return GetCode(kind(), Code::FIELD, name); 1813 } 1814 1815 1816 Handle<Code> StoreStubCompiler::CompileStoreViaSetter( 1817 Handle<JSObject> object, 1818 Handle<JSObject> holder, 1819 Handle<Name> name, 1820 Handle<JSFunction> setter) { 1821 Label success; 1822 HandlerFrontend(object, receiver(), holder, name, &success); 1823 1824 __ bind(&success); 1825 GenerateStoreViaSetter(masm(), setter); 1826 1827 return GetCode(kind(), Code::CALLBACKS, name); 1828 } 1829 1830 1831 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( 1832 Handle<Map> receiver_map) { 1833 ElementsKind elements_kind = receiver_map->elements_kind(); 1834 if (receiver_map->has_fast_elements() || 1835 receiver_map->has_external_array_elements()) { 1836 Handle<Code> stub = KeyedLoadFastElementStub( 1837 receiver_map->instance_type() == JS_ARRAY_TYPE, 1838 elements_kind).GetCode(isolate()); 1839 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); 1840 } else { 1841 Handle<Code> stub = 1842 KeyedLoadDictionaryElementStub().GetCode(isolate()); 1843 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); 1844 } 1845 1846 TailCallBuiltin(masm(), Builtins::kKeyedLoadIC_Miss); 1847 1848 // Return the generated code. 1849 return GetICCode(kind(), Code::NORMAL, factory()->empty_string()); 1850 } 1851 1852 1853 Handle<Code> KeyedStoreStubCompiler::CompileStoreElement( 1854 Handle<Map> receiver_map) { 1855 ElementsKind elements_kind = receiver_map->elements_kind(); 1856 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; 1857 Handle<Code> stub; 1858 if (FLAG_compiled_keyed_stores && 1859 (receiver_map->has_fast_elements() || 1860 receiver_map->has_external_array_elements())) { 1861 stub = KeyedStoreFastElementStub( 1862 is_jsarray, 1863 elements_kind, 1864 store_mode_).GetCode(isolate()); 1865 } else { 1866 stub = KeyedStoreElementStub(is_jsarray, 1867 elements_kind, 1868 store_mode_).GetCode(isolate()); 1869 } 1870 1871 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); 1872 1873 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); 1874 1875 // Return the generated code. 1876 return GetICCode(kind(), Code::NORMAL, factory()->empty_string()); 1877 } 1878 1879 1880 #undef __ 1881 1882 1883 void StubCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) { 1884 Handle<Code> code(masm->isolate()->builtins()->builtin(name)); 1885 GenerateTailCall(masm, code); 1886 } 1887 1888 1889 void LoadStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) { 1890 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code)); 1891 } 1892 1893 1894 void KeyedLoadStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) { 1895 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code)); 1896 } 1897 1898 1899 void StoreStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) { 1900 GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code)); 1901 } 1902 1903 1904 void KeyedStoreStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) { 1905 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code)); 1906 } 1907 1908 1909 Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind, 1910 Code::StubType type, 1911 Handle<Name> name, 1912 InlineCacheState state) { 1913 Code::Flags flags = Code::ComputeFlags( 1914 kind, state, extra_state(), type); 1915 Handle<Code> code = GetCodeWithFlags(flags, name); 1916 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); 1917 JitEvent(name, code); 1918 return code; 1919 } 1920 1921 1922 Handle<Code> BaseLoadStubCompiler::GetCode(Code::Kind kind, 1923 Code::StubType type, 1924 Handle<Name> name) { 1925 ASSERT(type != Code::NORMAL); 1926 Code::Flags flags = Code::ComputeFlags( 1927 Code::STUB, MONOMORPHIC, Code::kNoExtraICState, type, kind); 1928 Handle<Code> code = GetCodeWithFlags(flags, name); 1929 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); 1930 JitEvent(name, code); 1931 return code; 1932 } 1933 1934 1935 Handle<Code> BaseStoreStubCompiler::GetCode(Code::Kind kind, 1936 Code::StubType type, 1937 Handle<Name> name) { 1938 ASSERT(type != Code::NORMAL); 1939 Code::Flags flags = Code::ComputeFlags( 1940 Code::STUB, MONOMORPHIC, extra_state(), type, kind); 1941 Handle<Code> code = GetCodeWithFlags(flags, name); 1942 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); 1943 JitEvent(name, code); 1944 return code; 1945 } 1946 1947 1948 void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps, 1949 CodeHandleList* handlers) { 1950 for (int i = 0; i < receiver_maps->length(); ++i) { 1951 Handle<Map> receiver_map = receiver_maps->at(i); 1952 Handle<Code> cached_stub; 1953 1954 if ((receiver_map->instance_type() & kNotStringTag) == 0) { 1955 cached_stub = isolate()->builtins()->KeyedLoadIC_String(); 1956 } else { 1957 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; 1958 ElementsKind elements_kind = receiver_map->elements_kind(); 1959 1960 if (IsFastElementsKind(elements_kind) || 1961 IsExternalArrayElementsKind(elements_kind)) { 1962 cached_stub = 1963 KeyedLoadFastElementStub(is_js_array, 1964 elements_kind).GetCode(isolate()); 1965 } else { 1966 ASSERT(elements_kind == DICTIONARY_ELEMENTS); 1967 cached_stub = KeyedLoadDictionaryElementStub().GetCode(isolate()); 1968 } 1969 } 1970 1971 handlers->Add(cached_stub); 1972 } 1973 } 1974 1975 1976 Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic( 1977 MapHandleList* receiver_maps) { 1978 // Collect MONOMORPHIC stubs for all |receiver_maps|. 1979 CodeHandleList handlers(receiver_maps->length()); 1980 MapHandleList transitioned_maps(receiver_maps->length()); 1981 for (int i = 0; i < receiver_maps->length(); ++i) { 1982 Handle<Map> receiver_map(receiver_maps->at(i)); 1983 Handle<Code> cached_stub; 1984 Handle<Map> transitioned_map = 1985 receiver_map->FindTransitionedMap(receiver_maps); 1986 1987 // TODO(mvstanton): The code below is doing pessimistic elements 1988 // transitions. I would like to stop doing that and rely on Allocation Site 1989 // Tracking to do a better job of ensuring the data types are what they need 1990 // to be. Not all the elements are in place yet, pessimistic elements 1991 // transitions are still important for performance. 1992 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; 1993 ElementsKind elements_kind = receiver_map->elements_kind(); 1994 if (!transitioned_map.is_null()) { 1995 cached_stub = ElementsTransitionAndStoreStub( 1996 elements_kind, 1997 transitioned_map->elements_kind(), 1998 is_js_array, 1999 store_mode_).GetCode(isolate()); 2000 } else { 2001 if (FLAG_compiled_keyed_stores && 2002 (receiver_map->has_fast_elements() || 2003 receiver_map->has_external_array_elements())) { 2004 cached_stub = KeyedStoreFastElementStub( 2005 is_js_array, 2006 elements_kind, 2007 store_mode_).GetCode(isolate()); 2008 } else { 2009 cached_stub = KeyedStoreElementStub( 2010 is_js_array, 2011 elements_kind, 2012 store_mode_).GetCode(isolate()); 2013 } 2014 } 2015 ASSERT(!cached_stub.is_null()); 2016 handlers.Add(cached_stub); 2017 transitioned_maps.Add(transitioned_map); 2018 } 2019 Handle<Code> code = 2020 CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps); 2021 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); 2022 PROFILE(isolate(), 2023 CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0)); 2024 return code; 2025 } 2026 2027 2028 void KeyedStoreStubCompiler::GenerateStoreDictionaryElement( 2029 MacroAssembler* masm) { 2030 KeyedStoreIC::GenerateSlow(masm); 2031 } 2032 2033 2034 CallStubCompiler::CallStubCompiler(Isolate* isolate, 2035 int argc, 2036 Code::Kind kind, 2037 Code::ExtraICState extra_state, 2038 InlineCacheHolderFlag cache_holder) 2039 : StubCompiler(isolate), 2040 arguments_(argc), 2041 kind_(kind), 2042 extra_state_(extra_state), 2043 cache_holder_(cache_holder) { 2044 } 2045 2046 2047 bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) { 2048 if (function->shared()->HasBuiltinFunctionId()) { 2049 BuiltinFunctionId id = function->shared()->builtin_function_id(); 2050 #define CALL_GENERATOR_CASE(name) if (id == k##name) return true; 2051 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE) 2052 #undef CALL_GENERATOR_CASE 2053 } 2054 2055 CallOptimization optimization(function); 2056 return optimization.is_simple_api_call(); 2057 } 2058 2059 2060 bool CallStubCompiler::CanBeCached(Handle<JSFunction> function) { 2061 if (function->shared()->HasBuiltinFunctionId()) { 2062 BuiltinFunctionId id = function->shared()->builtin_function_id(); 2063 #define CALL_GENERATOR_CASE(name) if (id == k##name) return false; 2064 SITE_SPECIFIC_CALL_GENERATORS(CALL_GENERATOR_CASE) 2065 #undef CALL_GENERATOR_CASE 2066 } 2067 2068 return true; 2069 } 2070 2071 2072 Handle<Code> CallStubCompiler::CompileCustomCall( 2073 Handle<Object> object, 2074 Handle<JSObject> holder, 2075 Handle<Cell> cell, 2076 Handle<JSFunction> function, 2077 Handle<String> fname, 2078 Code::StubType type) { 2079 ASSERT(HasCustomCallGenerator(function)); 2080 2081 if (function->shared()->HasBuiltinFunctionId()) { 2082 BuiltinFunctionId id = function->shared()->builtin_function_id(); 2083 #define CALL_GENERATOR_CASE(name) \ 2084 if (id == k##name) { \ 2085 return CallStubCompiler::Compile##name##Call(object, \ 2086 holder, \ 2087 cell, \ 2088 function, \ 2089 fname, \ 2090 type); \ 2091 } 2092 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE) 2093 #undef CALL_GENERATOR_CASE 2094 } 2095 CallOptimization optimization(function); 2096 ASSERT(optimization.is_simple_api_call()); 2097 return CompileFastApiCall(optimization, 2098 object, 2099 holder, 2100 cell, 2101 function, 2102 fname); 2103 } 2104 2105 2106 Handle<Code> CallStubCompiler::GetCode(Code::StubType type, 2107 Handle<Name> name) { 2108 int argc = arguments_.immediate(); 2109 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_, 2110 extra_state_, 2111 type, 2112 argc, 2113 cache_holder_); 2114 return GetCodeWithFlags(flags, name); 2115 } 2116 2117 2118 Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) { 2119 Handle<String> function_name; 2120 if (function->shared()->name()->IsString()) { 2121 function_name = Handle<String>(String::cast(function->shared()->name())); 2122 } 2123 return GetCode(Code::CONSTANT, function_name); 2124 } 2125 2126 2127 CallOptimization::CallOptimization(LookupResult* lookup) { 2128 if (lookup->IsFound() && 2129 lookup->IsCacheable() && 2130 lookup->IsConstantFunction()) { 2131 // We only optimize constant function calls. 2132 Initialize(Handle<JSFunction>(lookup->GetConstantFunction())); 2133 } else { 2134 Initialize(Handle<JSFunction>::null()); 2135 } 2136 } 2137 2138 2139 CallOptimization::CallOptimization(Handle<JSFunction> function) { 2140 Initialize(function); 2141 } 2142 2143 2144 int CallOptimization::GetPrototypeDepthOfExpectedType( 2145 Handle<JSObject> object, 2146 Handle<JSObject> holder) const { 2147 ASSERT(is_simple_api_call()); 2148 if (expected_receiver_type_.is_null()) return 0; 2149 int depth = 0; 2150 while (!object.is_identical_to(holder)) { 2151 if (object->IsInstanceOf(*expected_receiver_type_)) return depth; 2152 object = Handle<JSObject>(JSObject::cast(object->GetPrototype())); 2153 if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth; 2154 ++depth; 2155 } 2156 if (holder->IsInstanceOf(*expected_receiver_type_)) return depth; 2157 return kInvalidProtoDepth; 2158 } 2159 2160 2161 void CallOptimization::Initialize(Handle<JSFunction> function) { 2162 constant_function_ = Handle<JSFunction>::null(); 2163 is_simple_api_call_ = false; 2164 expected_receiver_type_ = Handle<FunctionTemplateInfo>::null(); 2165 api_call_info_ = Handle<CallHandlerInfo>::null(); 2166 2167 if (function.is_null() || !function->is_compiled()) return; 2168 2169 constant_function_ = function; 2170 AnalyzePossibleApiFunction(function); 2171 } 2172 2173 2174 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) { 2175 if (!function->shared()->IsApiFunction()) return; 2176 Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data()); 2177 2178 // Require a C++ callback. 2179 if (info->call_code()->IsUndefined()) return; 2180 api_call_info_ = 2181 Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code())); 2182 2183 // Accept signatures that either have no restrictions at all or 2184 // only have restrictions on the receiver. 2185 if (!info->signature()->IsUndefined()) { 2186 Handle<SignatureInfo> signature = 2187 Handle<SignatureInfo>(SignatureInfo::cast(info->signature())); 2188 if (!signature->args()->IsUndefined()) return; 2189 if (!signature->receiver()->IsUndefined()) { 2190 expected_receiver_type_ = 2191 Handle<FunctionTemplateInfo>( 2192 FunctionTemplateInfo::cast(signature->receiver())); 2193 } 2194 } 2195 2196 is_simple_api_call_ = true; 2197 } 2198 2199 2200 } } // namespace v8::internal 2201