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