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