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); 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); 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); 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); 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 737 // HOLECHECK: guards "A[i] = V" 738 // We have to go to the runtime if the current value is the hole because 739 // there may be a callback on the element 740 Label holecheck_passed1; 741 __ cmp(CodeGenerator::FixedArrayElementOperand(ebx, ecx), 742 masm->isolate()->factory()->the_hole_value()); 743 __ j(not_equal, &holecheck_passed1); 744 __ JumpIfDictionaryInPrototypeChain(edx, ebx, edi, slow); 745 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 746 747 __ bind(&holecheck_passed1); 748 749 // Smi stores don't require further checks. 750 Label non_smi_value; 751 __ JumpIfNotSmi(eax, &non_smi_value); 752 if (increment_length == kIncrementLength) { 753 // Add 1 to receiver->length. 754 __ add(FieldOperand(edx, JSArray::kLengthOffset), 755 Immediate(Smi::FromInt(1))); 756 } 757 // It's irrelevant whether array is smi-only or not when writing a smi. 758 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax); 759 __ ret(0); 760 761 __ bind(&non_smi_value); 762 // Escape to elements kind transition case. 763 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 764 __ CheckFastObjectElements(edi, &transition_smi_elements); 765 766 // Fast elements array, store the value to the elements backing store. 767 __ bind(&finish_object_store); 768 if (increment_length == kIncrementLength) { 769 // Add 1 to receiver->length. 770 __ add(FieldOperand(edx, JSArray::kLengthOffset), 771 Immediate(Smi::FromInt(1))); 772 } 773 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax); 774 // Update write barrier for the elements array address. 775 __ mov(edx, eax); // Preserve the value which is returned. 776 __ RecordWriteArray( 777 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); 778 __ ret(0); 779 780 __ bind(fast_double); 781 if (check_map == kCheckMap) { 782 // Check for fast double array case. If this fails, call through to the 783 // runtime. 784 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map()); 785 __ j(not_equal, slow); 786 // If the value is a number, store it as a double in the FastDoubleElements 787 // array. 788 } 789 790 // HOLECHECK: guards "A[i] double hole?" 791 // We have to see if the double version of the hole is present. If so 792 // go to the runtime. 793 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); 794 __ cmp(FieldOperand(ebx, ecx, times_4, offset), Immediate(kHoleNanUpper32)); 795 __ j(not_equal, &fast_double_without_map_check); 796 __ JumpIfDictionaryInPrototypeChain(edx, ebx, edi, slow); 797 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 798 799 __ bind(&fast_double_without_map_check); 800 __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0, 801 &transition_double_elements, false); 802 if (increment_length == kIncrementLength) { 803 // Add 1 to receiver->length. 804 __ add(FieldOperand(edx, JSArray::kLengthOffset), 805 Immediate(Smi::FromInt(1))); 806 } 807 __ ret(0); 808 809 __ bind(&transition_smi_elements); 810 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 811 812 // Transition the array appropriately depending on the value type. 813 __ CheckMap(eax, 814 masm->isolate()->factory()->heap_number_map(), 815 &non_double_value, 816 DONT_DO_SMI_CHECK); 817 818 // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS 819 // and complete the store. 820 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, 821 FAST_DOUBLE_ELEMENTS, 822 ebx, 823 edi, 824 slow); 825 AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, 826 FAST_DOUBLE_ELEMENTS); 827 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow); 828 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 829 __ jmp(&fast_double_without_map_check); 830 831 __ bind(&non_double_value); 832 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS 833 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, 834 FAST_ELEMENTS, 835 ebx, 836 edi, 837 slow); 838 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); 839 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode, 840 slow); 841 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 842 __ jmp(&finish_object_store); 843 844 __ bind(&transition_double_elements); 845 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a 846 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and 847 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS 848 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 849 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, 850 FAST_ELEMENTS, 851 ebx, 852 edi, 853 slow); 854 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); 855 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow); 856 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 857 __ jmp(&finish_object_store); 858} 859 860 861void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, 862 StrictModeFlag strict_mode) { 863 // ----------- S t a t e ------------- 864 // -- eax : value 865 // -- ecx : key 866 // -- edx : receiver 867 // -- esp[0] : return address 868 // ----------------------------------- 869 Label slow, fast_object, fast_object_grow; 870 Label fast_double, fast_double_grow; 871 Label array, extra, check_if_double_array; 872 873 // Check that the object isn't a smi. 874 __ JumpIfSmi(edx, &slow); 875 // Get the map from the receiver. 876 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 877 // Check that the receiver does not require access checks and is not observed. 878 // The generic stub does not perform map checks or handle observed objects. 879 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), 880 1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved); 881 __ j(not_zero, &slow); 882 // Check that the key is a smi. 883 __ JumpIfNotSmi(ecx, &slow); 884 __ CmpInstanceType(edi, JS_ARRAY_TYPE); 885 __ j(equal, &array); 886 // Check that the object is some kind of JSObject. 887 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); 888 __ j(below, &slow); 889 890 // Object case: Check key against length in the elements array. 891 // eax: value 892 // edx: JSObject 893 // ecx: key (a smi) 894 // edi: receiver map 895 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 896 // Check array bounds. Both the key and the length of FixedArray are smis. 897 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); 898 __ j(below, &fast_object); 899 900 // Slow case: call runtime. 901 __ bind(&slow); 902 GenerateRuntimeSetProperty(masm, strict_mode); 903 904 // Extra capacity case: Check if there is extra capacity to 905 // perform the store and update the length. Used for adding one 906 // element to the array by writing to array[array.length]. 907 __ bind(&extra); 908 // eax: value 909 // edx: receiver, a JSArray 910 // ecx: key, a smi. 911 // ebx: receiver->elements, a FixedArray 912 // edi: receiver map 913 // flags: compare (ecx, edx.length()) 914 // do not leave holes in the array: 915 __ j(not_equal, &slow); 916 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); 917 __ j(above_equal, &slow); 918 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset)); 919 __ cmp(edi, masm->isolate()->factory()->fixed_array_map()); 920 __ j(not_equal, &check_if_double_array); 921 __ jmp(&fast_object_grow); 922 923 __ bind(&check_if_double_array); 924 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map()); 925 __ j(not_equal, &slow); 926 __ jmp(&fast_double_grow); 927 928 // Array case: Get the length and the elements array from the JS 929 // array. Check that the array is in fast mode (and writable); if it 930 // is the length is always a smi. 931 __ bind(&array); 932 // eax: value 933 // edx: receiver, a JSArray 934 // ecx: key, a smi. 935 // edi: receiver map 936 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 937 938 // Check the key against the length in the array and fall through to the 939 // common store code. 940 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. 941 __ j(above_equal, &extra); 942 943 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, 944 &slow, kCheckMap, kDontIncrementLength); 945 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, 946 &slow, kDontCheckMap, kIncrementLength); 947} 948 949 950// The generated code does not accept smi keys. 951// The generated code falls through if both probes miss. 952void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, 953 int argc, 954 Code::Kind kind, 955 ExtraICState extra_state) { 956 // ----------- S t a t e ------------- 957 // -- ecx : name 958 // -- edx : receiver 959 // ----------------------------------- 960 Label number, non_number, non_string, boolean, probe, miss; 961 962 // Probe the stub cache. 963 Code::Flags flags = Code::ComputeFlags(kind, 964 MONOMORPHIC, 965 extra_state, 966 Code::NORMAL, 967 argc); 968 Isolate* isolate = masm->isolate(); 969 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax); 970 971 // If the stub cache probing failed, the receiver might be a value. 972 // For value objects, we use the map of the prototype objects for 973 // the corresponding JSValue for the cache and that is what we need 974 // to probe. 975 // 976 // Check for number. 977 __ JumpIfSmi(edx, &number); 978 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); 979 __ j(not_equal, &non_number); 980 __ bind(&number); 981 StubCompiler::GenerateLoadGlobalFunctionPrototype( 982 masm, Context::NUMBER_FUNCTION_INDEX, edx); 983 __ jmp(&probe); 984 985 // Check for string. 986 __ bind(&non_number); 987 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE); 988 __ j(above_equal, &non_string); 989 StubCompiler::GenerateLoadGlobalFunctionPrototype( 990 masm, Context::STRING_FUNCTION_INDEX, edx); 991 __ jmp(&probe); 992 993 // Check for boolean. 994 __ bind(&non_string); 995 __ cmp(edx, isolate->factory()->true_value()); 996 __ j(equal, &boolean); 997 __ cmp(edx, isolate->factory()->false_value()); 998 __ j(not_equal, &miss); 999 __ bind(&boolean); 1000 StubCompiler::GenerateLoadGlobalFunctionPrototype( 1001 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); 1002 1003 // Probe the stub cache for the value object. 1004 __ bind(&probe); 1005 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); 1006 __ bind(&miss); 1007} 1008 1009 1010static void GenerateFunctionTailCall(MacroAssembler* masm, 1011 int argc, 1012 Label* miss) { 1013 // ----------- S t a t e ------------- 1014 // -- ecx : name 1015 // -- edi : function 1016 // -- esp[0] : return address 1017 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1018 // -- ... 1019 // -- esp[(argc + 1) * 4] : receiver 1020 // ----------------------------------- 1021 1022 // Check that the result is not a smi. 1023 __ JumpIfSmi(edi, miss); 1024 1025 // Check that the value is a JavaScript function, fetching its map into eax. 1026 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); 1027 __ j(not_equal, miss); 1028 1029 // Invoke the function. 1030 ParameterCount actual(argc); 1031 __ InvokeFunction(edi, actual, JUMP_FUNCTION, 1032 NullCallWrapper(), CALL_AS_METHOD); 1033} 1034 1035 1036// The generated code falls through if the call should be handled by runtime. 1037void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) { 1038 // ----------- S t a t e ------------- 1039 // -- ecx : name 1040 // -- esp[0] : return address 1041 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1042 // -- ... 1043 // -- esp[(argc + 1) * 4] : receiver 1044 // ----------------------------------- 1045 Label miss; 1046 1047 // Get the receiver of the function from the stack; 1 ~ return address. 1048 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1049 1050 GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss); 1051 1052 // eax: elements 1053 // Search the dictionary placing the result in edi. 1054 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi); 1055 GenerateFunctionTailCall(masm, argc, &miss); 1056 1057 __ bind(&miss); 1058} 1059 1060 1061void CallICBase::GenerateMiss(MacroAssembler* masm, 1062 int argc, 1063 IC::UtilityId id, 1064 ExtraICState extra_state) { 1065 // ----------- S t a t e ------------- 1066 // -- ecx : name 1067 // -- esp[0] : return address 1068 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1069 // -- ... 1070 // -- esp[(argc + 1) * 4] : receiver 1071 // ----------------------------------- 1072 1073 Counters* counters = masm->isolate()->counters(); 1074 if (id == IC::kCallIC_Miss) { 1075 __ IncrementCounter(counters->call_miss(), 1); 1076 } else { 1077 __ IncrementCounter(counters->keyed_call_miss(), 1); 1078 } 1079 1080 // Get the receiver of the function from the stack; 1 ~ return address. 1081 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1082 1083 { 1084 FrameScope scope(masm, StackFrame::INTERNAL); 1085 1086 // Push the receiver and the name of the function. 1087 __ push(edx); 1088 __ push(ecx); 1089 1090 // Call the entry. 1091 CEntryStub stub(1); 1092 __ mov(eax, Immediate(2)); 1093 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate()))); 1094 __ CallStub(&stub); 1095 1096 // Move result to edi and exit the internal frame. 1097 __ mov(edi, eax); 1098 } 1099 1100 // Check if the receiver is a global object of some sort. 1101 // This can happen only for regular CallIC but not KeyedCallIC. 1102 if (id == IC::kCallIC_Miss) { 1103 Label invoke, global; 1104 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver 1105 __ JumpIfSmi(edx, &invoke, Label::kNear); 1106 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 1107 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 1108 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); 1109 __ j(equal, &global, Label::kNear); 1110 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); 1111 __ j(not_equal, &invoke, Label::kNear); 1112 1113 // Patch the receiver on the stack. 1114 __ bind(&global); 1115 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); 1116 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); 1117 __ bind(&invoke); 1118 } 1119 1120 // Invoke the function. 1121 CallKind call_kind = CallICBase::Contextual::decode(extra_state) 1122 ? CALL_AS_FUNCTION 1123 : CALL_AS_METHOD; 1124 ParameterCount actual(argc); 1125 __ InvokeFunction(edi, 1126 actual, 1127 JUMP_FUNCTION, 1128 NullCallWrapper(), 1129 call_kind); 1130} 1131 1132 1133void CallIC::GenerateMegamorphic(MacroAssembler* masm, 1134 int argc, 1135 ExtraICState extra_state) { 1136 // ----------- S t a t e ------------- 1137 // -- ecx : name 1138 // -- esp[0] : return address 1139 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1140 // -- ... 1141 // -- esp[(argc + 1) * 4] : receiver 1142 // ----------------------------------- 1143 1144 // Get the receiver of the function from the stack; 1 ~ return address. 1145 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1146 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, 1147 extra_state); 1148 1149 GenerateMiss(masm, argc, extra_state); 1150} 1151 1152 1153void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { 1154 // ----------- S t a t e ------------- 1155 // -- ecx : name 1156 // -- esp[0] : return address 1157 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1158 // -- ... 1159 // -- esp[(argc + 1) * 4] : receiver 1160 // ----------------------------------- 1161 1162 // Get the receiver of the function from the stack; 1 ~ return address. 1163 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1164 1165 Label do_call, slow_call, slow_load, slow_reload_receiver; 1166 Label check_number_dictionary, check_name, lookup_monomorphic_cache; 1167 Label index_smi, index_name; 1168 1169 // Check that the key is a smi. 1170 __ JumpIfNotSmi(ecx, &check_name); 1171 1172 __ bind(&index_smi); 1173 // Now the key is known to be a smi. This place is also jumped to from 1174 // where a numeric string is converted to a smi. 1175 1176 GenerateKeyedLoadReceiverCheck( 1177 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); 1178 1179 GenerateFastArrayLoad( 1180 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); 1181 Isolate* isolate = masm->isolate(); 1182 Counters* counters = isolate->counters(); 1183 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1); 1184 1185 __ bind(&do_call); 1186 // receiver in edx is not used after this point. 1187 // ecx: key 1188 // edi: function 1189 GenerateFunctionTailCall(masm, argc, &slow_call); 1190 1191 __ bind(&check_number_dictionary); 1192 // eax: elements 1193 // ecx: smi key 1194 // Check whether the elements is a number dictionary. 1195 __ CheckMap(eax, 1196 isolate->factory()->hash_table_map(), 1197 &slow_load, 1198 DONT_DO_SMI_CHECK); 1199 __ mov(ebx, ecx); 1200 __ SmiUntag(ebx); 1201 // ebx: untagged index 1202 // Receiver in edx will be clobbered, need to reload it on miss. 1203 __ LoadFromNumberDictionary( 1204 &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi); 1205 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); 1206 __ jmp(&do_call); 1207 1208 __ bind(&slow_reload_receiver); 1209 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1210 1211 __ bind(&slow_load); 1212 // This branch is taken when calling KeyedCallIC_Miss is neither required 1213 // nor beneficial. 1214 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); 1215 1216 { 1217 FrameScope scope(masm, StackFrame::INTERNAL); 1218 __ push(ecx); // save the key 1219 __ push(edx); // pass the receiver 1220 __ push(ecx); // pass the key 1221 __ CallRuntime(Runtime::kKeyedGetProperty, 2); 1222 __ pop(ecx); // restore the key 1223 // Leave the internal frame. 1224 } 1225 1226 __ mov(edi, eax); 1227 __ jmp(&do_call); 1228 1229 __ bind(&check_name); 1230 GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow_call); 1231 1232 // The key is known to be a unique name. 1233 // If the receiver is a regular JS object with slow properties then do 1234 // a quick inline probe of the receiver's dictionary. 1235 // Otherwise do the monomorphic cache probe. 1236 GenerateKeyedLoadReceiverCheck( 1237 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); 1238 1239 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); 1240 __ CheckMap(ebx, 1241 isolate->factory()->hash_table_map(), 1242 &lookup_monomorphic_cache, 1243 DONT_DO_SMI_CHECK); 1244 1245 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi); 1246 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1); 1247 __ jmp(&do_call); 1248 1249 __ bind(&lookup_monomorphic_cache); 1250 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1); 1251 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC, 1252 kNoExtraICState); 1253 // Fall through on miss. 1254 1255 __ bind(&slow_call); 1256 // This branch is taken if: 1257 // - the receiver requires boxing or access check, 1258 // - the key is neither smi nor a unique name, 1259 // - the value loaded is not a function, 1260 // - there is hope that the runtime will create a monomorphic call stub 1261 // that will get fetched next time. 1262 __ IncrementCounter(counters->keyed_call_generic_slow(), 1); 1263 GenerateMiss(masm, argc); 1264 1265 __ bind(&index_name); 1266 __ IndexFromHash(ebx, ecx); 1267 // Now jump to the place where smi keys are handled. 1268 __ jmp(&index_smi); 1269} 1270 1271 1272void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm, 1273 int argc) { 1274 // ----------- S t a t e ------------- 1275 // -- ecx : name 1276 // -- esp[0] : return address 1277 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1278 // -- ... 1279 // -- esp[(argc + 1) * 4] : receiver 1280 // ----------------------------------- 1281 Label slow, notin; 1282 Factory* factory = masm->isolate()->factory(); 1283 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1284 Operand mapped_location = 1285 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, ¬in, &slow); 1286 __ mov(edi, mapped_location); 1287 GenerateFunctionTailCall(masm, argc, &slow); 1288 __ bind(¬in); 1289 // The unmapped lookup expects that the parameter map is in ebx. 1290 Operand unmapped_location = 1291 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow); 1292 __ cmp(unmapped_location, factory->the_hole_value()); 1293 __ j(equal, &slow); 1294 __ mov(edi, unmapped_location); 1295 GenerateFunctionTailCall(masm, argc, &slow); 1296 __ bind(&slow); 1297 GenerateMiss(masm, argc); 1298} 1299 1300 1301void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { 1302 // ----------- S t a t e ------------- 1303 // -- ecx : name 1304 // -- esp[0] : return address 1305 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1306 // -- ... 1307 // -- esp[(argc + 1) * 4] : receiver 1308 // ----------------------------------- 1309 1310 // Check if the name is really a name. 1311 Label miss; 1312 __ JumpIfSmi(ecx, &miss); 1313 Condition cond = masm->IsObjectNameType(ecx, eax, eax); 1314 __ j(NegateCondition(cond), &miss); 1315 CallICBase::GenerateNormal(masm, argc); 1316 __ bind(&miss); 1317 GenerateMiss(masm, argc); 1318} 1319 1320 1321void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { 1322 // ----------- S t a t e ------------- 1323 // -- ecx : name 1324 // -- edx : receiver 1325 // -- esp[0] : return address 1326 // ----------------------------------- 1327 1328 // Probe the stub cache. 1329 Code::Flags flags = Code::ComputeFlags( 1330 Code::HANDLER, MONOMORPHIC, kNoExtraICState, 1331 Code::NORMAL, Code::LOAD_IC); 1332 masm->isolate()->stub_cache()->GenerateProbe( 1333 masm, flags, edx, ecx, ebx, eax); 1334 1335 // Cache miss: Jump to runtime. 1336 GenerateMiss(masm); 1337} 1338 1339 1340void LoadIC::GenerateNormal(MacroAssembler* masm) { 1341 // ----------- S t a t e ------------- 1342 // -- ecx : name 1343 // -- edx : receiver 1344 // -- esp[0] : return address 1345 // ----------------------------------- 1346 Label miss; 1347 1348 GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss); 1349 1350 // eax: elements 1351 // Search the dictionary placing the result in eax. 1352 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax); 1353 __ ret(0); 1354 1355 // Cache miss: Jump to runtime. 1356 __ bind(&miss); 1357 GenerateMiss(masm); 1358} 1359 1360 1361void LoadIC::GenerateMiss(MacroAssembler* masm) { 1362 // ----------- S t a t e ------------- 1363 // -- ecx : name 1364 // -- edx : receiver 1365 // -- esp[0] : return address 1366 // ----------------------------------- 1367 1368 __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1); 1369 1370 __ pop(ebx); 1371 __ push(edx); // receiver 1372 __ push(ecx); // name 1373 __ push(ebx); // return address 1374 1375 // Perform tail call to the entry. 1376 ExternalReference ref = 1377 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); 1378 __ TailCallExternalReference(ref, 2, 1); 1379} 1380 1381 1382void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { 1383 // ----------- S t a t e ------------- 1384 // -- ecx : key 1385 // -- edx : receiver 1386 // -- esp[0] : return address 1387 // ----------------------------------- 1388 1389 __ pop(ebx); 1390 __ push(edx); // receiver 1391 __ push(ecx); // name 1392 __ push(ebx); // return address 1393 1394 // Perform tail call to the entry. 1395 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); 1396} 1397 1398 1399void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { 1400 // ----------- S t a t e ------------- 1401 // -- ecx : key 1402 // -- edx : receiver 1403 // -- esp[0] : return address 1404 // ----------------------------------- 1405 1406 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1); 1407 1408 __ pop(ebx); 1409 __ push(edx); // receiver 1410 __ push(ecx); // name 1411 __ push(ebx); // return address 1412 1413 // Perform tail call to the entry. 1414 ExternalReference ref = 1415 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); 1416 __ TailCallExternalReference(ref, 2, 1); 1417} 1418 1419 1420void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { 1421 // ----------- S t a t e ------------- 1422 // -- ecx : key 1423 // -- edx : receiver 1424 // -- esp[0] : return address 1425 // ----------------------------------- 1426 1427 __ pop(ebx); 1428 __ push(edx); // receiver 1429 __ push(ecx); // name 1430 __ push(ebx); // return address 1431 1432 // Perform tail call to the entry. 1433 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); 1434} 1435 1436 1437void StoreIC::GenerateMegamorphic(MacroAssembler* masm, 1438 ExtraICState extra_ic_state) { 1439 // ----------- S t a t e ------------- 1440 // -- eax : value 1441 // -- ecx : name 1442 // -- edx : receiver 1443 // -- esp[0] : return address 1444 // ----------------------------------- 1445 Code::Flags flags = Code::ComputeFlags( 1446 Code::HANDLER, MONOMORPHIC, extra_ic_state, 1447 Code::NORMAL, Code::STORE_IC); 1448 masm->isolate()->stub_cache()->GenerateProbe( 1449 masm, flags, edx, ecx, ebx, no_reg); 1450 1451 // Cache miss: Jump to runtime. 1452 GenerateMiss(masm); 1453} 1454 1455 1456void StoreIC::GenerateMiss(MacroAssembler* masm) { 1457 // ----------- S t a t e ------------- 1458 // -- eax : value 1459 // -- ecx : name 1460 // -- edx : receiver 1461 // -- esp[0] : return address 1462 // ----------------------------------- 1463 1464 __ pop(ebx); 1465 __ push(edx); 1466 __ push(ecx); 1467 __ push(eax); 1468 __ push(ebx); 1469 1470 // Perform tail call to the entry. 1471 ExternalReference ref = 1472 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate()); 1473 __ TailCallExternalReference(ref, 3, 1); 1474} 1475 1476 1477void StoreIC::GenerateNormal(MacroAssembler* masm) { 1478 // ----------- S t a t e ------------- 1479 // -- eax : value 1480 // -- ecx : name 1481 // -- edx : receiver 1482 // -- esp[0] : return address 1483 // ----------------------------------- 1484 1485 Label miss, restore_miss; 1486 1487 GenerateNameDictionaryReceiverCheck(masm, edx, ebx, edi, &miss); 1488 1489 // A lot of registers are needed for storing to slow case 1490 // objects. Push and restore receiver but rely on 1491 // GenerateDictionaryStore preserving the value and name. 1492 __ push(edx); 1493 GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi); 1494 __ Drop(1); 1495 Counters* counters = masm->isolate()->counters(); 1496 __ IncrementCounter(counters->store_normal_hit(), 1); 1497 __ ret(0); 1498 1499 __ bind(&restore_miss); 1500 __ pop(edx); 1501 1502 __ bind(&miss); 1503 __ IncrementCounter(counters->store_normal_miss(), 1); 1504 GenerateMiss(masm); 1505} 1506 1507 1508void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, 1509 StrictModeFlag strict_mode) { 1510 // ----------- S t a t e ------------- 1511 // -- eax : value 1512 // -- ecx : name 1513 // -- edx : receiver 1514 // -- esp[0] : return address 1515 // ----------------------------------- 1516 __ pop(ebx); 1517 __ push(edx); 1518 __ push(ecx); 1519 __ push(eax); 1520 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes 1521 __ push(Immediate(Smi::FromInt(strict_mode))); 1522 __ push(ebx); // return address 1523 1524 // Do tail-call to runtime routine. 1525 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); 1526} 1527 1528 1529void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, 1530 StrictModeFlag strict_mode) { 1531 // ----------- S t a t e ------------- 1532 // -- eax : value 1533 // -- ecx : key 1534 // -- edx : receiver 1535 // -- esp[0] : return address 1536 // ----------------------------------- 1537 1538 __ pop(ebx); 1539 __ push(edx); 1540 __ push(ecx); 1541 __ push(eax); 1542 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes 1543 __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode. 1544 __ push(ebx); // return address 1545 1546 // Do tail-call to runtime routine. 1547 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); 1548} 1549 1550 1551void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { 1552 // ----------- S t a t e ------------- 1553 // -- eax : value 1554 // -- ecx : key 1555 // -- edx : receiver 1556 // -- esp[0] : return address 1557 // ----------------------------------- 1558 1559 __ pop(ebx); 1560 __ push(edx); 1561 __ push(ecx); 1562 __ push(eax); 1563 __ push(ebx); 1564 1565 // Do tail-call to runtime routine. 1566 ExternalReference ref = 1567 ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate()); 1568 __ TailCallExternalReference(ref, 3, 1); 1569} 1570 1571 1572void StoreIC::GenerateSlow(MacroAssembler* masm) { 1573 // ----------- S t a t e ------------- 1574 // -- eax : value 1575 // -- ecx : key 1576 // -- edx : receiver 1577 // -- esp[0] : return address 1578 // ----------------------------------- 1579 1580 __ pop(ebx); 1581 __ push(edx); 1582 __ push(ecx); 1583 __ push(eax); 1584 __ push(ebx); // return address 1585 1586 // Do tail-call to runtime routine. 1587 ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate()); 1588 __ TailCallExternalReference(ref, 3, 1); 1589} 1590 1591 1592void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { 1593 // ----------- S t a t e ------------- 1594 // -- eax : value 1595 // -- ecx : key 1596 // -- edx : receiver 1597 // -- esp[0] : return address 1598 // ----------------------------------- 1599 1600 __ pop(ebx); 1601 __ push(edx); 1602 __ push(ecx); 1603 __ push(eax); 1604 __ push(ebx); // return address 1605 1606 // Do tail-call to runtime routine. 1607 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); 1608 __ TailCallExternalReference(ref, 3, 1); 1609} 1610 1611 1612#undef __ 1613 1614 1615Condition CompareIC::ComputeCondition(Token::Value op) { 1616 switch (op) { 1617 case Token::EQ_STRICT: 1618 case Token::EQ: 1619 return equal; 1620 case Token::LT: 1621 return less; 1622 case Token::GT: 1623 return greater; 1624 case Token::LTE: 1625 return less_equal; 1626 case Token::GTE: 1627 return greater_equal; 1628 default: 1629 UNREACHABLE(); 1630 return no_condition; 1631 } 1632} 1633 1634 1635bool CompareIC::HasInlinedSmiCode(Address address) { 1636 // The address of the instruction following the call. 1637 Address test_instruction_address = 1638 address + Assembler::kCallTargetAddressOffset; 1639 1640 // If the instruction following the call is not a test al, nothing 1641 // was inlined. 1642 return *test_instruction_address == Assembler::kTestAlByte; 1643} 1644 1645 1646void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { 1647 // The address of the instruction following the call. 1648 Address test_instruction_address = 1649 address + Assembler::kCallTargetAddressOffset; 1650 1651 // If the instruction following the call is not a test al, nothing 1652 // was inlined. 1653 if (*test_instruction_address != Assembler::kTestAlByte) { 1654 ASSERT(*test_instruction_address == Assembler::kNopByte); 1655 return; 1656 } 1657 1658 Address delta_address = test_instruction_address + 1; 1659 // The delta to the start of the map check instruction and the 1660 // condition code uses at the patched jump. 1661 int8_t delta = *reinterpret_cast<int8_t*>(delta_address); 1662 if (FLAG_trace_ic) { 1663 PrintF("[ patching ic at %p, test=%p, delta=%d\n", 1664 address, test_instruction_address, delta); 1665 } 1666 1667 // Patch with a short conditional jump. Enabling means switching from a short 1668 // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the 1669 // reverse operation of that. 1670 Address jmp_address = test_instruction_address - delta; 1671 ASSERT((check == ENABLE_INLINED_SMI_CHECK) 1672 ? (*jmp_address == Assembler::kJncShortOpcode || 1673 *jmp_address == Assembler::kJcShortOpcode) 1674 : (*jmp_address == Assembler::kJnzShortOpcode || 1675 *jmp_address == Assembler::kJzShortOpcode)); 1676 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) 1677 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) 1678 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); 1679 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); 1680} 1681 1682 1683} } // namespace v8::internal 1684 1685#endif // V8_TARGET_ARCH_IA32 1686