stub-cache.cc revision b0fe1620dcb4135ac3ab2d66ff93072373911299
1// Copyright 2006-2009 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 "ic-inl.h" 33#include "stub-cache.h" 34#include "vm-state-inl.h" 35 36namespace v8 { 37namespace internal { 38 39// ----------------------------------------------------------------------- 40// StubCache implementation. 41 42 43StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize]; 44StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize]; 45 46void StubCache::Initialize(bool create_heap_objects) { 47 ASSERT(IsPowerOf2(kPrimaryTableSize)); 48 ASSERT(IsPowerOf2(kSecondaryTableSize)); 49 if (create_heap_objects) { 50 HandleScope scope; 51 Clear(); 52 } 53} 54 55 56Code* StubCache::Set(String* name, Map* map, Code* code) { 57 // Get the flags from the code. 58 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); 59 60 // Validate that the name does not move on scavenge, and that we 61 // can use identity checks instead of string equality checks. 62 ASSERT(!Heap::InNewSpace(name)); 63 ASSERT(name->IsSymbol()); 64 65 // The state bits are not important to the hash function because 66 // the stub cache only contains monomorphic stubs. Make sure that 67 // the bits are the least significant so they will be the ones 68 // masked out. 69 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC); 70 ASSERT(Code::kFlagsICStateShift == 0); 71 72 // Make sure that the code type is not included in the hash. 73 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); 74 75 // Compute the primary entry. 76 int primary_offset = PrimaryOffset(name, flags, map); 77 Entry* primary = entry(primary_, primary_offset); 78 Code* hit = primary->value; 79 80 // If the primary entry has useful data in it, we retire it to the 81 // secondary cache before overwriting it. 82 if (hit != Builtins::builtin(Builtins::Illegal)) { 83 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags()); 84 int secondary_offset = 85 SecondaryOffset(primary->key, primary_flags, primary_offset); 86 Entry* secondary = entry(secondary_, secondary_offset); 87 *secondary = *primary; 88 } 89 90 // Update primary cache. 91 primary->key = name; 92 primary->value = code; 93 return code; 94} 95 96 97MaybeObject* StubCache::ComputeLoadNonexistent(String* name, 98 JSObject* receiver) { 99 ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties()); 100 // If no global objects are present in the prototype chain, the load 101 // nonexistent IC stub can be shared for all names for a given map 102 // and we use the empty string for the map cache in that case. If 103 // there are global objects involved, we need to check global 104 // property cells in the stub and therefore the stub will be 105 // specific to the name. 106 String* cache_name = Heap::empty_string(); 107 if (receiver->IsGlobalObject()) cache_name = name; 108 JSObject* last = receiver; 109 while (last->GetPrototype() != Heap::null_value()) { 110 last = JSObject::cast(last->GetPrototype()); 111 if (last->IsGlobalObject()) cache_name = name; 112 } 113 // Compile the stub that is either shared for all names or 114 // name specific if there are global objects involved. 115 Code::Flags flags = 116 Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT); 117 Object* code = receiver->map()->FindInCodeCache(cache_name, flags); 118 if (code->IsUndefined()) { 119 LoadStubCompiler compiler; 120 { MaybeObject* maybe_code = 121 compiler.CompileLoadNonexistent(cache_name, receiver, last); 122 if (!maybe_code->ToObject(&code)) return maybe_code; 123 } 124 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name)); 125 Object* result; 126 { MaybeObject* maybe_result = 127 receiver->UpdateMapCodeCache(cache_name, Code::cast(code)); 128 if (!maybe_result->ToObject(&result)) return maybe_result; 129 } 130 } 131 return code; 132} 133 134 135MaybeObject* StubCache::ComputeLoadField(String* name, 136 JSObject* receiver, 137 JSObject* holder, 138 int field_index) { 139 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP); 140 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD); 141 Object* code = receiver->map()->FindInCodeCache(name, flags); 142 if (code->IsUndefined()) { 143 LoadStubCompiler compiler; 144 { MaybeObject* maybe_code = 145 compiler.CompileLoadField(receiver, holder, field_index, name); 146 if (!maybe_code->ToObject(&code)) return maybe_code; 147 } 148 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 149 Object* result; 150 { MaybeObject* maybe_result = 151 receiver->UpdateMapCodeCache(name, Code::cast(code)); 152 if (!maybe_result->ToObject(&result)) return maybe_result; 153 } 154 } 155 return code; 156} 157 158 159MaybeObject* StubCache::ComputeLoadCallback(String* name, 160 JSObject* receiver, 161 JSObject* holder, 162 AccessorInfo* callback) { 163 ASSERT(v8::ToCData<Address>(callback->getter()) != 0); 164 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP); 165 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS); 166 Object* code = receiver->map()->FindInCodeCache(name, flags); 167 if (code->IsUndefined()) { 168 LoadStubCompiler compiler; 169 { MaybeObject* maybe_code = 170 compiler.CompileLoadCallback(name, receiver, holder, callback); 171 if (!maybe_code->ToObject(&code)) return maybe_code; 172 } 173 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 174 Object* result; 175 { MaybeObject* maybe_result = 176 receiver->UpdateMapCodeCache(name, Code::cast(code)); 177 if (!maybe_result->ToObject(&result)) return maybe_result; 178 } 179 } 180 return code; 181} 182 183 184MaybeObject* StubCache::ComputeLoadConstant(String* name, 185 JSObject* receiver, 186 JSObject* holder, 187 Object* value) { 188 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP); 189 Code::Flags flags = 190 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION); 191 Object* code = receiver->map()->FindInCodeCache(name, flags); 192 if (code->IsUndefined()) { 193 LoadStubCompiler compiler; 194 { MaybeObject* maybe_code = 195 compiler.CompileLoadConstant(receiver, holder, value, name); 196 if (!maybe_code->ToObject(&code)) return maybe_code; 197 } 198 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 199 Object* result; 200 { MaybeObject* maybe_result = 201 receiver->UpdateMapCodeCache(name, Code::cast(code)); 202 if (!maybe_result->ToObject(&result)) return maybe_result; 203 } 204 } 205 return code; 206} 207 208 209MaybeObject* StubCache::ComputeLoadInterceptor(String* name, 210 JSObject* receiver, 211 JSObject* holder) { 212 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP); 213 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR); 214 Object* code = receiver->map()->FindInCodeCache(name, flags); 215 if (code->IsUndefined()) { 216 LoadStubCompiler compiler; 217 { MaybeObject* maybe_code = 218 compiler.CompileLoadInterceptor(receiver, holder, name); 219 if (!maybe_code->ToObject(&code)) return maybe_code; 220 } 221 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 222 Object* result; 223 { MaybeObject* maybe_result = 224 receiver->UpdateMapCodeCache(name, Code::cast(code)); 225 if (!maybe_result->ToObject(&result)) return maybe_result; 226 } 227 } 228 return code; 229} 230 231 232MaybeObject* StubCache::ComputeLoadNormal() { 233 return Builtins::builtin(Builtins::LoadIC_Normal); 234} 235 236 237MaybeObject* StubCache::ComputeLoadGlobal(String* name, 238 JSObject* receiver, 239 GlobalObject* holder, 240 JSGlobalPropertyCell* cell, 241 bool is_dont_delete) { 242 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP); 243 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL); 244 Object* code = receiver->map()->FindInCodeCache(name, flags); 245 if (code->IsUndefined()) { 246 LoadStubCompiler compiler; 247 { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver, 248 holder, 249 cell, 250 name, 251 is_dont_delete); 252 if (!maybe_code->ToObject(&code)) return maybe_code; 253 } 254 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); 255 Object* result; 256 { MaybeObject* maybe_result = 257 receiver->UpdateMapCodeCache(name, Code::cast(code)); 258 if (!maybe_result->ToObject(&result)) return maybe_result; 259 } 260 } 261 return code; 262} 263 264 265MaybeObject* StubCache::ComputeKeyedLoadField(String* name, 266 JSObject* receiver, 267 JSObject* holder, 268 int field_index) { 269 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP); 270 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD); 271 Object* code = receiver->map()->FindInCodeCache(name, flags); 272 if (code->IsUndefined()) { 273 KeyedLoadStubCompiler compiler; 274 { MaybeObject* maybe_code = 275 compiler.CompileLoadField(name, receiver, holder, field_index); 276 if (!maybe_code->ToObject(&code)) return maybe_code; 277 } 278 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); 279 Object* result; 280 { MaybeObject* maybe_result = 281 receiver->UpdateMapCodeCache(name, Code::cast(code)); 282 if (!maybe_result->ToObject(&result)) return maybe_result; 283 } 284 } 285 return code; 286} 287 288 289MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name, 290 JSObject* receiver, 291 JSObject* holder, 292 Object* value) { 293 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP); 294 Code::Flags flags = 295 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION); 296 Object* code = receiver->map()->FindInCodeCache(name, flags); 297 if (code->IsUndefined()) { 298 KeyedLoadStubCompiler compiler; 299 { MaybeObject* maybe_code = 300 compiler.CompileLoadConstant(name, receiver, holder, value); 301 if (!maybe_code->ToObject(&code)) return maybe_code; 302 } 303 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); 304 Object* result; 305 { MaybeObject* maybe_result = 306 receiver->UpdateMapCodeCache(name, Code::cast(code)); 307 if (!maybe_result->ToObject(&result)) return maybe_result; 308 } 309 } 310 return code; 311} 312 313 314MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name, 315 JSObject* receiver, 316 JSObject* holder) { 317 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP); 318 Code::Flags flags = 319 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR); 320 Object* code = receiver->map()->FindInCodeCache(name, flags); 321 if (code->IsUndefined()) { 322 KeyedLoadStubCompiler compiler; 323 { MaybeObject* maybe_code = 324 compiler.CompileLoadInterceptor(receiver, holder, name); 325 if (!maybe_code->ToObject(&code)) return maybe_code; 326 } 327 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); 328 Object* result; 329 { MaybeObject* maybe_result = 330 receiver->UpdateMapCodeCache(name, Code::cast(code)); 331 if (!maybe_result->ToObject(&result)) return maybe_result; 332 } 333 } 334 return code; 335} 336 337 338MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name, 339 JSObject* receiver, 340 JSObject* holder, 341 AccessorInfo* callback) { 342 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP); 343 Code::Flags flags = 344 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS); 345 Object* code = receiver->map()->FindInCodeCache(name, flags); 346 if (code->IsUndefined()) { 347 KeyedLoadStubCompiler compiler; 348 { MaybeObject* maybe_code = 349 compiler.CompileLoadCallback(name, receiver, holder, callback); 350 if (!maybe_code->ToObject(&code)) return maybe_code; 351 } 352 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); 353 Object* result; 354 { MaybeObject* maybe_result = 355 receiver->UpdateMapCodeCache(name, Code::cast(code)); 356 if (!maybe_result->ToObject(&result)) return maybe_result; 357 } 358 } 359 return code; 360} 361 362 363 364MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name, 365 JSArray* receiver) { 366 Code::Flags flags = 367 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS); 368 ASSERT(receiver->IsJSObject()); 369 Object* code = receiver->map()->FindInCodeCache(name, flags); 370 if (code->IsUndefined()) { 371 KeyedLoadStubCompiler compiler; 372 { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name); 373 if (!maybe_code->ToObject(&code)) return maybe_code; 374 } 375 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); 376 Object* result; 377 { MaybeObject* maybe_result = 378 receiver->UpdateMapCodeCache(name, Code::cast(code)); 379 if (!maybe_result->ToObject(&result)) return maybe_result; 380 } 381 } 382 return code; 383} 384 385 386MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name, 387 String* receiver) { 388 Code::Flags flags = 389 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS); 390 Map* map = receiver->map(); 391 Object* code = map->FindInCodeCache(name, flags); 392 if (code->IsUndefined()) { 393 KeyedLoadStubCompiler compiler; 394 { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name); 395 if (!maybe_code->ToObject(&code)) return maybe_code; 396 } 397 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); 398 Object* result; 399 { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code)); 400 if (!maybe_result->ToObject(&result)) return maybe_result; 401 } 402 } 403 return code; 404} 405 406 407MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype( 408 String* name, 409 JSFunction* receiver) { 410 Code::Flags flags = 411 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS); 412 Object* code = receiver->map()->FindInCodeCache(name, flags); 413 if (code->IsUndefined()) { 414 KeyedLoadStubCompiler compiler; 415 { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name); 416 if (!maybe_code->ToObject(&code)) return maybe_code; 417 } 418 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); 419 Object* result; 420 { MaybeObject* maybe_result = 421 receiver->UpdateMapCodeCache(name, Code::cast(code)); 422 if (!maybe_result->ToObject(&result)) return maybe_result; 423 } 424 } 425 return code; 426} 427 428 429MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) { 430 Code::Flags flags = 431 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL); 432 String* name = Heap::KeyedLoadSpecialized_symbol(); 433 Object* code = receiver->map()->FindInCodeCache(name, flags); 434 if (code->IsUndefined()) { 435 KeyedLoadStubCompiler compiler; 436 { MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver); 437 if (!maybe_code->ToObject(&code)) return maybe_code; 438 } 439 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0)); 440 Object* result; 441 { MaybeObject* maybe_result = 442 receiver->UpdateMapCodeCache(name, Code::cast(code)); 443 if (!maybe_result->ToObject(&result)) return maybe_result; 444 } 445 } 446 return code; 447} 448 449 450MaybeObject* StubCache::ComputeStoreField(String* name, 451 JSObject* receiver, 452 int field_index, 453 Map* transition) { 454 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION; 455 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type); 456 Object* code = receiver->map()->FindInCodeCache(name, flags); 457 if (code->IsUndefined()) { 458 StoreStubCompiler compiler; 459 { MaybeObject* maybe_code = 460 compiler.CompileStoreField(receiver, field_index, transition, name); 461 if (!maybe_code->ToObject(&code)) return maybe_code; 462 } 463 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name)); 464 Object* result; 465 { MaybeObject* maybe_result = 466 receiver->UpdateMapCodeCache(name, Code::cast(code)); 467 if (!maybe_result->ToObject(&result)) return maybe_result; 468 } 469 } 470 return code; 471} 472 473 474MaybeObject* StubCache::ComputeKeyedStoreSpecialized(JSObject* receiver) { 475 Code::Flags flags = 476 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL); 477 String* name = Heap::KeyedStoreSpecialized_symbol(); 478 Object* code = receiver->map()->FindInCodeCache(name, flags); 479 if (code->IsUndefined()) { 480 KeyedStoreStubCompiler compiler; 481 { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver); 482 if (!maybe_code->ToObject(&code)) return maybe_code; 483 } 484 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0)); 485 Object* result; 486 { MaybeObject* maybe_result = 487 receiver->UpdateMapCodeCache(name, Code::cast(code)); 488 if (!maybe_result->ToObject(&result)) return maybe_result; 489 } 490 } 491 return code; 492} 493 494 495MaybeObject* StubCache::ComputeStoreNormal() { 496 return Builtins::builtin(Builtins::StoreIC_Normal); 497} 498 499 500MaybeObject* StubCache::ComputeStoreGlobal(String* name, 501 GlobalObject* receiver, 502 JSGlobalPropertyCell* cell) { 503 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL); 504 Object* code = receiver->map()->FindInCodeCache(name, flags); 505 if (code->IsUndefined()) { 506 StoreStubCompiler compiler; 507 { MaybeObject* maybe_code = 508 compiler.CompileStoreGlobal(receiver, cell, name); 509 if (!maybe_code->ToObject(&code)) return maybe_code; 510 } 511 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name)); 512 Object* result; 513 { MaybeObject* maybe_result = 514 receiver->UpdateMapCodeCache(name, Code::cast(code)); 515 if (!maybe_result->ToObject(&result)) return maybe_result; 516 } 517 } 518 return code; 519} 520 521 522MaybeObject* StubCache::ComputeStoreCallback(String* name, 523 JSObject* receiver, 524 AccessorInfo* callback) { 525 ASSERT(v8::ToCData<Address>(callback->setter()) != 0); 526 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS); 527 Object* code = receiver->map()->FindInCodeCache(name, flags); 528 if (code->IsUndefined()) { 529 StoreStubCompiler compiler; 530 { MaybeObject* maybe_code = 531 compiler.CompileStoreCallback(receiver, callback, name); 532 if (!maybe_code->ToObject(&code)) return maybe_code; 533 } 534 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name)); 535 Object* result; 536 { MaybeObject* maybe_result = 537 receiver->UpdateMapCodeCache(name, Code::cast(code)); 538 if (!maybe_result->ToObject(&result)) return maybe_result; 539 } 540 } 541 return code; 542} 543 544 545MaybeObject* StubCache::ComputeStoreInterceptor(String* name, 546 JSObject* receiver) { 547 Code::Flags flags = 548 Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR); 549 Object* code = receiver->map()->FindInCodeCache(name, flags); 550 if (code->IsUndefined()) { 551 StoreStubCompiler compiler; 552 { MaybeObject* maybe_code = 553 compiler.CompileStoreInterceptor(receiver, name); 554 if (!maybe_code->ToObject(&code)) return maybe_code; 555 } 556 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name)); 557 Object* result; 558 { MaybeObject* maybe_result = 559 receiver->UpdateMapCodeCache(name, Code::cast(code)); 560 if (!maybe_result->ToObject(&result)) return maybe_result; 561 } 562 } 563 return code; 564} 565 566 567MaybeObject* StubCache::ComputeKeyedStoreField(String* name, 568 JSObject* receiver, 569 int field_index, 570 Map* transition) { 571 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION; 572 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type); 573 Object* code = receiver->map()->FindInCodeCache(name, flags); 574 if (code->IsUndefined()) { 575 KeyedStoreStubCompiler compiler; 576 { MaybeObject* maybe_code = 577 compiler.CompileStoreField(receiver, field_index, transition, name); 578 if (!maybe_code->ToObject(&code)) return maybe_code; 579 } 580 PROFILE(CodeCreateEvent( 581 Logger::KEYED_STORE_IC_TAG, Code::cast(code), name)); 582 Object* result; 583 { MaybeObject* maybe_result = 584 receiver->UpdateMapCodeCache(name, Code::cast(code)); 585 if (!maybe_result->ToObject(&result)) return maybe_result; 586 } 587 } 588 return code; 589} 590 591#define CALL_LOGGER_TAG(kind, type) \ 592 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type) 593 594MaybeObject* StubCache::ComputeCallConstant(int argc, 595 InLoopFlag in_loop, 596 Code::Kind kind, 597 String* name, 598 Object* object, 599 JSObject* holder, 600 JSFunction* function) { 601 // Compute the check type and the map. 602 InlineCacheHolderFlag cache_holder = 603 IC::GetCodeCacheForObject(object, holder); 604 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder); 605 606 // Compute check type based on receiver/holder. 607 CheckType check = RECEIVER_MAP_CHECK; 608 if (object->IsString()) { 609 check = STRING_CHECK; 610 } else if (object->IsNumber()) { 611 check = NUMBER_CHECK; 612 } else if (object->IsBoolean()) { 613 check = BOOLEAN_CHECK; 614 } 615 616 Code::Flags flags = 617 Code::ComputeMonomorphicFlags(kind, 618 CONSTANT_FUNCTION, 619 cache_holder, 620 in_loop, 621 argc); 622 Object* code = map_holder->map()->FindInCodeCache(name, flags); 623 if (code->IsUndefined()) { 624 // If the function hasn't been compiled yet, we cannot do it now 625 // because it may cause GC. To avoid this issue, we return an 626 // internal error which will make sure we do not update any 627 // caches. 628 if (!function->is_compiled()) return Failure::InternalError(); 629 // Compile the stub - only create stubs for fully compiled functions. 630 CallStubCompiler compiler(argc, in_loop, kind, cache_holder); 631 { MaybeObject* maybe_code = 632 compiler.CompileCallConstant(object, holder, function, name, check); 633 if (!maybe_code->ToObject(&code)) return maybe_code; 634 } 635 Code::cast(code)->set_check_type(check); 636 ASSERT_EQ(flags, Code::cast(code)->flags()); 637 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), 638 Code::cast(code), name)); 639 Object* result; 640 { MaybeObject* maybe_result = 641 map_holder->UpdateMapCodeCache(name, Code::cast(code)); 642 if (!maybe_result->ToObject(&result)) return maybe_result; 643 } 644 } 645 return code; 646} 647 648 649MaybeObject* StubCache::ComputeCallField(int argc, 650 InLoopFlag in_loop, 651 Code::Kind kind, 652 String* name, 653 Object* object, 654 JSObject* holder, 655 int index) { 656 // Compute the check type and the map. 657 InlineCacheHolderFlag cache_holder = 658 IC::GetCodeCacheForObject(object, holder); 659 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder); 660 661 // TODO(1233596): We cannot do receiver map check for non-JS objects 662 // because they may be represented as immediates without a 663 // map. Instead, we check against the map in the holder. 664 if (object->IsNumber() || object->IsBoolean() || object->IsString()) { 665 object = holder; 666 } 667 668 Code::Flags flags = Code::ComputeMonomorphicFlags(kind, 669 FIELD, 670 cache_holder, 671 in_loop, 672 argc); 673 Object* code = map_holder->map()->FindInCodeCache(name, flags); 674 if (code->IsUndefined()) { 675 CallStubCompiler compiler(argc, in_loop, kind, cache_holder); 676 { MaybeObject* maybe_code = 677 compiler.CompileCallField(JSObject::cast(object), 678 holder, 679 index, 680 name); 681 if (!maybe_code->ToObject(&code)) return maybe_code; 682 } 683 ASSERT_EQ(flags, Code::cast(code)->flags()); 684 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), 685 Code::cast(code), name)); 686 Object* result; 687 { MaybeObject* maybe_result = 688 map_holder->UpdateMapCodeCache(name, Code::cast(code)); 689 if (!maybe_result->ToObject(&result)) return maybe_result; 690 } 691 } 692 return code; 693} 694 695 696MaybeObject* StubCache::ComputeCallInterceptor(int argc, 697 Code::Kind kind, 698 String* name, 699 Object* object, 700 JSObject* holder) { 701 // Compute the check type and the map. 702 InlineCacheHolderFlag cache_holder = 703 IC::GetCodeCacheForObject(object, holder); 704 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder); 705 706 // TODO(1233596): We cannot do receiver map check for non-JS objects 707 // because they may be represented as immediates without a 708 // map. Instead, we check against the map in the holder. 709 if (object->IsNumber() || object->IsBoolean() || object->IsString()) { 710 object = holder; 711 } 712 713 Code::Flags flags = 714 Code::ComputeMonomorphicFlags(kind, 715 INTERCEPTOR, 716 cache_holder, 717 NOT_IN_LOOP, 718 argc); 719 Object* code = map_holder->map()->FindInCodeCache(name, flags); 720 if (code->IsUndefined()) { 721 CallStubCompiler compiler(argc, NOT_IN_LOOP, kind, cache_holder); 722 { MaybeObject* maybe_code = 723 compiler.CompileCallInterceptor(JSObject::cast(object), holder, name); 724 if (!maybe_code->ToObject(&code)) return maybe_code; 725 } 726 ASSERT_EQ(flags, Code::cast(code)->flags()); 727 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), 728 Code::cast(code), name)); 729 Object* result; 730 { MaybeObject* maybe_result = 731 map_holder->UpdateMapCodeCache(name, Code::cast(code)); 732 if (!maybe_result->ToObject(&result)) return maybe_result; 733 } 734 } 735 return code; 736} 737 738 739MaybeObject* StubCache::ComputeCallNormal(int argc, 740 InLoopFlag in_loop, 741 Code::Kind kind, 742 String* name, 743 JSObject* receiver) { 744 Object* code; 745 { MaybeObject* maybe_code = ComputeCallNormal(argc, in_loop, kind); 746 if (!maybe_code->ToObject(&code)) return maybe_code; 747 } 748 return code; 749} 750 751 752MaybeObject* StubCache::ComputeCallGlobal(int argc, 753 InLoopFlag in_loop, 754 Code::Kind kind, 755 String* name, 756 JSObject* receiver, 757 GlobalObject* holder, 758 JSGlobalPropertyCell* cell, 759 JSFunction* function) { 760 InlineCacheHolderFlag cache_holder = 761 IC::GetCodeCacheForObject(receiver, holder); 762 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder); 763 Code::Flags flags = 764 Code::ComputeMonomorphicFlags(kind, 765 NORMAL, 766 cache_holder, 767 in_loop, 768 argc); 769 Object* code = map_holder->map()->FindInCodeCache(name, flags); 770 if (code->IsUndefined()) { 771 // If the function hasn't been compiled yet, we cannot do it now 772 // because it may cause GC. To avoid this issue, we return an 773 // internal error which will make sure we do not update any 774 // caches. 775 if (!function->is_compiled()) return Failure::InternalError(); 776 CallStubCompiler compiler(argc, in_loop, kind, cache_holder); 777 { MaybeObject* maybe_code = 778 compiler.CompileCallGlobal(receiver, holder, cell, function, name); 779 if (!maybe_code->ToObject(&code)) return maybe_code; 780 } 781 ASSERT_EQ(flags, Code::cast(code)->flags()); 782 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), 783 Code::cast(code), name)); 784 Object* result; 785 { MaybeObject* maybe_result = 786 map_holder->UpdateMapCodeCache(name, Code::cast(code)); 787 if (!maybe_result->ToObject(&result)) return maybe_result; 788 } 789 } 790 return code; 791} 792 793 794static Object* GetProbeValue(Code::Flags flags) { 795 // Use raw_unchecked... so we don't get assert failures during GC. 796 NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache(); 797 int entry = dictionary->FindEntry(flags); 798 if (entry != -1) return dictionary->ValueAt(entry); 799 return Heap::raw_unchecked_undefined_value(); 800} 801 802 803MUST_USE_RESULT static MaybeObject* ProbeCache(Code::Flags flags) { 804 Object* probe = GetProbeValue(flags); 805 if (probe != Heap::undefined_value()) return probe; 806 // Seed the cache with an undefined value to make sure that any 807 // generated code object can always be inserted into the cache 808 // without causing allocation failures. 809 Object* result; 810 { MaybeObject* maybe_result = 811 Heap::non_monomorphic_cache()->AtNumberPut(flags, 812 Heap::undefined_value()); 813 if (!maybe_result->ToObject(&result)) return maybe_result; 814 } 815 Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result)); 816 return probe; 817} 818 819 820static MaybeObject* FillCache(MaybeObject* maybe_code) { 821 Object* code; 822 if (maybe_code->ToObject(&code)) { 823 if (code->IsCode()) { 824 int entry = 825 Heap::non_monomorphic_cache()->FindEntry( 826 Code::cast(code)->flags()); 827 // The entry must be present see comment in ProbeCache. 828 ASSERT(entry != -1); 829 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) == 830 Heap::undefined_value()); 831 Heap::non_monomorphic_cache()->ValueAtPut(entry, code); 832 CHECK(GetProbeValue(Code::cast(code)->flags()) == code); 833 } 834 } 835 return maybe_code; 836} 837 838 839Code* StubCache::FindCallInitialize(int argc, 840 InLoopFlag in_loop, 841 Code::Kind kind) { 842 Code::Flags flags = 843 Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc); 844 Object* result = ProbeCache(flags)->ToObjectUnchecked(); 845 ASSERT(!result->IsUndefined()); 846 // This might be called during the marking phase of the collector 847 // hence the unchecked cast. 848 return reinterpret_cast<Code*>(result); 849} 850 851 852MaybeObject* StubCache::ComputeCallInitialize(int argc, 853 InLoopFlag in_loop, 854 Code::Kind kind) { 855 Code::Flags flags = 856 Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc); 857 Object* probe; 858 { MaybeObject* maybe_probe = ProbeCache(flags); 859 if (!maybe_probe->ToObject(&probe)) return maybe_probe; 860 } 861 if (!probe->IsUndefined()) return probe; 862 StubCompiler compiler; 863 return FillCache(compiler.CompileCallInitialize(flags)); 864} 865 866 867Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) { 868 if (in_loop == IN_LOOP) { 869 // Force the creation of the corresponding stub outside loops, 870 // because it may be used when clearing the ICs later - it is 871 // possible for a series of IC transitions to lose the in-loop 872 // information, and the IC clearing code can't generate a stub 873 // that it needs so we need to ensure it is generated already. 874 ComputeCallInitialize(argc, NOT_IN_LOOP); 875 } 876 CALL_HEAP_FUNCTION(ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code); 877} 878 879 880Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc, 881 InLoopFlag in_loop) { 882 if (in_loop == IN_LOOP) { 883 // Force the creation of the corresponding stub outside loops, 884 // because it may be used when clearing the ICs later - it is 885 // possible for a series of IC transitions to lose the in-loop 886 // information, and the IC clearing code can't generate a stub 887 // that it needs so we need to ensure it is generated already. 888 ComputeKeyedCallInitialize(argc, NOT_IN_LOOP); 889 } 890 CALL_HEAP_FUNCTION( 891 ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code); 892} 893 894 895MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc, 896 InLoopFlag in_loop, 897 Code::Kind kind) { 898 Code::Flags flags = 899 Code::ComputeFlags(kind, in_loop, PREMONOMORPHIC, NORMAL, argc); 900 Object* probe; 901 { MaybeObject* maybe_probe = ProbeCache(flags); 902 if (!maybe_probe->ToObject(&probe)) return maybe_probe; 903 } 904 if (!probe->IsUndefined()) return probe; 905 StubCompiler compiler; 906 return FillCache(compiler.CompileCallPreMonomorphic(flags)); 907} 908 909 910MaybeObject* StubCache::ComputeCallNormal(int argc, 911 InLoopFlag in_loop, 912 Code::Kind kind) { 913 Code::Flags flags = 914 Code::ComputeFlags(kind, in_loop, MONOMORPHIC, NORMAL, argc); 915 Object* probe; 916 { MaybeObject* maybe_probe = ProbeCache(flags); 917 if (!maybe_probe->ToObject(&probe)) return maybe_probe; 918 } 919 if (!probe->IsUndefined()) return probe; 920 StubCompiler compiler; 921 return FillCache(compiler.CompileCallNormal(flags)); 922} 923 924 925MaybeObject* StubCache::ComputeCallMegamorphic(int argc, 926 InLoopFlag in_loop, 927 Code::Kind kind) { 928 Code::Flags flags = 929 Code::ComputeFlags(kind, in_loop, MEGAMORPHIC, NORMAL, argc); 930 Object* probe; 931 { MaybeObject* maybe_probe = ProbeCache(flags); 932 if (!maybe_probe->ToObject(&probe)) return maybe_probe; 933 } 934 if (!probe->IsUndefined()) return probe; 935 StubCompiler compiler; 936 return FillCache(compiler.CompileCallMegamorphic(flags)); 937} 938 939 940MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) { 941 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs 942 // and monomorphic stubs are not mixed up together in the stub cache. 943 Code::Flags flags = Code::ComputeFlags( 944 kind, NOT_IN_LOOP, MONOMORPHIC_PROTOTYPE_FAILURE, NORMAL, argc); 945 Object* probe; 946 { MaybeObject* maybe_probe = ProbeCache(flags); 947 if (!maybe_probe->ToObject(&probe)) return maybe_probe; 948 } 949 if (!probe->IsUndefined()) return probe; 950 StubCompiler compiler; 951 return FillCache(compiler.CompileCallMiss(flags)); 952} 953 954 955#ifdef ENABLE_DEBUGGER_SUPPORT 956MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) { 957 Code::Flags flags = 958 Code::ComputeFlags(kind, NOT_IN_LOOP, DEBUG_BREAK, NORMAL, argc); 959 Object* probe; 960 { MaybeObject* maybe_probe = ProbeCache(flags); 961 if (!maybe_probe->ToObject(&probe)) return maybe_probe; 962 } 963 if (!probe->IsUndefined()) return probe; 964 StubCompiler compiler; 965 return FillCache(compiler.CompileCallDebugBreak(flags)); 966} 967 968 969MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc, 970 Code::Kind kind) { 971 Code::Flags flags = 972 Code::ComputeFlags(kind, 973 NOT_IN_LOOP, 974 DEBUG_PREPARE_STEP_IN, 975 NORMAL, 976 argc); 977 Object* probe; 978 { MaybeObject* maybe_probe = ProbeCache(flags); 979 if (!maybe_probe->ToObject(&probe)) return maybe_probe; 980 } 981 if (!probe->IsUndefined()) return probe; 982 StubCompiler compiler; 983 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags)); 984} 985#endif 986 987 988void StubCache::Clear() { 989 for (int i = 0; i < kPrimaryTableSize; i++) { 990 primary_[i].key = Heap::empty_string(); 991 primary_[i].value = Builtins::builtin(Builtins::Illegal); 992 } 993 for (int j = 0; j < kSecondaryTableSize; j++) { 994 secondary_[j].key = Heap::empty_string(); 995 secondary_[j].value = Builtins::builtin(Builtins::Illegal); 996 } 997} 998 999 1000void StubCache::CollectMatchingMaps(ZoneMapList* types, 1001 String* name, 1002 Code::Flags flags) { 1003 for (int i = 0; i < kPrimaryTableSize; i++) { 1004 if (primary_[i].key == name) { 1005 Map* map = primary_[i].value->FindFirstMap(); 1006 // Map can be NULL, if the stub is constant function call 1007 // with a primitive receiver. 1008 if (map == NULL) continue; 1009 1010 int offset = PrimaryOffset(name, flags, map); 1011 if (entry(primary_, offset) == &primary_[i]) { 1012 types->Add(Handle<Map>(map)); 1013 } 1014 } 1015 } 1016 1017 for (int i = 0; i < kSecondaryTableSize; i++) { 1018 if (secondary_[i].key == name) { 1019 Map* map = secondary_[i].value->FindFirstMap(); 1020 // Map can be NULL, if the stub is constant function call 1021 // with a primitive receiver. 1022 if (map == NULL) continue; 1023 1024 // Lookup in primary table and skip duplicates. 1025 int primary_offset = PrimaryOffset(name, flags, map); 1026 Entry* primary_entry = entry(primary_, primary_offset); 1027 if (primary_entry->key == name) { 1028 Map* primary_map = primary_entry->value->FindFirstMap(); 1029 if (map == primary_map) continue; 1030 } 1031 1032 // Lookup in secondary table and add matches. 1033 int offset = SecondaryOffset(name, flags, primary_offset); 1034 if (entry(secondary_, offset) == &secondary_[i]) { 1035 types->Add(Handle<Map>(map)); 1036 } 1037 } 1038 } 1039} 1040 1041 1042// ------------------------------------------------------------------------ 1043// StubCompiler implementation. 1044 1045 1046MaybeObject* LoadCallbackProperty(Arguments args) { 1047 ASSERT(args[0]->IsJSObject()); 1048 ASSERT(args[1]->IsJSObject()); 1049 AccessorInfo* callback = AccessorInfo::cast(args[3]); 1050 Address getter_address = v8::ToCData<Address>(callback->getter()); 1051 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address); 1052 ASSERT(fun != NULL); 1053 v8::AccessorInfo info(&args[0]); 1054 HandleScope scope; 1055 v8::Handle<v8::Value> result; 1056 { 1057 // Leaving JavaScript. 1058 VMState state(EXTERNAL); 1059 ExternalCallbackScope call_scope(getter_address); 1060 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info); 1061 } 1062 RETURN_IF_SCHEDULED_EXCEPTION(); 1063 if (result.IsEmpty()) return Heap::undefined_value(); 1064 return *v8::Utils::OpenHandle(*result); 1065} 1066 1067 1068MaybeObject* StoreCallbackProperty(Arguments args) { 1069 JSObject* recv = JSObject::cast(args[0]); 1070 AccessorInfo* callback = AccessorInfo::cast(args[1]); 1071 Address setter_address = v8::ToCData<Address>(callback->setter()); 1072 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address); 1073 ASSERT(fun != NULL); 1074 Handle<String> name = args.at<String>(2); 1075 Handle<Object> value = args.at<Object>(3); 1076 HandleScope scope; 1077 LOG(ApiNamedPropertyAccess("store", recv, *name)); 1078 CustomArguments custom_args(callback->data(), recv, recv); 1079 v8::AccessorInfo info(custom_args.end()); 1080 { 1081 // Leaving JavaScript. 1082 VMState state(EXTERNAL); 1083 ExternalCallbackScope call_scope(setter_address); 1084 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info); 1085 } 1086 RETURN_IF_SCHEDULED_EXCEPTION(); 1087 return *value; 1088} 1089 1090 1091static const int kAccessorInfoOffsetInInterceptorArgs = 2; 1092 1093 1094/** 1095 * Attempts to load a property with an interceptor (which must be present), 1096 * but doesn't search the prototype chain. 1097 * 1098 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't 1099 * provide any value for the given name. 1100 */ 1101MaybeObject* LoadPropertyWithInterceptorOnly(Arguments args) { 1102 Handle<String> name_handle = args.at<String>(0); 1103 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1); 1104 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2); 1105 ASSERT(args[2]->IsJSObject()); // Receiver. 1106 ASSERT(args[3]->IsJSObject()); // Holder. 1107 ASSERT(args.length() == 5); // Last arg is data object. 1108 1109 Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); 1110 v8::NamedPropertyGetter getter = 1111 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address); 1112 ASSERT(getter != NULL); 1113 1114 { 1115 // Use the interceptor getter. 1116 v8::AccessorInfo info(args.arguments() - 1117 kAccessorInfoOffsetInInterceptorArgs); 1118 HandleScope scope; 1119 v8::Handle<v8::Value> r; 1120 { 1121 // Leaving JavaScript. 1122 VMState state(EXTERNAL); 1123 r = getter(v8::Utils::ToLocal(name_handle), info); 1124 } 1125 RETURN_IF_SCHEDULED_EXCEPTION(); 1126 if (!r.IsEmpty()) { 1127 return *v8::Utils::OpenHandle(*r); 1128 } 1129 } 1130 1131 return Heap::no_interceptor_result_sentinel(); 1132} 1133 1134 1135static MaybeObject* ThrowReferenceError(String* name) { 1136 // If the load is non-contextual, just return the undefined result. 1137 // Note that both keyed and non-keyed loads may end up here, so we 1138 // can't use either LoadIC or KeyedLoadIC constructors. 1139 IC ic(IC::NO_EXTRA_FRAME); 1140 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub()); 1141 if (!ic.SlowIsContextual()) return Heap::undefined_value(); 1142 1143 // Throw a reference error. 1144 HandleScope scope; 1145 Handle<String> name_handle(name); 1146 Handle<Object> error = 1147 Factory::NewReferenceError("not_defined", 1148 HandleVector(&name_handle, 1)); 1149 return Top::Throw(*error); 1150} 1151 1152 1153static MaybeObject* LoadWithInterceptor(Arguments* args, 1154 PropertyAttributes* attrs) { 1155 Handle<String> name_handle = args->at<String>(0); 1156 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1); 1157 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2); 1158 Handle<JSObject> receiver_handle = args->at<JSObject>(2); 1159 Handle<JSObject> holder_handle = args->at<JSObject>(3); 1160 ASSERT(args->length() == 5); // Last arg is data object. 1161 1162 Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); 1163 v8::NamedPropertyGetter getter = 1164 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address); 1165 ASSERT(getter != NULL); 1166 1167 { 1168 // Use the interceptor getter. 1169 v8::AccessorInfo info(args->arguments() - 1170 kAccessorInfoOffsetInInterceptorArgs); 1171 HandleScope scope; 1172 v8::Handle<v8::Value> r; 1173 { 1174 // Leaving JavaScript. 1175 VMState state(EXTERNAL); 1176 r = getter(v8::Utils::ToLocal(name_handle), info); 1177 } 1178 RETURN_IF_SCHEDULED_EXCEPTION(); 1179 if (!r.IsEmpty()) { 1180 *attrs = NONE; 1181 return *v8::Utils::OpenHandle(*r); 1182 } 1183 } 1184 1185 MaybeObject* result = holder_handle->GetPropertyPostInterceptor( 1186 *receiver_handle, 1187 *name_handle, 1188 attrs); 1189 RETURN_IF_SCHEDULED_EXCEPTION(); 1190 return result; 1191} 1192 1193 1194/** 1195 * Loads a property with an interceptor performing post interceptor 1196 * lookup if interceptor failed. 1197 */ 1198MaybeObject* LoadPropertyWithInterceptorForLoad(Arguments args) { 1199 PropertyAttributes attr = NONE; 1200 Object* result; 1201 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr); 1202 if (!maybe_result->ToObject(&result)) return maybe_result; 1203 } 1204 1205 // If the property is present, return it. 1206 if (attr != ABSENT) return result; 1207 return ThrowReferenceError(String::cast(args[0])); 1208} 1209 1210 1211MaybeObject* LoadPropertyWithInterceptorForCall(Arguments args) { 1212 PropertyAttributes attr; 1213 MaybeObject* result = LoadWithInterceptor(&args, &attr); 1214 RETURN_IF_SCHEDULED_EXCEPTION(); 1215 // This is call IC. In this case, we simply return the undefined result which 1216 // will lead to an exception when trying to invoke the result as a 1217 // function. 1218 return result; 1219} 1220 1221 1222MaybeObject* StoreInterceptorProperty(Arguments args) { 1223 JSObject* recv = JSObject::cast(args[0]); 1224 String* name = String::cast(args[1]); 1225 Object* value = args[2]; 1226 ASSERT(recv->HasNamedInterceptor()); 1227 PropertyAttributes attr = NONE; 1228 MaybeObject* result = recv->SetPropertyWithInterceptor(name, value, attr); 1229 return result; 1230} 1231 1232 1233MaybeObject* KeyedLoadPropertyWithInterceptor(Arguments args) { 1234 JSObject* receiver = JSObject::cast(args[0]); 1235 ASSERT(Smi::cast(args[1])->value() >= 0); 1236 uint32_t index = Smi::cast(args[1])->value(); 1237 return receiver->GetElementWithInterceptor(receiver, index); 1238} 1239 1240 1241MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) { 1242 HandleScope scope; 1243 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1244 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1245 if (kind == Code::CALL_IC) { 1246 CallIC::GenerateInitialize(masm(), argc); 1247 } else { 1248 KeyedCallIC::GenerateInitialize(masm(), argc); 1249 } 1250 Object* result; 1251 { MaybeObject* maybe_result = 1252 GetCodeWithFlags(flags, "CompileCallInitialize"); 1253 if (!maybe_result->ToObject(&result)) return maybe_result; 1254 } 1255 Counters::call_initialize_stubs.Increment(); 1256 Code* code = Code::cast(result); 1257 USE(code); 1258 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG), 1259 code, code->arguments_count())); 1260 return result; 1261} 1262 1263 1264MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) { 1265 HandleScope scope; 1266 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1267 // The code of the PreMonomorphic stub is the same as the code 1268 // of the Initialized stub. They just differ on the code object flags. 1269 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1270 if (kind == Code::CALL_IC) { 1271 CallIC::GenerateInitialize(masm(), argc); 1272 } else { 1273 KeyedCallIC::GenerateInitialize(masm(), argc); 1274 } 1275 Object* result; 1276 { MaybeObject* maybe_result = 1277 GetCodeWithFlags(flags, "CompileCallPreMonomorphic"); 1278 if (!maybe_result->ToObject(&result)) return maybe_result; 1279 } 1280 Counters::call_premonomorphic_stubs.Increment(); 1281 Code* code = Code::cast(result); 1282 USE(code); 1283 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG), 1284 code, code->arguments_count())); 1285 return result; 1286} 1287 1288 1289MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) { 1290 HandleScope scope; 1291 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1292 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1293 if (kind == Code::CALL_IC) { 1294 CallIC::GenerateNormal(masm(), argc); 1295 } else { 1296 KeyedCallIC::GenerateNormal(masm(), argc); 1297 } 1298 Object* result; 1299 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal"); 1300 if (!maybe_result->ToObject(&result)) return maybe_result; 1301 } 1302 Counters::call_normal_stubs.Increment(); 1303 Code* code = Code::cast(result); 1304 USE(code); 1305 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG), 1306 code, code->arguments_count())); 1307 return result; 1308} 1309 1310 1311MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) { 1312 HandleScope scope; 1313 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1314 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1315 if (kind == Code::CALL_IC) { 1316 CallIC::GenerateMegamorphic(masm(), argc); 1317 } else { 1318 KeyedCallIC::GenerateMegamorphic(masm(), argc); 1319 } 1320 1321 Object* result; 1322 { MaybeObject* maybe_result = 1323 GetCodeWithFlags(flags, "CompileCallMegamorphic"); 1324 if (!maybe_result->ToObject(&result)) return maybe_result; 1325 } 1326 Counters::call_megamorphic_stubs.Increment(); 1327 Code* code = Code::cast(result); 1328 USE(code); 1329 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG), 1330 code, code->arguments_count())); 1331 return result; 1332} 1333 1334 1335MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) { 1336 HandleScope scope; 1337 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1338 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1339 if (kind == Code::CALL_IC) { 1340 CallIC::GenerateMiss(masm(), argc); 1341 } else { 1342 KeyedCallIC::GenerateMiss(masm(), argc); 1343 } 1344 Object* result; 1345 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss"); 1346 if (!maybe_result->ToObject(&result)) return maybe_result; 1347 } 1348 Counters::call_megamorphic_stubs.Increment(); 1349 Code* code = Code::cast(result); 1350 USE(code); 1351 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG), 1352 code, code->arguments_count())); 1353 return result; 1354} 1355 1356 1357#ifdef ENABLE_DEBUGGER_SUPPORT 1358MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) { 1359 HandleScope scope; 1360 Debug::GenerateCallICDebugBreak(masm()); 1361 Object* result; 1362 { MaybeObject* maybe_result = 1363 GetCodeWithFlags(flags, "CompileCallDebugBreak"); 1364 if (!maybe_result->ToObject(&result)) return maybe_result; 1365 } 1366 Code* code = Code::cast(result); 1367 USE(code); 1368 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1369 USE(kind); 1370 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG), 1371 code, code->arguments_count())); 1372 return result; 1373} 1374 1375 1376MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) { 1377 HandleScope scope; 1378 // Use the same code for the the step in preparations as we do for 1379 // the miss case. 1380 int argc = Code::ExtractArgumentsCountFromFlags(flags); 1381 Code::Kind kind = Code::ExtractKindFromFlags(flags); 1382 if (kind == Code::CALL_IC) { 1383 CallIC::GenerateMiss(masm(), argc); 1384 } else { 1385 KeyedCallIC::GenerateMiss(masm(), argc); 1386 } 1387 Object* result; 1388 { MaybeObject* maybe_result = 1389 GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn"); 1390 if (!maybe_result->ToObject(&result)) return maybe_result; 1391 } 1392 Code* code = Code::cast(result); 1393 USE(code); 1394 PROFILE(CodeCreateEvent( 1395 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG), 1396 code, 1397 code->arguments_count())); 1398 return result; 1399} 1400#endif 1401 1402#undef CALL_LOGGER_TAG 1403 1404MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, 1405 const char* name) { 1406 // Check for allocation failures during stub compilation. 1407 if (failure_->IsFailure()) return failure_; 1408 1409 // Create code object in the heap. 1410 CodeDesc desc; 1411 masm_.GetCode(&desc); 1412 MaybeObject* result = Heap::CreateCode(desc, flags, masm_.CodeObject()); 1413#ifdef ENABLE_DISASSEMBLER 1414 if (FLAG_print_code_stubs && !result->IsFailure()) { 1415 Code::cast(result->ToObjectUnchecked())->Disassemble(name); 1416 } 1417#endif 1418 return result; 1419} 1420 1421 1422MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) { 1423 if (FLAG_print_code_stubs && (name != NULL)) { 1424 return GetCodeWithFlags(flags, *name->ToCString()); 1425 } 1426 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL)); 1427} 1428 1429 1430void StubCompiler::LookupPostInterceptor(JSObject* holder, 1431 String* name, 1432 LookupResult* lookup) { 1433 holder->LocalLookupRealNamedProperty(name, lookup); 1434 if (!lookup->IsProperty()) { 1435 lookup->NotFound(); 1436 Object* proto = holder->GetPrototype(); 1437 if (proto != Heap::null_value()) { 1438 proto->Lookup(name, lookup); 1439 } 1440 } 1441} 1442 1443 1444 1445MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) { 1446 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type); 1447 MaybeObject* result = GetCodeWithFlags(flags, name); 1448 if (!result->IsFailure()) { 1449 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, 1450 Code::cast(result->ToObjectUnchecked()), 1451 name)); 1452 } 1453 return result; 1454} 1455 1456 1457MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) { 1458 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type); 1459 MaybeObject* result = GetCodeWithFlags(flags, name); 1460 if (!result->IsFailure()) { 1461 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, 1462 Code::cast(result->ToObjectUnchecked()), 1463 name)); 1464 } 1465 return result; 1466} 1467 1468 1469MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) { 1470 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type); 1471 MaybeObject* result = GetCodeWithFlags(flags, name); 1472 if (!result->IsFailure()) { 1473 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, 1474 Code::cast(result->ToObjectUnchecked()), 1475 name)); 1476 } 1477 return result; 1478} 1479 1480 1481MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) { 1482 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type); 1483 MaybeObject* result = GetCodeWithFlags(flags, name); 1484 if (!result->IsFailure()) { 1485 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, 1486 Code::cast(result->ToObjectUnchecked()), 1487 name)); 1488 } 1489 return result; 1490} 1491 1492 1493CallStubCompiler::CallStubCompiler(int argc, 1494 InLoopFlag in_loop, 1495 Code::Kind kind, 1496 InlineCacheHolderFlag cache_holder) 1497 : arguments_(argc) 1498 , in_loop_(in_loop) 1499 , kind_(kind) 1500 , cache_holder_(cache_holder) { 1501} 1502 1503 1504bool CallStubCompiler::HasCustomCallGenerator(BuiltinFunctionId id) { 1505#define CALL_GENERATOR_CASE(name) if (id == k##name) return true; 1506 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE) 1507#undef CALL_GENERATOR_CASE 1508 return false; 1509} 1510 1511 1512MaybeObject* CallStubCompiler::CompileCustomCall(BuiltinFunctionId id, 1513 Object* object, 1514 JSObject* holder, 1515 JSGlobalPropertyCell* cell, 1516 JSFunction* function, 1517 String* fname) { 1518#define CALL_GENERATOR_CASE(name) \ 1519 if (id == k##name) { \ 1520 return CallStubCompiler::Compile##name##Call(object, \ 1521 holder, \ 1522 cell, \ 1523 function, \ 1524 fname); \ 1525 } 1526 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE) 1527#undef CALL_GENERATOR_CASE 1528 ASSERT(!HasCustomCallGenerator(id)); 1529 return Heap::undefined_value(); 1530} 1531 1532 1533MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) { 1534 int argc = arguments_.immediate(); 1535 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_, 1536 type, 1537 cache_holder_, 1538 in_loop_, 1539 argc); 1540 return GetCodeWithFlags(flags, name); 1541} 1542 1543 1544MaybeObject* CallStubCompiler::GetCode(JSFunction* function) { 1545 String* function_name = NULL; 1546 if (function->shared()->name()->IsString()) { 1547 function_name = String::cast(function->shared()->name()); 1548 } 1549 return GetCode(CONSTANT_FUNCTION, function_name); 1550} 1551 1552 1553MaybeObject* ConstructStubCompiler::GetCode() { 1554 Code::Flags flags = Code::ComputeFlags(Code::STUB); 1555 Object* result; 1556 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub"); 1557 if (!maybe_result->ToObject(&result)) return maybe_result; 1558 } 1559 Code* code = Code::cast(result); 1560 USE(code); 1561 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub")); 1562 return result; 1563} 1564 1565 1566CallOptimization::CallOptimization(LookupResult* lookup) { 1567 if (!lookup->IsProperty() || !lookup->IsCacheable() || 1568 lookup->type() != CONSTANT_FUNCTION) { 1569 Initialize(NULL); 1570 } else { 1571 // We only optimize constant function calls. 1572 Initialize(lookup->GetConstantFunction()); 1573 } 1574} 1575 1576CallOptimization::CallOptimization(JSFunction* function) { 1577 Initialize(function); 1578} 1579 1580 1581int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object, 1582 JSObject* holder) const { 1583 ASSERT(is_simple_api_call_); 1584 if (expected_receiver_type_ == NULL) return 0; 1585 int depth = 0; 1586 while (object != holder) { 1587 if (object->IsInstanceOf(expected_receiver_type_)) return depth; 1588 object = JSObject::cast(object->GetPrototype()); 1589 ++depth; 1590 } 1591 if (holder->IsInstanceOf(expected_receiver_type_)) return depth; 1592 return kInvalidProtoDepth; 1593} 1594 1595 1596void CallOptimization::Initialize(JSFunction* function) { 1597 constant_function_ = NULL; 1598 is_simple_api_call_ = false; 1599 expected_receiver_type_ = NULL; 1600 api_call_info_ = NULL; 1601 1602 if (function == NULL || !function->is_compiled()) return; 1603 1604 constant_function_ = function; 1605 AnalyzePossibleApiFunction(function); 1606} 1607 1608 1609void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) { 1610 SharedFunctionInfo* sfi = function->shared(); 1611 if (!sfi->IsApiFunction()) return; 1612 FunctionTemplateInfo* info = sfi->get_api_func_data(); 1613 1614 // Require a C++ callback. 1615 if (info->call_code()->IsUndefined()) return; 1616 api_call_info_ = CallHandlerInfo::cast(info->call_code()); 1617 1618 // Accept signatures that either have no restrictions at all or 1619 // only have restrictions on the receiver. 1620 if (!info->signature()->IsUndefined()) { 1621 SignatureInfo* signature = SignatureInfo::cast(info->signature()); 1622 if (!signature->args()->IsUndefined()) return; 1623 if (!signature->receiver()->IsUndefined()) { 1624 expected_receiver_type_ = 1625 FunctionTemplateInfo::cast(signature->receiver()); 1626 } 1627 } 1628 1629 is_simple_api_call_ = true; 1630} 1631 1632 1633} } // namespace v8::internal 1634