ic-ia32.cc revision 50ef84f5fad2def87d3fbc737bec4a32711fdef4
1// Copyright 2010 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 defined(V8_TARGET_ARCH_IA32) 31 32#include "codegen-inl.h" 33#include "ic-inl.h" 34#include "runtime.h" 35#include "stub-cache.h" 36#include "utils.h" 37 38namespace v8 { 39namespace internal { 40 41// ---------------------------------------------------------------------------- 42// Static IC stub generators. 43// 44 45#define __ ACCESS_MASM(masm) 46 47 48static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, 49 Register type, 50 Label* global_object) { 51 // Register usage: 52 // type: holds the receiver instance type on entry. 53 __ cmp(type, JS_GLOBAL_OBJECT_TYPE); 54 __ j(equal, global_object, not_taken); 55 __ cmp(type, JS_BUILTINS_OBJECT_TYPE); 56 __ j(equal, global_object, not_taken); 57 __ cmp(type, JS_GLOBAL_PROXY_TYPE); 58 __ j(equal, global_object, not_taken); 59} 60 61 62// Generated code falls through if the receiver is a regular non-global 63// JS object with slow properties and no interceptors. 64static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm, 65 Register receiver, 66 Register r0, 67 Register r1, 68 Label* miss) { 69 // Register usage: 70 // receiver: holds the receiver on entry and is unchanged. 71 // r0: used to hold receiver instance type. 72 // Holds the property dictionary on fall through. 73 // r1: used to hold receivers map. 74 75 // Check that the receiver isn't a smi. 76 __ test(receiver, Immediate(kSmiTagMask)); 77 __ j(zero, miss, not_taken); 78 79 // Check that the receiver is a valid JS object. 80 __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset)); 81 __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset)); 82 __ cmp(r0, FIRST_JS_OBJECT_TYPE); 83 __ j(below, miss, not_taken); 84 85 // If this assert fails, we have to check upper bound too. 86 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); 87 88 GenerateGlobalInstanceTypeCheck(masm, r0, miss); 89 90 // Check for non-global object that requires access check. 91 __ test_b(FieldOperand(r1, Map::kBitFieldOffset), 92 (1 << Map::kIsAccessCheckNeeded) | 93 (1 << Map::kHasNamedInterceptor)); 94 __ j(not_zero, miss, not_taken); 95 96 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); 97 __ CheckMap(r0, Factory::hash_table_map(), miss, true); 98} 99 100 101// Probe the string dictionary in the |elements| register. Jump to the 102// |done| label if a property with the given name is found leaving the 103// index into the dictionary in |r0|. Jump to the |miss| label 104// otherwise. 105static void GenerateStringDictionaryProbes(MacroAssembler* masm, 106 Label* miss, 107 Label* done, 108 Register elements, 109 Register name, 110 Register r0, 111 Register r1) { 112 // Compute the capacity mask. 113 const int kCapacityOffset = 114 StringDictionary::kHeaderSize + 115 StringDictionary::kCapacityIndex * kPointerSize; 116 __ mov(r1, FieldOperand(elements, kCapacityOffset)); 117 __ shr(r1, kSmiTagSize); // convert smi to int 118 __ dec(r1); 119 120 // Generate an unrolled loop that performs a few probes before 121 // giving up. Measurements done on Gmail indicate that 2 probes 122 // cover ~93% of loads from dictionaries. 123 static const int kProbes = 4; 124 const int kElementsStartOffset = 125 StringDictionary::kHeaderSize + 126 StringDictionary::kElementsStartIndex * kPointerSize; 127 for (int i = 0; i < kProbes; i++) { 128 // Compute the masked index: (hash + i + i * i) & mask. 129 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 130 __ shr(r0, String::kHashShift); 131 if (i > 0) { 132 __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i))); 133 } 134 __ and_(r0, Operand(r1)); 135 136 // Scale the index by multiplying by the entry size. 137 ASSERT(StringDictionary::kEntrySize == 3); 138 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 139 140 // Check if the key is identical to the name. 141 __ cmp(name, Operand(elements, r0, times_4, 142 kElementsStartOffset - kHeapObjectTag)); 143 if (i != kProbes - 1) { 144 __ j(equal, done, taken); 145 } else { 146 __ j(not_equal, miss, not_taken); 147 } 148 } 149} 150 151 152 153// Helper function used to load a property from a dictionary backing 154// storage. This function may fail to load a property even though it is 155// in the dictionary, so code at miss_label must always call a backup 156// property load that is complete. This function is safe to call if 157// name is not a symbol, and will jump to the miss_label in that 158// case. The generated code assumes that the receiver has slow 159// properties, is not a global object and does not have interceptors. 160static void GenerateDictionaryLoad(MacroAssembler* masm, 161 Label* miss_label, 162 Register elements, 163 Register name, 164 Register r0, 165 Register r1, 166 Register result) { 167 // Register use: 168 // 169 // elements - holds the property dictionary on entry and is unchanged. 170 // 171 // name - holds the name of the property on entry and is unchanged. 172 // 173 // Scratch registers: 174 // 175 // r0 - used for the index into the property dictionary 176 // 177 // r1 - used to hold the capacity of the property dictionary. 178 // 179 // result - holds the result on exit. 180 181 Label done; 182 183 // Probe the dictionary. 184 GenerateStringDictionaryProbes(masm, 185 miss_label, 186 &done, 187 elements, 188 name, 189 r0, 190 r1); 191 192 // If probing finds an entry in the dictionary, r0 contains the 193 // index into the dictionary. Check that the value is a normal 194 // property. 195 __ bind(&done); 196 const int kElementsStartOffset = 197 StringDictionary::kHeaderSize + 198 StringDictionary::kElementsStartIndex * kPointerSize; 199 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; 200 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), 201 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); 202 __ j(not_zero, miss_label, not_taken); 203 204 // Get the value at the masked, scaled index. 205 const int kValueOffset = kElementsStartOffset + kPointerSize; 206 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); 207} 208 209 210// Helper function used to store a property to a dictionary backing 211// storage. This function may fail to store a property eventhough it 212// is in the dictionary, so code at miss_label must always call a 213// backup property store that is complete. This function is safe to 214// call if name is not a symbol, and will jump to the miss_label in 215// that case. The generated code assumes that the receiver has slow 216// properties, is not a global object and does not have interceptors. 217static void GenerateDictionaryStore(MacroAssembler* masm, 218 Label* miss_label, 219 Register elements, 220 Register name, 221 Register value, 222 Register r0, 223 Register r1) { 224 // Register use: 225 // 226 // elements - holds the property dictionary on entry and is clobbered. 227 // 228 // name - holds the name of the property on entry and is unchanged. 229 // 230 // value - holds the value to store and is unchanged. 231 // 232 // r0 - used for index into the property dictionary and is clobbered. 233 // 234 // r1 - used to hold the capacity of the property dictionary and is clobbered. 235 Label done; 236 237 238 // Probe the dictionary. 239 GenerateStringDictionaryProbes(masm, 240 miss_label, 241 &done, 242 elements, 243 name, 244 r0, 245 r1); 246 247 // If probing finds an entry in the dictionary, r0 contains the 248 // index into the dictionary. Check that the value is a normal 249 // property that is not read only. 250 __ bind(&done); 251 const int kElementsStartOffset = 252 StringDictionary::kHeaderSize + 253 StringDictionary::kElementsStartIndex * kPointerSize; 254 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; 255 const int kTypeAndReadOnlyMask 256 = (PropertyDetails::TypeField::mask() | 257 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; 258 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), 259 Immediate(kTypeAndReadOnlyMask)); 260 __ j(not_zero, miss_label, not_taken); 261 262 // Store the value at the masked, scaled index. 263 const int kValueOffset = kElementsStartOffset + kPointerSize; 264 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); 265 __ mov(Operand(r0, 0), value); 266 267 // Update write barrier. Make sure not to clobber the value. 268 __ mov(r1, value); 269 __ RecordWrite(elements, r0, r1); 270} 271 272 273static void GenerateNumberDictionaryLoad(MacroAssembler* masm, 274 Label* miss, 275 Register elements, 276 Register key, 277 Register r0, 278 Register r1, 279 Register r2, 280 Register result) { 281 // Register use: 282 // 283 // elements - holds the slow-case elements of the receiver and is unchanged. 284 // 285 // key - holds the smi key on entry and is unchanged. 286 // 287 // Scratch registers: 288 // 289 // r0 - holds the untagged key on entry and holds the hash once computed. 290 // 291 // r1 - used to hold the capacity mask of the dictionary 292 // 293 // r2 - used for the index into the dictionary. 294 // 295 // result - holds the result on exit if the load succeeds and we fall through. 296 297 Label done; 298 299 // Compute the hash code from the untagged key. This must be kept in sync 300 // with ComputeIntegerHash in utils.h. 301 // 302 // hash = ~hash + (hash << 15); 303 __ mov(r1, r0); 304 __ not_(r0); 305 __ shl(r1, 15); 306 __ add(r0, Operand(r1)); 307 // hash = hash ^ (hash >> 12); 308 __ mov(r1, r0); 309 __ shr(r1, 12); 310 __ xor_(r0, Operand(r1)); 311 // hash = hash + (hash << 2); 312 __ lea(r0, Operand(r0, r0, times_4, 0)); 313 // hash = hash ^ (hash >> 4); 314 __ mov(r1, r0); 315 __ shr(r1, 4); 316 __ xor_(r0, Operand(r1)); 317 // hash = hash * 2057; 318 __ imul(r0, r0, 2057); 319 // hash = hash ^ (hash >> 16); 320 __ mov(r1, r0); 321 __ shr(r1, 16); 322 __ xor_(r0, Operand(r1)); 323 324 // Compute capacity mask. 325 __ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset)); 326 __ shr(r1, kSmiTagSize); // convert smi to int 327 __ dec(r1); 328 329 // Generate an unrolled loop that performs a few probes before giving up. 330 const int kProbes = 4; 331 for (int i = 0; i < kProbes; i++) { 332 // Use r2 for index calculations and keep the hash intact in r0. 333 __ mov(r2, r0); 334 // Compute the masked index: (hash + i + i * i) & mask. 335 if (i > 0) { 336 __ add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i))); 337 } 338 __ and_(r2, Operand(r1)); 339 340 // Scale the index by multiplying by the entry size. 341 ASSERT(NumberDictionary::kEntrySize == 3); 342 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 343 344 // Check if the key matches. 345 __ cmp(key, FieldOperand(elements, 346 r2, 347 times_pointer_size, 348 NumberDictionary::kElementsStartOffset)); 349 if (i != (kProbes - 1)) { 350 __ j(equal, &done, taken); 351 } else { 352 __ j(not_equal, miss, not_taken); 353 } 354 } 355 356 __ bind(&done); 357 // Check that the value is a normal propety. 358 const int kDetailsOffset = 359 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; 360 ASSERT_EQ(NORMAL, 0); 361 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), 362 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); 363 __ j(not_zero, miss); 364 365 // Get the value at the masked, scaled index. 366 const int kValueOffset = 367 NumberDictionary::kElementsStartOffset + kPointerSize; 368 __ mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); 369} 370 371 372// The offset from the inlined patch site to the start of the 373// inlined load instruction. It is 7 bytes (test eax, imm) plus 374// 6 bytes (jne slow_label). 375const int LoadIC::kOffsetToLoadInstruction = 13; 376 377 378void LoadIC::GenerateArrayLength(MacroAssembler* masm) { 379 // ----------- S t a t e ------------- 380 // -- eax : receiver 381 // -- ecx : name 382 // -- esp[0] : return address 383 // ----------------------------------- 384 Label miss; 385 386 StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss); 387 __ bind(&miss); 388 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 389} 390 391 392void LoadIC::GenerateStringLength(MacroAssembler* masm) { 393 // ----------- S t a t e ------------- 394 // -- eax : receiver 395 // -- ecx : name 396 // -- esp[0] : return address 397 // ----------------------------------- 398 Label miss; 399 400 StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss); 401 __ bind(&miss); 402 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 403} 404 405 406void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { 407 // ----------- S t a t e ------------- 408 // -- eax : receiver 409 // -- ecx : name 410 // -- esp[0] : return address 411 // ----------------------------------- 412 Label miss; 413 414 StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss); 415 __ bind(&miss); 416 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 417} 418 419 420// Checks the receiver for special cases (value type, slow case bits). 421// Falls through for regular JS object. 422static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, 423 Register receiver, 424 Register map, 425 int interceptor_bit, 426 Label* slow) { 427 // Register use: 428 // receiver - holds the receiver and is unchanged. 429 // Scratch registers: 430 // map - used to hold the map of the receiver. 431 432 // Check that the object isn't a smi. 433 __ test(receiver, Immediate(kSmiTagMask)); 434 __ j(zero, slow, not_taken); 435 436 // Get the map of the receiver. 437 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); 438 439 // Check bit field. 440 __ test_b(FieldOperand(map, Map::kBitFieldOffset), 441 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)); 442 __ j(not_zero, slow, not_taken); 443 // Check that the object is some kind of JS object EXCEPT JS Value type. 444 // In the case that the object is a value-wrapper object, 445 // we enter the runtime system to make sure that indexing 446 // into string objects works as intended. 447 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); 448 449 __ CmpInstanceType(map, JS_OBJECT_TYPE); 450 __ j(below, slow, not_taken); 451} 452 453 454// Loads an indexed element from a fast case array. 455static void GenerateFastArrayLoad(MacroAssembler* masm, 456 Register receiver, 457 Register key, 458 Register scratch, 459 Register result, 460 Label* not_fast_array, 461 Label* out_of_range) { 462 // Register use: 463 // receiver - holds the receiver and is unchanged. 464 // key - holds the key and is unchanged (must be a smi). 465 // Scratch registers: 466 // scratch - used to hold elements of the receiver and the loaded value. 467 // result - holds the result on exit if the load succeeds and 468 // we fall through. 469 470 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); 471 // Check that the object is in fast mode (not dictionary). 472 __ CheckMap(scratch, Factory::fixed_array_map(), not_fast_array, true); 473 // Check that the key (index) is within bounds. 474 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); 475 __ j(above_equal, out_of_range); 476 // Fast case: Do the load. 477 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); 478 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); 479 __ cmp(Operand(scratch), Immediate(Factory::the_hole_value())); 480 // In case the loaded value is the_hole we have to consult GetProperty 481 // to ensure the prototype chain is searched. 482 __ j(equal, out_of_range); 483 if (!result.is(scratch)) { 484 __ mov(result, scratch); 485 } 486} 487 488 489// Checks whether a key is an array index string or a symbol string. 490// Falls through if the key is a symbol. 491static void GenerateKeyStringCheck(MacroAssembler* masm, 492 Register key, 493 Register map, 494 Register hash, 495 Label* index_string, 496 Label* not_symbol) { 497 // Register use: 498 // key - holds the key and is unchanged. Assumed to be non-smi. 499 // Scratch registers: 500 // map - used to hold the map of the key. 501 // hash - used to hold the hash of the key. 502 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); 503 __ j(above_equal, not_symbol); 504 505 // Is the string an array index, with cached numeric value? 506 __ mov(hash, FieldOperand(key, String::kHashFieldOffset)); 507 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask)); 508 __ j(zero, index_string, not_taken); 509 510 // Is the string a symbol? 511 ASSERT(kSymbolTag != 0); 512 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); 513 __ j(zero, not_symbol, not_taken); 514} 515 516 517// Picks out an array index from the hash field. 518static void GenerateIndexFromHash(MacroAssembler* masm, 519 Register key, 520 Register hash) { 521 // Register use: 522 // key - holds the overwritten key on exit. 523 // hash - holds the key's hash. Clobbered. 524 525 // The assert checks that the constants for the maximum number of digits 526 // for an array index cached in the hash field and the number of bits 527 // reserved for it does not conflict. 528 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < 529 (1 << String::kArrayIndexValueBits)); 530 // We want the smi-tagged index in key. kArrayIndexValueMask has zeros in 531 // the low kHashShift bits. 532 ASSERT(String::kHashShift >= kSmiTagSize); 533 __ and_(hash, String::kArrayIndexValueMask); 534 __ shr(hash, String::kHashShift - kSmiTagSize); 535 // Here we actually clobber the key which will be used if calling into 536 // runtime later. However as the new key is the numeric value of a string key 537 // there is no difference in using either key. 538 __ mov(key, hash); 539} 540 541 542void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { 543 // ----------- S t a t e ------------- 544 // -- eax : key 545 // -- edx : receiver 546 // -- esp[0] : return address 547 // ----------------------------------- 548 Label slow, check_string, index_smi, index_string; 549 Label check_pixel_array, probe_dictionary, check_number_dictionary; 550 551 // Check that the key is a smi. 552 __ test(eax, Immediate(kSmiTagMask)); 553 __ j(not_zero, &check_string, not_taken); 554 __ bind(&index_smi); 555 // Now the key is known to be a smi. This place is also jumped to from 556 // where a numeric string is converted to a smi. 557 558 GenerateKeyedLoadReceiverCheck( 559 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); 560 561 GenerateFastArrayLoad(masm, 562 edx, 563 eax, 564 ecx, 565 eax, 566 &check_pixel_array, 567 &slow); 568 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); 569 __ ret(0); 570 571 __ bind(&check_pixel_array); 572 // Check whether the elements is a pixel array. 573 // edx: receiver 574 // eax: key 575 // ecx: elements 576 __ mov(ebx, eax); 577 __ SmiUntag(ebx); 578 __ CheckMap(ecx, Factory::pixel_array_map(), &check_number_dictionary, true); 579 __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset)); 580 __ j(above_equal, &slow); 581 __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset)); 582 __ movzx_b(eax, Operand(eax, ebx, times_1, 0)); 583 __ SmiTag(eax); 584 __ ret(0); 585 586 __ bind(&check_number_dictionary); 587 // Check whether the elements is a number dictionary. 588 // edx: receiver 589 // ebx: untagged index 590 // eax: key 591 // ecx: elements 592 __ CheckMap(ecx, Factory::hash_table_map(), &slow, true); 593 Label slow_pop_receiver; 594 // Push receiver on the stack to free up a register for the dictionary 595 // probing. 596 __ push(edx); 597 GenerateNumberDictionaryLoad(masm, 598 &slow_pop_receiver, 599 ecx, 600 eax, 601 ebx, 602 edx, 603 edi, 604 eax); 605 // Pop receiver before returning. 606 __ pop(edx); 607 __ ret(0); 608 609 __ bind(&slow_pop_receiver); 610 // Pop the receiver from the stack and jump to runtime. 611 __ pop(edx); 612 613 __ bind(&slow); 614 // Slow case: jump to runtime. 615 // edx: receiver 616 // eax: key 617 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); 618 GenerateRuntimeGetProperty(masm); 619 620 __ bind(&check_string); 621 GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow); 622 623 GenerateKeyedLoadReceiverCheck( 624 masm, edx, ecx, Map::kHasNamedInterceptor, &slow); 625 626 // If the receiver is a fast-case object, check the keyed lookup 627 // cache. Otherwise probe the dictionary. 628 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); 629 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 630 Immediate(Factory::hash_table_map())); 631 __ j(equal, &probe_dictionary); 632 633 // Load the map of the receiver, compute the keyed lookup cache hash 634 // based on 32 bits of the map pointer and the string hash. 635 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 636 __ mov(ecx, ebx); 637 __ shr(ecx, KeyedLookupCache::kMapHashShift); 638 __ mov(edi, FieldOperand(eax, String::kHashFieldOffset)); 639 __ shr(edi, String::kHashShift); 640 __ xor_(ecx, Operand(edi)); 641 __ and_(ecx, KeyedLookupCache::kCapacityMask); 642 643 // Load the key (consisting of map and symbol) from the cache and 644 // check for match. 645 ExternalReference cache_keys 646 = ExternalReference::keyed_lookup_cache_keys(); 647 __ mov(edi, ecx); 648 __ shl(edi, kPointerSizeLog2 + 1); 649 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); 650 __ j(not_equal, &slow); 651 __ add(Operand(edi), Immediate(kPointerSize)); 652 __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys)); 653 __ j(not_equal, &slow); 654 655 // Get field offset and check that it is an in-object property. 656 // edx : receiver 657 // ebx : receiver's map 658 // eax : key 659 // ecx : lookup cache index 660 ExternalReference cache_field_offsets 661 = ExternalReference::keyed_lookup_cache_field_offsets(); 662 __ mov(edi, 663 Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets)); 664 __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); 665 __ sub(edi, Operand(ecx)); 666 __ j(above_equal, &slow); 667 668 // Load in-object property. 669 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); 670 __ add(ecx, Operand(edi)); 671 __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0)); 672 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1); 673 __ ret(0); 674 675 // Do a quick inline probe of the receiver's dictionary, if it 676 // exists. 677 __ bind(&probe_dictionary); 678 679 __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset)); 680 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 681 GenerateGlobalInstanceTypeCheck(masm, ecx, &slow); 682 683 GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax); 684 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); 685 __ ret(0); 686 687 __ bind(&index_string); 688 GenerateIndexFromHash(masm, eax, ebx); 689 // Now jump to the place where smi keys are handled. 690 __ jmp(&index_smi); 691} 692 693 694void KeyedLoadIC::GenerateString(MacroAssembler* masm) { 695 // ----------- S t a t e ------------- 696 // -- eax : key (index) 697 // -- edx : receiver 698 // -- esp[0] : return address 699 // ----------------------------------- 700 Label miss; 701 Label index_out_of_range; 702 703 Register receiver = edx; 704 Register index = eax; 705 Register scratch1 = ebx; 706 Register scratch2 = ecx; 707 Register result = eax; 708 709 StringCharAtGenerator char_at_generator(receiver, 710 index, 711 scratch1, 712 scratch2, 713 result, 714 &miss, // When not a string. 715 &miss, // When not a number. 716 &index_out_of_range, 717 STRING_INDEX_IS_ARRAY_INDEX); 718 char_at_generator.GenerateFast(masm); 719 __ ret(0); 720 721 ICRuntimeCallHelper call_helper; 722 char_at_generator.GenerateSlow(masm, call_helper); 723 724 __ bind(&index_out_of_range); 725 __ Set(eax, Immediate(Factory::undefined_value())); 726 __ ret(0); 727 728 __ bind(&miss); 729 GenerateMiss(masm); 730} 731 732 733void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, 734 ExternalArrayType array_type) { 735 // ----------- S t a t e ------------- 736 // -- eax : key 737 // -- edx : receiver 738 // -- esp[0] : return address 739 // ----------------------------------- 740 Label slow, failed_allocation; 741 742 // Check that the object isn't a smi. 743 __ test(edx, Immediate(kSmiTagMask)); 744 __ j(zero, &slow, not_taken); 745 746 // Check that the key is a smi. 747 __ test(eax, Immediate(kSmiTagMask)); 748 __ j(not_zero, &slow, not_taken); 749 750 // Get the map of the receiver. 751 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 752 // Check that the receiver does not require access checks. We need 753 // to check this explicitly since this generic stub does not perform 754 // map checks. 755 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 756 1 << Map::kIsAccessCheckNeeded); 757 __ j(not_zero, &slow, not_taken); 758 759 __ CmpInstanceType(ecx, JS_OBJECT_TYPE); 760 __ j(not_equal, &slow, not_taken); 761 762 // Check that the elements array is the appropriate type of 763 // ExternalArray. 764 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 765 Handle<Map> map(Heap::MapForExternalArrayType(array_type)); 766 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 767 Immediate(map)); 768 __ j(not_equal, &slow, not_taken); 769 770 // eax: key, known to be a smi. 771 // edx: receiver, known to be a JSObject. 772 // ebx: elements object, known to be an external array. 773 // Check that the index is in range. 774 __ mov(ecx, eax); 775 __ SmiUntag(ecx); // Untag the index. 776 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); 777 // Unsigned comparison catches both negative and too-large values. 778 __ j(above_equal, &slow); 779 780 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); 781 // ebx: base pointer of external storage 782 switch (array_type) { 783 case kExternalByteArray: 784 __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0)); 785 break; 786 case kExternalUnsignedByteArray: 787 __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0)); 788 break; 789 case kExternalShortArray: 790 __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0)); 791 break; 792 case kExternalUnsignedShortArray: 793 __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0)); 794 break; 795 case kExternalIntArray: 796 case kExternalUnsignedIntArray: 797 __ mov(ecx, Operand(ebx, ecx, times_4, 0)); 798 break; 799 case kExternalFloatArray: 800 __ fld_s(Operand(ebx, ecx, times_4, 0)); 801 break; 802 default: 803 UNREACHABLE(); 804 break; 805 } 806 807 // For integer array types: 808 // ecx: value 809 // For floating-point array type: 810 // FP(0): value 811 812 if (array_type == kExternalIntArray || 813 array_type == kExternalUnsignedIntArray) { 814 // For the Int and UnsignedInt array types, we need to see whether 815 // the value can be represented in a Smi. If not, we need to convert 816 // it to a HeapNumber. 817 Label box_int; 818 if (array_type == kExternalIntArray) { 819 __ cmp(ecx, 0xC0000000); 820 __ j(sign, &box_int); 821 } else { 822 ASSERT_EQ(array_type, kExternalUnsignedIntArray); 823 // The test is different for unsigned int values. Since we need 824 // the value to be in the range of a positive smi, we can't 825 // handle either of the top two bits being set in the value. 826 __ test(ecx, Immediate(0xC0000000)); 827 __ j(not_zero, &box_int); 828 } 829 830 __ mov(eax, ecx); 831 __ SmiTag(eax); 832 __ ret(0); 833 834 __ bind(&box_int); 835 836 // Allocate a HeapNumber for the int and perform int-to-double 837 // conversion. 838 if (array_type == kExternalIntArray) { 839 __ push(ecx); 840 __ fild_s(Operand(esp, 0)); 841 __ pop(ecx); 842 } else { 843 ASSERT(array_type == kExternalUnsignedIntArray); 844 // Need to zero-extend the value. 845 // There's no fild variant for unsigned values, so zero-extend 846 // to a 64-bit int manually. 847 __ push(Immediate(0)); 848 __ push(ecx); 849 __ fild_d(Operand(esp, 0)); 850 __ pop(ecx); 851 __ pop(ecx); 852 } 853 // FP(0): value 854 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); 855 // Set the value. 856 __ mov(eax, ecx); 857 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 858 __ ret(0); 859 } else if (array_type == kExternalFloatArray) { 860 // For the floating-point array type, we need to always allocate a 861 // HeapNumber. 862 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); 863 // Set the value. 864 __ mov(eax, ecx); 865 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 866 __ ret(0); 867 } else { 868 __ mov(eax, ecx); 869 __ SmiTag(eax); 870 __ ret(0); 871 } 872 873 // If we fail allocation of the HeapNumber, we still have a value on 874 // top of the FPU stack. Remove it. 875 __ bind(&failed_allocation); 876 __ ffree(); 877 __ fincstp(); 878 // Fall through to slow case. 879 880 // Slow case: Jump to runtime. 881 __ bind(&slow); 882 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); 883 GenerateRuntimeGetProperty(masm); 884} 885 886 887void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { 888 // ----------- S t a t e ------------- 889 // -- eax : key 890 // -- edx : receiver 891 // -- esp[0] : return address 892 // ----------------------------------- 893 Label slow; 894 895 // Check that the receiver isn't a smi. 896 __ test(edx, Immediate(kSmiTagMask)); 897 __ j(zero, &slow, not_taken); 898 899 // Check that the key is a smi. 900 __ test(eax, Immediate(kSmiTagMask)); 901 __ j(not_zero, &slow, not_taken); 902 903 // Get the map of the receiver. 904 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 905 906 // Check that it has indexed interceptor and access checks 907 // are not enabled for this object. 908 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); 909 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); 910 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); 911 __ j(not_zero, &slow, not_taken); 912 913 // Everything is fine, call runtime. 914 __ pop(ecx); 915 __ push(edx); // receiver 916 __ push(eax); // key 917 __ push(ecx); // return address 918 919 // Perform tail call to the entry. 920 ExternalReference ref = ExternalReference( 921 IC_Utility(kKeyedLoadPropertyWithInterceptor)); 922 __ TailCallExternalReference(ref, 2, 1); 923 924 __ bind(&slow); 925 GenerateMiss(masm); 926} 927 928 929void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { 930 // ----------- S t a t e ------------- 931 // -- eax : value 932 // -- ecx : key 933 // -- edx : receiver 934 // -- esp[0] : return address 935 // ----------------------------------- 936 Label slow, fast, array, extra, check_pixel_array; 937 938 // Check that the object isn't a smi. 939 __ test(edx, Immediate(kSmiTagMask)); 940 __ j(zero, &slow, not_taken); 941 // Get the map from the receiver. 942 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 943 // Check that the receiver does not require access checks. We need 944 // to do this because this generic stub does not perform map checks. 945 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), 946 1 << Map::kIsAccessCheckNeeded); 947 __ j(not_zero, &slow, not_taken); 948 // Check that the key is a smi. 949 __ test(ecx, Immediate(kSmiTagMask)); 950 __ j(not_zero, &slow, not_taken); 951 __ CmpInstanceType(edi, JS_ARRAY_TYPE); 952 __ j(equal, &array); 953 // Check that the object is some kind of JS object. 954 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); 955 __ j(below, &slow, not_taken); 956 957 // Object case: Check key against length in the elements array. 958 // eax: value 959 // edx: JSObject 960 // ecx: key (a smi) 961 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); 962 // Check that the object is in fast mode (not dictionary). 963 __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true); 964 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); 965 __ j(below, &fast, taken); 966 967 // Slow case: call runtime. 968 __ bind(&slow); 969 GenerateRuntimeSetProperty(masm); 970 971 // Check whether the elements is a pixel array. 972 __ bind(&check_pixel_array); 973 // eax: value 974 // ecx: key (a smi) 975 // edx: receiver 976 // edi: elements array 977 __ CheckMap(edi, Factory::pixel_array_map(), &slow, true); 978 // Check that the value is a smi. If a conversion is needed call into the 979 // runtime to convert and clamp. 980 __ test(eax, Immediate(kSmiTagMask)); 981 __ j(not_zero, &slow); 982 __ mov(ebx, ecx); 983 __ SmiUntag(ebx); 984 __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset)); 985 __ j(above_equal, &slow); 986 __ mov(ecx, eax); // Save the value. Key is not longer needed. 987 __ SmiUntag(ecx); 988 { // Clamp the value to [0..255]. 989 Label done; 990 __ test(ecx, Immediate(0xFFFFFF00)); 991 __ j(zero, &done); 992 __ setcc(negative, ecx); // 1 if negative, 0 if positive. 993 __ dec_b(ecx); // 0 if negative, 255 if positive. 994 __ bind(&done); 995 } 996 __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset)); 997 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); 998 __ ret(0); // Return value in eax. 999 1000 // Extra capacity case: Check if there is extra capacity to 1001 // perform the store and update the length. Used for adding one 1002 // element to the array by writing to array[array.length]. 1003 __ bind(&extra); 1004 // eax: value 1005 // edx: receiver, a JSArray 1006 // ecx: key, a smi. 1007 // edi: receiver->elements, a FixedArray 1008 // flags: compare (ecx, edx.length()) 1009 __ j(not_equal, &slow, not_taken); // do not leave holes in the array 1010 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); 1011 __ j(above_equal, &slow, not_taken); 1012 // Add 1 to receiver->length, and go to fast array write. 1013 __ add(FieldOperand(edx, JSArray::kLengthOffset), 1014 Immediate(Smi::FromInt(1))); 1015 __ jmp(&fast); 1016 1017 // Array case: Get the length and the elements array from the JS 1018 // array. Check that the array is in fast mode; if it is the 1019 // length is always a smi. 1020 __ bind(&array); 1021 // eax: value 1022 // edx: receiver, a JSArray 1023 // ecx: key, a smi. 1024 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); 1025 __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true); 1026 1027 // Check the key against the length in the array, compute the 1028 // address to store into and fall through to fast case. 1029 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. 1030 __ j(above_equal, &extra, not_taken); 1031 1032 // Fast case: Do the store. 1033 __ bind(&fast); 1034 // eax: value 1035 // ecx: key (a smi) 1036 // edx: receiver 1037 // edi: FixedArray receiver->elements 1038 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax); 1039 // Update write barrier for the elements array address. 1040 __ mov(edx, Operand(eax)); 1041 __ RecordWrite(edi, 0, edx, ecx); 1042 __ ret(0); 1043} 1044 1045 1046void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, 1047 ExternalArrayType array_type) { 1048 // ----------- S t a t e ------------- 1049 // -- eax : value 1050 // -- ecx : key 1051 // -- edx : receiver 1052 // -- esp[0] : return address 1053 // ----------------------------------- 1054 Label slow, check_heap_number; 1055 1056 // Check that the object isn't a smi. 1057 __ test(edx, Immediate(kSmiTagMask)); 1058 __ j(zero, &slow); 1059 // Get the map from the receiver. 1060 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 1061 // Check that the receiver does not require access checks. We need 1062 // to do this because this generic stub does not perform map checks. 1063 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), 1064 1 << Map::kIsAccessCheckNeeded); 1065 __ j(not_zero, &slow); 1066 // Check that the key is a smi. 1067 __ test(ecx, Immediate(kSmiTagMask)); 1068 __ j(not_zero, &slow); 1069 // Get the instance type from the map of the receiver. 1070 __ CmpInstanceType(edi, JS_OBJECT_TYPE); 1071 __ j(not_equal, &slow); 1072 1073 // Check that the elements array is the appropriate type of 1074 // ExternalArray. 1075 // eax: value 1076 // edx: receiver, a JSObject 1077 // ecx: key, a smi 1078 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); 1079 __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)), 1080 &slow, true); 1081 1082 // Check that the index is in range. 1083 __ mov(ebx, ecx); 1084 __ SmiUntag(ebx); 1085 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); 1086 // Unsigned comparison catches both negative and too-large values. 1087 __ j(above_equal, &slow); 1088 1089 // Handle both smis and HeapNumbers in the fast path. Go to the 1090 // runtime for all other kinds of values. 1091 // eax: value 1092 // edx: receiver 1093 // ecx: key 1094 // edi: elements array 1095 // ebx: untagged index 1096 __ test(eax, Immediate(kSmiTagMask)); 1097 __ j(not_equal, &check_heap_number); 1098 // smi case 1099 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. 1100 __ SmiUntag(ecx); 1101 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); 1102 // ecx: base pointer of external storage 1103 switch (array_type) { 1104 case kExternalByteArray: 1105 case kExternalUnsignedByteArray: 1106 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); 1107 break; 1108 case kExternalShortArray: 1109 case kExternalUnsignedShortArray: 1110 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); 1111 break; 1112 case kExternalIntArray: 1113 case kExternalUnsignedIntArray: 1114 __ mov(Operand(edi, ebx, times_4, 0), ecx); 1115 break; 1116 case kExternalFloatArray: 1117 // Need to perform int-to-float conversion. 1118 __ push(ecx); 1119 __ fild_s(Operand(esp, 0)); 1120 __ pop(ecx); 1121 __ fstp_s(Operand(edi, ebx, times_4, 0)); 1122 break; 1123 default: 1124 UNREACHABLE(); 1125 break; 1126 } 1127 __ ret(0); // Return the original value. 1128 1129 __ bind(&check_heap_number); 1130 // eax: value 1131 // edx: receiver 1132 // ecx: key 1133 // edi: elements array 1134 // ebx: untagged index 1135 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), 1136 Immediate(Factory::heap_number_map())); 1137 __ j(not_equal, &slow); 1138 1139 // The WebGL specification leaves the behavior of storing NaN and 1140 // +/-Infinity into integer arrays basically undefined. For more 1141 // reproducible behavior, convert these to zero. 1142 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1143 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); 1144 // ebx: untagged index 1145 // edi: base pointer of external storage 1146 // top of FPU stack: value 1147 if (array_type == kExternalFloatArray) { 1148 __ fstp_s(Operand(edi, ebx, times_4, 0)); 1149 __ ret(0); 1150 } else { 1151 // Need to perform float-to-int conversion. 1152 // Test the top of the FP stack for NaN. 1153 Label is_nan; 1154 __ fucomi(0); 1155 __ j(parity_even, &is_nan); 1156 1157 if (array_type != kExternalUnsignedIntArray) { 1158 __ push(ecx); // Make room on stack 1159 __ fistp_s(Operand(esp, 0)); 1160 __ pop(ecx); 1161 } else { 1162 // fistp stores values as signed integers. 1163 // To represent the entire range, we need to store as a 64-bit 1164 // int and discard the high 32 bits. 1165 __ sub(Operand(esp), Immediate(2 * kPointerSize)); 1166 __ fistp_d(Operand(esp, 0)); 1167 __ pop(ecx); 1168 __ add(Operand(esp), Immediate(kPointerSize)); 1169 } 1170 // ecx: untagged integer value 1171 switch (array_type) { 1172 case kExternalByteArray: 1173 case kExternalUnsignedByteArray: 1174 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); 1175 break; 1176 case kExternalShortArray: 1177 case kExternalUnsignedShortArray: 1178 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); 1179 break; 1180 case kExternalIntArray: 1181 case kExternalUnsignedIntArray: { 1182 // We also need to explicitly check for +/-Infinity. These are 1183 // converted to MIN_INT, but we need to be careful not to 1184 // confuse with legal uses of MIN_INT. 1185 Label not_infinity; 1186 // This test would apparently detect both NaN and Infinity, 1187 // but we've already checked for NaN using the FPU hardware 1188 // above. 1189 __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6)); 1190 __ and_(edx, 0x7FF0); 1191 __ cmp(edx, 0x7FF0); 1192 __ j(not_equal, ¬_infinity); 1193 __ mov(ecx, 0); 1194 __ bind(¬_infinity); 1195 __ mov(Operand(edi, ebx, times_4, 0), ecx); 1196 break; 1197 } 1198 default: 1199 UNREACHABLE(); 1200 break; 1201 } 1202 __ ret(0); // Return original value. 1203 1204 __ bind(&is_nan); 1205 __ ffree(); 1206 __ fincstp(); 1207 switch (array_type) { 1208 case kExternalByteArray: 1209 case kExternalUnsignedByteArray: 1210 __ mov_b(Operand(edi, ebx, times_1, 0), 0); 1211 break; 1212 case kExternalShortArray: 1213 case kExternalUnsignedShortArray: 1214 __ xor_(ecx, Operand(ecx)); 1215 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); 1216 break; 1217 case kExternalIntArray: 1218 case kExternalUnsignedIntArray: 1219 __ mov(Operand(edi, ebx, times_4, 0), Immediate(0)); 1220 break; 1221 default: 1222 UNREACHABLE(); 1223 break; 1224 } 1225 __ ret(0); // Return the original value. 1226 } 1227 1228 // Slow case: call runtime. 1229 __ bind(&slow); 1230 GenerateRuntimeSetProperty(masm); 1231} 1232 1233 1234// Defined in ic.cc. 1235Object* CallIC_Miss(Arguments args); 1236 1237// The generated code does not accept smi keys. 1238// The generated code falls through if both probes miss. 1239static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, 1240 int argc, 1241 Code::Kind kind) { 1242 // ----------- S t a t e ------------- 1243 // -- ecx : name 1244 // -- edx : receiver 1245 // ----------------------------------- 1246 Label number, non_number, non_string, boolean, probe, miss; 1247 1248 // Probe the stub cache. 1249 Code::Flags flags = 1250 Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); 1251 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax); 1252 1253 // If the stub cache probing failed, the receiver might be a value. 1254 // For value objects, we use the map of the prototype objects for 1255 // the corresponding JSValue for the cache and that is what we need 1256 // to probe. 1257 // 1258 // Check for number. 1259 __ test(edx, Immediate(kSmiTagMask)); 1260 __ j(zero, &number, not_taken); 1261 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); 1262 __ j(not_equal, &non_number, taken); 1263 __ bind(&number); 1264 StubCompiler::GenerateLoadGlobalFunctionPrototype( 1265 masm, Context::NUMBER_FUNCTION_INDEX, edx); 1266 __ jmp(&probe); 1267 1268 // Check for string. 1269 __ bind(&non_number); 1270 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE); 1271 __ j(above_equal, &non_string, taken); 1272 StubCompiler::GenerateLoadGlobalFunctionPrototype( 1273 masm, Context::STRING_FUNCTION_INDEX, edx); 1274 __ jmp(&probe); 1275 1276 // Check for boolean. 1277 __ bind(&non_string); 1278 __ cmp(edx, Factory::true_value()); 1279 __ j(equal, &boolean, not_taken); 1280 __ cmp(edx, Factory::false_value()); 1281 __ j(not_equal, &miss, taken); 1282 __ bind(&boolean); 1283 StubCompiler::GenerateLoadGlobalFunctionPrototype( 1284 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); 1285 1286 // Probe the stub cache for the value object. 1287 __ bind(&probe); 1288 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); 1289 __ bind(&miss); 1290} 1291 1292 1293static void GenerateFunctionTailCall(MacroAssembler* masm, 1294 int argc, 1295 Label* miss) { 1296 // ----------- S t a t e ------------- 1297 // -- ecx : name 1298 // -- edi : function 1299 // -- esp[0] : return address 1300 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1301 // -- ... 1302 // -- esp[(argc + 1) * 4] : receiver 1303 // ----------------------------------- 1304 1305 // Check that the result is not a smi. 1306 __ test(edi, Immediate(kSmiTagMask)); 1307 __ j(zero, miss, not_taken); 1308 1309 // Check that the value is a JavaScript function, fetching its map into eax. 1310 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); 1311 __ j(not_equal, miss, not_taken); 1312 1313 // Invoke the function. 1314 ParameterCount actual(argc); 1315 __ InvokeFunction(edi, actual, JUMP_FUNCTION); 1316} 1317 1318// The generated code falls through if the call should be handled by runtime. 1319static void GenerateCallNormal(MacroAssembler* masm, int argc) { 1320 // ----------- S t a t e ------------- 1321 // -- ecx : name 1322 // -- esp[0] : return address 1323 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1324 // -- ... 1325 // -- esp[(argc + 1) * 4] : receiver 1326 // ----------------------------------- 1327 Label miss; 1328 1329 // Get the receiver of the function from the stack; 1 ~ return address. 1330 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1331 1332 GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss); 1333 1334 // eax: elements 1335 // Search the dictionary placing the result in edi. 1336 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi); 1337 GenerateFunctionTailCall(masm, argc, &miss); 1338 1339 __ bind(&miss); 1340} 1341 1342 1343static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { 1344 // ----------- S t a t e ------------- 1345 // -- ecx : name 1346 // -- esp[0] : return address 1347 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1348 // -- ... 1349 // -- esp[(argc + 1) * 4] : receiver 1350 // ----------------------------------- 1351 1352 if (id == IC::kCallIC_Miss) { 1353 __ IncrementCounter(&Counters::call_miss, 1); 1354 } else { 1355 __ IncrementCounter(&Counters::keyed_call_miss, 1); 1356 } 1357 1358 // Get the receiver of the function from the stack; 1 ~ return address. 1359 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1360 1361 // Enter an internal frame. 1362 __ EnterInternalFrame(); 1363 1364 // Push the receiver and the name of the function. 1365 __ push(edx); 1366 __ push(ecx); 1367 1368 // Call the entry. 1369 CEntryStub stub(1); 1370 __ mov(eax, Immediate(2)); 1371 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id)))); 1372 __ CallStub(&stub); 1373 1374 // Move result to edi and exit the internal frame. 1375 __ mov(edi, eax); 1376 __ LeaveInternalFrame(); 1377 1378 // Check if the receiver is a global object of some sort. 1379 // This can happen only for regular CallIC but not KeyedCallIC. 1380 if (id == IC::kCallIC_Miss) { 1381 Label invoke, global; 1382 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver 1383 __ test(edx, Immediate(kSmiTagMask)); 1384 __ j(zero, &invoke, not_taken); 1385 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 1386 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 1387 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); 1388 __ j(equal, &global); 1389 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); 1390 __ j(not_equal, &invoke); 1391 1392 // Patch the receiver on the stack. 1393 __ bind(&global); 1394 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); 1395 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); 1396 __ bind(&invoke); 1397 } 1398 1399 // Invoke the function. 1400 ParameterCount actual(argc); 1401 __ InvokeFunction(edi, actual, JUMP_FUNCTION); 1402} 1403 1404 1405void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { 1406 // ----------- S t a t e ------------- 1407 // -- ecx : name 1408 // -- esp[0] : return address 1409 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1410 // -- ... 1411 // -- esp[(argc + 1) * 4] : receiver 1412 // ----------------------------------- 1413 1414 // Get the receiver of the function from the stack; 1 ~ return address. 1415 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1416 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC); 1417 GenerateMiss(masm, argc); 1418} 1419 1420 1421void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { 1422 // ----------- S t a t e ------------- 1423 // -- ecx : name 1424 // -- esp[0] : return address 1425 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1426 // -- ... 1427 // -- esp[(argc + 1) * 4] : receiver 1428 // ----------------------------------- 1429 1430 GenerateCallNormal(masm, argc); 1431 GenerateMiss(masm, argc); 1432} 1433 1434 1435void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { 1436 // ----------- S t a t e ------------- 1437 // -- ecx : name 1438 // -- esp[0] : return address 1439 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1440 // -- ... 1441 // -- esp[(argc + 1) * 4] : receiver 1442 // ----------------------------------- 1443 1444 GenerateCallMiss(masm, argc, IC::kCallIC_Miss); 1445} 1446 1447 1448void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { 1449 // ----------- S t a t e ------------- 1450 // -- ecx : name 1451 // -- esp[0] : return address 1452 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1453 // -- ... 1454 // -- esp[(argc + 1) * 4] : receiver 1455 // ----------------------------------- 1456 1457 // Get the receiver of the function from the stack; 1 ~ return address. 1458 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1459 1460 Label do_call, slow_call, slow_load, slow_reload_receiver; 1461 Label check_number_dictionary, check_string, lookup_monomorphic_cache; 1462 Label index_smi, index_string; 1463 1464 // Check that the key is a smi. 1465 __ test(ecx, Immediate(kSmiTagMask)); 1466 __ j(not_zero, &check_string, not_taken); 1467 1468 __ bind(&index_smi); 1469 // Now the key is known to be a smi. This place is also jumped to from 1470 // where a numeric string is converted to a smi. 1471 1472 GenerateKeyedLoadReceiverCheck( 1473 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); 1474 1475 GenerateFastArrayLoad( 1476 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); 1477 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); 1478 1479 __ bind(&do_call); 1480 // receiver in edx is not used after this point. 1481 // ecx: key 1482 // edi: function 1483 GenerateFunctionTailCall(masm, argc, &slow_call); 1484 1485 __ bind(&check_number_dictionary); 1486 // eax: elements 1487 // ecx: smi key 1488 // Check whether the elements is a number dictionary. 1489 __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true); 1490 __ mov(ebx, ecx); 1491 __ SmiUntag(ebx); 1492 // ebx: untagged index 1493 // Receiver in edx will be clobbered, need to reload it on miss. 1494 GenerateNumberDictionaryLoad( 1495 masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi); 1496 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1); 1497 __ jmp(&do_call); 1498 1499 __ bind(&slow_reload_receiver); 1500 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1501 1502 __ bind(&slow_load); 1503 // This branch is taken when calling KeyedCallIC_Miss is neither required 1504 // nor beneficial. 1505 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1); 1506 __ EnterInternalFrame(); 1507 __ push(ecx); // save the key 1508 __ push(edx); // pass the receiver 1509 __ push(ecx); // pass the key 1510 __ CallRuntime(Runtime::kKeyedGetProperty, 2); 1511 __ pop(ecx); // restore the key 1512 __ LeaveInternalFrame(); 1513 __ mov(edi, eax); 1514 __ jmp(&do_call); 1515 1516 __ bind(&check_string); 1517 GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call); 1518 1519 // The key is known to be a symbol. 1520 // If the receiver is a regular JS object with slow properties then do 1521 // a quick inline probe of the receiver's dictionary. 1522 // Otherwise do the monomorphic cache probe. 1523 GenerateKeyedLoadReceiverCheck( 1524 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); 1525 1526 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); 1527 __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true); 1528 1529 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi); 1530 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); 1531 __ jmp(&do_call); 1532 1533 __ bind(&lookup_monomorphic_cache); 1534 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); 1535 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); 1536 // Fall through on miss. 1537 1538 __ bind(&slow_call); 1539 // This branch is taken if: 1540 // - the receiver requires boxing or access check, 1541 // - the key is neither smi nor symbol, 1542 // - the value loaded is not a function, 1543 // - there is hope that the runtime will create a monomorphic call stub 1544 // that will get fetched next time. 1545 __ IncrementCounter(&Counters::keyed_call_generic_slow, 1); 1546 GenerateMiss(masm, argc); 1547 1548 __ bind(&index_string); 1549 GenerateIndexFromHash(masm, ecx, ebx); 1550 // Now jump to the place where smi keys are handled. 1551 __ jmp(&index_smi); 1552} 1553 1554 1555void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { 1556 // ----------- S t a t e ------------- 1557 // -- ecx : name 1558 // -- esp[0] : return address 1559 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1560 // -- ... 1561 // -- esp[(argc + 1) * 4] : receiver 1562 // ----------------------------------- 1563 1564 GenerateCallNormal(masm, argc); 1565 GenerateMiss(masm, argc); 1566} 1567 1568 1569void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { 1570 // ----------- S t a t e ------------- 1571 // -- ecx : name 1572 // -- esp[0] : return address 1573 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1574 // -- ... 1575 // -- esp[(argc + 1) * 4] : receiver 1576 // ----------------------------------- 1577 1578 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss); 1579} 1580 1581 1582// Defined in ic.cc. 1583Object* LoadIC_Miss(Arguments args); 1584 1585void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { 1586 // ----------- S t a t e ------------- 1587 // -- eax : receiver 1588 // -- ecx : name 1589 // -- esp[0] : return address 1590 // ----------------------------------- 1591 1592 // Probe the stub cache. 1593 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, 1594 NOT_IN_LOOP, 1595 MONOMORPHIC); 1596 StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx); 1597 1598 // Cache miss: Jump to runtime. 1599 GenerateMiss(masm); 1600} 1601 1602 1603void LoadIC::GenerateNormal(MacroAssembler* masm) { 1604 // ----------- S t a t e ------------- 1605 // -- eax : receiver 1606 // -- ecx : name 1607 // -- esp[0] : return address 1608 // ----------------------------------- 1609 Label miss; 1610 1611 GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss); 1612 1613 // edx: elements 1614 // Search the dictionary placing the result in eax. 1615 GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax); 1616 __ ret(0); 1617 1618 // Cache miss: Jump to runtime. 1619 __ bind(&miss); 1620 GenerateMiss(masm); 1621} 1622 1623 1624void LoadIC::GenerateMiss(MacroAssembler* masm) { 1625 // ----------- S t a t e ------------- 1626 // -- eax : receiver 1627 // -- ecx : name 1628 // -- esp[0] : return address 1629 // ----------------------------------- 1630 1631 __ IncrementCounter(&Counters::load_miss, 1); 1632 1633 __ pop(ebx); 1634 __ push(eax); // receiver 1635 __ push(ecx); // name 1636 __ push(ebx); // return address 1637 1638 // Perform tail call to the entry. 1639 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); 1640 __ TailCallExternalReference(ref, 2, 1); 1641} 1642 1643 1644// One byte opcode for test eax,0xXXXXXXXX. 1645static const byte kTestEaxByte = 0xA9; 1646 1647bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { 1648 // The address of the instruction following the call. 1649 Address test_instruction_address = 1650 address + Assembler::kCallTargetAddressOffset; 1651 // If the instruction following the call is not a test eax, nothing 1652 // was inlined. 1653 if (*test_instruction_address != kTestEaxByte) return false; 1654 1655 Address delta_address = test_instruction_address + 1; 1656 // The delta to the start of the map check instruction. 1657 int delta = *reinterpret_cast<int*>(delta_address); 1658 1659 // The map address is the last 4 bytes of the 7-byte 1660 // operand-immediate compare instruction, so we add 3 to get the 1661 // offset to the last 4 bytes. 1662 Address map_address = test_instruction_address + delta + 3; 1663 *(reinterpret_cast<Object**>(map_address)) = map; 1664 1665 // The offset is in the last 4 bytes of a six byte 1666 // memory-to-register move instruction, so we add 2 to get the 1667 // offset to the last 4 bytes. 1668 Address offset_address = 1669 test_instruction_address + delta + kOffsetToLoadInstruction + 2; 1670 *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag; 1671 return true; 1672} 1673 1674 1675bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) { 1676 // The address of the instruction following the call. 1677 Address test_instruction_address = 1678 address + Assembler::kCallTargetAddressOffset; 1679 1680 // If the instruction following the call is not a test eax, nothing 1681 // was inlined. 1682 if (*test_instruction_address != kTestEaxByte) return false; 1683 1684 // Extract the encoded deltas from the test eax instruction. 1685 Address encoded_offsets_address = test_instruction_address + 1; 1686 int encoded_offsets = *reinterpret_cast<int*>(encoded_offsets_address); 1687 int delta_to_map_check = -(encoded_offsets & 0xFFFF); 1688 int delta_to_record_write = encoded_offsets >> 16; 1689 1690 // Patch the map to check. The map address is the last 4 bytes of 1691 // the 7-byte operand-immediate compare instruction. 1692 Address map_check_address = test_instruction_address + delta_to_map_check; 1693 Address map_address = map_check_address + 3; 1694 *(reinterpret_cast<Object**>(map_address)) = map; 1695 1696 // Patch the offset in the store instruction. The offset is in the 1697 // last 4 bytes of a six byte register-to-memory move instruction. 1698 Address offset_address = 1699 map_check_address + StoreIC::kOffsetToStoreInstruction + 2; 1700 // The offset should have initial value (kMaxInt - 1), cleared value 1701 // (-1) or we should be clearing the inlined version. 1702 ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 || 1703 *reinterpret_cast<int*>(offset_address) == -1 || 1704 (offset == 0 && map == Heap::null_value())); 1705 *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag; 1706 1707 // Patch the offset in the write-barrier code. The offset is the 1708 // last 4 bytes of a six byte lea instruction. 1709 offset_address = map_check_address + delta_to_record_write + 2; 1710 // The offset should have initial value (kMaxInt), cleared value 1711 // (-1) or we should be clearing the inlined version. 1712 ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt || 1713 *reinterpret_cast<int*>(offset_address) == -1 || 1714 (offset == 0 && map == Heap::null_value())); 1715 *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag; 1716 1717 return true; 1718} 1719 1720 1721static bool PatchInlinedMapCheck(Address address, Object* map) { 1722 Address test_instruction_address = 1723 address + Assembler::kCallTargetAddressOffset; 1724 // The keyed load has a fast inlined case if the IC call instruction 1725 // is immediately followed by a test instruction. 1726 if (*test_instruction_address != kTestEaxByte) return false; 1727 1728 // Fetch the offset from the test instruction to the map cmp 1729 // instruction. This offset is stored in the last 4 bytes of the 5 1730 // byte test instruction. 1731 Address delta_address = test_instruction_address + 1; 1732 int delta = *reinterpret_cast<int*>(delta_address); 1733 // Compute the map address. The map address is in the last 4 bytes 1734 // of the 7-byte operand-immediate compare instruction, so we add 3 1735 // to the offset to get the map address. 1736 Address map_address = test_instruction_address + delta + 3; 1737 // Patch the map check. 1738 *(reinterpret_cast<Object**>(map_address)) = map; 1739 return true; 1740} 1741 1742 1743bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) { 1744 return PatchInlinedMapCheck(address, map); 1745} 1746 1747 1748bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) { 1749 return PatchInlinedMapCheck(address, map); 1750} 1751 1752 1753// Defined in ic.cc. 1754Object* KeyedLoadIC_Miss(Arguments args); 1755 1756 1757void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { 1758 // ----------- S t a t e ------------- 1759 // -- eax : key 1760 // -- edx : receiver 1761 // -- esp[0] : return address 1762 // ----------------------------------- 1763 1764 __ IncrementCounter(&Counters::keyed_load_miss, 1); 1765 1766 __ pop(ebx); 1767 __ push(edx); // receiver 1768 __ push(eax); // name 1769 __ push(ebx); // return address 1770 1771 // Perform tail call to the entry. 1772 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss)); 1773 __ TailCallExternalReference(ref, 2, 1); 1774} 1775 1776 1777void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { 1778 // ----------- S t a t e ------------- 1779 // -- eax : key 1780 // -- edx : receiver 1781 // -- esp[0] : return address 1782 // ----------------------------------- 1783 1784 __ pop(ebx); 1785 __ push(edx); // receiver 1786 __ push(eax); // name 1787 __ push(ebx); // return address 1788 1789 // Perform tail call to the entry. 1790 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); 1791} 1792 1793 1794void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { 1795 // ----------- S t a t e ------------- 1796 // -- eax : value 1797 // -- ecx : name 1798 // -- edx : receiver 1799 // -- esp[0] : return address 1800 // ----------------------------------- 1801 1802 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, 1803 NOT_IN_LOOP, 1804 MONOMORPHIC); 1805 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); 1806 1807 // Cache miss: Jump to runtime. 1808 GenerateMiss(masm); 1809} 1810 1811 1812void StoreIC::GenerateMiss(MacroAssembler* masm) { 1813 // ----------- S t a t e ------------- 1814 // -- eax : value 1815 // -- ecx : name 1816 // -- edx : receiver 1817 // -- esp[0] : return address 1818 // ----------------------------------- 1819 1820 __ pop(ebx); 1821 __ push(edx); 1822 __ push(ecx); 1823 __ push(eax); 1824 __ push(ebx); 1825 1826 // Perform tail call to the entry. 1827 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss)); 1828 __ TailCallExternalReference(ref, 3, 1); 1829} 1830 1831 1832// The offset from the inlined patch site to the start of the inlined 1833// store instruction. It is 7 bytes (test reg, imm) plus 6 bytes (jne 1834// slow_label). 1835const int StoreIC::kOffsetToStoreInstruction = 13; 1836 1837 1838void StoreIC::GenerateArrayLength(MacroAssembler* masm) { 1839 // ----------- S t a t e ------------- 1840 // -- eax : value 1841 // -- ecx : name 1842 // -- edx : receiver 1843 // -- esp[0] : return address 1844 // ----------------------------------- 1845 // 1846 // This accepts as a receiver anything JSObject::SetElementsLength accepts 1847 // (currently anything except for external and pixel arrays which means 1848 // anything with elements of FixedArray type.), but currently is restricted 1849 // to JSArray. 1850 // Value must be a number, but only smis are accepted as the most common case. 1851 1852 Label miss; 1853 1854 Register receiver = edx; 1855 Register value = eax; 1856 Register scratch = ebx; 1857 1858 // Check that the receiver isn't a smi. 1859 __ test(receiver, Immediate(kSmiTagMask)); 1860 __ j(zero, &miss, not_taken); 1861 1862 // Check that the object is a JS array. 1863 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); 1864 __ j(not_equal, &miss, not_taken); 1865 1866 // Check that elements are FixedArray. 1867 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset)); 1868 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch); 1869 __ j(not_equal, &miss, not_taken); 1870 1871 // Check that value is a smi. 1872 __ test(value, Immediate(kSmiTagMask)); 1873 __ j(not_zero, &miss, not_taken); 1874 1875 // Prepare tail call to StoreIC_ArrayLength. 1876 __ pop(scratch); 1877 __ push(receiver); 1878 __ push(value); 1879 __ push(scratch); // return address 1880 1881 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength)); 1882 __ TailCallExternalReference(ref, 2, 1); 1883 1884 __ bind(&miss); 1885 1886 GenerateMiss(masm); 1887} 1888 1889 1890void StoreIC::GenerateNormal(MacroAssembler* masm) { 1891 // ----------- S t a t e ------------- 1892 // -- eax : value 1893 // -- ecx : name 1894 // -- edx : receiver 1895 // -- esp[0] : return address 1896 // ----------------------------------- 1897 1898 Label miss, restore_miss; 1899 1900 GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss); 1901 1902 // A lot of registers are needed for storing to slow case 1903 // objects. Push and restore receiver but rely on 1904 // GenerateDictionaryStore preserving the value and name. 1905 __ push(edx); 1906 GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi); 1907 __ Drop(1); 1908 __ IncrementCounter(&Counters::store_normal_hit, 1); 1909 __ ret(0); 1910 1911 __ bind(&restore_miss); 1912 __ pop(edx); 1913 1914 __ bind(&miss); 1915 __ IncrementCounter(&Counters::store_normal_miss, 1); 1916 GenerateMiss(masm); 1917} 1918 1919 1920// Defined in ic.cc. 1921Object* KeyedStoreIC_Miss(Arguments args); 1922 1923void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { 1924 // ----------- S t a t e ------------- 1925 // -- eax : value 1926 // -- ecx : key 1927 // -- edx : receiver 1928 // -- esp[0] : return address 1929 // ----------------------------------- 1930 1931 __ pop(ebx); 1932 __ push(edx); 1933 __ push(ecx); 1934 __ push(eax); 1935 __ push(ebx); 1936 1937 // Do tail-call to runtime routine. 1938 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); 1939} 1940 1941 1942void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { 1943 // ----------- S t a t e ------------- 1944 // -- eax : value 1945 // -- ecx : key 1946 // -- edx : receiver 1947 // -- esp[0] : return address 1948 // ----------------------------------- 1949 1950 __ pop(ebx); 1951 __ push(edx); 1952 __ push(ecx); 1953 __ push(eax); 1954 __ push(ebx); 1955 1956 // Do tail-call to runtime routine. 1957 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss)); 1958 __ TailCallExternalReference(ref, 3, 1); 1959} 1960 1961#undef __ 1962 1963 1964} } // namespace v8::internal 1965 1966#endif // V8_TARGET_ARCH_IA32 1967