1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "codegen-inl.h" 31 #include "ic-inl.h" 32 #include "runtime.h" 33 #include "stub-cache.h" 34 #include "utils.h" 35 36 namespace v8 { 37 namespace internal { 38 39 // ---------------------------------------------------------------------------- 40 // Static IC stub generators. 41 // 42 43 #define __ ACCESS_MASM(masm) 44 45 46 // Helper function used to load a property from a dictionary backing storage. 47 // This function may return false negatives, so miss_label 48 // must always call a backup property load that is complete. 49 // This function is safe to call if the receiver has fast properties, 50 // or if name is not a symbol, and will jump to the miss_label in that case. 51 static void GenerateDictionaryLoad(MacroAssembler* masm, 52 Label* miss_label, 53 Register receiver, 54 Register name, 55 Register r0, 56 Register r1, 57 Register r2, 58 DictionaryCheck check_dictionary) { 59 // Register use: 60 // 61 // name - holds the name of the property and is unchanged. 62 // receiver - holds the receiver and is unchanged. 63 // Scratch registers: 64 // r0 - used to hold the property dictionary. 65 // 66 // r1 - used for the index into the property dictionary 67 // - holds the result on exit. 68 // 69 // r2 - used to hold the capacity of the property dictionary. 70 71 Label done; 72 73 // Check for the absence of an interceptor. 74 // Load the map into r0. 75 __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset)); 76 // Test the has_named_interceptor bit in the map. 77 __ test(FieldOperand(r0, Map::kInstanceAttributesOffset), 78 Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8)))); 79 80 // Jump to miss if the interceptor bit is set. 81 __ j(not_zero, miss_label, not_taken); 82 83 // Bail out if we have a JS global proxy object. 84 __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset)); 85 __ cmp(r0, JS_GLOBAL_PROXY_TYPE); 86 __ j(equal, miss_label, not_taken); 87 88 // Possible work-around for http://crbug.com/16276. 89 __ cmp(r0, JS_GLOBAL_OBJECT_TYPE); 90 __ j(equal, miss_label, not_taken); 91 __ cmp(r0, JS_BUILTINS_OBJECT_TYPE); 92 __ j(equal, miss_label, not_taken); 93 94 // Load properties array. 95 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); 96 97 // Check that the properties array is a dictionary. 98 if (check_dictionary == CHECK_DICTIONARY) { 99 __ cmp(FieldOperand(r0, HeapObject::kMapOffset), 100 Immediate(Factory::hash_table_map())); 101 __ j(not_equal, miss_label); 102 } 103 104 // Compute the capacity mask. 105 const int kCapacityOffset = 106 StringDictionary::kHeaderSize + 107 StringDictionary::kCapacityIndex * kPointerSize; 108 __ mov(r2, FieldOperand(r0, kCapacityOffset)); 109 __ shr(r2, kSmiTagSize); // convert smi to int 110 __ dec(r2); 111 112 // Generate an unrolled loop that performs a few probes before 113 // giving up. Measurements done on Gmail indicate that 2 probes 114 // cover ~93% of loads from dictionaries. 115 static const int kProbes = 4; 116 const int kElementsStartOffset = 117 StringDictionary::kHeaderSize + 118 StringDictionary::kElementsStartIndex * kPointerSize; 119 for (int i = 0; i < kProbes; i++) { 120 // Compute the masked index: (hash + i + i * i) & mask. 121 __ mov(r1, FieldOperand(name, String::kHashFieldOffset)); 122 __ shr(r1, String::kHashShift); 123 if (i > 0) { 124 __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i))); 125 } 126 __ and_(r1, Operand(r2)); 127 128 // Scale the index by multiplying by the entry size. 129 ASSERT(StringDictionary::kEntrySize == 3); 130 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 131 132 // Check if the key is identical to the name. 133 __ cmp(name, 134 Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag)); 135 if (i != kProbes - 1) { 136 __ j(equal, &done, taken); 137 } else { 138 __ j(not_equal, miss_label, not_taken); 139 } 140 } 141 142 // Check that the value is a normal property. 143 __ bind(&done); 144 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; 145 __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag), 146 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); 147 __ j(not_zero, miss_label, not_taken); 148 149 // Get the value at the masked, scaled index. 150 const int kValueOffset = kElementsStartOffset + kPointerSize; 151 __ mov(r1, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag)); 152 } 153 154 155 // The offset from the inlined patch site to the start of the 156 // inlined load instruction. It is 7 bytes (test eax, imm) plus 157 // 6 bytes (jne slow_label). 158 const int LoadIC::kOffsetToLoadInstruction = 13; 159 160 161 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { 162 // ----------- S t a t e ------------- 163 // -- eax : receiver 164 // -- ecx : name 165 // -- esp[0] : return address 166 // ----------------------------------- 167 Label miss; 168 169 StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss); 170 __ bind(&miss); 171 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 172 } 173 174 175 void LoadIC::GenerateStringLength(MacroAssembler* masm) { 176 // ----------- S t a t e ------------- 177 // -- eax : receiver 178 // -- ecx : name 179 // -- esp[0] : return address 180 // ----------------------------------- 181 Label miss; 182 183 StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss); 184 __ bind(&miss); 185 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 186 } 187 188 189 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { 190 // ----------- S t a t e ------------- 191 // -- eax : receiver 192 // -- ecx : name 193 // -- esp[0] : return address 194 // ----------------------------------- 195 Label miss; 196 197 StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss); 198 __ bind(&miss); 199 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 200 } 201 202 203 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { 204 // ----------- S t a t e ------------- 205 // -- eax : key 206 // -- edx : receiver 207 // -- esp[0] : return address 208 // ----------------------------------- 209 Label slow, check_string, index_int, index_string; 210 Label check_pixel_array, probe_dictionary; 211 212 // Check that the object isn't a smi. 213 __ test(edx, Immediate(kSmiTagMask)); 214 __ j(zero, &slow, not_taken); 215 216 // Get the map of the receiver. 217 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 218 219 // Check bit field. 220 __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset)); 221 __ test(ebx, Immediate(kSlowCaseBitFieldMask)); 222 __ j(not_zero, &slow, not_taken); 223 // Check that the object is some kind of JS object EXCEPT JS Value type. 224 // In the case that the object is a value-wrapper object, 225 // we enter the runtime system to make sure that indexing 226 // into string objects work as intended. 227 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); 228 __ CmpInstanceType(ecx, JS_OBJECT_TYPE); 229 __ j(below, &slow, not_taken); 230 // Check that the key is a smi. 231 __ test(eax, Immediate(kSmiTagMask)); 232 __ j(not_zero, &check_string, not_taken); 233 __ mov(ebx, eax); 234 __ SmiUntag(ebx); 235 // Get the elements array of the object. 236 __ bind(&index_int); 237 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); 238 // Check that the object is in fast mode (not dictionary). 239 __ CheckMap(ecx, Factory::fixed_array_map(), &check_pixel_array, true); 240 // Check that the key (index) is within bounds. 241 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); 242 __ j(above_equal, &slow); 243 // Fast case: Do the load. 244 __ mov(ecx, FieldOperand(ecx, ebx, times_4, FixedArray::kHeaderSize)); 245 __ cmp(Operand(ecx), Immediate(Factory::the_hole_value())); 246 // In case the loaded value is the_hole we have to consult GetProperty 247 // to ensure the prototype chain is searched. 248 __ j(equal, &slow); 249 __ mov(eax, ecx); 250 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); 251 __ ret(0); 252 253 __ bind(&check_pixel_array); 254 // Check whether the elements is a pixel array. 255 // edx: receiver 256 // ebx: untagged index 257 // eax: key 258 // ecx: elements 259 __ CheckMap(ecx, Factory::pixel_array_map(), &slow, true); 260 __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset)); 261 __ j(above_equal, &slow); 262 __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset)); 263 __ movzx_b(eax, Operand(eax, ebx, times_1, 0)); 264 __ SmiTag(eax); 265 __ ret(0); 266 267 __ bind(&slow); 268 // Slow case: jump to runtime. 269 // edx: receiver 270 // eax: key 271 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); 272 GenerateRuntimeGetProperty(masm); 273 274 __ bind(&check_string); 275 // The key is not a smi. 276 // Is it a string? 277 // edx: receiver 278 // eax: key 279 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); 280 __ j(above_equal, &slow); 281 // Is the string an array index, with cached numeric value? 282 __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset)); 283 __ test(ebx, Immediate(String::kIsArrayIndexMask)); 284 __ j(not_zero, &index_string, not_taken); 285 286 // Is the string a symbol? 287 __ movzx_b(ebx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 288 ASSERT(kSymbolTag != 0); 289 __ test(ebx, Immediate(kIsSymbolMask)); 290 __ j(zero, &slow, not_taken); 291 292 // If the receiver is a fast-case object, check the keyed lookup 293 // cache. Otherwise probe the dictionary. 294 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); 295 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 296 Immediate(Factory::hash_table_map())); 297 __ j(equal, &probe_dictionary); 298 299 // Load the map of the receiver, compute the keyed lookup cache hash 300 // based on 32 bits of the map pointer and the string hash. 301 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 302 __ mov(ecx, ebx); 303 __ shr(ecx, KeyedLookupCache::kMapHashShift); 304 __ mov(edi, FieldOperand(eax, String::kHashFieldOffset)); 305 __ shr(edi, String::kHashShift); 306 __ xor_(ecx, Operand(edi)); 307 __ and_(ecx, KeyedLookupCache::kCapacityMask); 308 309 // Load the key (consisting of map and symbol) from the cache and 310 // check for match. 311 ExternalReference cache_keys 312 = ExternalReference::keyed_lookup_cache_keys(); 313 __ mov(edi, ecx); 314 __ shl(edi, kPointerSizeLog2 + 1); 315 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); 316 __ j(not_equal, &slow); 317 __ add(Operand(edi), Immediate(kPointerSize)); 318 __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys)); 319 __ j(not_equal, &slow); 320 321 // Get field offset and check that it is an in-object property. 322 // edx : receiver 323 // ebx : receiver's map 324 // eax : key 325 // ecx : lookup cache index 326 ExternalReference cache_field_offsets 327 = ExternalReference::keyed_lookup_cache_field_offsets(); 328 __ mov(edi, 329 Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets)); 330 __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); 331 __ cmp(edi, Operand(ecx)); 332 __ j(above_equal, &slow); 333 334 // Load in-object property. 335 __ sub(edi, Operand(ecx)); 336 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); 337 __ add(ecx, Operand(edi)); 338 __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0)); 339 __ ret(0); 340 341 // Do a quick inline probe of the receiver's dictionary, if it 342 // exists. 343 __ bind(&probe_dictionary); 344 GenerateDictionaryLoad(masm, 345 &slow, 346 edx, 347 eax, 348 ebx, 349 ecx, 350 edi, 351 DICTIONARY_CHECK_DONE); 352 __ mov(eax, Operand(ecx)); 353 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); 354 __ ret(0); 355 356 // If the hash field contains an array index pick it out. The assert checks 357 // that the constants for the maximum number of digits for an array index 358 // cached in the hash field and the number of bits reserved for it does not 359 // conflict. 360 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < 361 (1 << String::kArrayIndexValueBits)); 362 __ bind(&index_string); 363 __ and_(ebx, String::kArrayIndexHashMask); 364 __ shr(ebx, String::kHashShift); 365 __ jmp(&index_int); 366 } 367 368 369 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { 370 // ----------- S t a t e ------------- 371 // -- eax : key 372 // -- edx : receiver 373 // -- esp[0] : return address 374 // ----------------------------------- 375 Label miss, index_ok; 376 377 // Pop return address. 378 // Performing the load early is better in the common case. 379 __ pop(ebx); 380 381 __ test(edx, Immediate(kSmiTagMask)); 382 __ j(zero, &miss); 383 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 384 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 385 __ test(ecx, Immediate(kIsNotStringMask)); 386 __ j(not_zero, &miss); 387 388 // Check if key is a smi or a heap number. 389 __ test(eax, Immediate(kSmiTagMask)); 390 __ j(zero, &index_ok); 391 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 392 __ cmp(ecx, Factory::heap_number_map()); 393 __ j(not_equal, &miss); 394 395 __ bind(&index_ok); 396 // Push receiver and key on the stack, and make a tail call. 397 __ push(edx); // receiver 398 __ push(eax); // key 399 __ push(ebx); // return address 400 __ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_FUNCTION); 401 402 __ bind(&miss); 403 __ push(ebx); 404 GenerateMiss(masm); 405 } 406 407 408 void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, 409 ExternalArrayType array_type) { 410 // ----------- S t a t e ------------- 411 // -- eax : key 412 // -- edx : receiver 413 // -- esp[0] : return address 414 // ----------------------------------- 415 Label slow, failed_allocation; 416 417 // Check that the object isn't a smi. 418 __ test(edx, Immediate(kSmiTagMask)); 419 __ j(zero, &slow, not_taken); 420 421 // Check that the key is a smi. 422 __ test(eax, Immediate(kSmiTagMask)); 423 __ j(not_zero, &slow, not_taken); 424 425 // Get the map of the receiver. 426 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 427 // Check that the receiver does not require access checks. We need 428 // to check this explicitly since this generic stub does not perform 429 // map checks. 430 __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset)); 431 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded)); 432 __ j(not_zero, &slow, not_taken); 433 434 __ CmpInstanceType(ecx, JS_OBJECT_TYPE); 435 __ j(not_equal, &slow, not_taken); 436 437 // Check that the elements array is the appropriate type of 438 // ExternalArray. 439 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); 440 Handle<Map> map(Heap::MapForExternalArrayType(array_type)); 441 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 442 Immediate(map)); 443 __ j(not_equal, &slow, not_taken); 444 445 // eax: key, known to be a smi. 446 // edx: receiver, known to be a JSObject. 447 // ebx: elements object, known to be an external array. 448 // Check that the index is in range. 449 __ mov(ecx, eax); 450 __ SmiUntag(ecx); // Untag the index. 451 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); 452 // Unsigned comparison catches both negative and too-large values. 453 __ j(above_equal, &slow); 454 455 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); 456 // ebx: base pointer of external storage 457 switch (array_type) { 458 case kExternalByteArray: 459 __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0)); 460 break; 461 case kExternalUnsignedByteArray: 462 __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0)); 463 break; 464 case kExternalShortArray: 465 __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0)); 466 break; 467 case kExternalUnsignedShortArray: 468 __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0)); 469 break; 470 case kExternalIntArray: 471 case kExternalUnsignedIntArray: 472 __ mov(ecx, Operand(ebx, ecx, times_4, 0)); 473 break; 474 case kExternalFloatArray: 475 __ fld_s(Operand(ebx, ecx, times_4, 0)); 476 break; 477 default: 478 UNREACHABLE(); 479 break; 480 } 481 482 // For integer array types: 483 // ecx: value 484 // For floating-point array type: 485 // FP(0): value 486 487 if (array_type == kExternalIntArray || 488 array_type == kExternalUnsignedIntArray) { 489 // For the Int and UnsignedInt array types, we need to see whether 490 // the value can be represented in a Smi. If not, we need to convert 491 // it to a HeapNumber. 492 Label box_int; 493 if (array_type == kExternalIntArray) { 494 __ cmp(ecx, 0xC0000000); 495 __ j(sign, &box_int); 496 } else { 497 ASSERT_EQ(array_type, kExternalUnsignedIntArray); 498 // The test is different for unsigned int values. Since we need 499 // the value to be in the range of a positive smi, we can't 500 // handle either of the top two bits being set in the value. 501 __ test(ecx, Immediate(0xC0000000)); 502 __ j(not_zero, &box_int); 503 } 504 505 __ mov(eax, ecx); 506 __ SmiTag(eax); 507 __ ret(0); 508 509 __ bind(&box_int); 510 511 // Allocate a HeapNumber for the int and perform int-to-double 512 // conversion. 513 if (array_type == kExternalIntArray) { 514 __ push(ecx); 515 __ fild_s(Operand(esp, 0)); 516 __ pop(ecx); 517 } else { 518 ASSERT(array_type == kExternalUnsignedIntArray); 519 // Need to zero-extend the value. 520 // There's no fild variant for unsigned values, so zero-extend 521 // to a 64-bit int manually. 522 __ push(Immediate(0)); 523 __ push(ecx); 524 __ fild_d(Operand(esp, 0)); 525 __ pop(ecx); 526 __ pop(ecx); 527 } 528 // FP(0): value 529 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); 530 // Set the value. 531 __ mov(eax, ecx); 532 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 533 __ ret(0); 534 } else if (array_type == kExternalFloatArray) { 535 // For the floating-point array type, we need to always allocate a 536 // HeapNumber. 537 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); 538 // Set the value. 539 __ mov(eax, ecx); 540 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 541 __ ret(0); 542 } else { 543 __ mov(eax, ecx); 544 __ SmiTag(eax); 545 __ ret(0); 546 } 547 548 // If we fail allocation of the HeapNumber, we still have a value on 549 // top of the FPU stack. Remove it. 550 __ bind(&failed_allocation); 551 __ ffree(); 552 __ fincstp(); 553 // Fall through to slow case. 554 555 // Slow case: Load key and receiver from stack and jump to runtime. 556 __ bind(&slow); 557 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); 558 GenerateRuntimeGetProperty(masm); 559 } 560 561 562 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { 563 // ----------- S t a t e ------------- 564 // -- eax : key 565 // -- edx : receiver 566 // -- esp[0] : return address 567 // ----------------------------------- 568 Label slow; 569 570 // Check that the receiver isn't a smi. 571 __ test(edx, Immediate(kSmiTagMask)); 572 __ j(zero, &slow, not_taken); 573 574 // Check that the key is a smi. 575 __ test(eax, Immediate(kSmiTagMask)); 576 __ j(not_zero, &slow, not_taken); 577 578 // Get the map of the receiver. 579 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 580 581 // Check that it has indexed interceptor and access checks 582 // are not enabled for this object. 583 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); 584 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); 585 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); 586 __ j(not_zero, &slow, not_taken); 587 588 // Everything is fine, call runtime. 589 __ pop(ecx); 590 __ push(edx); // receiver 591 __ push(eax); // key 592 __ push(ecx); // return address 593 594 // Perform tail call to the entry. 595 __ TailCallRuntime(ExternalReference( 596 IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1); 597 598 __ bind(&slow); 599 GenerateMiss(masm); 600 } 601 602 603 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { 604 // ----------- S t a t e ------------- 605 // -- eax : value 606 // -- esp[0] : return address 607 // -- esp[4] : key 608 // -- esp[8] : receiver 609 // ----------------------------------- 610 Label slow, fast, array, extra, check_pixel_array; 611 612 // Get the receiver from the stack. 613 __ mov(edx, Operand(esp, 2 * kPointerSize)); // 2 ~ return address, key 614 // Check that the object isn't a smi. 615 __ test(edx, Immediate(kSmiTagMask)); 616 __ j(zero, &slow, not_taken); 617 // Get the map from the receiver. 618 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 619 // Check that the receiver does not require access checks. We need 620 // to do this because this generic stub does not perform map checks. 621 __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset)); 622 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded)); 623 __ j(not_zero, &slow, not_taken); 624 // Get the key from the stack. 625 __ mov(ebx, Operand(esp, 1 * kPointerSize)); // 1 ~ return address 626 // Check that the key is a smi. 627 __ test(ebx, Immediate(kSmiTagMask)); 628 __ j(not_zero, &slow, not_taken); 629 // Get the instance type from the map of the receiver. 630 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 631 // Check if the object is a JS array or not. 632 __ cmp(ecx, JS_ARRAY_TYPE); 633 __ j(equal, &array); 634 // Check that the object is some kind of JS object. 635 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); 636 __ j(less, &slow, not_taken); 637 638 // Object case: Check key against length in the elements array. 639 // eax: value 640 // edx: JSObject 641 // ebx: index (as a smi) 642 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); 643 // Check that the object is in fast mode (not dictionary). 644 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), 645 Immediate(Factory::fixed_array_map())); 646 __ j(not_equal, &check_pixel_array, not_taken); 647 // Untag the key (for checking against untagged length in the fixed array). 648 __ mov(edx, Operand(ebx)); 649 __ sar(edx, kSmiTagSize); // untag the index and use it for the comparison 650 __ cmp(edx, FieldOperand(ecx, Array::kLengthOffset)); 651 // eax: value 652 // ecx: FixedArray 653 // ebx: index (as a smi) 654 __ j(below, &fast, taken); 655 656 // Slow case: call runtime. 657 __ bind(&slow); 658 GenerateRuntimeSetProperty(masm); 659 660 // Check whether the elements is a pixel array. 661 // eax: value 662 // ecx: elements array 663 // ebx: index (as a smi) 664 __ bind(&check_pixel_array); 665 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), 666 Immediate(Factory::pixel_array_map())); 667 __ j(not_equal, &slow); 668 // Check that the value is a smi. If a conversion is needed call into the 669 // runtime to convert and clamp. 670 __ test(eax, Immediate(kSmiTagMask)); 671 __ j(not_zero, &slow); 672 __ sar(ebx, kSmiTagSize); // Untag the index. 673 __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset)); 674 __ j(above_equal, &slow); 675 __ mov(edx, eax); // Save the value. 676 __ sar(eax, kSmiTagSize); // Untag the value. 677 { // Clamp the value to [0..255]. 678 Label done; 679 __ test(eax, Immediate(0xFFFFFF00)); 680 __ j(zero, &done); 681 __ setcc(negative, eax); // 1 if negative, 0 if positive. 682 __ dec_b(eax); // 0 if negative, 255 if positive. 683 __ bind(&done); 684 } 685 __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset)); 686 __ mov_b(Operand(ecx, ebx, times_1, 0), eax); 687 __ mov(eax, edx); // Return the original value. 688 __ ret(0); 689 690 // Extra capacity case: Check if there is extra capacity to 691 // perform the store and update the length. Used for adding one 692 // element to the array by writing to array[array.length]. 693 __ bind(&extra); 694 // eax: value 695 // edx: JSArray 696 // ecx: FixedArray 697 // ebx: index (as a smi) 698 // flags: compare (ebx, edx.length()) 699 __ j(not_equal, &slow, not_taken); // do not leave holes in the array 700 __ sar(ebx, kSmiTagSize); // untag 701 __ cmp(ebx, FieldOperand(ecx, Array::kLengthOffset)); 702 __ j(above_equal, &slow, not_taken); 703 // Restore tag and increment. 704 __ lea(ebx, Operand(ebx, times_2, 1 << kSmiTagSize)); 705 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ebx); 706 __ sub(Operand(ebx), Immediate(1 << kSmiTagSize)); // decrement ebx again 707 __ jmp(&fast); 708 709 // Array case: Get the length and the elements array from the JS 710 // array. Check that the array is in fast mode; if it is the 711 // length is always a smi. 712 __ bind(&array); 713 // eax: value 714 // edx: JSArray 715 // ebx: index (as a smi) 716 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); 717 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), 718 Immediate(Factory::fixed_array_map())); 719 __ j(not_equal, &check_pixel_array); 720 721 // Check the key against the length in the array, compute the 722 // address to store into and fall through to fast case. 723 __ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset)); 724 __ j(above_equal, &extra, not_taken); 725 726 // Fast case: Do the store. 727 __ bind(&fast); 728 // eax: value 729 // ecx: FixedArray 730 // ebx: index (as a smi) 731 __ mov(Operand(ecx, ebx, times_2, FixedArray::kHeaderSize - kHeapObjectTag), 732 eax); 733 // Update write barrier for the elements array address. 734 __ mov(edx, Operand(eax)); 735 __ RecordWrite(ecx, 0, edx, ebx); 736 __ ret(0); 737 } 738 739 740 void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, 741 ExternalArrayType array_type) { 742 // ----------- S t a t e ------------- 743 // -- eax : value 744 // -- esp[0] : return address 745 // -- esp[4] : key 746 // -- esp[8] : receiver 747 // ----------------------------------- 748 Label slow, check_heap_number; 749 750 // Get the receiver from the stack. 751 __ mov(edx, Operand(esp, 2 * kPointerSize)); 752 // Check that the object isn't a smi. 753 __ test(edx, Immediate(kSmiTagMask)); 754 __ j(zero, &slow); 755 // Get the map from the receiver. 756 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 757 // Check that the receiver does not require access checks. We need 758 // to do this because this generic stub does not perform map checks. 759 __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset)); 760 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded)); 761 __ j(not_zero, &slow); 762 // Get the key from the stack. 763 __ mov(ebx, Operand(esp, 1 * kPointerSize)); // 1 ~ return address 764 // Check that the key is a smi. 765 __ test(ebx, Immediate(kSmiTagMask)); 766 __ j(not_zero, &slow); 767 // Get the instance type from the map of the receiver. 768 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 769 // Check that the object is a JS object. 770 __ cmp(ecx, JS_OBJECT_TYPE); 771 __ j(not_equal, &slow); 772 773 // Check that the elements array is the appropriate type of 774 // ExternalArray. 775 // eax: value 776 // edx: JSObject 777 // ebx: index (as a smi) 778 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); 779 Handle<Map> map(Heap::MapForExternalArrayType(array_type)); 780 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), 781 Immediate(map)); 782 __ j(not_equal, &slow); 783 784 // Check that the index is in range. 785 __ sar(ebx, kSmiTagSize); // Untag the index. 786 __ cmp(ebx, FieldOperand(ecx, ExternalArray::kLengthOffset)); 787 // Unsigned comparison catches both negative and too-large values. 788 __ j(above_equal, &slow); 789 790 // Handle both smis and HeapNumbers in the fast path. Go to the 791 // runtime for all other kinds of values. 792 // eax: value 793 // ecx: elements array 794 // ebx: untagged index 795 __ test(eax, Immediate(kSmiTagMask)); 796 __ j(not_equal, &check_heap_number); 797 // smi case 798 __ mov(edx, eax); // Save the value. 799 __ sar(eax, kSmiTagSize); // Untag the value. 800 __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset)); 801 // ecx: base pointer of external storage 802 switch (array_type) { 803 case kExternalByteArray: 804 case kExternalUnsignedByteArray: 805 __ mov_b(Operand(ecx, ebx, times_1, 0), eax); 806 break; 807 case kExternalShortArray: 808 case kExternalUnsignedShortArray: 809 __ mov_w(Operand(ecx, ebx, times_2, 0), eax); 810 break; 811 case kExternalIntArray: 812 case kExternalUnsignedIntArray: 813 __ mov(Operand(ecx, ebx, times_4, 0), eax); 814 break; 815 case kExternalFloatArray: 816 // Need to perform int-to-float conversion. 817 __ push(eax); 818 __ fild_s(Operand(esp, 0)); 819 __ pop(eax); 820 __ fstp_s(Operand(ecx, ebx, times_4, 0)); 821 break; 822 default: 823 UNREACHABLE(); 824 break; 825 } 826 __ mov(eax, edx); // Return the original value. 827 __ ret(0); 828 829 __ bind(&check_heap_number); 830 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), 831 Immediate(Factory::heap_number_map())); 832 __ j(not_equal, &slow); 833 834 // The WebGL specification leaves the behavior of storing NaN and 835 // +/-Infinity into integer arrays basically undefined. For more 836 // reproducible behavior, convert these to zero. 837 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); 838 __ mov(edx, eax); // Save the value. 839 __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset)); 840 // ebx: untagged index 841 // ecx: base pointer of external storage 842 // top of FPU stack: value 843 if (array_type == kExternalFloatArray) { 844 __ fstp_s(Operand(ecx, ebx, times_4, 0)); 845 __ mov(eax, edx); // Return the original value. 846 __ ret(0); 847 } else { 848 // Need to perform float-to-int conversion. 849 // Test the top of the FP stack for NaN. 850 Label is_nan; 851 __ fucomi(0); 852 __ j(parity_even, &is_nan); 853 854 if (array_type != kExternalUnsignedIntArray) { 855 __ push(eax); // Make room on stack 856 __ fistp_s(Operand(esp, 0)); 857 __ pop(eax); 858 } else { 859 // fistp stores values as signed integers. 860 // To represent the entire range, we need to store as a 64-bit 861 // int and discard the high 32 bits. 862 __ push(eax); // Make room on stack 863 __ push(eax); // Make room on stack 864 __ fistp_d(Operand(esp, 0)); 865 __ pop(eax); 866 __ mov(Operand(esp, 0), eax); 867 __ pop(eax); 868 } 869 // eax: untagged integer value 870 switch (array_type) { 871 case kExternalByteArray: 872 case kExternalUnsignedByteArray: 873 __ mov_b(Operand(ecx, ebx, times_1, 0), eax); 874 break; 875 case kExternalShortArray: 876 case kExternalUnsignedShortArray: 877 __ mov_w(Operand(ecx, ebx, times_2, 0), eax); 878 break; 879 case kExternalIntArray: 880 case kExternalUnsignedIntArray: { 881 // We also need to explicitly check for +/-Infinity. These are 882 // converted to MIN_INT, but we need to be careful not to 883 // confuse with legal uses of MIN_INT. 884 Label not_infinity; 885 // This test would apparently detect both NaN and Infinity, 886 // but we've already checked for NaN using the FPU hardware 887 // above. 888 __ mov_w(edi, FieldOperand(edx, HeapNumber::kValueOffset + 6)); 889 __ and_(edi, 0x7FF0); 890 __ cmp(edi, 0x7FF0); 891 __ j(not_equal, ¬_infinity); 892 __ mov(eax, 0); 893 __ bind(¬_infinity); 894 __ mov(Operand(ecx, ebx, times_4, 0), eax); 895 break; 896 } 897 default: 898 UNREACHABLE(); 899 break; 900 } 901 __ mov(eax, edx); // Return the original value. 902 __ ret(0); 903 904 __ bind(&is_nan); 905 __ ffree(); 906 __ fincstp(); 907 switch (array_type) { 908 case kExternalByteArray: 909 case kExternalUnsignedByteArray: 910 __ mov_b(Operand(ecx, ebx, times_1, 0), 0); 911 break; 912 case kExternalShortArray: 913 case kExternalUnsignedShortArray: 914 __ mov(eax, 0); 915 __ mov_w(Operand(ecx, ebx, times_2, 0), eax); 916 break; 917 case kExternalIntArray: 918 case kExternalUnsignedIntArray: 919 __ mov(Operand(ecx, ebx, times_4, 0), Immediate(0)); 920 break; 921 default: 922 UNREACHABLE(); 923 break; 924 } 925 __ mov(eax, edx); // Return the original value. 926 __ ret(0); 927 } 928 929 // Slow case: call runtime. 930 __ bind(&slow); 931 GenerateRuntimeSetProperty(masm); 932 } 933 934 935 // Defined in ic.cc. 936 Object* CallIC_Miss(Arguments args); 937 938 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { 939 // ----------- S t a t e ------------- 940 // -- ecx : name 941 // -- esp[0] : return address 942 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 943 // -- ... 944 // -- esp[(argc + 1) * 4] : receiver 945 // ----------------------------------- 946 Label number, non_number, non_string, boolean, probe, miss; 947 948 // Get the receiver of the function from the stack; 1 ~ return address. 949 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 950 951 // Probe the stub cache. 952 Code::Flags flags = 953 Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); 954 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax); 955 956 // If the stub cache probing failed, the receiver might be a value. 957 // For value objects, we use the map of the prototype objects for 958 // the corresponding JSValue for the cache and that is what we need 959 // to probe. 960 // 961 // Check for number. 962 __ test(edx, Immediate(kSmiTagMask)); 963 __ j(zero, &number, not_taken); 964 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); 965 __ j(not_equal, &non_number, taken); 966 __ bind(&number); 967 StubCompiler::GenerateLoadGlobalFunctionPrototype( 968 masm, Context::NUMBER_FUNCTION_INDEX, edx); 969 __ jmp(&probe); 970 971 // Check for string. 972 __ bind(&non_number); 973 __ cmp(ebx, FIRST_NONSTRING_TYPE); 974 __ j(above_equal, &non_string, taken); 975 StubCompiler::GenerateLoadGlobalFunctionPrototype( 976 masm, Context::STRING_FUNCTION_INDEX, edx); 977 __ jmp(&probe); 978 979 // Check for boolean. 980 __ bind(&non_string); 981 __ cmp(edx, Factory::true_value()); 982 __ j(equal, &boolean, not_taken); 983 __ cmp(edx, Factory::false_value()); 984 __ j(not_equal, &miss, taken); 985 __ bind(&boolean); 986 StubCompiler::GenerateLoadGlobalFunctionPrototype( 987 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); 988 989 // Probe the stub cache for the value object. 990 __ bind(&probe); 991 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); 992 993 // Cache miss: Jump to runtime. 994 __ bind(&miss); 995 GenerateMiss(masm, argc); 996 } 997 998 999 static void GenerateNormalHelper(MacroAssembler* masm, 1000 int argc, 1001 bool is_global_object, 1002 Label* miss) { 1003 // ----------- S t a t e ------------- 1004 // -- ecx : name 1005 // -- edx : receiver 1006 // -- esp[0] : return address 1007 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1008 // -- ... 1009 // -- esp[(argc + 1) * 4] : receiver 1010 // ----------------------------------- 1011 1012 // Search dictionary - put result in register edi. 1013 __ mov(edi, edx); 1014 GenerateDictionaryLoad(masm, miss, edx, ecx, eax, edi, ebx, CHECK_DICTIONARY); 1015 1016 // Check that the result is not a smi. 1017 __ test(edi, Immediate(kSmiTagMask)); 1018 __ j(zero, miss, not_taken); 1019 1020 // Check that the value is a JavaScript function, fetching its map into eax. 1021 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); 1022 __ j(not_equal, miss, not_taken); 1023 1024 // Patch the receiver on stack with the global proxy if necessary. 1025 if (is_global_object) { 1026 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); 1027 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); 1028 } 1029 1030 // Invoke the function. 1031 ParameterCount actual(argc); 1032 __ InvokeFunction(edi, actual, JUMP_FUNCTION); 1033 } 1034 1035 1036 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { 1037 // ----------- S t a t e ------------- 1038 // -- ecx : name 1039 // -- esp[0] : return address 1040 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1041 // -- ... 1042 // -- esp[(argc + 1) * 4] : receiver 1043 // ----------------------------------- 1044 Label miss, global_object, non_global_object; 1045 1046 // Get the receiver of the function from the stack; 1 ~ return address. 1047 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1048 1049 // Check that the receiver isn't a smi. 1050 __ test(edx, Immediate(kSmiTagMask)); 1051 __ j(zero, &miss, not_taken); 1052 1053 // Check that the receiver is a valid JS object. 1054 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 1055 __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset)); 1056 __ cmp(eax, FIRST_JS_OBJECT_TYPE); 1057 __ j(below, &miss, not_taken); 1058 1059 // If this assert fails, we have to check upper bound too. 1060 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); 1061 1062 // Check for access to global object. 1063 __ cmp(eax, JS_GLOBAL_OBJECT_TYPE); 1064 __ j(equal, &global_object); 1065 __ cmp(eax, JS_BUILTINS_OBJECT_TYPE); 1066 __ j(not_equal, &non_global_object); 1067 1068 // Accessing global object: Load and invoke. 1069 __ bind(&global_object); 1070 // Check that the global object does not require access checks. 1071 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset)); 1072 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded)); 1073 __ j(not_equal, &miss, not_taken); 1074 GenerateNormalHelper(masm, argc, true, &miss); 1075 1076 // Accessing non-global object: Check for access to global proxy. 1077 Label global_proxy, invoke; 1078 __ bind(&non_global_object); 1079 __ cmp(eax, JS_GLOBAL_PROXY_TYPE); 1080 __ j(equal, &global_proxy, not_taken); 1081 // Check that the non-global, non-global-proxy object does not 1082 // require access checks. 1083 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset)); 1084 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded)); 1085 __ j(not_equal, &miss, not_taken); 1086 __ bind(&invoke); 1087 GenerateNormalHelper(masm, argc, false, &miss); 1088 1089 // Global object proxy access: Check access rights. 1090 __ bind(&global_proxy); 1091 __ CheckAccessGlobalProxy(edx, eax, &miss); 1092 __ jmp(&invoke); 1093 1094 // Cache miss: Jump to runtime. 1095 __ bind(&miss); 1096 GenerateMiss(masm, argc); 1097 } 1098 1099 1100 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { 1101 // ----------- S t a t e ------------- 1102 // -- ecx : name 1103 // -- esp[0] : return address 1104 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1105 // -- ... 1106 // -- esp[(argc + 1) * 4] : receiver 1107 // ----------------------------------- 1108 1109 // Get the receiver of the function from the stack; 1 ~ return address. 1110 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1111 1112 // Enter an internal frame. 1113 __ EnterInternalFrame(); 1114 1115 // Push the receiver and the name of the function. 1116 __ push(edx); 1117 __ push(ecx); 1118 1119 // Call the entry. 1120 CEntryStub stub(1); 1121 __ mov(eax, Immediate(2)); 1122 __ mov(ebx, Immediate(ExternalReference(IC_Utility(kCallIC_Miss)))); 1123 __ CallStub(&stub); 1124 1125 // Move result to edi and exit the internal frame. 1126 __ mov(edi, eax); 1127 __ LeaveInternalFrame(); 1128 1129 // Check if the receiver is a global object of some sort. 1130 Label invoke, global; 1131 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver 1132 __ test(edx, Immediate(kSmiTagMask)); 1133 __ j(zero, &invoke, not_taken); 1134 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 1135 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 1136 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); 1137 __ j(equal, &global); 1138 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); 1139 __ j(not_equal, &invoke); 1140 1141 // Patch the receiver on the stack. 1142 __ bind(&global); 1143 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); 1144 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); 1145 1146 // Invoke the function. 1147 ParameterCount actual(argc); 1148 __ bind(&invoke); 1149 __ InvokeFunction(edi, actual, JUMP_FUNCTION); 1150 } 1151 1152 1153 // Defined in ic.cc. 1154 Object* LoadIC_Miss(Arguments args); 1155 1156 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { 1157 // ----------- S t a t e ------------- 1158 // -- eax : receiver 1159 // -- ecx : name 1160 // -- esp[0] : return address 1161 // ----------------------------------- 1162 1163 // Probe the stub cache. 1164 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, 1165 NOT_IN_LOOP, 1166 MONOMORPHIC); 1167 StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx); 1168 1169 // Cache miss: Jump to runtime. 1170 GenerateMiss(masm); 1171 } 1172 1173 1174 void LoadIC::GenerateNormal(MacroAssembler* masm) { 1175 // ----------- S t a t e ------------- 1176 // -- eax : receiver 1177 // -- ecx : name 1178 // -- esp[0] : return address 1179 // ----------------------------------- 1180 Label miss, probe, global; 1181 1182 // Check that the receiver isn't a smi. 1183 __ test(eax, Immediate(kSmiTagMask)); 1184 __ j(zero, &miss, not_taken); 1185 1186 // Check that the receiver is a valid JS object. 1187 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 1188 __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 1189 __ cmp(edx, FIRST_JS_OBJECT_TYPE); 1190 __ j(less, &miss, not_taken); 1191 1192 // If this assert fails, we have to check upper bound too. 1193 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); 1194 1195 // Check for access to global object (unlikely). 1196 __ cmp(edx, JS_GLOBAL_PROXY_TYPE); 1197 __ j(equal, &global, not_taken); 1198 1199 // Check for non-global object that requires access check. 1200 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset)); 1201 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded)); 1202 __ j(not_zero, &miss, not_taken); 1203 1204 // Search the dictionary placing the result in eax. 1205 __ bind(&probe); 1206 GenerateDictionaryLoad(masm, 1207 &miss, 1208 eax, 1209 ecx, 1210 edx, 1211 edi, 1212 ebx, 1213 CHECK_DICTIONARY); 1214 __ mov(eax, edi); 1215 __ ret(0); 1216 1217 // Global object access: Check access rights. 1218 __ bind(&global); 1219 __ CheckAccessGlobalProxy(eax, edx, &miss); 1220 __ jmp(&probe); 1221 1222 // Cache miss: Restore receiver from stack and jump to runtime. 1223 __ bind(&miss); 1224 GenerateMiss(masm); 1225 } 1226 1227 1228 void LoadIC::GenerateMiss(MacroAssembler* masm) { 1229 // ----------- S t a t e ------------- 1230 // -- eax : receiver 1231 // -- ecx : name 1232 // -- esp[0] : return address 1233 // ----------------------------------- 1234 1235 __ pop(ebx); 1236 __ push(eax); // receiver 1237 __ push(ecx); // name 1238 __ push(ebx); // return address 1239 1240 // Perform tail call to the entry. 1241 __ TailCallRuntime(ExternalReference(IC_Utility(kLoadIC_Miss)), 2, 1); 1242 } 1243 1244 1245 // One byte opcode for test eax,0xXXXXXXXX. 1246 static const byte kTestEaxByte = 0xA9; 1247 1248 1249 void LoadIC::ClearInlinedVersion(Address address) { 1250 // Reset the map check of the inlined inobject property load (if 1251 // present) to guarantee failure by holding an invalid map (the null 1252 // value). The offset can be patched to anything. 1253 PatchInlinedLoad(address, Heap::null_value(), kMaxInt); 1254 } 1255 1256 1257 void KeyedLoadIC::ClearInlinedVersion(Address address) { 1258 // Insert null as the map to check for to make sure the map check fails 1259 // sending control flow to the IC instead of the inlined version. 1260 PatchInlinedLoad(address, Heap::null_value()); 1261 } 1262 1263 1264 void KeyedStoreIC::ClearInlinedVersion(Address address) { 1265 // Insert null as the elements map to check for. This will make 1266 // sure that the elements fast-case map check fails so that control 1267 // flows to the IC instead of the inlined version. 1268 PatchInlinedStore(address, Heap::null_value()); 1269 } 1270 1271 1272 void KeyedStoreIC::RestoreInlinedVersion(Address address) { 1273 // Restore the fast-case elements map check so that the inlined 1274 // version can be used again. 1275 PatchInlinedStore(address, Heap::fixed_array_map()); 1276 } 1277 1278 1279 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { 1280 // The address of the instruction following the call. 1281 Address test_instruction_address = 1282 address + Assembler::kCallTargetAddressOffset; 1283 // If the instruction following the call is not a test eax, nothing 1284 // was inlined. 1285 if (*test_instruction_address != kTestEaxByte) return false; 1286 1287 Address delta_address = test_instruction_address + 1; 1288 // The delta to the start of the map check instruction. 1289 int delta = *reinterpret_cast<int*>(delta_address); 1290 1291 // The map address is the last 4 bytes of the 7-byte 1292 // operand-immediate compare instruction, so we add 3 to get the 1293 // offset to the last 4 bytes. 1294 Address map_address = test_instruction_address + delta + 3; 1295 *(reinterpret_cast<Object**>(map_address)) = map; 1296 1297 // The offset is in the last 4 bytes of a six byte 1298 // memory-to-register move instruction, so we add 2 to get the 1299 // offset to the last 4 bytes. 1300 Address offset_address = 1301 test_instruction_address + delta + kOffsetToLoadInstruction + 2; 1302 *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag; 1303 return true; 1304 } 1305 1306 1307 static bool PatchInlinedMapCheck(Address address, Object* map) { 1308 Address test_instruction_address = 1309 address + Assembler::kCallTargetAddressOffset; 1310 // The keyed load has a fast inlined case if the IC call instruction 1311 // is immediately followed by a test instruction. 1312 if (*test_instruction_address != kTestEaxByte) return false; 1313 1314 // Fetch the offset from the test instruction to the map cmp 1315 // instruction. This offset is stored in the last 4 bytes of the 5 1316 // byte test instruction. 1317 Address delta_address = test_instruction_address + 1; 1318 int delta = *reinterpret_cast<int*>(delta_address); 1319 // Compute the map address. The map address is in the last 4 bytes 1320 // of the 7-byte operand-immediate compare instruction, so we add 3 1321 // to the offset to get the map address. 1322 Address map_address = test_instruction_address + delta + 3; 1323 // Patch the map check. 1324 *(reinterpret_cast<Object**>(map_address)) = map; 1325 return true; 1326 } 1327 1328 1329 bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) { 1330 return PatchInlinedMapCheck(address, map); 1331 } 1332 1333 1334 bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) { 1335 return PatchInlinedMapCheck(address, map); 1336 } 1337 1338 1339 // Defined in ic.cc. 1340 Object* KeyedLoadIC_Miss(Arguments args); 1341 1342 1343 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { 1344 // ----------- S t a t e ------------- 1345 // -- eax : key 1346 // -- edx : receiver 1347 // -- esp[0] : return address 1348 // ----------------------------------- 1349 1350 __ pop(ebx); 1351 __ push(edx); // receiver 1352 __ push(eax); // name 1353 __ push(ebx); // return address 1354 1355 // Perform tail call to the entry. 1356 __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedLoadIC_Miss)), 2, 1); 1357 } 1358 1359 1360 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { 1361 // ----------- S t a t e ------------- 1362 // -- eax : key 1363 // -- edx : receiver 1364 // -- esp[0] : return address 1365 // ----------------------------------- 1366 1367 __ pop(ebx); 1368 __ push(edx); // receiver 1369 __ push(eax); // name 1370 __ push(ebx); // return address 1371 1372 // Perform tail call to the entry. 1373 __ TailCallRuntime(ExternalReference(Runtime::kKeyedGetProperty), 2, 1); 1374 } 1375 1376 1377 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { 1378 // ----------- S t a t e ------------- 1379 // -- eax : value 1380 // -- ecx : name 1381 // -- edx : receiver 1382 // -- esp[0] : return address 1383 // ----------------------------------- 1384 1385 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, 1386 NOT_IN_LOOP, 1387 MONOMORPHIC); 1388 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); 1389 1390 // Cache miss: Jump to runtime. 1391 GenerateMiss(masm); 1392 } 1393 1394 1395 void StoreIC::GenerateMiss(MacroAssembler* masm) { 1396 // ----------- S t a t e ------------- 1397 // -- eax : value 1398 // -- ecx : name 1399 // -- edx : receiver 1400 // -- esp[0] : return address 1401 // ----------------------------------- 1402 1403 __ pop(ebx); 1404 __ push(edx); 1405 __ push(ecx); 1406 __ push(eax); 1407 __ push(ebx); 1408 1409 // Perform tail call to the entry. 1410 __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_Miss)), 3, 1); 1411 } 1412 1413 1414 // Defined in ic.cc. 1415 Object* KeyedStoreIC_Miss(Arguments args); 1416 1417 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { 1418 // ----------- S t a t e ------------- 1419 // -- eax : value 1420 // -- esp[0] : return address 1421 // -- esp[4] : key 1422 // -- esp[8] : receiver 1423 // ----------------------------------- 1424 1425 __ pop(ecx); 1426 __ push(Operand(esp, 1 * kPointerSize)); 1427 __ push(Operand(esp, 1 * kPointerSize)); 1428 __ push(eax); 1429 __ push(ecx); 1430 1431 // Do tail-call to runtime routine. 1432 __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1); 1433 } 1434 1435 1436 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { 1437 // ----------- S t a t e ------------- 1438 // -- eax : value 1439 // -- esp[0] : return address 1440 // -- esp[4] : key 1441 // -- esp[8] : receiver 1442 // ----------------------------------- 1443 1444 __ pop(ecx); 1445 __ push(Operand(esp, 1 * kPointerSize)); 1446 __ push(Operand(esp, 1 * kPointerSize)); 1447 __ push(eax); 1448 __ push(ecx); 1449 1450 // Do tail-call to runtime routine. 1451 __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedStoreIC_Miss)), 3, 1); 1452 } 1453 1454 #undef __ 1455 1456 1457 } } // namespace v8::internal 1458