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#if V8_TARGET_ARCH_IA32 31 32#include "codegen.h" 33#include "ic-inl.h" 34#include "runtime.h" 35#include "stub-cache.h" 36 37namespace v8 { 38namespace internal { 39 40// ---------------------------------------------------------------------------- 41// Static IC stub generators. 42// 43 44#define __ ACCESS_MASM(masm) 45 46 47static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, 48 Register type, 49 Label* global_object) { 50 // Register usage: 51 // type: holds the receiver instance type on entry. 52 __ cmp(type, JS_GLOBAL_OBJECT_TYPE); 53 __ j(equal, global_object); 54 __ cmp(type, JS_BUILTINS_OBJECT_TYPE); 55 __ j(equal, global_object); 56 __ cmp(type, JS_GLOBAL_PROXY_TYPE); 57 __ j(equal, global_object); 58} 59 60 61// Generated code falls through if the receiver is a regular non-global 62// JS object with slow properties and no interceptors. 63static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm, 64 Register receiver, 65 Register r0, 66 Register r1, 67 Label* miss) { 68 // Register usage: 69 // receiver: holds the receiver on entry and is unchanged. 70 // r0: used to hold receiver instance type. 71 // Holds the property dictionary on fall through. 72 // r1: used to hold receivers map. 73 74 // Check that the receiver isn't a smi. 75 __ JumpIfSmi(receiver, miss); 76 77 // Check that the receiver is a valid JS object. 78 __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset)); 79 __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset)); 80 __ cmp(r0, FIRST_SPEC_OBJECT_TYPE); 81 __ j(below, miss); 82 83 // If this assert fails, we have to check upper bound too. 84 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); 85 86 GenerateGlobalInstanceTypeCheck(masm, r0, miss); 87 88 // Check for non-global object that requires access check. 89 __ test_b(FieldOperand(r1, Map::kBitFieldOffset), 90 (1 << Map::kIsAccessCheckNeeded) | 91 (1 << Map::kHasNamedInterceptor)); 92 __ j(not_zero, miss); 93 94 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); 95 __ CheckMap(r0, masm->isolate()->factory()->hash_table_map(), miss, 96 DONT_DO_SMI_CHECK); 97} 98 99 100// Helper function used to load a property from a dictionary backing 101// storage. This function may fail to load a property even though it is 102// in the dictionary, so code at miss_label must always call a backup 103// property load that is complete. This function is safe to call if 104// name is not internalized, and will jump to the miss_label in that 105// case. The generated code assumes that the receiver has slow 106// properties, is not a global object and does not have interceptors. 107static void GenerateDictionaryLoad(MacroAssembler* masm, 108 Label* miss_label, 109 Register elements, 110 Register name, 111 Register r0, 112 Register r1, 113 Register result) { 114 // Register use: 115 // 116 // elements - holds the property dictionary on entry and is unchanged. 117 // 118 // name - holds the name of the property on entry and is unchanged. 119 // 120 // Scratch registers: 121 // 122 // r0 - used for the index into the property dictionary 123 // 124 // r1 - used to hold the capacity of the property dictionary. 125 // 126 // result - holds the result on exit. 127 128 Label done; 129 130 // Probe the dictionary. 131 NameDictionaryLookupStub::GeneratePositiveLookup(masm, 132 miss_label, 133 &done, 134 elements, 135 name, 136 r0, 137 r1); 138 139 // If probing finds an entry in the dictionary, r0 contains the 140 // index into the dictionary. Check that the value is a normal 141 // property. 142 __ bind(&done); 143 const int kElementsStartOffset = 144 NameDictionary::kHeaderSize + 145 NameDictionary::kElementsStartIndex * kPointerSize; 146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; 147 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), 148 Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize)); 149 __ j(not_zero, miss_label); 150 151 // Get the value at the masked, scaled index. 152 const int kValueOffset = kElementsStartOffset + kPointerSize; 153 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); 154} 155 156 157// Helper function used to store a property to a dictionary backing 158// storage. This function may fail to store a property eventhough it 159// is in the dictionary, so code at miss_label must always call a 160// backup property store that is complete. This function is safe to 161// call if name is not internalized, and will jump to the miss_label in 162// that case. The generated code assumes that the receiver has slow 163// properties, is not a global object and does not have interceptors. 164static void GenerateDictionaryStore(MacroAssembler* masm, 165 Label* miss_label, 166 Register elements, 167 Register name, 168 Register value, 169 Register r0, 170 Register r1) { 171 // Register use: 172 // 173 // elements - holds the property dictionary on entry and is clobbered. 174 // 175 // name - holds the name of the property on entry and is unchanged. 176 // 177 // value - holds the value to store and is unchanged. 178 // 179 // r0 - used for index into the property dictionary and is clobbered. 180 // 181 // r1 - used to hold the capacity of the property dictionary and is clobbered. 182 Label done; 183 184 185 // Probe the dictionary. 186 NameDictionaryLookupStub::GeneratePositiveLookup(masm, 187 miss_label, 188 &done, 189 elements, 190 name, 191 r0, 192 r1); 193 194 // If probing finds an entry in the dictionary, r0 contains the 195 // index into the dictionary. Check that the value is a normal 196 // property that is not read only. 197 __ bind(&done); 198 const int kElementsStartOffset = 199 NameDictionary::kHeaderSize + 200 NameDictionary::kElementsStartIndex * kPointerSize; 201 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; 202 const int kTypeAndReadOnlyMask = 203 (PropertyDetails::TypeField::kMask | 204 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; 205 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), 206 Immediate(kTypeAndReadOnlyMask)); 207 __ j(not_zero, miss_label); 208 209 // Store the value at the masked, scaled index. 210 const int kValueOffset = kElementsStartOffset + kPointerSize; 211 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); 212 __ mov(Operand(r0, 0), value); 213 214 // Update write barrier. Make sure not to clobber the value. 215 __ mov(r1, value); 216 __ RecordWrite(elements, r0, r1, kDontSaveFPRegs); 217} 218 219 220// Checks the receiver for special cases (value type, slow case bits). 221// Falls through for regular JS object. 222static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, 223 Register receiver, 224 Register map, 225 int interceptor_bit, 226 Label* slow) { 227 // Register use: 228 // receiver - holds the receiver and is unchanged. 229 // Scratch registers: 230 // map - used to hold the map of the receiver. 231 232 // Check that the object isn't a smi. 233 __ JumpIfSmi(receiver, slow); 234 235 // Get the map of the receiver. 236 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); 237 238 // Check bit field. 239 __ test_b(FieldOperand(map, Map::kBitFieldOffset), 240 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)); 241 __ j(not_zero, slow); 242 // Check that the object is some kind of JS object EXCEPT JS Value type. 243 // In the case that the object is a value-wrapper object, 244 // we enter the runtime system to make sure that indexing 245 // into string objects works as intended. 246 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); 247 248 __ CmpInstanceType(map, JS_OBJECT_TYPE); 249 __ j(below, slow); 250} 251 252 253// Loads an indexed element from a fast case array. 254// If not_fast_array is NULL, doesn't perform the elements map check. 255static void GenerateFastArrayLoad(MacroAssembler* masm, 256 Register receiver, 257 Register key, 258 Register scratch, 259 Register result, 260 Label* not_fast_array, 261 Label* out_of_range) { 262 // Register use: 263 // receiver - holds the receiver and is unchanged. 264 // key - holds the key and is unchanged (must be a smi). 265 // Scratch registers: 266 // scratch - used to hold elements of the receiver and the loaded value. 267 // result - holds the result on exit if the load succeeds and 268 // we fall through. 269 270 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); 271 if (not_fast_array != NULL) { 272 // Check that the object is in fast mode and writable. 273 __ CheckMap(scratch, 274 masm->isolate()->factory()->fixed_array_map(), 275 not_fast_array, 276 DONT_DO_SMI_CHECK); 277 } else { 278 __ AssertFastElements(scratch); 279 } 280 // Check that the key (index) is within bounds. 281 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); 282 __ j(above_equal, out_of_range); 283 // Fast case: Do the load. 284 STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); 285 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); 286 __ cmp(scratch, Immediate(masm->isolate()->factory()->the_hole_value())); 287 // In case the loaded value is the_hole we have to consult GetProperty 288 // to ensure the prototype chain is searched. 289 __ j(equal, out_of_range); 290 if (!result.is(scratch)) { 291 __ mov(result, scratch); 292 } 293} 294 295 296// Checks whether a key is an array index string or a unique name. 297// Falls through if the key is a unique name. 298static void GenerateKeyNameCheck(MacroAssembler* masm, 299 Register key, 300 Register map, 301 Register hash, 302 Label* index_string, 303 Label* not_unique) { 304 // Register use: 305 // key - holds the key and is unchanged. Assumed to be non-smi. 306 // Scratch registers: 307 // map - used to hold the map of the key. 308 // hash - used to hold the hash of the key. 309 Label unique; 310 __ CmpObjectType(key, LAST_UNIQUE_NAME_TYPE, map); 311 __ j(above, not_unique); 312 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE); 313 __ j(equal, &unique); 314 315 // Is the string an array index, with cached numeric value? 316 __ mov(hash, FieldOperand(key, Name::kHashFieldOffset)); 317 __ test(hash, Immediate(Name::kContainsCachedArrayIndexMask)); 318 __ j(zero, index_string); 319 320 // Is the string internalized? We already know it's a string so a single 321 // bit test is enough. 322 STATIC_ASSERT(kNotInternalizedTag != 0); 323 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), 324 kIsNotInternalizedMask); 325 __ j(not_zero, not_unique); 326 327 __ bind(&unique); 328} 329 330 331static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm, 332 Register object, 333 Register key, 334 Register scratch1, 335 Register scratch2, 336 Label* unmapped_case, 337 Label* slow_case) { 338 Heap* heap = masm->isolate()->heap(); 339 Factory* factory = masm->isolate()->factory(); 340 341 // Check that the receiver is a JSObject. Because of the elements 342 // map check later, we do not need to check for interceptors or 343 // whether it requires access checks. 344 __ JumpIfSmi(object, slow_case); 345 // Check that the object is some kind of JSObject. 346 __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1); 347 __ j(below, slow_case); 348 349 // Check that the key is a positive smi. 350 __ test(key, Immediate(0x80000001)); 351 __ j(not_zero, slow_case); 352 353 // Load the elements into scratch1 and check its map. 354 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map()); 355 __ mov(scratch1, FieldOperand(object, JSObject::kElementsOffset)); 356 __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK); 357 358 // Check if element is in the range of mapped arguments. If not, jump 359 // to the unmapped lookup with the parameter map in scratch1. 360 __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset)); 361 __ sub(scratch2, Immediate(Smi::FromInt(2))); 362 __ cmp(key, scratch2); 363 __ j(above_equal, unmapped_case); 364 365 // Load element index and check whether it is the hole. 366 const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize; 367 __ mov(scratch2, FieldOperand(scratch1, 368 key, 369 times_half_pointer_size, 370 kHeaderSize)); 371 __ cmp(scratch2, factory->the_hole_value()); 372 __ j(equal, unmapped_case); 373 374 // Load value from context and return it. We can reuse scratch1 because 375 // we do not jump to the unmapped lookup (which requires the parameter 376 // map in scratch1). 377 const int kContextOffset = FixedArray::kHeaderSize; 378 __ mov(scratch1, FieldOperand(scratch1, kContextOffset)); 379 return FieldOperand(scratch1, 380 scratch2, 381 times_half_pointer_size, 382 Context::kHeaderSize); 383} 384 385 386static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm, 387 Register key, 388 Register parameter_map, 389 Register scratch, 390 Label* slow_case) { 391 // Element is in arguments backing store, which is referenced by the 392 // second element of the parameter_map. 393 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; 394 Register backing_store = parameter_map; 395 __ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset)); 396 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map()); 397 __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK); 398 __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset)); 399 __ cmp(key, scratch); 400 __ j(greater_equal, slow_case); 401 return FieldOperand(backing_store, 402 key, 403 times_half_pointer_size, 404 FixedArray::kHeaderSize); 405} 406 407 408void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { 409 // ----------- S t a t e ------------- 410 // -- ecx : key 411 // -- edx : receiver 412 // -- esp[0] : return address 413 // ----------------------------------- 414 Label slow, check_name, index_smi, index_name, property_array_property; 415 Label probe_dictionary, check_number_dictionary; 416 417 // Check that the key is a smi. 418 __ JumpIfNotSmi(ecx, &check_name); 419 __ bind(&index_smi); 420 // Now the key is known to be a smi. This place is also jumped to from 421 // where a numeric string is converted to a smi. 422 423 GenerateKeyedLoadReceiverCheck( 424 masm, edx, eax, Map::kHasIndexedInterceptor, &slow); 425 426 // Check the receiver's map to see if it has fast elements. 427 __ CheckFastElements(eax, &check_number_dictionary); 428 429 GenerateFastArrayLoad(masm, edx, ecx, eax, eax, NULL, &slow); 430 Isolate* isolate = masm->isolate(); 431 Counters* counters = isolate->counters(); 432 __ IncrementCounter(counters->keyed_load_generic_smi(), 1); 433 __ ret(0); 434 435 __ bind(&check_number_dictionary); 436 __ mov(ebx, ecx); 437 __ SmiUntag(ebx); 438 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); 439 440 // Check whether the elements is a number dictionary. 441 // edx: receiver 442 // ebx: untagged index 443 // ecx: key 444 // eax: elements 445 __ CheckMap(eax, 446 isolate->factory()->hash_table_map(), 447 &slow, 448 DONT_DO_SMI_CHECK); 449 Label slow_pop_receiver; 450 // Push receiver on the stack to free up a register for the dictionary 451 // probing. 452 __ push(edx); 453 __ LoadFromNumberDictionary(&slow_pop_receiver, eax, ecx, ebx, edx, edi, eax); 454 // Pop receiver before returning. 455 __ pop(edx); 456 __ ret(0); 457 458 __ bind(&slow_pop_receiver); 459 // Pop the receiver from the stack and jump to runtime. 460 __ pop(edx); 461 462 __ bind(&slow); 463 // Slow case: jump to runtime. 464 // edx: receiver 465 // ecx: key 466 __ IncrementCounter(counters->keyed_load_generic_slow(), 1); 467 GenerateRuntimeGetProperty(masm); 468 469 __ bind(&check_name); 470 GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow); 471 472 GenerateKeyedLoadReceiverCheck( 473 masm, edx, eax, Map::kHasNamedInterceptor, &slow); 474 475 // If the receiver is a fast-case object, check the keyed lookup 476 // cache. Otherwise probe the dictionary. 477 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); 478 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 479 Immediate(isolate->factory()->hash_table_map())); 480 __ j(equal, &probe_dictionary); 481 482 // The receiver's map is still in eax, compute the keyed lookup cache hash 483 // based on 32 bits of the map pointer and the string hash. 484 if (FLAG_debug_code) { 485 __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset)); 486 __ Check(equal, kMapIsNoLongerInEax); 487 } 488 __ mov(ebx, eax); // Keep the map around for later. 489 __ shr(eax, KeyedLookupCache::kMapHashShift); 490 __ mov(edi, FieldOperand(ecx, String::kHashFieldOffset)); 491 __ shr(edi, String::kHashShift); 492 __ xor_(eax, edi); 493 __ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); 494 495 // Load the key (consisting of map and internalized string) from the cache and 496 // check for match. 497 Label load_in_object_property; 498 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket; 499 Label hit_on_nth_entry[kEntriesPerBucket]; 500 ExternalReference cache_keys = 501 ExternalReference::keyed_lookup_cache_keys(masm->isolate()); 502 503 for (int i = 0; i < kEntriesPerBucket - 1; i++) { 504 Label try_next_entry; 505 __ mov(edi, eax); 506 __ shl(edi, kPointerSizeLog2 + 1); 507 if (i != 0) { 508 __ add(edi, Immediate(kPointerSize * i * 2)); 509 } 510 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); 511 __ j(not_equal, &try_next_entry); 512 __ add(edi, Immediate(kPointerSize)); 513 __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys)); 514 __ j(equal, &hit_on_nth_entry[i]); 515 __ bind(&try_next_entry); 516 } 517 518 __ lea(edi, Operand(eax, 1)); 519 __ shl(edi, kPointerSizeLog2 + 1); 520 __ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2)); 521 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); 522 __ j(not_equal, &slow); 523 __ add(edi, Immediate(kPointerSize)); 524 __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys)); 525 __ j(not_equal, &slow); 526 527 // Get field offset. 528 // edx : receiver 529 // ebx : receiver's map 530 // ecx : key 531 // eax : lookup cache index 532 ExternalReference cache_field_offsets = 533 ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate()); 534 535 // Hit on nth entry. 536 for (int i = kEntriesPerBucket - 1; i >= 0; i--) { 537 __ bind(&hit_on_nth_entry[i]); 538 if (i != 0) { 539 __ add(eax, Immediate(i)); 540 } 541 __ mov(edi, 542 Operand::StaticArray(eax, times_pointer_size, cache_field_offsets)); 543 __ movzx_b(eax, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); 544 __ sub(edi, eax); 545 __ j(above_equal, &property_array_property); 546 if (i != 0) { 547 __ jmp(&load_in_object_property); 548 } 549 } 550 551 // Load in-object property. 552 __ bind(&load_in_object_property); 553 __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceSizeOffset)); 554 __ add(eax, edi); 555 __ mov(eax, FieldOperand(edx, eax, times_pointer_size, 0)); 556 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1); 557 __ ret(0); 558 559 // Load property array property. 560 __ bind(&property_array_property); 561 __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset)); 562 __ mov(eax, FieldOperand(eax, edi, times_pointer_size, 563 FixedArray::kHeaderSize)); 564 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1); 565 __ ret(0); 566 567 // Do a quick inline probe of the receiver's dictionary, if it 568 // exists. 569 __ bind(&probe_dictionary); 570 571 __ mov(eax, FieldOperand(edx, JSObject::kMapOffset)); 572 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); 573 GenerateGlobalInstanceTypeCheck(masm, eax, &slow); 574 575 GenerateDictionaryLoad(masm, &slow, ebx, ecx, eax, edi, eax); 576 __ IncrementCounter(counters->keyed_load_generic_symbol(), 1); 577 __ ret(0); 578 579 __ bind(&index_name); 580 __ IndexFromHash(ebx, ecx); 581 // Now jump to the place where smi keys are handled. 582 __ jmp(&index_smi); 583} 584 585 586void KeyedLoadIC::GenerateString(MacroAssembler* masm) { 587 // ----------- S t a t e ------------- 588 // -- ecx : key (index) 589 // -- edx : receiver 590 // -- esp[0] : return address 591 // ----------------------------------- 592 Label miss; 593 594 Register receiver = edx; 595 Register index = ecx; 596 Register scratch = ebx; 597 Register result = eax; 598 599 StringCharAtGenerator char_at_generator(receiver, 600 index, 601 scratch, 602 result, 603 &miss, // When not a string. 604 &miss, // When not a number. 605 &miss, // When index out of range. 606 STRING_INDEX_IS_ARRAY_INDEX); 607 char_at_generator.GenerateFast(masm); 608 __ ret(0); 609 610 StubRuntimeCallHelper call_helper; 611 char_at_generator.GenerateSlow(masm, call_helper); 612 613 __ bind(&miss); 614 GenerateMiss(masm, MISS); 615} 616 617 618void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { 619 // ----------- S t a t e ------------- 620 // -- ecx : key 621 // -- edx : receiver 622 // -- esp[0] : return address 623 // ----------------------------------- 624 Label slow; 625 626 // Check that the receiver isn't a smi. 627 __ JumpIfSmi(edx, &slow); 628 629 // Check that the key is an array index, that is Uint32. 630 __ test(ecx, Immediate(kSmiTagMask | kSmiSignMask)); 631 __ j(not_zero, &slow); 632 633 // Get the map of the receiver. 634 __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset)); 635 636 // Check that it has indexed interceptor and access checks 637 // are not enabled for this object. 638 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset)); 639 __ and_(eax, Immediate(kSlowCaseBitFieldMask)); 640 __ cmp(eax, Immediate(1 << Map::kHasIndexedInterceptor)); 641 __ j(not_zero, &slow); 642 643 // Everything is fine, call runtime. 644 __ pop(eax); 645 __ push(edx); // receiver 646 __ push(ecx); // key 647 __ push(eax); // return address 648 649 // Perform tail call to the entry. 650 ExternalReference ref = 651 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), 652 masm->isolate()); 653 __ TailCallExternalReference(ref, 2, 1); 654 655 __ bind(&slow); 656 GenerateMiss(masm, MISS); 657} 658 659 660void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) { 661 // ----------- S t a t e ------------- 662 // -- ecx : key 663 // -- edx : receiver 664 // -- esp[0] : return address 665 // ----------------------------------- 666 Label slow, notin; 667 Factory* factory = masm->isolate()->factory(); 668 Operand mapped_location = 669 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, ¬in, &slow); 670 __ mov(eax, mapped_location); 671 __ Ret(); 672 __ bind(¬in); 673 // The unmapped lookup expects that the parameter map is in ebx. 674 Operand unmapped_location = 675 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow); 676 __ cmp(unmapped_location, factory->the_hole_value()); 677 __ j(equal, &slow); 678 __ mov(eax, unmapped_location); 679 __ Ret(); 680 __ bind(&slow); 681 GenerateMiss(masm, MISS); 682} 683 684 685void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) { 686 // ----------- S t a t e ------------- 687 // -- eax : value 688 // -- ecx : key 689 // -- edx : receiver 690 // -- esp[0] : return address 691 // ----------------------------------- 692 Label slow, notin; 693 Operand mapped_location = 694 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, edi, ¬in, &slow); 695 __ mov(mapped_location, eax); 696 __ lea(ecx, mapped_location); 697 __ mov(edx, eax); 698 __ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs); 699 __ Ret(); 700 __ bind(¬in); 701 // The unmapped lookup expects that the parameter map is in ebx. 702 Operand unmapped_location = 703 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, edi, &slow); 704 __ mov(unmapped_location, eax); 705 __ lea(edi, unmapped_location); 706 __ mov(edx, eax); 707 __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs); 708 __ Ret(); 709 __ bind(&slow); 710 GenerateMiss(masm, MISS); 711} 712 713 714static void KeyedStoreGenerateGenericHelper( 715 MacroAssembler* masm, 716 Label* fast_object, 717 Label* fast_double, 718 Label* slow, 719 KeyedStoreCheckMap check_map, 720 KeyedStoreIncrementLength increment_length) { 721 Label transition_smi_elements; 722 Label finish_object_store, non_double_value, transition_double_elements; 723 Label fast_double_without_map_check; 724 // eax: value 725 // ecx: key (a smi) 726 // edx: receiver 727 // ebx: FixedArray receiver->elements 728 // edi: receiver map 729 // Fast case: Do the store, could either Object or double. 730 __ bind(fast_object); 731 if (check_map == kCheckMap) { 732 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset)); 733 __ cmp(edi, masm->isolate()->factory()->fixed_array_map()); 734 __ j(not_equal, fast_double); 735 } 736 // Smi stores don't require further checks. 737 Label non_smi_value; 738 __ JumpIfNotSmi(eax, &non_smi_value); 739 if (increment_length == kIncrementLength) { 740 // Add 1 to receiver->length. 741 __ add(FieldOperand(edx, JSArray::kLengthOffset), 742 Immediate(Smi::FromInt(1))); 743 } 744 // It's irrelevant whether array is smi-only or not when writing a smi. 745 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax); 746 __ ret(0); 747 748 __ bind(&non_smi_value); 749 // Escape to elements kind transition case. 750 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 751 __ CheckFastObjectElements(edi, &transition_smi_elements); 752 753 // Fast elements array, store the value to the elements backing store. 754 __ bind(&finish_object_store); 755 if (increment_length == kIncrementLength) { 756 // Add 1 to receiver->length. 757 __ add(FieldOperand(edx, JSArray::kLengthOffset), 758 Immediate(Smi::FromInt(1))); 759 } 760 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax); 761 // Update write barrier for the elements array address. 762 __ mov(edx, eax); // Preserve the value which is returned. 763 __ RecordWriteArray( 764 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); 765 __ ret(0); 766 767 __ bind(fast_double); 768 if (check_map == kCheckMap) { 769 // Check for fast double array case. If this fails, call through to the 770 // runtime. 771 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map()); 772 __ j(not_equal, slow); 773 // If the value is a number, store it as a double in the FastDoubleElements 774 // array. 775 } 776 __ bind(&fast_double_without_map_check); 777 __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0, 778 &transition_double_elements, false); 779 if (increment_length == kIncrementLength) { 780 // Add 1 to receiver->length. 781 __ add(FieldOperand(edx, JSArray::kLengthOffset), 782 Immediate(Smi::FromInt(1))); 783 } 784 __ ret(0); 785 786 __ bind(&transition_smi_elements); 787 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 788 789 // Transition the array appropriately depending on the value type. 790 __ CheckMap(eax, 791 masm->isolate()->factory()->heap_number_map(), 792 &non_double_value, 793 DONT_DO_SMI_CHECK); 794 795 // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS 796 // and complete the store. 797 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, 798 FAST_DOUBLE_ELEMENTS, 799 ebx, 800 edi, 801 slow); 802 AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, 803 FAST_DOUBLE_ELEMENTS); 804 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow); 805 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 806 __ jmp(&fast_double_without_map_check); 807 808 __ bind(&non_double_value); 809 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS 810 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, 811 FAST_ELEMENTS, 812 ebx, 813 edi, 814 slow); 815 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); 816 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode, 817 slow); 818 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 819 __ jmp(&finish_object_store); 820 821 __ bind(&transition_double_elements); 822 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a 823 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and 824 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS 825 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 826 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, 827 FAST_ELEMENTS, 828 ebx, 829 edi, 830 slow); 831 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); 832 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow); 833 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 834 __ jmp(&finish_object_store); 835} 836 837 838void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, 839 StrictModeFlag strict_mode) { 840 // ----------- S t a t e ------------- 841 // -- eax : value 842 // -- ecx : key 843 // -- edx : receiver 844 // -- esp[0] : return address 845 // ----------------------------------- 846 Label slow, fast_object, fast_object_grow; 847 Label fast_double, fast_double_grow; 848 Label array, extra, check_if_double_array; 849 850 // Check that the object isn't a smi. 851 __ JumpIfSmi(edx, &slow); 852 // Get the map from the receiver. 853 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 854 // Check that the receiver does not require access checks. We need 855 // to do this because this generic stub does not perform map checks. 856 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), 857 1 << Map::kIsAccessCheckNeeded); 858 __ j(not_zero, &slow); 859 // Check that the key is a smi. 860 __ JumpIfNotSmi(ecx, &slow); 861 __ CmpInstanceType(edi, JS_ARRAY_TYPE); 862 __ j(equal, &array); 863 // Check that the object is some kind of JSObject. 864 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); 865 __ j(below, &slow); 866 867 // Object case: Check key against length in the elements array. 868 // eax: value 869 // edx: JSObject 870 // ecx: key (a smi) 871 // edi: receiver map 872 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 873 // Check array bounds. Both the key and the length of FixedArray are smis. 874 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); 875 __ j(below, &fast_object); 876 877 // Slow case: call runtime. 878 __ bind(&slow); 879 GenerateRuntimeSetProperty(masm, strict_mode); 880 881 // Extra capacity case: Check if there is extra capacity to 882 // perform the store and update the length. Used for adding one 883 // element to the array by writing to array[array.length]. 884 __ bind(&extra); 885 // eax: value 886 // edx: receiver, a JSArray 887 // ecx: key, a smi. 888 // ebx: receiver->elements, a FixedArray 889 // edi: receiver map 890 // flags: compare (ecx, edx.length()) 891 // do not leave holes in the array: 892 __ j(not_equal, &slow); 893 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); 894 __ j(above_equal, &slow); 895 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset)); 896 __ cmp(edi, masm->isolate()->factory()->fixed_array_map()); 897 __ j(not_equal, &check_if_double_array); 898 __ jmp(&fast_object_grow); 899 900 __ bind(&check_if_double_array); 901 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map()); 902 __ j(not_equal, &slow); 903 __ jmp(&fast_double_grow); 904 905 // Array case: Get the length and the elements array from the JS 906 // array. Check that the array is in fast mode (and writable); if it 907 // is the length is always a smi. 908 __ bind(&array); 909 // eax: value 910 // edx: receiver, a JSArray 911 // ecx: key, a smi. 912 // edi: receiver map 913 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 914 915 // Check the key against the length in the array and fall through to the 916 // common store code. 917 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. 918 __ j(above_equal, &extra); 919 920 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, 921 &slow, kCheckMap, kDontIncrementLength); 922 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, 923 &slow, kDontCheckMap, kIncrementLength); 924} 925 926 927// The generated code does not accept smi keys. 928// The generated code falls through if both probes miss. 929void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, 930 int argc, 931 Code::Kind kind, 932 Code::ExtraICState extra_state) { 933 // ----------- S t a t e ------------- 934 // -- ecx : name 935 // -- edx : receiver 936 // ----------------------------------- 937 Label number, non_number, non_string, boolean, probe, miss; 938 939 // Probe the stub cache. 940 Code::Flags flags = Code::ComputeFlags(kind, 941 MONOMORPHIC, 942 extra_state, 943 Code::NORMAL, 944 argc); 945 Isolate* isolate = masm->isolate(); 946 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax); 947 948 // If the stub cache probing failed, the receiver might be a value. 949 // For value objects, we use the map of the prototype objects for 950 // the corresponding JSValue for the cache and that is what we need 951 // to probe. 952 // 953 // Check for number. 954 __ JumpIfSmi(edx, &number); 955 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); 956 __ j(not_equal, &non_number); 957 __ bind(&number); 958 StubCompiler::GenerateLoadGlobalFunctionPrototype( 959 masm, Context::NUMBER_FUNCTION_INDEX, edx); 960 __ jmp(&probe); 961 962 // Check for string. 963 __ bind(&non_number); 964 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE); 965 __ j(above_equal, &non_string); 966 StubCompiler::GenerateLoadGlobalFunctionPrototype( 967 masm, Context::STRING_FUNCTION_INDEX, edx); 968 __ jmp(&probe); 969 970 // Check for boolean. 971 __ bind(&non_string); 972 __ cmp(edx, isolate->factory()->true_value()); 973 __ j(equal, &boolean); 974 __ cmp(edx, isolate->factory()->false_value()); 975 __ j(not_equal, &miss); 976 __ bind(&boolean); 977 StubCompiler::GenerateLoadGlobalFunctionPrototype( 978 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); 979 980 // Probe the stub cache for the value object. 981 __ bind(&probe); 982 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); 983 __ bind(&miss); 984} 985 986 987static void GenerateFunctionTailCall(MacroAssembler* masm, 988 int argc, 989 Label* miss) { 990 // ----------- S t a t e ------------- 991 // -- ecx : name 992 // -- edi : function 993 // -- esp[0] : return address 994 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 995 // -- ... 996 // -- esp[(argc + 1) * 4] : receiver 997 // ----------------------------------- 998 999 // Check that the result is not a smi. 1000 __ JumpIfSmi(edi, miss); 1001 1002 // Check that the value is a JavaScript function, fetching its map into eax. 1003 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); 1004 __ j(not_equal, miss); 1005 1006 // Invoke the function. 1007 ParameterCount actual(argc); 1008 __ InvokeFunction(edi, actual, JUMP_FUNCTION, 1009 NullCallWrapper(), CALL_AS_METHOD); 1010} 1011 1012 1013// The generated code falls through if the call should be handled by runtime. 1014void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) { 1015 // ----------- S t a t e ------------- 1016 // -- ecx : name 1017 // -- esp[0] : return address 1018 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1019 // -- ... 1020 // -- esp[(argc + 1) * 4] : receiver 1021 // ----------------------------------- 1022 Label miss; 1023 1024 // Get the receiver of the function from the stack; 1 ~ return address. 1025 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1026 1027 GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss); 1028 1029 // eax: elements 1030 // Search the dictionary placing the result in edi. 1031 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi); 1032 GenerateFunctionTailCall(masm, argc, &miss); 1033 1034 __ bind(&miss); 1035} 1036 1037 1038void CallICBase::GenerateMiss(MacroAssembler* masm, 1039 int argc, 1040 IC::UtilityId id, 1041 Code::ExtraICState extra_state) { 1042 // ----------- S t a t e ------------- 1043 // -- ecx : name 1044 // -- esp[0] : return address 1045 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1046 // -- ... 1047 // -- esp[(argc + 1) * 4] : receiver 1048 // ----------------------------------- 1049 1050 Counters* counters = masm->isolate()->counters(); 1051 if (id == IC::kCallIC_Miss) { 1052 __ IncrementCounter(counters->call_miss(), 1); 1053 } else { 1054 __ IncrementCounter(counters->keyed_call_miss(), 1); 1055 } 1056 1057 // Get the receiver of the function from the stack; 1 ~ return address. 1058 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1059 1060 { 1061 FrameScope scope(masm, StackFrame::INTERNAL); 1062 1063 // Push the receiver and the name of the function. 1064 __ push(edx); 1065 __ push(ecx); 1066 1067 // Call the entry. 1068 CEntryStub stub(1); 1069 __ mov(eax, Immediate(2)); 1070 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate()))); 1071 __ CallStub(&stub); 1072 1073 // Move result to edi and exit the internal frame. 1074 __ mov(edi, eax); 1075 } 1076 1077 // Check if the receiver is a global object of some sort. 1078 // This can happen only for regular CallIC but not KeyedCallIC. 1079 if (id == IC::kCallIC_Miss) { 1080 Label invoke, global; 1081 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver 1082 __ JumpIfSmi(edx, &invoke, Label::kNear); 1083 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 1084 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 1085 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); 1086 __ j(equal, &global, Label::kNear); 1087 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); 1088 __ j(not_equal, &invoke, Label::kNear); 1089 1090 // Patch the receiver on the stack. 1091 __ bind(&global); 1092 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); 1093 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); 1094 __ bind(&invoke); 1095 } 1096 1097 // Invoke the function. 1098 CallKind call_kind = CallICBase::Contextual::decode(extra_state) 1099 ? CALL_AS_FUNCTION 1100 : CALL_AS_METHOD; 1101 ParameterCount actual(argc); 1102 __ InvokeFunction(edi, 1103 actual, 1104 JUMP_FUNCTION, 1105 NullCallWrapper(), 1106 call_kind); 1107} 1108 1109 1110void CallIC::GenerateMegamorphic(MacroAssembler* masm, 1111 int argc, 1112 Code::ExtraICState extra_state) { 1113 // ----------- S t a t e ------------- 1114 // -- ecx : name 1115 // -- esp[0] : return address 1116 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1117 // -- ... 1118 // -- esp[(argc + 1) * 4] : receiver 1119 // ----------------------------------- 1120 1121 // Get the receiver of the function from the stack; 1 ~ return address. 1122 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1123 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, 1124 extra_state); 1125 1126 GenerateMiss(masm, argc, extra_state); 1127} 1128 1129 1130void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { 1131 // ----------- S t a t e ------------- 1132 // -- ecx : name 1133 // -- esp[0] : return address 1134 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1135 // -- ... 1136 // -- esp[(argc + 1) * 4] : receiver 1137 // ----------------------------------- 1138 1139 // Get the receiver of the function from the stack; 1 ~ return address. 1140 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1141 1142 Label do_call, slow_call, slow_load, slow_reload_receiver; 1143 Label check_number_dictionary, check_name, lookup_monomorphic_cache; 1144 Label index_smi, index_name; 1145 1146 // Check that the key is a smi. 1147 __ JumpIfNotSmi(ecx, &check_name); 1148 1149 __ bind(&index_smi); 1150 // Now the key is known to be a smi. This place is also jumped to from 1151 // where a numeric string is converted to a smi. 1152 1153 GenerateKeyedLoadReceiverCheck( 1154 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); 1155 1156 GenerateFastArrayLoad( 1157 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); 1158 Isolate* isolate = masm->isolate(); 1159 Counters* counters = isolate->counters(); 1160 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1); 1161 1162 __ bind(&do_call); 1163 // receiver in edx is not used after this point. 1164 // ecx: key 1165 // edi: function 1166 GenerateFunctionTailCall(masm, argc, &slow_call); 1167 1168 __ bind(&check_number_dictionary); 1169 // eax: elements 1170 // ecx: smi key 1171 // Check whether the elements is a number dictionary. 1172 __ CheckMap(eax, 1173 isolate->factory()->hash_table_map(), 1174 &slow_load, 1175 DONT_DO_SMI_CHECK); 1176 __ mov(ebx, ecx); 1177 __ SmiUntag(ebx); 1178 // ebx: untagged index 1179 // Receiver in edx will be clobbered, need to reload it on miss. 1180 __ LoadFromNumberDictionary( 1181 &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi); 1182 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); 1183 __ jmp(&do_call); 1184 1185 __ bind(&slow_reload_receiver); 1186 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1187 1188 __ bind(&slow_load); 1189 // This branch is taken when calling KeyedCallIC_Miss is neither required 1190 // nor beneficial. 1191 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); 1192 1193 { 1194 FrameScope scope(masm, StackFrame::INTERNAL); 1195 __ push(ecx); // save the key 1196 __ push(edx); // pass the receiver 1197 __ push(ecx); // pass the key 1198 __ CallRuntime(Runtime::kKeyedGetProperty, 2); 1199 __ pop(ecx); // restore the key 1200 // Leave the internal frame. 1201 } 1202 1203 __ mov(edi, eax); 1204 __ jmp(&do_call); 1205 1206 __ bind(&check_name); 1207 GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow_call); 1208 1209 // The key is known to be a unique name. 1210 // If the receiver is a regular JS object with slow properties then do 1211 // a quick inline probe of the receiver's dictionary. 1212 // Otherwise do the monomorphic cache probe. 1213 GenerateKeyedLoadReceiverCheck( 1214 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); 1215 1216 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); 1217 __ CheckMap(ebx, 1218 isolate->factory()->hash_table_map(), 1219 &lookup_monomorphic_cache, 1220 DONT_DO_SMI_CHECK); 1221 1222 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi); 1223 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1); 1224 __ jmp(&do_call); 1225 1226 __ bind(&lookup_monomorphic_cache); 1227 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1); 1228 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC, 1229 Code::kNoExtraICState); 1230 // Fall through on miss. 1231 1232 __ bind(&slow_call); 1233 // This branch is taken if: 1234 // - the receiver requires boxing or access check, 1235 // - the key is neither smi nor a unique name, 1236 // - the value loaded is not a function, 1237 // - there is hope that the runtime will create a monomorphic call stub 1238 // that will get fetched next time. 1239 __ IncrementCounter(counters->keyed_call_generic_slow(), 1); 1240 GenerateMiss(masm, argc); 1241 1242 __ bind(&index_name); 1243 __ IndexFromHash(ebx, ecx); 1244 // Now jump to the place where smi keys are handled. 1245 __ jmp(&index_smi); 1246} 1247 1248 1249void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm, 1250 int argc) { 1251 // ----------- S t a t e ------------- 1252 // -- ecx : name 1253 // -- esp[0] : return address 1254 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1255 // -- ... 1256 // -- esp[(argc + 1) * 4] : receiver 1257 // ----------------------------------- 1258 Label slow, notin; 1259 Factory* factory = masm->isolate()->factory(); 1260 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1261 Operand mapped_location = 1262 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, ¬in, &slow); 1263 __ mov(edi, mapped_location); 1264 GenerateFunctionTailCall(masm, argc, &slow); 1265 __ bind(¬in); 1266 // The unmapped lookup expects that the parameter map is in ebx. 1267 Operand unmapped_location = 1268 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow); 1269 __ cmp(unmapped_location, factory->the_hole_value()); 1270 __ j(equal, &slow); 1271 __ mov(edi, unmapped_location); 1272 GenerateFunctionTailCall(masm, argc, &slow); 1273 __ bind(&slow); 1274 GenerateMiss(masm, argc); 1275} 1276 1277 1278void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { 1279 // ----------- S t a t e ------------- 1280 // -- ecx : name 1281 // -- esp[0] : return address 1282 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1283 // -- ... 1284 // -- esp[(argc + 1) * 4] : receiver 1285 // ----------------------------------- 1286 1287 // Check if the name is really a name. 1288 Label miss; 1289 __ JumpIfSmi(ecx, &miss); 1290 Condition cond = masm->IsObjectNameType(ecx, eax, eax); 1291 __ j(NegateCondition(cond), &miss); 1292 CallICBase::GenerateNormal(masm, argc); 1293 __ bind(&miss); 1294 GenerateMiss(masm, argc); 1295} 1296 1297 1298void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { 1299 // ----------- S t a t e ------------- 1300 // -- ecx : name 1301 // -- edx : receiver 1302 // -- esp[0] : return address 1303 // ----------------------------------- 1304 1305 // Probe the stub cache. 1306 Code::Flags flags = Code::ComputeFlags( 1307 Code::STUB, MONOMORPHIC, Code::kNoExtraICState, 1308 Code::NORMAL, Code::LOAD_IC); 1309 Isolate::Current()->stub_cache()->GenerateProbe( 1310 masm, flags, edx, ecx, ebx, eax); 1311 1312 // Cache miss: Jump to runtime. 1313 GenerateMiss(masm); 1314} 1315 1316 1317void LoadIC::GenerateNormal(MacroAssembler* masm) { 1318 // ----------- S t a t e ------------- 1319 // -- ecx : name 1320 // -- edx : receiver 1321 // -- esp[0] : return address 1322 // ----------------------------------- 1323 Label miss; 1324 1325 GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss); 1326 1327 // eax: elements 1328 // Search the dictionary placing the result in eax. 1329 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax); 1330 __ ret(0); 1331 1332 // Cache miss: Jump to runtime. 1333 __ bind(&miss); 1334 GenerateMiss(masm); 1335} 1336 1337 1338void LoadIC::GenerateMiss(MacroAssembler* masm) { 1339 // ----------- S t a t e ------------- 1340 // -- ecx : name 1341 // -- edx : receiver 1342 // -- esp[0] : return address 1343 // ----------------------------------- 1344 1345 __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1); 1346 1347 __ pop(ebx); 1348 __ push(edx); // receiver 1349 __ push(ecx); // name 1350 __ push(ebx); // return address 1351 1352 // Perform tail call to the entry. 1353 ExternalReference ref = 1354 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); 1355 __ TailCallExternalReference(ref, 2, 1); 1356} 1357 1358 1359void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { 1360 // ----------- S t a t e ------------- 1361 // -- ecx : key 1362 // -- edx : receiver 1363 // -- esp[0] : return address 1364 // ----------------------------------- 1365 1366 __ pop(ebx); 1367 __ push(edx); // receiver 1368 __ push(ecx); // name 1369 __ push(ebx); // return address 1370 1371 // Perform tail call to the entry. 1372 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); 1373} 1374 1375 1376void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) { 1377 // ----------- S t a t e ------------- 1378 // -- ecx : key 1379 // -- edx : receiver 1380 // -- esp[0] : return address 1381 // ----------------------------------- 1382 1383 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1); 1384 1385 __ pop(ebx); 1386 __ push(edx); // receiver 1387 __ push(ecx); // name 1388 __ push(ebx); // return address 1389 1390 // Perform tail call to the entry. 1391 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC 1392 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), 1393 masm->isolate()) 1394 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); 1395 __ TailCallExternalReference(ref, 2, 1); 1396} 1397 1398 1399void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { 1400 // ----------- S t a t e ------------- 1401 // -- ecx : key 1402 // -- edx : receiver 1403 // -- esp[0] : return address 1404 // ----------------------------------- 1405 1406 __ pop(ebx); 1407 __ push(edx); // receiver 1408 __ push(ecx); // name 1409 __ push(ebx); // return address 1410 1411 // Perform tail call to the entry. 1412 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); 1413} 1414 1415 1416void StoreIC::GenerateMegamorphic(MacroAssembler* masm, 1417 StrictModeFlag strict_mode) { 1418 // ----------- S t a t e ------------- 1419 // -- eax : value 1420 // -- ecx : name 1421 // -- edx : receiver 1422 // -- esp[0] : return address 1423 // ----------------------------------- 1424 1425 Code::Flags flags = Code::ComputeFlags( 1426 Code::STUB, MONOMORPHIC, strict_mode, 1427 Code::NORMAL, Code::STORE_IC); 1428 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, 1429 no_reg); 1430 1431 // Cache miss: Jump to runtime. 1432 GenerateMiss(masm); 1433} 1434 1435 1436void StoreIC::GenerateMiss(MacroAssembler* masm) { 1437 // ----------- S t a t e ------------- 1438 // -- eax : value 1439 // -- ecx : name 1440 // -- edx : receiver 1441 // -- esp[0] : return address 1442 // ----------------------------------- 1443 1444 __ pop(ebx); 1445 __ push(edx); 1446 __ push(ecx); 1447 __ push(eax); 1448 __ push(ebx); 1449 1450 // Perform tail call to the entry. 1451 ExternalReference ref = 1452 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate()); 1453 __ TailCallExternalReference(ref, 3, 1); 1454} 1455 1456 1457void StoreIC::GenerateNormal(MacroAssembler* masm) { 1458 // ----------- S t a t e ------------- 1459 // -- eax : value 1460 // -- ecx : name 1461 // -- edx : receiver 1462 // -- esp[0] : return address 1463 // ----------------------------------- 1464 1465 Label miss, restore_miss; 1466 1467 GenerateNameDictionaryReceiverCheck(masm, edx, ebx, edi, &miss); 1468 1469 // A lot of registers are needed for storing to slow case 1470 // objects. Push and restore receiver but rely on 1471 // GenerateDictionaryStore preserving the value and name. 1472 __ push(edx); 1473 GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi); 1474 __ Drop(1); 1475 Counters* counters = masm->isolate()->counters(); 1476 __ IncrementCounter(counters->store_normal_hit(), 1); 1477 __ ret(0); 1478 1479 __ bind(&restore_miss); 1480 __ pop(edx); 1481 1482 __ bind(&miss); 1483 __ IncrementCounter(counters->store_normal_miss(), 1); 1484 GenerateMiss(masm); 1485} 1486 1487 1488void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, 1489 StrictModeFlag strict_mode) { 1490 // ----------- S t a t e ------------- 1491 // -- eax : value 1492 // -- ecx : name 1493 // -- edx : receiver 1494 // -- esp[0] : return address 1495 // ----------------------------------- 1496 __ pop(ebx); 1497 __ push(edx); 1498 __ push(ecx); 1499 __ push(eax); 1500 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes 1501 __ push(Immediate(Smi::FromInt(strict_mode))); 1502 __ push(ebx); // return address 1503 1504 // Do tail-call to runtime routine. 1505 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); 1506} 1507 1508 1509void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, 1510 StrictModeFlag strict_mode) { 1511 // ----------- S t a t e ------------- 1512 // -- eax : value 1513 // -- ecx : key 1514 // -- edx : receiver 1515 // -- esp[0] : return address 1516 // ----------------------------------- 1517 1518 __ pop(ebx); 1519 __ push(edx); 1520 __ push(ecx); 1521 __ push(eax); 1522 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes 1523 __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode. 1524 __ push(ebx); // return address 1525 1526 // Do tail-call to runtime routine. 1527 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); 1528} 1529 1530 1531void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) { 1532 // ----------- S t a t e ------------- 1533 // -- eax : value 1534 // -- ecx : key 1535 // -- edx : receiver 1536 // -- esp[0] : return address 1537 // ----------------------------------- 1538 1539 __ pop(ebx); 1540 __ push(edx); 1541 __ push(ecx); 1542 __ push(eax); 1543 __ push(ebx); 1544 1545 // Do tail-call to runtime routine. 1546 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC 1547 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric), 1548 masm->isolate()) 1549 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate()); 1550 __ TailCallExternalReference(ref, 3, 1); 1551} 1552 1553 1554void StoreIC::GenerateSlow(MacroAssembler* masm) { 1555 // ----------- S t a t e ------------- 1556 // -- eax : value 1557 // -- ecx : key 1558 // -- edx : receiver 1559 // -- esp[0] : return address 1560 // ----------------------------------- 1561 1562 __ pop(ebx); 1563 __ push(edx); 1564 __ push(ecx); 1565 __ push(eax); 1566 __ push(ebx); // return address 1567 1568 // Do tail-call to runtime routine. 1569 ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate()); 1570 __ TailCallExternalReference(ref, 3, 1); 1571} 1572 1573 1574void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { 1575 // ----------- S t a t e ------------- 1576 // -- eax : value 1577 // -- ecx : key 1578 // -- edx : receiver 1579 // -- esp[0] : return address 1580 // ----------------------------------- 1581 1582 __ pop(ebx); 1583 __ push(edx); 1584 __ push(ecx); 1585 __ push(eax); 1586 __ push(ebx); // return address 1587 1588 // Do tail-call to runtime routine. 1589 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); 1590 __ TailCallExternalReference(ref, 3, 1); 1591} 1592 1593 1594#undef __ 1595 1596 1597Condition CompareIC::ComputeCondition(Token::Value op) { 1598 switch (op) { 1599 case Token::EQ_STRICT: 1600 case Token::EQ: 1601 return equal; 1602 case Token::LT: 1603 return less; 1604 case Token::GT: 1605 return greater; 1606 case Token::LTE: 1607 return less_equal; 1608 case Token::GTE: 1609 return greater_equal; 1610 default: 1611 UNREACHABLE(); 1612 return no_condition; 1613 } 1614} 1615 1616 1617bool CompareIC::HasInlinedSmiCode(Address address) { 1618 // The address of the instruction following the call. 1619 Address test_instruction_address = 1620 address + Assembler::kCallTargetAddressOffset; 1621 1622 // If the instruction following the call is not a test al, nothing 1623 // was inlined. 1624 return *test_instruction_address == Assembler::kTestAlByte; 1625} 1626 1627 1628void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { 1629 // The address of the instruction following the call. 1630 Address test_instruction_address = 1631 address + Assembler::kCallTargetAddressOffset; 1632 1633 // If the instruction following the call is not a test al, nothing 1634 // was inlined. 1635 if (*test_instruction_address != Assembler::kTestAlByte) { 1636 ASSERT(*test_instruction_address == Assembler::kNopByte); 1637 return; 1638 } 1639 1640 Address delta_address = test_instruction_address + 1; 1641 // The delta to the start of the map check instruction and the 1642 // condition code uses at the patched jump. 1643 int8_t delta = *reinterpret_cast<int8_t*>(delta_address); 1644 if (FLAG_trace_ic) { 1645 PrintF("[ patching ic at %p, test=%p, delta=%d\n", 1646 address, test_instruction_address, delta); 1647 } 1648 1649 // Patch with a short conditional jump. Enabling means switching from a short 1650 // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the 1651 // reverse operation of that. 1652 Address jmp_address = test_instruction_address - delta; 1653 ASSERT((check == ENABLE_INLINED_SMI_CHECK) 1654 ? (*jmp_address == Assembler::kJncShortOpcode || 1655 *jmp_address == Assembler::kJcShortOpcode) 1656 : (*jmp_address == Assembler::kJnzShortOpcode || 1657 *jmp_address == Assembler::kJzShortOpcode)); 1658 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) 1659 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) 1660 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); 1661 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); 1662} 1663 1664 1665} } // namespace v8::internal 1666 1667#endif // V8_TARGET_ARCH_IA32 1668