ic-ia32.cc revision 0d5e116f6aee03185f237311a943491bb079a768
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. 455// If not_fast_array is NULL, doesn't perform the elements map check. 456static void GenerateFastArrayLoad(MacroAssembler* masm, 457 Register receiver, 458 Register key, 459 Register scratch, 460 Register result, 461 Label* not_fast_array, 462 Label* out_of_range) { 463 // Register use: 464 // receiver - holds the receiver and is unchanged. 465 // key - holds the key and is unchanged (must be a smi). 466 // Scratch registers: 467 // scratch - used to hold elements of the receiver and the loaded value. 468 // result - holds the result on exit if the load succeeds and 469 // we fall through. 470 471 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); 472 if (not_fast_array != NULL) { 473 // Check that the object is in fast mode and writable. 474 __ CheckMap(scratch, Factory::fixed_array_map(), not_fast_array, true); 475 } else { 476 __ AssertFastElements(scratch); 477 } 478 // Check that the key (index) is within bounds. 479 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); 480 __ j(above_equal, out_of_range); 481 // Fast case: Do the load. 482 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); 483 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); 484 __ cmp(Operand(scratch), Immediate(Factory::the_hole_value())); 485 // In case the loaded value is the_hole we have to consult GetProperty 486 // to ensure the prototype chain is searched. 487 __ j(equal, out_of_range); 488 if (!result.is(scratch)) { 489 __ mov(result, scratch); 490 } 491} 492 493 494// Checks whether a key is an array index string or a symbol string. 495// Falls through if the key is a symbol. 496static void GenerateKeyStringCheck(MacroAssembler* masm, 497 Register key, 498 Register map, 499 Register hash, 500 Label* index_string, 501 Label* not_symbol) { 502 // Register use: 503 // key - holds the key and is unchanged. Assumed to be non-smi. 504 // Scratch registers: 505 // map - used to hold the map of the key. 506 // hash - used to hold the hash of the key. 507 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); 508 __ j(above_equal, not_symbol); 509 510 // Is the string an array index, with cached numeric value? 511 __ mov(hash, FieldOperand(key, String::kHashFieldOffset)); 512 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask)); 513 __ j(zero, index_string, not_taken); 514 515 // Is the string a symbol? 516 ASSERT(kSymbolTag != 0); 517 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); 518 __ j(zero, not_symbol, not_taken); 519} 520 521 522void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { 523 // ----------- S t a t e ------------- 524 // -- eax : key 525 // -- edx : receiver 526 // -- esp[0] : return address 527 // ----------------------------------- 528 Label slow, check_string, index_smi, index_string, property_array_property; 529 Label check_pixel_array, probe_dictionary, check_number_dictionary; 530 531 // Check that the key is a smi. 532 __ test(eax, Immediate(kSmiTagMask)); 533 __ j(not_zero, &check_string, not_taken); 534 __ bind(&index_smi); 535 // Now the key is known to be a smi. This place is also jumped to from 536 // where a numeric string is converted to a smi. 537 538 GenerateKeyedLoadReceiverCheck( 539 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); 540 541 // Check the "has fast elements" bit in the receiver's map which is 542 // now in ecx. 543 __ test_b(FieldOperand(ecx, Map::kBitField2Offset), 544 1 << Map::kHasFastElements); 545 __ j(zero, &check_pixel_array, not_taken); 546 547 GenerateFastArrayLoad(masm, 548 edx, 549 eax, 550 ecx, 551 eax, 552 NULL, 553 &slow); 554 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); 555 __ ret(0); 556 557 __ bind(&check_pixel_array); 558 // Check whether the elements is a pixel array. 559 // edx: receiver 560 // eax: key 561 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); 562 __ mov(ebx, eax); 563 __ SmiUntag(ebx); 564 __ CheckMap(ecx, Factory::pixel_array_map(), &check_number_dictionary, true); 565 __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset)); 566 __ j(above_equal, &slow); 567 __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset)); 568 __ movzx_b(eax, Operand(eax, ebx, times_1, 0)); 569 __ SmiTag(eax); 570 __ ret(0); 571 572 __ bind(&check_number_dictionary); 573 // Check whether the elements is a number dictionary. 574 // edx: receiver 575 // ebx: untagged index 576 // eax: key 577 // ecx: elements 578 __ CheckMap(ecx, Factory::hash_table_map(), &slow, true); 579 Label slow_pop_receiver; 580 // Push receiver on the stack to free up a register for the dictionary 581 // probing. 582 __ push(edx); 583 GenerateNumberDictionaryLoad(masm, 584 &slow_pop_receiver, 585 ecx, 586 eax, 587 ebx, 588 edx, 589 edi, 590 eax); 591 // Pop receiver before returning. 592 __ pop(edx); 593 __ ret(0); 594 595 __ bind(&slow_pop_receiver); 596 // Pop the receiver from the stack and jump to runtime. 597 __ pop(edx); 598 599 __ bind(&slow); 600 // Slow case: jump to runtime. 601 // edx: receiver 602 // eax: key 603 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); 604 GenerateRuntimeGetProperty(masm); 605 606 __ bind(&check_string); 607 GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow); 608 609 GenerateKeyedLoadReceiverCheck( 610 masm, edx, ecx, Map::kHasNamedInterceptor, &slow); 611 612 // If the receiver is a fast-case object, check the keyed lookup 613 // cache. Otherwise probe the dictionary. 614 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); 615 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 616 Immediate(Factory::hash_table_map())); 617 __ j(equal, &probe_dictionary); 618 619 // Load the map of the receiver, compute the keyed lookup cache hash 620 // based on 32 bits of the map pointer and the string hash. 621 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 622 __ mov(ecx, ebx); 623 __ shr(ecx, KeyedLookupCache::kMapHashShift); 624 __ mov(edi, FieldOperand(eax, String::kHashFieldOffset)); 625 __ shr(edi, String::kHashShift); 626 __ xor_(ecx, Operand(edi)); 627 __ and_(ecx, KeyedLookupCache::kCapacityMask); 628 629 // Load the key (consisting of map and symbol) from the cache and 630 // check for match. 631 ExternalReference cache_keys 632 = ExternalReference::keyed_lookup_cache_keys(); 633 __ mov(edi, ecx); 634 __ shl(edi, kPointerSizeLog2 + 1); 635 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); 636 __ j(not_equal, &slow); 637 __ add(Operand(edi), Immediate(kPointerSize)); 638 __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys)); 639 __ j(not_equal, &slow); 640 641 // Get field offset. 642 // edx : receiver 643 // ebx : receiver's map 644 // eax : key 645 // ecx : lookup cache index 646 ExternalReference cache_field_offsets 647 = ExternalReference::keyed_lookup_cache_field_offsets(); 648 __ mov(edi, 649 Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets)); 650 __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); 651 __ sub(edi, Operand(ecx)); 652 __ j(above_equal, &property_array_property); 653 654 // Load in-object property. 655 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); 656 __ add(ecx, Operand(edi)); 657 __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0)); 658 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1); 659 __ ret(0); 660 661 // Load property array property. 662 __ bind(&property_array_property); 663 __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset)); 664 __ mov(eax, FieldOperand(eax, edi, times_pointer_size, 665 FixedArray::kHeaderSize)); 666 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1); 667 __ ret(0); 668 669 // Do a quick inline probe of the receiver's dictionary, if it 670 // exists. 671 __ bind(&probe_dictionary); 672 673 __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset)); 674 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 675 GenerateGlobalInstanceTypeCheck(masm, ecx, &slow); 676 677 GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax); 678 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); 679 __ ret(0); 680 681 __ bind(&index_string); 682 __ IndexFromHash(ebx, eax); 683 // Now jump to the place where smi keys are handled. 684 __ jmp(&index_smi); 685} 686 687 688void KeyedLoadIC::GenerateString(MacroAssembler* masm) { 689 // ----------- S t a t e ------------- 690 // -- eax : key (index) 691 // -- edx : receiver 692 // -- esp[0] : return address 693 // ----------------------------------- 694 Label miss; 695 696 Register receiver = edx; 697 Register index = eax; 698 Register scratch1 = ebx; 699 Register scratch2 = ecx; 700 Register result = eax; 701 702 StringCharAtGenerator char_at_generator(receiver, 703 index, 704 scratch1, 705 scratch2, 706 result, 707 &miss, // When not a string. 708 &miss, // When not a number. 709 &miss, // When index out of range. 710 STRING_INDEX_IS_ARRAY_INDEX); 711 char_at_generator.GenerateFast(masm); 712 __ ret(0); 713 714 ICRuntimeCallHelper call_helper; 715 char_at_generator.GenerateSlow(masm, call_helper); 716 717 __ bind(&miss); 718 GenerateMiss(masm); 719} 720 721 722void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, 723 ExternalArrayType array_type) { 724 // ----------- S t a t e ------------- 725 // -- eax : key 726 // -- edx : receiver 727 // -- esp[0] : return address 728 // ----------------------------------- 729 Label slow, failed_allocation; 730 731 // Check that the object isn't a smi. 732 __ test(edx, Immediate(kSmiTagMask)); 733 __ j(zero, &slow, not_taken); 734 735 // Check that the key is a smi. 736 __ test(eax, Immediate(kSmiTagMask)); 737 __ j(not_zero, &slow, not_taken); 738 739 // Get the map of the receiver. 740 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 741 // Check that the receiver does not require access checks. We need 742 // to check this explicitly since this generic stub does not perform 743 // map checks. 744 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 745 1 << Map::kIsAccessCheckNeeded); 746 __ j(not_zero, &slow, not_taken); 747 748 __ CmpInstanceType(ecx, JS_OBJECT_TYPE); 749 __ j(not_equal, &slow, not_taken); 750 751 // Check that the elements array is the appropriate type of 752 // ExternalArray. 753 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 754 Handle<Map> map(Heap::MapForExternalArrayType(array_type)); 755 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 756 Immediate(map)); 757 __ j(not_equal, &slow, not_taken); 758 759 // eax: key, known to be a smi. 760 // edx: receiver, known to be a JSObject. 761 // ebx: elements object, known to be an external array. 762 // Check that the index is in range. 763 __ mov(ecx, eax); 764 __ SmiUntag(ecx); // Untag the index. 765 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); 766 // Unsigned comparison catches both negative and too-large values. 767 __ j(above_equal, &slow); 768 769 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); 770 // ebx: base pointer of external storage 771 switch (array_type) { 772 case kExternalByteArray: 773 __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0)); 774 break; 775 case kExternalUnsignedByteArray: 776 __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0)); 777 break; 778 case kExternalShortArray: 779 __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0)); 780 break; 781 case kExternalUnsignedShortArray: 782 __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0)); 783 break; 784 case kExternalIntArray: 785 case kExternalUnsignedIntArray: 786 __ mov(ecx, Operand(ebx, ecx, times_4, 0)); 787 break; 788 case kExternalFloatArray: 789 __ fld_s(Operand(ebx, ecx, times_4, 0)); 790 break; 791 default: 792 UNREACHABLE(); 793 break; 794 } 795 796 // For integer array types: 797 // ecx: value 798 // For floating-point array type: 799 // FP(0): value 800 801 if (array_type == kExternalIntArray || 802 array_type == kExternalUnsignedIntArray) { 803 // For the Int and UnsignedInt array types, we need to see whether 804 // the value can be represented in a Smi. If not, we need to convert 805 // it to a HeapNumber. 806 Label box_int; 807 if (array_type == kExternalIntArray) { 808 __ cmp(ecx, 0xC0000000); 809 __ j(sign, &box_int); 810 } else { 811 ASSERT_EQ(array_type, kExternalUnsignedIntArray); 812 // The test is different for unsigned int values. Since we need 813 // the value to be in the range of a positive smi, we can't 814 // handle either of the top two bits being set in the value. 815 __ test(ecx, Immediate(0xC0000000)); 816 __ j(not_zero, &box_int); 817 } 818 819 __ mov(eax, ecx); 820 __ SmiTag(eax); 821 __ ret(0); 822 823 __ bind(&box_int); 824 825 // Allocate a HeapNumber for the int and perform int-to-double 826 // conversion. 827 if (array_type == kExternalIntArray) { 828 __ push(ecx); 829 __ fild_s(Operand(esp, 0)); 830 __ pop(ecx); 831 } else { 832 ASSERT(array_type == kExternalUnsignedIntArray); 833 // Need to zero-extend the value. 834 // There's no fild variant for unsigned values, so zero-extend 835 // to a 64-bit int manually. 836 __ push(Immediate(0)); 837 __ push(ecx); 838 __ fild_d(Operand(esp, 0)); 839 __ pop(ecx); 840 __ pop(ecx); 841 } 842 // FP(0): value 843 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); 844 // Set the value. 845 __ mov(eax, ecx); 846 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 847 __ ret(0); 848 } else if (array_type == kExternalFloatArray) { 849 // For the floating-point array type, we need to always allocate a 850 // HeapNumber. 851 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); 852 // Set the value. 853 __ mov(eax, ecx); 854 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 855 __ ret(0); 856 } else { 857 __ mov(eax, ecx); 858 __ SmiTag(eax); 859 __ ret(0); 860 } 861 862 // If we fail allocation of the HeapNumber, we still have a value on 863 // top of the FPU stack. Remove it. 864 __ bind(&failed_allocation); 865 __ ffree(); 866 __ fincstp(); 867 // Fall through to slow case. 868 869 // Slow case: Jump to runtime. 870 __ bind(&slow); 871 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); 872 GenerateRuntimeGetProperty(masm); 873} 874 875 876void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { 877 // ----------- S t a t e ------------- 878 // -- eax : key 879 // -- edx : receiver 880 // -- esp[0] : return address 881 // ----------------------------------- 882 Label slow; 883 884 // Check that the receiver isn't a smi. 885 __ test(edx, Immediate(kSmiTagMask)); 886 __ j(zero, &slow, not_taken); 887 888 // Check that the key is a smi. 889 __ test(eax, Immediate(kSmiTagMask)); 890 __ j(not_zero, &slow, not_taken); 891 892 // Get the map of the receiver. 893 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 894 895 // Check that it has indexed interceptor and access checks 896 // are not enabled for this object. 897 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); 898 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); 899 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); 900 __ j(not_zero, &slow, not_taken); 901 902 // Everything is fine, call runtime. 903 __ pop(ecx); 904 __ push(edx); // receiver 905 __ push(eax); // key 906 __ push(ecx); // return address 907 908 // Perform tail call to the entry. 909 ExternalReference ref = ExternalReference( 910 IC_Utility(kKeyedLoadPropertyWithInterceptor)); 911 __ TailCallExternalReference(ref, 2, 1); 912 913 __ bind(&slow); 914 GenerateMiss(masm); 915} 916 917 918void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { 919 // ----------- S t a t e ------------- 920 // -- eax : value 921 // -- ecx : key 922 // -- edx : receiver 923 // -- esp[0] : return address 924 // ----------------------------------- 925 Label slow, fast, array, extra, check_pixel_array; 926 927 // Check that the object isn't a smi. 928 __ test(edx, Immediate(kSmiTagMask)); 929 __ j(zero, &slow, not_taken); 930 // Get the map from the receiver. 931 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 932 // Check that the receiver does not require access checks. We need 933 // to do this because this generic stub does not perform map checks. 934 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), 935 1 << Map::kIsAccessCheckNeeded); 936 __ j(not_zero, &slow, not_taken); 937 // Check that the key is a smi. 938 __ test(ecx, Immediate(kSmiTagMask)); 939 __ j(not_zero, &slow, not_taken); 940 __ CmpInstanceType(edi, JS_ARRAY_TYPE); 941 __ j(equal, &array); 942 // Check that the object is some kind of JS object. 943 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); 944 __ j(below, &slow, not_taken); 945 946 // Object case: Check key against length in the elements array. 947 // eax: value 948 // edx: JSObject 949 // ecx: key (a smi) 950 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); 951 // Check that the object is in fast mode and writable. 952 __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true); 953 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); 954 __ j(below, &fast, taken); 955 956 // Slow case: call runtime. 957 __ bind(&slow); 958 GenerateRuntimeSetProperty(masm); 959 960 // Check whether the elements is a pixel array. 961 __ bind(&check_pixel_array); 962 // eax: value 963 // ecx: key (a smi) 964 // edx: receiver 965 // edi: elements array 966 __ CheckMap(edi, Factory::pixel_array_map(), &slow, true); 967 // Check that the value is a smi. If a conversion is needed call into the 968 // runtime to convert and clamp. 969 __ test(eax, Immediate(kSmiTagMask)); 970 __ j(not_zero, &slow); 971 __ mov(ebx, ecx); 972 __ SmiUntag(ebx); 973 __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset)); 974 __ j(above_equal, &slow); 975 __ mov(ecx, eax); // Save the value. Key is not longer needed. 976 __ SmiUntag(ecx); 977 { // Clamp the value to [0..255]. 978 Label done; 979 __ test(ecx, Immediate(0xFFFFFF00)); 980 __ j(zero, &done); 981 __ setcc(negative, ecx); // 1 if negative, 0 if positive. 982 __ dec_b(ecx); // 0 if negative, 255 if positive. 983 __ bind(&done); 984 } 985 __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset)); 986 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); 987 __ ret(0); // Return value in eax. 988 989 // Extra capacity case: Check if there is extra capacity to 990 // perform the store and update the length. Used for adding one 991 // element to the array by writing to array[array.length]. 992 __ bind(&extra); 993 // eax: value 994 // edx: receiver, a JSArray 995 // ecx: key, a smi. 996 // edi: receiver->elements, a FixedArray 997 // flags: compare (ecx, edx.length()) 998 __ j(not_equal, &slow, not_taken); // do not leave holes in the array 999 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); 1000 __ j(above_equal, &slow, not_taken); 1001 // Add 1 to receiver->length, and go to fast array write. 1002 __ add(FieldOperand(edx, JSArray::kLengthOffset), 1003 Immediate(Smi::FromInt(1))); 1004 __ jmp(&fast); 1005 1006 // Array case: Get the length and the elements array from the JS 1007 // array. Check that the array is in fast mode (and writable); if it 1008 // is the length is always a smi. 1009 __ bind(&array); 1010 // eax: value 1011 // edx: receiver, a JSArray 1012 // ecx: key, a smi. 1013 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); 1014 __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true); 1015 1016 // Check the key against the length in the array, compute the 1017 // address to store into and fall through to fast case. 1018 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. 1019 __ j(above_equal, &extra, not_taken); 1020 1021 // Fast case: Do the store. 1022 __ bind(&fast); 1023 // eax: value 1024 // ecx: key (a smi) 1025 // edx: receiver 1026 // edi: FixedArray receiver->elements 1027 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax); 1028 // Update write barrier for the elements array address. 1029 __ mov(edx, Operand(eax)); 1030 __ RecordWrite(edi, 0, edx, ecx); 1031 __ ret(0); 1032} 1033 1034 1035void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, 1036 ExternalArrayType array_type) { 1037 // ----------- S t a t e ------------- 1038 // -- eax : value 1039 // -- ecx : key 1040 // -- edx : receiver 1041 // -- esp[0] : return address 1042 // ----------------------------------- 1043 Label slow, check_heap_number; 1044 1045 // Check that the object isn't a smi. 1046 __ test(edx, Immediate(kSmiTagMask)); 1047 __ j(zero, &slow); 1048 // Get the map from the receiver. 1049 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 1050 // Check that the receiver does not require access checks. We need 1051 // to do this because this generic stub does not perform map checks. 1052 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), 1053 1 << Map::kIsAccessCheckNeeded); 1054 __ j(not_zero, &slow); 1055 // Check that the key is a smi. 1056 __ test(ecx, Immediate(kSmiTagMask)); 1057 __ j(not_zero, &slow); 1058 // Get the instance type from the map of the receiver. 1059 __ CmpInstanceType(edi, JS_OBJECT_TYPE); 1060 __ j(not_equal, &slow); 1061 1062 // Check that the elements array is the appropriate type of 1063 // ExternalArray. 1064 // eax: value 1065 // edx: receiver, a JSObject 1066 // ecx: key, a smi 1067 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); 1068 __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)), 1069 &slow, true); 1070 1071 // Check that the index is in range. 1072 __ mov(ebx, ecx); 1073 __ SmiUntag(ebx); 1074 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); 1075 // Unsigned comparison catches both negative and too-large values. 1076 __ j(above_equal, &slow); 1077 1078 // Handle both smis and HeapNumbers in the fast path. Go to the 1079 // runtime for all other kinds of values. 1080 // eax: value 1081 // edx: receiver 1082 // ecx: key 1083 // edi: elements array 1084 // ebx: untagged index 1085 __ test(eax, Immediate(kSmiTagMask)); 1086 __ j(not_equal, &check_heap_number); 1087 // smi case 1088 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. 1089 __ SmiUntag(ecx); 1090 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); 1091 // ecx: base pointer of external storage 1092 switch (array_type) { 1093 case kExternalByteArray: 1094 case kExternalUnsignedByteArray: 1095 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); 1096 break; 1097 case kExternalShortArray: 1098 case kExternalUnsignedShortArray: 1099 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); 1100 break; 1101 case kExternalIntArray: 1102 case kExternalUnsignedIntArray: 1103 __ mov(Operand(edi, ebx, times_4, 0), ecx); 1104 break; 1105 case kExternalFloatArray: 1106 // Need to perform int-to-float conversion. 1107 __ push(ecx); 1108 __ fild_s(Operand(esp, 0)); 1109 __ pop(ecx); 1110 __ fstp_s(Operand(edi, ebx, times_4, 0)); 1111 break; 1112 default: 1113 UNREACHABLE(); 1114 break; 1115 } 1116 __ ret(0); // Return the original value. 1117 1118 __ bind(&check_heap_number); 1119 // eax: value 1120 // edx: receiver 1121 // ecx: key 1122 // edi: elements array 1123 // ebx: untagged index 1124 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), 1125 Immediate(Factory::heap_number_map())); 1126 __ j(not_equal, &slow); 1127 1128 // The WebGL specification leaves the behavior of storing NaN and 1129 // +/-Infinity into integer arrays basically undefined. For more 1130 // reproducible behavior, convert these to zero. 1131 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1132 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); 1133 // ebx: untagged index 1134 // edi: base pointer of external storage 1135 // top of FPU stack: value 1136 if (array_type == kExternalFloatArray) { 1137 __ fstp_s(Operand(edi, ebx, times_4, 0)); 1138 __ ret(0); 1139 } else { 1140 // Need to perform float-to-int conversion. 1141 // Test the top of the FP stack for NaN. 1142 Label is_nan; 1143 __ fucomi(0); 1144 __ j(parity_even, &is_nan); 1145 1146 if (array_type != kExternalUnsignedIntArray) { 1147 __ push(ecx); // Make room on stack 1148 __ fistp_s(Operand(esp, 0)); 1149 __ pop(ecx); 1150 } else { 1151 // fistp stores values as signed integers. 1152 // To represent the entire range, we need to store as a 64-bit 1153 // int and discard the high 32 bits. 1154 __ sub(Operand(esp), Immediate(2 * kPointerSize)); 1155 __ fistp_d(Operand(esp, 0)); 1156 __ pop(ecx); 1157 __ add(Operand(esp), Immediate(kPointerSize)); 1158 } 1159 // ecx: untagged integer value 1160 switch (array_type) { 1161 case kExternalByteArray: 1162 case kExternalUnsignedByteArray: 1163 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); 1164 break; 1165 case kExternalShortArray: 1166 case kExternalUnsignedShortArray: 1167 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); 1168 break; 1169 case kExternalIntArray: 1170 case kExternalUnsignedIntArray: { 1171 // We also need to explicitly check for +/-Infinity. These are 1172 // converted to MIN_INT, but we need to be careful not to 1173 // confuse with legal uses of MIN_INT. 1174 Label not_infinity; 1175 // This test would apparently detect both NaN and Infinity, 1176 // but we've already checked for NaN using the FPU hardware 1177 // above. 1178 __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6)); 1179 __ and_(edx, 0x7FF0); 1180 __ cmp(edx, 0x7FF0); 1181 __ j(not_equal, ¬_infinity); 1182 __ mov(ecx, 0); 1183 __ bind(¬_infinity); 1184 __ mov(Operand(edi, ebx, times_4, 0), ecx); 1185 break; 1186 } 1187 default: 1188 UNREACHABLE(); 1189 break; 1190 } 1191 __ ret(0); // Return original value. 1192 1193 __ bind(&is_nan); 1194 __ ffree(); 1195 __ fincstp(); 1196 switch (array_type) { 1197 case kExternalByteArray: 1198 case kExternalUnsignedByteArray: 1199 __ mov_b(Operand(edi, ebx, times_1, 0), 0); 1200 break; 1201 case kExternalShortArray: 1202 case kExternalUnsignedShortArray: 1203 __ xor_(ecx, Operand(ecx)); 1204 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); 1205 break; 1206 case kExternalIntArray: 1207 case kExternalUnsignedIntArray: 1208 __ mov(Operand(edi, ebx, times_4, 0), Immediate(0)); 1209 break; 1210 default: 1211 UNREACHABLE(); 1212 break; 1213 } 1214 __ ret(0); // Return the original value. 1215 } 1216 1217 // Slow case: call runtime. 1218 __ bind(&slow); 1219 GenerateRuntimeSetProperty(masm); 1220} 1221 1222 1223// Defined in ic.cc. 1224Object* CallIC_Miss(Arguments args); 1225 1226// The generated code does not accept smi keys. 1227// The generated code falls through if both probes miss. 1228static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, 1229 int argc, 1230 Code::Kind kind) { 1231 // ----------- S t a t e ------------- 1232 // -- ecx : name 1233 // -- edx : receiver 1234 // ----------------------------------- 1235 Label number, non_number, non_string, boolean, probe, miss; 1236 1237 // Probe the stub cache. 1238 Code::Flags flags = 1239 Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); 1240 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax); 1241 1242 // If the stub cache probing failed, the receiver might be a value. 1243 // For value objects, we use the map of the prototype objects for 1244 // the corresponding JSValue for the cache and that is what we need 1245 // to probe. 1246 // 1247 // Check for number. 1248 __ test(edx, Immediate(kSmiTagMask)); 1249 __ j(zero, &number, not_taken); 1250 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); 1251 __ j(not_equal, &non_number, taken); 1252 __ bind(&number); 1253 StubCompiler::GenerateLoadGlobalFunctionPrototype( 1254 masm, Context::NUMBER_FUNCTION_INDEX, edx); 1255 __ jmp(&probe); 1256 1257 // Check for string. 1258 __ bind(&non_number); 1259 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE); 1260 __ j(above_equal, &non_string, taken); 1261 StubCompiler::GenerateLoadGlobalFunctionPrototype( 1262 masm, Context::STRING_FUNCTION_INDEX, edx); 1263 __ jmp(&probe); 1264 1265 // Check for boolean. 1266 __ bind(&non_string); 1267 __ cmp(edx, Factory::true_value()); 1268 __ j(equal, &boolean, not_taken); 1269 __ cmp(edx, Factory::false_value()); 1270 __ j(not_equal, &miss, taken); 1271 __ bind(&boolean); 1272 StubCompiler::GenerateLoadGlobalFunctionPrototype( 1273 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); 1274 1275 // Probe the stub cache for the value object. 1276 __ bind(&probe); 1277 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); 1278 __ bind(&miss); 1279} 1280 1281 1282static void GenerateFunctionTailCall(MacroAssembler* masm, 1283 int argc, 1284 Label* miss) { 1285 // ----------- S t a t e ------------- 1286 // -- ecx : name 1287 // -- edi : function 1288 // -- esp[0] : return address 1289 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1290 // -- ... 1291 // -- esp[(argc + 1) * 4] : receiver 1292 // ----------------------------------- 1293 1294 // Check that the result is not a smi. 1295 __ test(edi, Immediate(kSmiTagMask)); 1296 __ j(zero, miss, not_taken); 1297 1298 // Check that the value is a JavaScript function, fetching its map into eax. 1299 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); 1300 __ j(not_equal, miss, not_taken); 1301 1302 // Invoke the function. 1303 ParameterCount actual(argc); 1304 __ InvokeFunction(edi, actual, JUMP_FUNCTION); 1305} 1306 1307// The generated code falls through if the call should be handled by runtime. 1308static void GenerateCallNormal(MacroAssembler* masm, int argc) { 1309 // ----------- S t a t e ------------- 1310 // -- ecx : name 1311 // -- esp[0] : return address 1312 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1313 // -- ... 1314 // -- esp[(argc + 1) * 4] : receiver 1315 // ----------------------------------- 1316 Label miss; 1317 1318 // Get the receiver of the function from the stack; 1 ~ return address. 1319 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1320 1321 GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss); 1322 1323 // eax: elements 1324 // Search the dictionary placing the result in edi. 1325 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi); 1326 GenerateFunctionTailCall(masm, argc, &miss); 1327 1328 __ bind(&miss); 1329} 1330 1331 1332static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { 1333 // ----------- S t a t e ------------- 1334 // -- ecx : name 1335 // -- esp[0] : return address 1336 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1337 // -- ... 1338 // -- esp[(argc + 1) * 4] : receiver 1339 // ----------------------------------- 1340 1341 if (id == IC::kCallIC_Miss) { 1342 __ IncrementCounter(&Counters::call_miss, 1); 1343 } else { 1344 __ IncrementCounter(&Counters::keyed_call_miss, 1); 1345 } 1346 1347 // Get the receiver of the function from the stack; 1 ~ return address. 1348 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1349 1350 // Enter an internal frame. 1351 __ EnterInternalFrame(); 1352 1353 // Push the receiver and the name of the function. 1354 __ push(edx); 1355 __ push(ecx); 1356 1357 // Call the entry. 1358 CEntryStub stub(1); 1359 __ mov(eax, Immediate(2)); 1360 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id)))); 1361 __ CallStub(&stub); 1362 1363 // Move result to edi and exit the internal frame. 1364 __ mov(edi, eax); 1365 __ LeaveInternalFrame(); 1366 1367 // Check if the receiver is a global object of some sort. 1368 // This can happen only for regular CallIC but not KeyedCallIC. 1369 if (id == IC::kCallIC_Miss) { 1370 Label invoke, global; 1371 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver 1372 __ test(edx, Immediate(kSmiTagMask)); 1373 __ j(zero, &invoke, not_taken); 1374 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 1375 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 1376 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); 1377 __ j(equal, &global); 1378 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); 1379 __ j(not_equal, &invoke); 1380 1381 // Patch the receiver on the stack. 1382 __ bind(&global); 1383 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); 1384 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); 1385 __ bind(&invoke); 1386 } 1387 1388 // Invoke the function. 1389 ParameterCount actual(argc); 1390 __ InvokeFunction(edi, actual, JUMP_FUNCTION); 1391} 1392 1393 1394void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { 1395 // ----------- S t a t e ------------- 1396 // -- ecx : name 1397 // -- esp[0] : return address 1398 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1399 // -- ... 1400 // -- esp[(argc + 1) * 4] : receiver 1401 // ----------------------------------- 1402 1403 // Get the receiver of the function from the stack; 1 ~ return address. 1404 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1405 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC); 1406 GenerateMiss(masm, argc); 1407} 1408 1409 1410void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { 1411 // ----------- S t a t e ------------- 1412 // -- ecx : name 1413 // -- esp[0] : return address 1414 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1415 // -- ... 1416 // -- esp[(argc + 1) * 4] : receiver 1417 // ----------------------------------- 1418 1419 GenerateCallNormal(masm, argc); 1420 GenerateMiss(masm, argc); 1421} 1422 1423 1424void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { 1425 // ----------- S t a t e ------------- 1426 // -- ecx : name 1427 // -- esp[0] : return address 1428 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1429 // -- ... 1430 // -- esp[(argc + 1) * 4] : receiver 1431 // ----------------------------------- 1432 1433 GenerateCallMiss(masm, argc, IC::kCallIC_Miss); 1434} 1435 1436 1437void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { 1438 // ----------- S t a t e ------------- 1439 // -- ecx : name 1440 // -- esp[0] : return address 1441 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1442 // -- ... 1443 // -- esp[(argc + 1) * 4] : receiver 1444 // ----------------------------------- 1445 1446 // Get the receiver of the function from the stack; 1 ~ return address. 1447 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1448 1449 Label do_call, slow_call, slow_load, slow_reload_receiver; 1450 Label check_number_dictionary, check_string, lookup_monomorphic_cache; 1451 Label index_smi, index_string; 1452 1453 // Check that the key is a smi. 1454 __ test(ecx, Immediate(kSmiTagMask)); 1455 __ j(not_zero, &check_string, not_taken); 1456 1457 __ bind(&index_smi); 1458 // Now the key is known to be a smi. This place is also jumped to from 1459 // where a numeric string is converted to a smi. 1460 1461 GenerateKeyedLoadReceiverCheck( 1462 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); 1463 1464 GenerateFastArrayLoad( 1465 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); 1466 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); 1467 1468 __ bind(&do_call); 1469 // receiver in edx is not used after this point. 1470 // ecx: key 1471 // edi: function 1472 GenerateFunctionTailCall(masm, argc, &slow_call); 1473 1474 __ bind(&check_number_dictionary); 1475 // eax: elements 1476 // ecx: smi key 1477 // Check whether the elements is a number dictionary. 1478 __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true); 1479 __ mov(ebx, ecx); 1480 __ SmiUntag(ebx); 1481 // ebx: untagged index 1482 // Receiver in edx will be clobbered, need to reload it on miss. 1483 GenerateNumberDictionaryLoad( 1484 masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi); 1485 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1); 1486 __ jmp(&do_call); 1487 1488 __ bind(&slow_reload_receiver); 1489 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1490 1491 __ bind(&slow_load); 1492 // This branch is taken when calling KeyedCallIC_Miss is neither required 1493 // nor beneficial. 1494 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1); 1495 __ EnterInternalFrame(); 1496 __ push(ecx); // save the key 1497 __ push(edx); // pass the receiver 1498 __ push(ecx); // pass the key 1499 __ CallRuntime(Runtime::kKeyedGetProperty, 2); 1500 __ pop(ecx); // restore the key 1501 __ LeaveInternalFrame(); 1502 __ mov(edi, eax); 1503 __ jmp(&do_call); 1504 1505 __ bind(&check_string); 1506 GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call); 1507 1508 // The key is known to be a symbol. 1509 // If the receiver is a regular JS object with slow properties then do 1510 // a quick inline probe of the receiver's dictionary. 1511 // Otherwise do the monomorphic cache probe. 1512 GenerateKeyedLoadReceiverCheck( 1513 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); 1514 1515 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); 1516 __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true); 1517 1518 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi); 1519 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); 1520 __ jmp(&do_call); 1521 1522 __ bind(&lookup_monomorphic_cache); 1523 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); 1524 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); 1525 // Fall through on miss. 1526 1527 __ bind(&slow_call); 1528 // This branch is taken if: 1529 // - the receiver requires boxing or access check, 1530 // - the key is neither smi nor symbol, 1531 // - the value loaded is not a function, 1532 // - there is hope that the runtime will create a monomorphic call stub 1533 // that will get fetched next time. 1534 __ IncrementCounter(&Counters::keyed_call_generic_slow, 1); 1535 GenerateMiss(masm, argc); 1536 1537 __ bind(&index_string); 1538 __ IndexFromHash(ebx, ecx); 1539 // Now jump to the place where smi keys are handled. 1540 __ jmp(&index_smi); 1541} 1542 1543 1544void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { 1545 // ----------- S t a t e ------------- 1546 // -- ecx : name 1547 // -- esp[0] : return address 1548 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1549 // -- ... 1550 // -- esp[(argc + 1) * 4] : receiver 1551 // ----------------------------------- 1552 1553 GenerateCallNormal(masm, argc); 1554 GenerateMiss(masm, argc); 1555} 1556 1557 1558void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { 1559 // ----------- S t a t e ------------- 1560 // -- ecx : name 1561 // -- esp[0] : return address 1562 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1563 // -- ... 1564 // -- esp[(argc + 1) * 4] : receiver 1565 // ----------------------------------- 1566 1567 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss); 1568} 1569 1570 1571// Defined in ic.cc. 1572Object* LoadIC_Miss(Arguments args); 1573 1574void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { 1575 // ----------- S t a t e ------------- 1576 // -- eax : receiver 1577 // -- ecx : name 1578 // -- esp[0] : return address 1579 // ----------------------------------- 1580 1581 // Probe the stub cache. 1582 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, 1583 NOT_IN_LOOP, 1584 MONOMORPHIC); 1585 StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx); 1586 1587 // Cache miss: Jump to runtime. 1588 GenerateMiss(masm); 1589} 1590 1591 1592void LoadIC::GenerateNormal(MacroAssembler* masm) { 1593 // ----------- S t a t e ------------- 1594 // -- eax : receiver 1595 // -- ecx : name 1596 // -- esp[0] : return address 1597 // ----------------------------------- 1598 Label miss; 1599 1600 GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss); 1601 1602 // edx: elements 1603 // Search the dictionary placing the result in eax. 1604 GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax); 1605 __ ret(0); 1606 1607 // Cache miss: Jump to runtime. 1608 __ bind(&miss); 1609 GenerateMiss(masm); 1610} 1611 1612 1613void LoadIC::GenerateMiss(MacroAssembler* masm) { 1614 // ----------- S t a t e ------------- 1615 // -- eax : receiver 1616 // -- ecx : name 1617 // -- esp[0] : return address 1618 // ----------------------------------- 1619 1620 __ IncrementCounter(&Counters::load_miss, 1); 1621 1622 __ pop(ebx); 1623 __ push(eax); // receiver 1624 __ push(ecx); // name 1625 __ push(ebx); // return address 1626 1627 // Perform tail call to the entry. 1628 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); 1629 __ TailCallExternalReference(ref, 2, 1); 1630} 1631 1632 1633// One byte opcode for test eax,0xXXXXXXXX. 1634static const byte kTestEaxByte = 0xA9; 1635 1636bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { 1637 // The address of the instruction following the call. 1638 Address test_instruction_address = 1639 address + Assembler::kCallTargetAddressOffset; 1640 // If the instruction following the call is not a test eax, nothing 1641 // was inlined. 1642 if (*test_instruction_address != kTestEaxByte) return false; 1643 1644 Address delta_address = test_instruction_address + 1; 1645 // The delta to the start of the map check instruction. 1646 int delta = *reinterpret_cast<int*>(delta_address); 1647 1648 // The map address is the last 4 bytes of the 7-byte 1649 // operand-immediate compare instruction, so we add 3 to get the 1650 // offset to the last 4 bytes. 1651 Address map_address = test_instruction_address + delta + 3; 1652 *(reinterpret_cast<Object**>(map_address)) = map; 1653 1654 // The offset is in the last 4 bytes of a six byte 1655 // memory-to-register move instruction, so we add 2 to get the 1656 // offset to the last 4 bytes. 1657 Address offset_address = 1658 test_instruction_address + delta + kOffsetToLoadInstruction + 2; 1659 *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag; 1660 return true; 1661} 1662 1663 1664// One byte opcode for mov ecx,0xXXXXXXXX. 1665static const byte kMovEcxByte = 0xB9; 1666 1667bool LoadIC::PatchInlinedContextualLoad(Address address, 1668 Object* map, 1669 Object* cell) { 1670 // The address of the instruction following the call. 1671 Address mov_instruction_address = 1672 address + Assembler::kCallTargetAddressOffset; 1673 // If the instruction following the call is not a cmp eax, nothing 1674 // was inlined. 1675 if (*mov_instruction_address != kMovEcxByte) return false; 1676 1677 Address delta_address = mov_instruction_address + 1; 1678 // The delta to the start of the map check instruction. 1679 int delta = *reinterpret_cast<int*>(delta_address); 1680 1681 // The map address is the last 4 bytes of the 7-byte 1682 // operand-immediate compare instruction, so we add 3 to get the 1683 // offset to the last 4 bytes. 1684 Address map_address = mov_instruction_address + delta + 3; 1685 *(reinterpret_cast<Object**>(map_address)) = map; 1686 1687 // The cell is in the last 4 bytes of a five byte mov reg, imm32 1688 // instruction, so we add 1 to get the offset to the last 4 bytes. 1689 Address offset_address = 1690 mov_instruction_address + delta + kOffsetToLoadInstruction + 1; 1691 *reinterpret_cast<Object**>(offset_address) = cell; 1692 return true; 1693} 1694 1695 1696bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) { 1697 // The address of the instruction following the call. 1698 Address test_instruction_address = 1699 address + Assembler::kCallTargetAddressOffset; 1700 1701 // If the instruction following the call is not a test eax, nothing 1702 // was inlined. 1703 if (*test_instruction_address != kTestEaxByte) return false; 1704 1705 // Extract the encoded deltas from the test eax instruction. 1706 Address encoded_offsets_address = test_instruction_address + 1; 1707 int encoded_offsets = *reinterpret_cast<int*>(encoded_offsets_address); 1708 int delta_to_map_check = -(encoded_offsets & 0xFFFF); 1709 int delta_to_record_write = encoded_offsets >> 16; 1710 1711 // Patch the map to check. The map address is the last 4 bytes of 1712 // the 7-byte operand-immediate compare instruction. 1713 Address map_check_address = test_instruction_address + delta_to_map_check; 1714 Address map_address = map_check_address + 3; 1715 *(reinterpret_cast<Object**>(map_address)) = map; 1716 1717 // Patch the offset in the store instruction. The offset is in the 1718 // last 4 bytes of a six byte register-to-memory move instruction. 1719 Address offset_address = 1720 map_check_address + StoreIC::kOffsetToStoreInstruction + 2; 1721 // The offset should have initial value (kMaxInt - 1), cleared value 1722 // (-1) or we should be clearing the inlined version. 1723 ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 || 1724 *reinterpret_cast<int*>(offset_address) == -1 || 1725 (offset == 0 && map == Heap::null_value())); 1726 *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag; 1727 1728 // Patch the offset in the write-barrier code. The offset is the 1729 // last 4 bytes of a six byte lea instruction. 1730 offset_address = map_check_address + delta_to_record_write + 2; 1731 // The offset should have initial value (kMaxInt), cleared value 1732 // (-1) or we should be clearing the inlined version. 1733 ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt || 1734 *reinterpret_cast<int*>(offset_address) == -1 || 1735 (offset == 0 && map == Heap::null_value())); 1736 *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag; 1737 1738 return true; 1739} 1740 1741 1742static bool PatchInlinedMapCheck(Address address, Object* map) { 1743 Address test_instruction_address = 1744 address + Assembler::kCallTargetAddressOffset; 1745 // The keyed load has a fast inlined case if the IC call instruction 1746 // is immediately followed by a test instruction. 1747 if (*test_instruction_address != kTestEaxByte) return false; 1748 1749 // Fetch the offset from the test instruction to the map cmp 1750 // instruction. This offset is stored in the last 4 bytes of the 5 1751 // byte test instruction. 1752 Address delta_address = test_instruction_address + 1; 1753 int delta = *reinterpret_cast<int*>(delta_address); 1754 // Compute the map address. The map address is in the last 4 bytes 1755 // of the 7-byte operand-immediate compare instruction, so we add 3 1756 // to the offset to get the map address. 1757 Address map_address = test_instruction_address + delta + 3; 1758 // Patch the map check. 1759 *(reinterpret_cast<Object**>(map_address)) = map; 1760 return true; 1761} 1762 1763 1764bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) { 1765 return PatchInlinedMapCheck(address, map); 1766} 1767 1768 1769bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) { 1770 return PatchInlinedMapCheck(address, map); 1771} 1772 1773 1774// Defined in ic.cc. 1775Object* KeyedLoadIC_Miss(Arguments args); 1776 1777 1778void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { 1779 // ----------- S t a t e ------------- 1780 // -- eax : key 1781 // -- edx : receiver 1782 // -- esp[0] : return address 1783 // ----------------------------------- 1784 1785 __ IncrementCounter(&Counters::keyed_load_miss, 1); 1786 1787 __ pop(ebx); 1788 __ push(edx); // receiver 1789 __ push(eax); // name 1790 __ push(ebx); // return address 1791 1792 // Perform tail call to the entry. 1793 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss)); 1794 __ TailCallExternalReference(ref, 2, 1); 1795} 1796 1797 1798void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { 1799 // ----------- S t a t e ------------- 1800 // -- eax : key 1801 // -- edx : receiver 1802 // -- esp[0] : return address 1803 // ----------------------------------- 1804 1805 __ pop(ebx); 1806 __ push(edx); // receiver 1807 __ push(eax); // name 1808 __ push(ebx); // return address 1809 1810 // Perform tail call to the entry. 1811 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); 1812} 1813 1814 1815void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { 1816 // ----------- S t a t e ------------- 1817 // -- eax : value 1818 // -- ecx : name 1819 // -- edx : receiver 1820 // -- esp[0] : return address 1821 // ----------------------------------- 1822 1823 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, 1824 NOT_IN_LOOP, 1825 MONOMORPHIC); 1826 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); 1827 1828 // Cache miss: Jump to runtime. 1829 GenerateMiss(masm); 1830} 1831 1832 1833void StoreIC::GenerateMiss(MacroAssembler* masm) { 1834 // ----------- S t a t e ------------- 1835 // -- eax : value 1836 // -- ecx : name 1837 // -- edx : receiver 1838 // -- esp[0] : return address 1839 // ----------------------------------- 1840 1841 __ pop(ebx); 1842 __ push(edx); 1843 __ push(ecx); 1844 __ push(eax); 1845 __ push(ebx); 1846 1847 // Perform tail call to the entry. 1848 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss)); 1849 __ TailCallExternalReference(ref, 3, 1); 1850} 1851 1852 1853// The offset from the inlined patch site to the start of the inlined 1854// store instruction. It is 7 bytes (test reg, imm) plus 6 bytes (jne 1855// slow_label). 1856const int StoreIC::kOffsetToStoreInstruction = 13; 1857 1858 1859void StoreIC::GenerateArrayLength(MacroAssembler* masm) { 1860 // ----------- S t a t e ------------- 1861 // -- eax : value 1862 // -- ecx : name 1863 // -- edx : receiver 1864 // -- esp[0] : return address 1865 // ----------------------------------- 1866 // 1867 // This accepts as a receiver anything JSObject::SetElementsLength accepts 1868 // (currently anything except for external and pixel arrays which means 1869 // anything with elements of FixedArray type.), but currently is restricted 1870 // to JSArray. 1871 // Value must be a number, but only smis are accepted as the most common case. 1872 1873 Label miss; 1874 1875 Register receiver = edx; 1876 Register value = eax; 1877 Register scratch = ebx; 1878 1879 // Check that the receiver isn't a smi. 1880 __ test(receiver, Immediate(kSmiTagMask)); 1881 __ j(zero, &miss, not_taken); 1882 1883 // Check that the object is a JS array. 1884 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); 1885 __ j(not_equal, &miss, not_taken); 1886 1887 // Check that elements are FixedArray. 1888 // We rely on StoreIC_ArrayLength below to deal with all types of 1889 // fast elements (including COW). 1890 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset)); 1891 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch); 1892 __ j(not_equal, &miss, not_taken); 1893 1894 // Check that value is a smi. 1895 __ test(value, Immediate(kSmiTagMask)); 1896 __ j(not_zero, &miss, not_taken); 1897 1898 // Prepare tail call to StoreIC_ArrayLength. 1899 __ pop(scratch); 1900 __ push(receiver); 1901 __ push(value); 1902 __ push(scratch); // return address 1903 1904 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength)); 1905 __ TailCallExternalReference(ref, 2, 1); 1906 1907 __ bind(&miss); 1908 1909 GenerateMiss(masm); 1910} 1911 1912 1913void StoreIC::GenerateNormal(MacroAssembler* masm) { 1914 // ----------- S t a t e ------------- 1915 // -- eax : value 1916 // -- ecx : name 1917 // -- edx : receiver 1918 // -- esp[0] : return address 1919 // ----------------------------------- 1920 1921 Label miss, restore_miss; 1922 1923 GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss); 1924 1925 // A lot of registers are needed for storing to slow case 1926 // objects. Push and restore receiver but rely on 1927 // GenerateDictionaryStore preserving the value and name. 1928 __ push(edx); 1929 GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi); 1930 __ Drop(1); 1931 __ IncrementCounter(&Counters::store_normal_hit, 1); 1932 __ ret(0); 1933 1934 __ bind(&restore_miss); 1935 __ pop(edx); 1936 1937 __ bind(&miss); 1938 __ IncrementCounter(&Counters::store_normal_miss, 1); 1939 GenerateMiss(masm); 1940} 1941 1942 1943// Defined in ic.cc. 1944Object* KeyedStoreIC_Miss(Arguments args); 1945 1946void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { 1947 // ----------- S t a t e ------------- 1948 // -- eax : value 1949 // -- ecx : key 1950 // -- edx : receiver 1951 // -- esp[0] : return address 1952 // ----------------------------------- 1953 1954 __ pop(ebx); 1955 __ push(edx); 1956 __ push(ecx); 1957 __ push(eax); 1958 __ push(ebx); 1959 1960 // Do tail-call to runtime routine. 1961 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); 1962} 1963 1964 1965void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { 1966 // ----------- S t a t e ------------- 1967 // -- eax : value 1968 // -- ecx : key 1969 // -- edx : receiver 1970 // -- esp[0] : return address 1971 // ----------------------------------- 1972 1973 __ pop(ebx); 1974 __ push(edx); 1975 __ push(ecx); 1976 __ push(eax); 1977 __ push(ebx); 1978 1979 // Do tail-call to runtime routine. 1980 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss)); 1981 __ TailCallExternalReference(ref, 3, 1); 1982} 1983 1984#undef __ 1985 1986 1987} } // namespace v8::internal 1988 1989#endif // V8_TARGET_ARCH_IA32 1990