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