1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 29 30 #include "v8.h" 31 32 #if defined(V8_TARGET_ARCH_MIPS) 33 34 #include "codegen.h" 35 #include "code-stubs.h" 36 #include "ic-inl.h" 37 #include "runtime.h" 38 #include "stub-cache.h" 39 40 namespace v8 { 41 namespace internal { 42 43 44 // ---------------------------------------------------------------------------- 45 // Static IC stub generators. 46 // 47 48 #define __ ACCESS_MASM(masm) 49 50 51 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, 52 Register type, 53 Label* global_object) { 54 // Register usage: 55 // type: holds the receiver instance type on entry. 56 __ Branch(global_object, eq, type, Operand(JS_GLOBAL_OBJECT_TYPE)); 57 __ Branch(global_object, eq, type, Operand(JS_BUILTINS_OBJECT_TYPE)); 58 __ Branch(global_object, eq, type, Operand(JS_GLOBAL_PROXY_TYPE)); 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. 64 static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm, 65 Register receiver, 66 Register elements, 67 Register scratch0, 68 Register scratch1, 69 Label* miss) { 70 // Register usage: 71 // receiver: holds the receiver on entry and is unchanged. 72 // elements: holds the property dictionary on fall through. 73 // Scratch registers: 74 // scratch0: used to holds the receiver map. 75 // scratch1: used to holds the receiver instance type, receiver bit mask 76 // and elements map. 77 78 // Check that the receiver isn't a smi. 79 __ JumpIfSmi(receiver, miss); 80 81 // Check that the receiver is a valid JS object. 82 __ GetObjectType(receiver, scratch0, scratch1); 83 __ Branch(miss, lt, scratch1, Operand(FIRST_SPEC_OBJECT_TYPE)); 84 85 // If this assert fails, we have to check upper bound too. 86 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); 87 88 GenerateGlobalInstanceTypeCheck(masm, scratch1, miss); 89 90 // Check that the global object does not require access checks. 91 __ lbu(scratch1, FieldMemOperand(scratch0, Map::kBitFieldOffset)); 92 __ And(scratch1, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) | 93 (1 << Map::kHasNamedInterceptor))); 94 __ Branch(miss, ne, scratch1, Operand(zero_reg)); 95 96 __ lw(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); 97 __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset)); 98 __ LoadRoot(scratch0, Heap::kHashTableMapRootIndex); 99 __ Branch(miss, ne, scratch1, Operand(scratch0)); 100 } 101 102 103 // Helper function used from LoadIC/CallIC GenerateNormal. 104 // 105 // elements: Property dictionary. It is not clobbered if a jump to the miss 106 // label is done. 107 // name: Property name. It is not clobbered if a jump to the miss label is 108 // done 109 // result: Register for the result. It is only updated if a jump to the miss 110 // label is not done. Can be the same as elements or name clobbering 111 // one of these in the case of not jumping to the miss label. 112 // The two scratch registers need to be different from elements, name and 113 // result. 114 // The generated code assumes that the receiver has slow properties, 115 // is not a global object and does not have interceptors. 116 // The address returned from GenerateStringDictionaryProbes() in scratch2 117 // is used. 118 static void GenerateDictionaryLoad(MacroAssembler* masm, 119 Label* miss, 120 Register elements, 121 Register name, 122 Register result, 123 Register scratch1, 124 Register scratch2) { 125 // Main use of the scratch registers. 126 // scratch1: Used as temporary and to hold the capacity of the property 127 // dictionary. 128 // scratch2: Used as temporary. 129 Label done; 130 131 // Probe the dictionary. 132 StringDictionaryLookupStub::GeneratePositiveLookup(masm, 133 miss, 134 &done, 135 elements, 136 name, 137 scratch1, 138 scratch2); 139 140 // If probing finds an entry check that the value is a normal 141 // property. 142 __ bind(&done); // scratch2 == elements + 4 * index. 143 const int kElementsStartOffset = StringDictionary::kHeaderSize + 144 StringDictionary::kElementsStartIndex * kPointerSize; 145 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; 146 __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); 147 __ And(at, 148 scratch1, 149 Operand(PropertyDetails::TypeField::kMask << kSmiTagSize)); 150 __ Branch(miss, ne, at, Operand(zero_reg)); 151 152 // Get the value at the masked, scaled index and return. 153 __ lw(result, 154 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize)); 155 } 156 157 158 // Helper function used from StoreIC::GenerateNormal. 159 // 160 // elements: Property dictionary. It is not clobbered if a jump to the miss 161 // label is done. 162 // name: Property name. It is not clobbered if a jump to the miss label is 163 // done 164 // value: The value to store. 165 // The two scratch registers need to be different from elements, name and 166 // result. 167 // The generated code assumes that the receiver has slow properties, 168 // is not a global object and does not have interceptors. 169 // The address returned from GenerateStringDictionaryProbes() in scratch2 170 // is used. 171 static void GenerateDictionaryStore(MacroAssembler* masm, 172 Label* miss, 173 Register elements, 174 Register name, 175 Register value, 176 Register scratch1, 177 Register scratch2) { 178 // Main use of the scratch registers. 179 // scratch1: Used as temporary and to hold the capacity of the property 180 // dictionary. 181 // scratch2: Used as temporary. 182 Label done; 183 184 // Probe the dictionary. 185 StringDictionaryLookupStub::GeneratePositiveLookup(masm, 186 miss, 187 &done, 188 elements, 189 name, 190 scratch1, 191 scratch2); 192 193 // If probing finds an entry in the dictionary check that the value 194 // is a normal property that is not read only. 195 __ bind(&done); // scratch2 == elements + 4 * index. 196 const int kElementsStartOffset = StringDictionary::kHeaderSize + 197 StringDictionary::kElementsStartIndex * kPointerSize; 198 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; 199 const int kTypeAndReadOnlyMask = 200 (PropertyDetails::TypeField::kMask | 201 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; 202 __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); 203 __ And(at, scratch1, Operand(kTypeAndReadOnlyMask)); 204 __ Branch(miss, ne, at, Operand(zero_reg)); 205 206 // Store the value at the masked, scaled index and return. 207 const int kValueOffset = kElementsStartOffset + kPointerSize; 208 __ Addu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag)); 209 __ sw(value, MemOperand(scratch2)); 210 211 // Update the write barrier. Make sure not to clobber the value. 212 __ mov(scratch1, value); 213 __ RecordWrite( 214 elements, scratch2, scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs); 215 } 216 217 218 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { 219 // ----------- S t a t e ------------- 220 // -- a2 : name 221 // -- ra : return address 222 // -- a0 : receiver 223 // -- sp[0] : receiver 224 // ----------------------------------- 225 Label miss; 226 227 StubCompiler::GenerateLoadArrayLength(masm, a0, a3, &miss); 228 __ bind(&miss); 229 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 230 } 231 232 233 void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) { 234 // ----------- S t a t e ------------- 235 // -- a2 : name 236 // -- lr : return address 237 // -- a0 : receiver 238 // -- sp[0] : receiver 239 // ----------------------------------- 240 Label miss; 241 242 StubCompiler::GenerateLoadStringLength(masm, a0, a1, a3, &miss, 243 support_wrappers); 244 // Cache miss: Jump to runtime. 245 __ bind(&miss); 246 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 247 } 248 249 250 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { 251 // ----------- S t a t e ------------- 252 // -- a2 : name 253 // -- lr : return address 254 // -- a0 : receiver 255 // -- sp[0] : receiver 256 // ----------------------------------- 257 Label miss; 258 259 StubCompiler::GenerateLoadFunctionPrototype(masm, a0, a1, a3, &miss); 260 __ bind(&miss); 261 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 262 } 263 264 265 // Checks the receiver for special cases (value type, slow case bits). 266 // Falls through for regular JS object. 267 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, 268 Register receiver, 269 Register map, 270 Register scratch, 271 int interceptor_bit, 272 Label* slow) { 273 // Check that the object isn't a smi. 274 __ JumpIfSmi(receiver, slow); 275 // Get the map of the receiver. 276 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); 277 // Check bit field. 278 __ lbu(scratch, FieldMemOperand(map, Map::kBitFieldOffset)); 279 __ And(at, scratch, Operand(KeyedLoadIC::kSlowCaseBitFieldMask)); 280 __ Branch(slow, ne, at, Operand(zero_reg)); 281 // Check that the object is some kind of JS object EXCEPT JS Value type. 282 // In the case that the object is a value-wrapper object, 283 // we enter the runtime system to make sure that indexing into string 284 // objects work as intended. 285 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); 286 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); 287 __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE)); 288 } 289 290 291 // Loads an indexed element from a fast case array. 292 // If not_fast_array is NULL, doesn't perform the elements map check. 293 static void GenerateFastArrayLoad(MacroAssembler* masm, 294 Register receiver, 295 Register key, 296 Register elements, 297 Register scratch1, 298 Register scratch2, 299 Register result, 300 Label* not_fast_array, 301 Label* out_of_range) { 302 // Register use: 303 // 304 // receiver - holds the receiver on entry. 305 // Unchanged unless 'result' is the same register. 306 // 307 // key - holds the smi key on entry. 308 // Unchanged unless 'result' is the same register. 309 // 310 // elements - holds the elements of the receiver on exit. 311 // 312 // result - holds the result on exit if the load succeeded. 313 // Allowed to be the the same as 'receiver' or 'key'. 314 // Unchanged on bailout so 'receiver' and 'key' can be safely 315 // used by further computation. 316 // 317 // Scratch registers: 318 // 319 // scratch1 - used to hold elements map and elements length. 320 // Holds the elements map if not_fast_array branch is taken. 321 // 322 // scratch2 - used to hold the loaded value. 323 324 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); 325 if (not_fast_array != NULL) { 326 // Check that the object is in fast mode (not dictionary). 327 __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset)); 328 __ LoadRoot(at, Heap::kFixedArrayMapRootIndex); 329 __ Branch(not_fast_array, ne, scratch1, Operand(at)); 330 } else { 331 __ AssertFastElements(elements); 332 } 333 334 // Check that the key (index) is within bounds. 335 __ lw(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); 336 __ Branch(out_of_range, hs, key, Operand(scratch1)); 337 338 // Fast case: Do the load. 339 __ Addu(scratch1, elements, 340 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 341 // The key is a smi. 342 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); 343 __ sll(at, key, kPointerSizeLog2 - kSmiTagSize); 344 __ addu(at, at, scratch1); 345 __ lw(scratch2, MemOperand(at)); 346 347 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); 348 // In case the loaded value is the_hole we have to consult GetProperty 349 // to ensure the prototype chain is searched. 350 __ Branch(out_of_range, eq, scratch2, Operand(at)); 351 __ mov(result, scratch2); 352 } 353 354 355 // Checks whether a key is an array index string or a symbol string. 356 // Falls through if a key is a symbol. 357 static void GenerateKeyStringCheck(MacroAssembler* masm, 358 Register key, 359 Register map, 360 Register hash, 361 Label* index_string, 362 Label* not_symbol) { 363 // The key is not a smi. 364 // Is it a string? 365 __ GetObjectType(key, map, hash); 366 __ Branch(not_symbol, ge, hash, Operand(FIRST_NONSTRING_TYPE)); 367 368 // Is the string an array index, with cached numeric value? 369 __ lw(hash, FieldMemOperand(key, String::kHashFieldOffset)); 370 __ And(at, hash, Operand(String::kContainsCachedArrayIndexMask)); 371 __ Branch(index_string, eq, at, Operand(zero_reg)); 372 373 // Is the string a symbol? 374 // map: key map 375 __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); 376 STATIC_ASSERT(kSymbolTag != 0); 377 __ And(at, hash, Operand(kIsSymbolMask)); 378 __ Branch(not_symbol, eq, at, Operand(zero_reg)); 379 } 380 381 382 // Defined in ic.cc. 383 Object* CallIC_Miss(Arguments args); 384 385 // The generated code does not accept smi keys. 386 // The generated code falls through if both probes miss. 387 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, 388 int argc, 389 Code::Kind kind, 390 Code::ExtraICState extra_state) { 391 // ----------- S t a t e ------------- 392 // -- a1 : receiver 393 // -- a2 : name 394 // ----------------------------------- 395 Label number, non_number, non_string, boolean, probe, miss; 396 397 // Probe the stub cache. 398 Code::Flags flags = Code::ComputeFlags(kind, 399 MONOMORPHIC, 400 extra_state, 401 NORMAL, 402 argc); 403 Isolate::Current()->stub_cache()->GenerateProbe( 404 masm, flags, a1, a2, a3, t0, t1, t2); 405 406 // If the stub cache probing failed, the receiver might be a value. 407 // For value objects, we use the map of the prototype objects for 408 // the corresponding JSValue for the cache and that is what we need 409 // to probe. 410 // 411 // Check for number. 412 __ JumpIfSmi(a1, &number, t1); 413 __ GetObjectType(a1, a3, a3); 414 __ Branch(&non_number, ne, a3, Operand(HEAP_NUMBER_TYPE)); 415 __ bind(&number); 416 StubCompiler::GenerateLoadGlobalFunctionPrototype( 417 masm, Context::NUMBER_FUNCTION_INDEX, a1); 418 __ Branch(&probe); 419 420 // Check for string. 421 __ bind(&non_number); 422 __ Branch(&non_string, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE)); 423 StubCompiler::GenerateLoadGlobalFunctionPrototype( 424 masm, Context::STRING_FUNCTION_INDEX, a1); 425 __ Branch(&probe); 426 427 // Check for boolean. 428 __ bind(&non_string); 429 __ LoadRoot(t0, Heap::kTrueValueRootIndex); 430 __ Branch(&boolean, eq, a1, Operand(t0)); 431 __ LoadRoot(t1, Heap::kFalseValueRootIndex); 432 __ Branch(&miss, ne, a1, Operand(t1)); 433 __ bind(&boolean); 434 StubCompiler::GenerateLoadGlobalFunctionPrototype( 435 masm, Context::BOOLEAN_FUNCTION_INDEX, a1); 436 437 // Probe the stub cache for the value object. 438 __ bind(&probe); 439 Isolate::Current()->stub_cache()->GenerateProbe( 440 masm, flags, a1, a2, a3, t0, t1, t2); 441 442 __ bind(&miss); 443 } 444 445 446 static void GenerateFunctionTailCall(MacroAssembler* masm, 447 int argc, 448 Label* miss, 449 Register scratch) { 450 // a1: function 451 452 // Check that the value isn't a smi. 453 __ JumpIfSmi(a1, miss); 454 455 // Check that the value is a JSFunction. 456 __ GetObjectType(a1, scratch, scratch); 457 __ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE)); 458 459 // Invoke the function. 460 ParameterCount actual(argc); 461 __ InvokeFunction(a1, actual, JUMP_FUNCTION, 462 NullCallWrapper(), CALL_AS_METHOD); 463 } 464 465 466 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) { 467 // ----------- S t a t e ------------- 468 // -- a2 : name 469 // -- ra : return address 470 // ----------------------------------- 471 Label miss; 472 473 // Get the receiver of the function from the stack into a1. 474 __ lw(a1, MemOperand(sp, argc * kPointerSize)); 475 476 GenerateStringDictionaryReceiverCheck(masm, a1, a0, a3, t0, &miss); 477 478 // a0: elements 479 // Search the dictionary - put result in register a1. 480 GenerateDictionaryLoad(masm, &miss, a0, a2, a1, a3, t0); 481 482 GenerateFunctionTailCall(masm, argc, &miss, t0); 483 484 // Cache miss: Jump to runtime. 485 __ bind(&miss); 486 } 487 488 489 void CallICBase::GenerateMiss(MacroAssembler* masm, 490 int argc, 491 IC::UtilityId id, 492 Code::ExtraICState extra_state) { 493 // ----------- S t a t e ------------- 494 // -- a2 : name 495 // -- ra : return address 496 // ----------------------------------- 497 Isolate* isolate = masm->isolate(); 498 499 if (id == IC::kCallIC_Miss) { 500 __ IncrementCounter(isolate->counters()->call_miss(), 1, a3, t0); 501 } else { 502 __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, a3, t0); 503 } 504 505 // Get the receiver of the function from the stack. 506 __ lw(a3, MemOperand(sp, argc*kPointerSize)); 507 508 { 509 FrameScope scope(masm, StackFrame::INTERNAL); 510 511 // Push the receiver and the name of the function. 512 __ Push(a3, a2); 513 514 // Call the entry. 515 __ PrepareCEntryArgs(2); 516 __ PrepareCEntryFunction(ExternalReference(IC_Utility(id), isolate)); 517 518 CEntryStub stub(1); 519 __ CallStub(&stub); 520 521 // Move result to a1 and leave the internal frame. 522 __ mov(a1, v0); 523 } 524 525 // Check if the receiver is a global object of some sort. 526 // This can happen only for regular CallIC but not KeyedCallIC. 527 if (id == IC::kCallIC_Miss) { 528 Label invoke, global; 529 __ lw(a2, MemOperand(sp, argc * kPointerSize)); 530 __ JumpIfSmi(a2, &invoke); 531 __ GetObjectType(a2, a3, a3); 532 __ Branch(&global, eq, a3, Operand(JS_GLOBAL_OBJECT_TYPE)); 533 __ Branch(&invoke, ne, a3, Operand(JS_BUILTINS_OBJECT_TYPE)); 534 535 // Patch the receiver on the stack. 536 __ bind(&global); 537 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset)); 538 __ sw(a2, MemOperand(sp, argc * kPointerSize)); 539 __ bind(&invoke); 540 } 541 // Invoke the function. 542 CallKind call_kind = CallICBase::Contextual::decode(extra_state) 543 ? CALL_AS_FUNCTION 544 : CALL_AS_METHOD; 545 ParameterCount actual(argc); 546 __ InvokeFunction(a1, 547 actual, 548 JUMP_FUNCTION, 549 NullCallWrapper(), 550 call_kind); 551 } 552 553 554 void CallIC::GenerateMegamorphic(MacroAssembler* masm, 555 int argc, 556 Code::ExtraICState extra_ic_state) { 557 // ----------- S t a t e ------------- 558 // -- a2 : name 559 // -- ra : return address 560 // ----------------------------------- 561 562 // Get the receiver of the function from the stack into a1. 563 __ lw(a1, MemOperand(sp, argc * kPointerSize)); 564 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state); 565 GenerateMiss(masm, argc, extra_ic_state); 566 } 567 568 569 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { 570 // ----------- S t a t e ------------- 571 // -- a2 : name 572 // -- ra : return address 573 // ----------------------------------- 574 575 // Get the receiver of the function from the stack into a1. 576 __ lw(a1, MemOperand(sp, argc * kPointerSize)); 577 578 Label do_call, slow_call, slow_load, slow_reload_receiver; 579 Label check_number_dictionary, check_string, lookup_monomorphic_cache; 580 Label index_smi, index_string; 581 582 // Check that the key is a smi. 583 __ JumpIfNotSmi(a2, &check_string); 584 __ bind(&index_smi); 585 // Now the key is known to be a smi. This place is also jumped to from below 586 // where a numeric string is converted to a smi. 587 588 GenerateKeyedLoadReceiverCheck( 589 masm, a1, a0, a3, Map::kHasIndexedInterceptor, &slow_call); 590 591 GenerateFastArrayLoad( 592 masm, a1, a2, t0, a3, a0, a1, &check_number_dictionary, &slow_load); 593 Counters* counters = masm->isolate()->counters(); 594 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, a0, a3); 595 596 __ bind(&do_call); 597 // receiver in a1 is not used after this point. 598 // a2: key 599 // a1: function 600 601 GenerateFunctionTailCall(masm, argc, &slow_call, a0); 602 603 __ bind(&check_number_dictionary); 604 // a2: key 605 // a3: elements map 606 // t0: elements pointer 607 // Check whether the elements is a number dictionary. 608 __ LoadRoot(at, Heap::kHashTableMapRootIndex); 609 __ Branch(&slow_load, ne, a3, Operand(at)); 610 __ sra(a0, a2, kSmiTagSize); 611 // a0: untagged index 612 __ LoadFromNumberDictionary(&slow_load, t0, a2, a1, a0, a3, t1); 613 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, a0, a3); 614 __ jmp(&do_call); 615 616 __ bind(&slow_load); 617 // This branch is taken when calling KeyedCallIC_Miss is neither required 618 // nor beneficial. 619 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, a0, a3); 620 { 621 FrameScope scope(masm, StackFrame::INTERNAL); 622 __ push(a2); // Save the key. 623 __ Push(a1, a2); // Pass the receiver and the key. 624 __ CallRuntime(Runtime::kKeyedGetProperty, 2); 625 __ pop(a2); // Restore the key. 626 } 627 __ mov(a1, v0); 628 __ jmp(&do_call); 629 630 __ bind(&check_string); 631 GenerateKeyStringCheck(masm, a2, a0, a3, &index_string, &slow_call); 632 633 // The key is known to be a symbol. 634 // If the receiver is a regular JS object with slow properties then do 635 // a quick inline probe of the receiver's dictionary. 636 // Otherwise do the monomorphic cache probe. 637 GenerateKeyedLoadReceiverCheck( 638 masm, a1, a0, a3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); 639 640 __ lw(a0, FieldMemOperand(a1, JSObject::kPropertiesOffset)); 641 __ lw(a3, FieldMemOperand(a0, HeapObject::kMapOffset)); 642 __ LoadRoot(at, Heap::kHashTableMapRootIndex); 643 __ Branch(&lookup_monomorphic_cache, ne, a3, Operand(at)); 644 645 GenerateDictionaryLoad(masm, &slow_load, a0, a2, a1, a3, t0); 646 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, a0, a3); 647 __ jmp(&do_call); 648 649 __ bind(&lookup_monomorphic_cache); 650 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, a0, a3); 651 GenerateMonomorphicCacheProbe(masm, 652 argc, 653 Code::KEYED_CALL_IC, 654 Code::kNoExtraICState); 655 // Fall through on miss. 656 657 __ bind(&slow_call); 658 // This branch is taken if: 659 // - the receiver requires boxing or access check, 660 // - the key is neither smi nor symbol, 661 // - the value loaded is not a function, 662 // - there is hope that the runtime will create a monomorphic call stub, 663 // that will get fetched next time. 664 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, a0, a3); 665 GenerateMiss(masm, argc); 666 667 __ bind(&index_string); 668 __ IndexFromHash(a3, a2); 669 // Now jump to the place where smi keys are handled. 670 __ jmp(&index_smi); 671 } 672 673 674 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { 675 // ----------- S t a t e ------------- 676 // -- a2 : name 677 // -- ra : return address 678 // ----------------------------------- 679 680 // Check if the name is a string. 681 Label miss; 682 __ JumpIfSmi(a2, &miss); 683 __ IsObjectJSStringType(a2, a0, &miss); 684 685 CallICBase::GenerateNormal(masm, argc); 686 __ bind(&miss); 687 GenerateMiss(masm, argc); 688 } 689 690 691 // Defined in ic.cc. 692 Object* LoadIC_Miss(Arguments args); 693 694 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { 695 // ----------- S t a t e ------------- 696 // -- a2 : name 697 // -- ra : return address 698 // -- a0 : receiver 699 // -- sp[0] : receiver 700 // ----------------------------------- 701 702 // Probe the stub cache. 703 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC); 704 Isolate::Current()->stub_cache()->GenerateProbe( 705 masm, flags, a0, a2, a3, t0, t1, t2); 706 707 // Cache miss: Jump to runtime. 708 GenerateMiss(masm); 709 } 710 711 712 void LoadIC::GenerateNormal(MacroAssembler* masm) { 713 // ----------- S t a t e ------------- 714 // -- a2 : name 715 // -- lr : return address 716 // -- a0 : receiver 717 // -- sp[0] : receiver 718 // ----------------------------------- 719 Label miss; 720 721 GenerateStringDictionaryReceiverCheck(masm, a0, a1, a3, t0, &miss); 722 723 // a1: elements 724 GenerateDictionaryLoad(masm, &miss, a1, a2, v0, a3, t0); 725 __ Ret(); 726 727 // Cache miss: Jump to runtime. 728 __ bind(&miss); 729 GenerateMiss(masm); 730 } 731 732 733 void LoadIC::GenerateMiss(MacroAssembler* masm) { 734 // ----------- S t a t e ------------- 735 // -- a2 : name 736 // -- ra : return address 737 // -- a0 : receiver 738 // -- sp[0] : receiver 739 // ----------------------------------- 740 Isolate* isolate = masm->isolate(); 741 742 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0); 743 744 __ mov(a3, a0); 745 __ Push(a3, a2); 746 747 // Perform tail call to the entry. 748 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate); 749 __ TailCallExternalReference(ref, 2, 1); 750 } 751 752 753 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, 754 Register object, 755 Register key, 756 Register scratch1, 757 Register scratch2, 758 Register scratch3, 759 Label* unmapped_case, 760 Label* slow_case) { 761 // Check that the receiver is a JSObject. Because of the map check 762 // later, we do not need to check for interceptors or whether it 763 // requires access checks. 764 __ JumpIfSmi(object, slow_case); 765 // Check that the object is some kind of JSObject. 766 __ GetObjectType(object, scratch1, scratch2); 767 __ Branch(slow_case, lt, scratch2, Operand(FIRST_JS_RECEIVER_TYPE)); 768 769 // Check that the key is a positive smi. 770 __ And(scratch1, key, Operand(0x80000001)); 771 __ Branch(slow_case, ne, scratch1, Operand(zero_reg)); 772 773 // Load the elements into scratch1 and check its map. 774 __ lw(scratch1, FieldMemOperand(object, JSObject::kElementsOffset)); 775 __ CheckMap(scratch1, 776 scratch2, 777 Heap::kNonStrictArgumentsElementsMapRootIndex, 778 slow_case, 779 DONT_DO_SMI_CHECK); 780 // Check if element is in the range of mapped arguments. If not, jump 781 // to the unmapped lookup with the parameter map in scratch1. 782 __ lw(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset)); 783 __ Subu(scratch2, scratch2, Operand(Smi::FromInt(2))); 784 __ Branch(unmapped_case, Ugreater_equal, key, Operand(scratch2)); 785 786 // Load element index and check whether it is the hole. 787 const int kOffset = 788 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag; 789 790 __ li(scratch3, Operand(kPointerSize >> 1)); 791 __ Mul(scratch3, key, scratch3); 792 __ Addu(scratch3, scratch3, Operand(kOffset)); 793 794 __ Addu(scratch2, scratch1, scratch3); 795 __ lw(scratch2, MemOperand(scratch2)); 796 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex); 797 __ Branch(unmapped_case, eq, scratch2, Operand(scratch3)); 798 799 // Load value from context and return it. We can reuse scratch1 because 800 // we do not jump to the unmapped lookup (which requires the parameter 801 // map in scratch1). 802 __ lw(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize)); 803 __ li(scratch3, Operand(kPointerSize >> 1)); 804 __ Mul(scratch3, scratch2, scratch3); 805 __ Addu(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag)); 806 __ Addu(scratch2, scratch1, scratch3); 807 return MemOperand(scratch2); 808 } 809 810 811 static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm, 812 Register key, 813 Register parameter_map, 814 Register scratch, 815 Label* slow_case) { 816 // Element is in arguments backing store, which is referenced by the 817 // second element of the parameter_map. The parameter_map register 818 // must be loaded with the parameter map of the arguments object and is 819 // overwritten. 820 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; 821 Register backing_store = parameter_map; 822 __ lw(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset)); 823 __ CheckMap(backing_store, 824 scratch, 825 Heap::kFixedArrayMapRootIndex, 826 slow_case, 827 DONT_DO_SMI_CHECK); 828 __ lw(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset)); 829 __ Branch(slow_case, Ugreater_equal, key, Operand(scratch)); 830 __ li(scratch, Operand(kPointerSize >> 1)); 831 __ Mul(scratch, key, scratch); 832 __ Addu(scratch, 833 scratch, 834 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 835 __ Addu(scratch, backing_store, scratch); 836 return MemOperand(scratch); 837 } 838 839 840 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) { 841 // ---------- S t a t e -------------- 842 // -- lr : return address 843 // -- a0 : key 844 // -- a1 : receiver 845 // ----------------------------------- 846 Label slow, notin; 847 MemOperand mapped_location = 848 GenerateMappedArgumentsLookup(masm, a1, a0, a2, a3, t0, ¬in, &slow); 849 __ Ret(USE_DELAY_SLOT); 850 __ lw(v0, mapped_location); 851 __ bind(¬in); 852 // The unmapped lookup expects that the parameter map is in a2. 853 MemOperand unmapped_location = 854 GenerateUnmappedArgumentsLookup(masm, a0, a2, a3, &slow); 855 __ lw(a2, unmapped_location); 856 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex); 857 __ Branch(&slow, eq, a2, Operand(a3)); 858 __ Ret(USE_DELAY_SLOT); 859 __ mov(v0, a2); 860 __ bind(&slow); 861 GenerateMiss(masm, false); 862 } 863 864 865 void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) { 866 // ---------- S t a t e -------------- 867 // -- a0 : value 868 // -- a1 : key 869 // -- a2 : receiver 870 // -- lr : return address 871 // ----------------------------------- 872 Label slow, notin; 873 // Store address is returned in register (of MemOperand) mapped_location. 874 MemOperand mapped_location = 875 GenerateMappedArgumentsLookup(masm, a2, a1, a3, t0, t1, ¬in, &slow); 876 __ sw(a0, mapped_location); 877 __ mov(t5, a0); 878 ASSERT_EQ(mapped_location.offset(), 0); 879 __ RecordWrite(a3, mapped_location.rm(), t5, 880 kRAHasNotBeenSaved, kDontSaveFPRegs); 881 __ Ret(USE_DELAY_SLOT); 882 __ mov(v0, a0); // (In delay slot) return the value stored in v0. 883 __ bind(¬in); 884 // The unmapped lookup expects that the parameter map is in a3. 885 // Store address is returned in register (of MemOperand) unmapped_location. 886 MemOperand unmapped_location = 887 GenerateUnmappedArgumentsLookup(masm, a1, a3, t0, &slow); 888 __ sw(a0, unmapped_location); 889 __ mov(t5, a0); 890 ASSERT_EQ(unmapped_location.offset(), 0); 891 __ RecordWrite(a3, unmapped_location.rm(), t5, 892 kRAHasNotBeenSaved, kDontSaveFPRegs); 893 __ Ret(USE_DELAY_SLOT); 894 __ mov(v0, a0); // (In delay slot) return the value stored in v0. 895 __ bind(&slow); 896 GenerateMiss(masm, false); 897 } 898 899 900 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm, 901 int argc) { 902 // ----------- S t a t e ------------- 903 // -- a2 : name 904 // -- lr : return address 905 // ----------------------------------- 906 Label slow, notin; 907 // Load receiver. 908 __ lw(a1, MemOperand(sp, argc * kPointerSize)); 909 MemOperand mapped_location = 910 GenerateMappedArgumentsLookup(masm, a1, a2, a3, t0, t1, ¬in, &slow); 911 __ lw(a1, mapped_location); 912 GenerateFunctionTailCall(masm, argc, &slow, a3); 913 __ bind(¬in); 914 // The unmapped lookup expects that the parameter map is in a3. 915 MemOperand unmapped_location = 916 GenerateUnmappedArgumentsLookup(masm, a2, a3, t0, &slow); 917 __ lw(a1, unmapped_location); 918 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex); 919 __ Branch(&slow, eq, a1, Operand(a3)); 920 GenerateFunctionTailCall(masm, argc, &slow, a3); 921 __ bind(&slow); 922 GenerateMiss(masm, argc); 923 } 924 925 926 Object* KeyedLoadIC_Miss(Arguments args); 927 928 929 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) { 930 // ---------- S t a t e -------------- 931 // -- ra : return address 932 // -- a0 : key 933 // -- a1 : receiver 934 // ----------------------------------- 935 Isolate* isolate = masm->isolate(); 936 937 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0); 938 939 __ Push(a1, a0); 940 941 // Perform tail call to the entry. 942 ExternalReference ref = force_generic 943 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate) 944 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate); 945 946 __ TailCallExternalReference(ref, 2, 1); 947 } 948 949 950 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { 951 // ---------- S t a t e -------------- 952 // -- ra : return address 953 // -- a0 : key 954 // -- a1 : receiver 955 // ----------------------------------- 956 957 __ Push(a1, a0); 958 959 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); 960 } 961 962 963 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { 964 // ---------- S t a t e -------------- 965 // -- ra : return address 966 // -- a0 : key 967 // -- a1 : receiver 968 // ----------------------------------- 969 Label slow, check_string, index_smi, index_string, property_array_property; 970 Label probe_dictionary, check_number_dictionary; 971 972 Register key = a0; 973 Register receiver = a1; 974 975 Isolate* isolate = masm->isolate(); 976 977 // Check that the key is a smi. 978 __ JumpIfNotSmi(key, &check_string); 979 __ bind(&index_smi); 980 // Now the key is known to be a smi. This place is also jumped to from below 981 // where a numeric string is converted to a smi. 982 983 GenerateKeyedLoadReceiverCheck( 984 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow); 985 986 // Check the receiver's map to see if it has fast elements. 987 __ CheckFastElements(a2, a3, &check_number_dictionary); 988 989 GenerateFastArrayLoad( 990 masm, receiver, key, t0, a3, a2, v0, NULL, &slow); 991 992 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a2, a3); 993 __ Ret(); 994 995 __ bind(&check_number_dictionary); 996 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset)); 997 __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset)); 998 999 // Check whether the elements is a number dictionary. 1000 // a0: key 1001 // a3: elements map 1002 // t0: elements 1003 __ LoadRoot(at, Heap::kHashTableMapRootIndex); 1004 __ Branch(&slow, ne, a3, Operand(at)); 1005 __ sra(a2, a0, kSmiTagSize); 1006 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1); 1007 __ Ret(); 1008 1009 // Slow case, key and receiver still in a0 and a1. 1010 __ bind(&slow); 1011 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1012 1, 1013 a2, 1014 a3); 1015 GenerateRuntimeGetProperty(masm); 1016 1017 __ bind(&check_string); 1018 GenerateKeyStringCheck(masm, key, a2, a3, &index_string, &slow); 1019 1020 GenerateKeyedLoadReceiverCheck( 1021 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow); 1022 1023 1024 // If the receiver is a fast-case object, check the keyed lookup 1025 // cache. Otherwise probe the dictionary. 1026 __ lw(a3, FieldMemOperand(a1, JSObject::kPropertiesOffset)); 1027 __ lw(t0, FieldMemOperand(a3, HeapObject::kMapOffset)); 1028 __ LoadRoot(at, Heap::kHashTableMapRootIndex); 1029 __ Branch(&probe_dictionary, eq, t0, Operand(at)); 1030 1031 // Load the map of the receiver, compute the keyed lookup cache hash 1032 // based on 32 bits of the map pointer and the string hash. 1033 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset)); 1034 __ sra(a3, a2, KeyedLookupCache::kMapHashShift); 1035 __ lw(t0, FieldMemOperand(a0, String::kHashFieldOffset)); 1036 __ sra(at, t0, String::kHashShift); 1037 __ xor_(a3, a3, at); 1038 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask; 1039 __ And(a3, a3, Operand(mask)); 1040 1041 // Load the key (consisting of map and symbol) from the cache and 1042 // check for match. 1043 Label load_in_object_property; 1044 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket; 1045 Label hit_on_nth_entry[kEntriesPerBucket]; 1046 ExternalReference cache_keys = 1047 ExternalReference::keyed_lookup_cache_keys(isolate); 1048 __ li(t0, Operand(cache_keys)); 1049 __ sll(at, a3, kPointerSizeLog2 + 1); 1050 __ addu(t0, t0, at); 1051 1052 for (int i = 0; i < kEntriesPerBucket - 1; i++) { 1053 Label try_next_entry; 1054 __ lw(t1, MemOperand(t0, kPointerSize * i * 2)); 1055 __ Branch(&try_next_entry, ne, a2, Operand(t1)); 1056 __ lw(t1, MemOperand(t0, kPointerSize * (i * 2 + 1))); 1057 __ Branch(&hit_on_nth_entry[i], eq, a0, Operand(t1)); 1058 __ bind(&try_next_entry); 1059 } 1060 1061 __ lw(t1, MemOperand(t0, kPointerSize * (kEntriesPerBucket - 1) * 2)); 1062 __ Branch(&slow, ne, a2, Operand(t1)); 1063 __ lw(t1, MemOperand(t0, kPointerSize * ((kEntriesPerBucket - 1) * 2 + 1))); 1064 __ Branch(&slow, ne, a0, Operand(t1)); 1065 1066 // Get field offset. 1067 // a0 : key 1068 // a1 : receiver 1069 // a2 : receiver's map 1070 // a3 : lookup cache index 1071 ExternalReference cache_field_offsets = 1072 ExternalReference::keyed_lookup_cache_field_offsets(isolate); 1073 1074 // Hit on nth entry. 1075 for (int i = kEntriesPerBucket - 1; i >= 0; i--) { 1076 __ bind(&hit_on_nth_entry[i]); 1077 __ li(t0, Operand(cache_field_offsets)); 1078 __ sll(at, a3, kPointerSizeLog2); 1079 __ addu(at, t0, at); 1080 __ lw(t1, MemOperand(at, kPointerSize * i)); 1081 __ lbu(t2, FieldMemOperand(a2, Map::kInObjectPropertiesOffset)); 1082 __ Subu(t1, t1, t2); 1083 __ Branch(&property_array_property, ge, t1, Operand(zero_reg)); 1084 if (i != 0) { 1085 __ Branch(&load_in_object_property); 1086 } 1087 } 1088 1089 // Load in-object property. 1090 __ bind(&load_in_object_property); 1091 __ lbu(t2, FieldMemOperand(a2, Map::kInstanceSizeOffset)); 1092 __ addu(t2, t2, t1); // Index from start of object. 1093 __ Subu(a1, a1, Operand(kHeapObjectTag)); // Remove the heap tag. 1094 __ sll(at, t2, kPointerSizeLog2); 1095 __ addu(at, a1, at); 1096 __ lw(v0, MemOperand(at)); 1097 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1098 1, 1099 a2, 1100 a3); 1101 __ Ret(); 1102 1103 // Load property array property. 1104 __ bind(&property_array_property); 1105 __ lw(a1, FieldMemOperand(a1, JSObject::kPropertiesOffset)); 1106 __ Addu(a1, a1, FixedArray::kHeaderSize - kHeapObjectTag); 1107 __ sll(t0, t1, kPointerSizeLog2); 1108 __ Addu(t0, t0, a1); 1109 __ lw(v0, MemOperand(t0)); 1110 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1111 1, 1112 a2, 1113 a3); 1114 __ Ret(); 1115 1116 1117 // Do a quick inline probe of the receiver's dictionary, if it 1118 // exists. 1119 __ bind(&probe_dictionary); 1120 // a1: receiver 1121 // a0: key 1122 // a3: elements 1123 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset)); 1124 __ lbu(a2, FieldMemOperand(a2, Map::kInstanceTypeOffset)); 1125 GenerateGlobalInstanceTypeCheck(masm, a2, &slow); 1126 // Load the property to v0. 1127 GenerateDictionaryLoad(masm, &slow, a3, a0, v0, a2, t0); 1128 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(), 1129 1, 1130 a2, 1131 a3); 1132 __ Ret(); 1133 1134 __ bind(&index_string); 1135 __ IndexFromHash(a3, key); 1136 // Now jump to the place where smi keys are handled. 1137 __ Branch(&index_smi); 1138 } 1139 1140 1141 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { 1142 // ---------- S t a t e -------------- 1143 // -- ra : return address 1144 // -- a0 : key (index) 1145 // -- a1 : receiver 1146 // ----------------------------------- 1147 Label miss; 1148 1149 Register receiver = a1; 1150 Register index = a0; 1151 Register scratch = a3; 1152 Register result = v0; 1153 1154 StringCharAtGenerator char_at_generator(receiver, 1155 index, 1156 scratch, 1157 result, 1158 &miss, // When not a string. 1159 &miss, // When not a number. 1160 &miss, // When index out of range. 1161 STRING_INDEX_IS_ARRAY_INDEX); 1162 char_at_generator.GenerateFast(masm); 1163 __ Ret(); 1164 1165 StubRuntimeCallHelper call_helper; 1166 char_at_generator.GenerateSlow(masm, call_helper); 1167 1168 __ bind(&miss); 1169 GenerateMiss(masm, false); 1170 } 1171 1172 1173 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, 1174 StrictModeFlag strict_mode) { 1175 // ---------- S t a t e -------------- 1176 // -- a0 : value 1177 // -- a1 : key 1178 // -- a2 : receiver 1179 // -- ra : return address 1180 // ----------------------------------- 1181 1182 // Push receiver, key and value for runtime call. 1183 __ Push(a2, a1, a0); 1184 __ li(a1, Operand(Smi::FromInt(NONE))); // PropertyAttributes. 1185 __ li(a0, Operand(Smi::FromInt(strict_mode))); // Strict mode. 1186 __ Push(a1, a0); 1187 1188 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); 1189 } 1190 1191 1192 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, 1193 StrictModeFlag strict_mode) { 1194 // ---------- S t a t e -------------- 1195 // -- a0 : value 1196 // -- a1 : key 1197 // -- a2 : receiver 1198 // -- ra : return address 1199 // ----------------------------------- 1200 Label slow, array, extra, check_if_double_array; 1201 Label fast_object_with_map_check, fast_object_without_map_check; 1202 Label fast_double_with_map_check, fast_double_without_map_check; 1203 Label transition_smi_elements, finish_object_store, non_double_value; 1204 Label transition_double_elements; 1205 1206 // Register usage. 1207 Register value = a0; 1208 Register key = a1; 1209 Register receiver = a2; 1210 Register receiver_map = a3; 1211 Register elements_map = t2; 1212 Register elements = t3; // Elements array of the receiver. 1213 // t0 and t1 are used as general scratch registers. 1214 1215 // Check that the key is a smi. 1216 __ JumpIfNotSmi(key, &slow); 1217 // Check that the object isn't a smi. 1218 __ JumpIfSmi(receiver, &slow); 1219 // Get the map of the object. 1220 __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); 1221 // Check that the receiver does not require access checks. We need 1222 // to do this because this generic stub does not perform map checks. 1223 __ lbu(t0, FieldMemOperand(receiver_map, Map::kBitFieldOffset)); 1224 __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded)); 1225 __ Branch(&slow, ne, t0, Operand(zero_reg)); 1226 // Check if the object is a JS array or not. 1227 __ lbu(t0, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset)); 1228 __ Branch(&array, eq, t0, Operand(JS_ARRAY_TYPE)); 1229 // Check that the object is some kind of JSObject. 1230 __ Branch(&slow, lt, t0, Operand(FIRST_JS_OBJECT_TYPE)); 1231 1232 // Object case: Check key against length in the elements array. 1233 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); 1234 // Check array bounds. Both the key and the length of FixedArray are smis. 1235 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); 1236 __ Branch(&fast_object_with_map_check, lo, key, Operand(t0)); 1237 1238 // Slow case, handle jump to runtime. 1239 __ bind(&slow); 1240 // Entry registers are intact. 1241 // a0: value. 1242 // a1: key. 1243 // a2: receiver. 1244 GenerateRuntimeSetProperty(masm, strict_mode); 1245 1246 // Extra capacity case: Check if there is extra capacity to 1247 // perform the store and update the length. Used for adding one 1248 // element to the array by writing to array[array.length]. 1249 __ bind(&extra); 1250 // Condition code from comparing key and array length is still available. 1251 // Only support writing to array[array.length]. 1252 __ Branch(&slow, ne, key, Operand(t0)); 1253 // Check for room in the elements backing store. 1254 // Both the key and the length of FixedArray are smis. 1255 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); 1256 __ Branch(&slow, hs, key, Operand(t0)); 1257 __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); 1258 __ Branch( 1259 &check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex); 1260 1261 // Calculate key + 1 as smi. 1262 STATIC_ASSERT(kSmiTag == 0); 1263 __ Addu(t0, key, Operand(Smi::FromInt(1))); 1264 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1265 __ Branch(&fast_object_without_map_check); 1266 1267 __ bind(&check_if_double_array); 1268 __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex); 1269 // Add 1 to key, and go to common element store code for doubles. 1270 STATIC_ASSERT(kSmiTag == 0); 1271 __ Addu(t0, key, Operand(Smi::FromInt(1))); 1272 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1273 __ jmp(&fast_double_without_map_check); 1274 1275 // Array case: Get the length and the elements array from the JS 1276 // array. Check that the array is in fast mode (and writable); if it 1277 // is the length is always a smi. 1278 __ bind(&array); 1279 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); 1280 1281 // Check the key against the length in the array. 1282 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1283 __ Branch(&extra, hs, key, Operand(t0)); 1284 // Fall through to fast case. 1285 1286 __ bind(&fast_object_with_map_check); 1287 Register scratch_value = t0; 1288 Register address = t1; 1289 __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); 1290 __ Branch(&fast_double_with_map_check, 1291 ne, 1292 elements_map, 1293 Heap::kFixedArrayMapRootIndex); 1294 __ bind(&fast_object_without_map_check); 1295 // Smi stores don't require further checks. 1296 Label non_smi_value; 1297 __ JumpIfNotSmi(value, &non_smi_value); 1298 // It's irrelevant whether array is smi-only or not when writing a smi. 1299 __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 1300 __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); 1301 __ Addu(address, address, scratch_value); 1302 __ sw(value, MemOperand(address)); 1303 __ Ret(USE_DELAY_SLOT); 1304 __ mov(v0, value); 1305 1306 __ bind(&non_smi_value); 1307 // Escape to elements kind transition case. 1308 __ CheckFastObjectElements(receiver_map, scratch_value, 1309 &transition_smi_elements); 1310 // Fast elements array, store the value to the elements backing store. 1311 __ bind(&finish_object_store); 1312 __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 1313 __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); 1314 __ Addu(address, address, scratch_value); 1315 __ sw(value, MemOperand(address)); 1316 // Update write barrier for the elements array address. 1317 __ mov(v0, value); // Preserve the value which is returned. 1318 __ RecordWrite(elements, 1319 address, 1320 value, 1321 kRAHasNotBeenSaved, 1322 kDontSaveFPRegs, 1323 EMIT_REMEMBERED_SET, 1324 OMIT_SMI_CHECK); 1325 __ Ret(); 1326 1327 __ bind(&fast_double_with_map_check); 1328 // Check for fast double array case. If this fails, call through to the 1329 // runtime. 1330 __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex); 1331 __ bind(&fast_double_without_map_check); 1332 __ StoreNumberToDoubleElements(value, 1333 key, 1334 receiver, 1335 elements, 1336 a3, 1337 t0, 1338 t1, 1339 t2, 1340 &transition_double_elements); 1341 __ Ret(USE_DELAY_SLOT); 1342 __ mov(v0, value); 1343 1344 __ bind(&transition_smi_elements); 1345 // Transition the array appropriately depending on the value type. 1346 __ lw(t0, FieldMemOperand(value, HeapObject::kMapOffset)); 1347 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); 1348 __ Branch(&non_double_value, ne, t0, Operand(at)); 1349 1350 // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS -> 1351 // FAST_DOUBLE_ELEMENTS and complete the store. 1352 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS, 1353 FAST_DOUBLE_ELEMENTS, 1354 receiver_map, 1355 t0, 1356 &slow); 1357 ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 1358 ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow); 1359 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); 1360 __ jmp(&fast_double_without_map_check); 1361 1362 __ bind(&non_double_value); 1363 // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS 1364 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS, 1365 FAST_ELEMENTS, 1366 receiver_map, 1367 t0, 1368 &slow); 1369 ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 1370 ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm); 1371 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); 1372 __ jmp(&finish_object_store); 1373 1374 __ bind(&transition_double_elements); 1375 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a 1376 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and 1377 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS 1378 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, 1379 FAST_ELEMENTS, 1380 receiver_map, 1381 t0, 1382 &slow); 1383 ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 1384 ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow); 1385 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); 1386 __ jmp(&finish_object_store); 1387 } 1388 1389 1390 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { 1391 // ---------- S t a t e -------------- 1392 // -- ra : return address 1393 // -- a0 : key 1394 // -- a1 : receiver 1395 // ----------------------------------- 1396 Label slow; 1397 1398 // Check that the receiver isn't a smi. 1399 __ JumpIfSmi(a1, &slow); 1400 1401 // Check that the key is an array index, that is Uint32. 1402 __ And(t0, a0, Operand(kSmiTagMask | kSmiSignMask)); 1403 __ Branch(&slow, ne, t0, Operand(zero_reg)); 1404 1405 // Get the map of the receiver. 1406 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset)); 1407 1408 // Check that it has indexed interceptor and access checks 1409 // are not enabled for this object. 1410 __ lbu(a3, FieldMemOperand(a2, Map::kBitFieldOffset)); 1411 __ And(a3, a3, Operand(kSlowCaseBitFieldMask)); 1412 __ Branch(&slow, ne, a3, Operand(1 << Map::kHasIndexedInterceptor)); 1413 // Everything is fine, call runtime. 1414 __ Push(a1, a0); // Receiver, key. 1415 1416 // Perform tail call to the entry. 1417 __ TailCallExternalReference(ExternalReference( 1418 IC_Utility(kKeyedLoadPropertyWithInterceptor), masm->isolate()), 2, 1); 1419 1420 __ bind(&slow); 1421 GenerateMiss(masm, false); 1422 } 1423 1424 1425 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) { 1426 // ---------- S t a t e -------------- 1427 // -- a0 : value 1428 // -- a1 : key 1429 // -- a2 : receiver 1430 // -- ra : return address 1431 // ----------------------------------- 1432 1433 // Push receiver, key and value for runtime call. 1434 __ Push(a2, a1, a0); 1435 1436 ExternalReference ref = force_generic 1437 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric), 1438 masm->isolate()) 1439 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate()); 1440 __ TailCallExternalReference(ref, 3, 1); 1441 } 1442 1443 1444 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { 1445 // ---------- S t a t e -------------- 1446 // -- a0 : value 1447 // -- a1 : key 1448 // -- a2 : receiver 1449 // -- ra : return address 1450 // ----------------------------------- 1451 1452 // Push receiver, key and value for runtime call. 1453 // We can't use MultiPush as the order of the registers is important. 1454 __ Push(a2, a1, a0); 1455 1456 // The slow case calls into the runtime to complete the store without causing 1457 // an IC miss that would otherwise cause a transition to the generic stub. 1458 ExternalReference ref = 1459 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); 1460 1461 __ TailCallExternalReference(ref, 3, 1); 1462 } 1463 1464 1465 void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) { 1466 // ---------- S t a t e -------------- 1467 // -- a2 : receiver 1468 // -- a3 : target map 1469 // -- ra : return address 1470 // ----------------------------------- 1471 // Must return the modified receiver in v0. 1472 if (!FLAG_trace_elements_transitions) { 1473 Label fail; 1474 ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail); 1475 __ Ret(USE_DELAY_SLOT); 1476 __ mov(v0, a2); 1477 __ bind(&fail); 1478 } 1479 1480 __ push(a2); 1481 __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1); 1482 } 1483 1484 1485 void KeyedStoreIC::GenerateTransitionElementsDoubleToObject( 1486 MacroAssembler* masm) { 1487 // ---------- S t a t e -------------- 1488 // -- a2 : receiver 1489 // -- a3 : target map 1490 // -- ra : return address 1491 // ----------------------------------- 1492 // Must return the modified receiver in v0. 1493 if (!FLAG_trace_elements_transitions) { 1494 Label fail; 1495 ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail); 1496 __ Ret(USE_DELAY_SLOT); 1497 __ mov(v0, a2); 1498 __ bind(&fail); 1499 } 1500 1501 __ push(a2); 1502 __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1); 1503 } 1504 1505 1506 void StoreIC::GenerateMegamorphic(MacroAssembler* masm, 1507 StrictModeFlag strict_mode) { 1508 // ----------- S t a t e ------------- 1509 // -- a0 : value 1510 // -- a1 : receiver 1511 // -- a2 : name 1512 // -- ra : return address 1513 // ----------------------------------- 1514 1515 // Get the receiver from the stack and probe the stub cache. 1516 Code::Flags flags = 1517 Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode); 1518 Isolate::Current()->stub_cache()->GenerateProbe( 1519 masm, flags, a1, a2, a3, t0, t1, t2); 1520 1521 // Cache miss: Jump to runtime. 1522 GenerateMiss(masm); 1523 } 1524 1525 1526 void StoreIC::GenerateMiss(MacroAssembler* masm) { 1527 // ----------- S t a t e ------------- 1528 // -- a0 : value 1529 // -- a1 : receiver 1530 // -- a2 : name 1531 // -- ra : return address 1532 // ----------------------------------- 1533 1534 __ Push(a1, a2, a0); 1535 // Perform tail call to the entry. 1536 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss), 1537 masm->isolate()); 1538 __ TailCallExternalReference(ref, 3, 1); 1539 } 1540 1541 1542 void StoreIC::GenerateArrayLength(MacroAssembler* masm) { 1543 // ----------- S t a t e ------------- 1544 // -- a0 : value 1545 // -- a1 : receiver 1546 // -- a2 : name 1547 // -- ra : return address 1548 // ----------------------------------- 1549 // 1550 // This accepts as a receiver anything JSArray::SetElementsLength accepts 1551 // (currently anything except for external arrays which means anything with 1552 // elements of FixedArray type). Value must be a number, but only smis are 1553 // accepted as the most common case. 1554 1555 Label miss; 1556 1557 Register receiver = a1; 1558 Register value = a0; 1559 Register scratch = a3; 1560 1561 // Check that the receiver isn't a smi. 1562 __ JumpIfSmi(receiver, &miss); 1563 1564 // Check that the object is a JS array. 1565 __ GetObjectType(receiver, scratch, scratch); 1566 __ Branch(&miss, ne, scratch, Operand(JS_ARRAY_TYPE)); 1567 1568 // Check that elements are FixedArray. 1569 // We rely on StoreIC_ArrayLength below to deal with all types of 1570 // fast elements (including COW). 1571 __ lw(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset)); 1572 __ GetObjectType(scratch, scratch, scratch); 1573 __ Branch(&miss, ne, scratch, Operand(FIXED_ARRAY_TYPE)); 1574 1575 // Check that the array has fast properties, otherwise the length 1576 // property might have been redefined. 1577 __ lw(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset)); 1578 __ lw(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset)); 1579 __ LoadRoot(at, Heap::kHashTableMapRootIndex); 1580 __ Branch(&miss, eq, scratch, Operand(at)); 1581 1582 // Check that value is a smi. 1583 __ JumpIfNotSmi(value, &miss); 1584 1585 // Prepare tail call to StoreIC_ArrayLength. 1586 __ Push(receiver, value); 1587 1588 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength), 1589 masm->isolate()); 1590 __ TailCallExternalReference(ref, 2, 1); 1591 1592 __ bind(&miss); 1593 1594 GenerateMiss(masm); 1595 } 1596 1597 1598 void StoreIC::GenerateNormal(MacroAssembler* masm) { 1599 // ----------- S t a t e ------------- 1600 // -- a0 : value 1601 // -- a1 : receiver 1602 // -- a2 : name 1603 // -- ra : return address 1604 // ----------------------------------- 1605 Label miss; 1606 1607 GenerateStringDictionaryReceiverCheck(masm, a1, a3, t0, t1, &miss); 1608 1609 GenerateDictionaryStore(masm, &miss, a3, a2, a0, t0, t1); 1610 Counters* counters = masm->isolate()->counters(); 1611 __ IncrementCounter(counters->store_normal_hit(), 1, t0, t1); 1612 __ Ret(); 1613 1614 __ bind(&miss); 1615 __ IncrementCounter(counters->store_normal_miss(), 1, t0, t1); 1616 GenerateMiss(masm); 1617 } 1618 1619 1620 void StoreIC::GenerateGlobalProxy(MacroAssembler* masm, 1621 StrictModeFlag strict_mode) { 1622 // ----------- S t a t e ------------- 1623 // -- a0 : value 1624 // -- a1 : receiver 1625 // -- a2 : name 1626 // -- ra : return address 1627 // ----------------------------------- 1628 1629 __ Push(a1, a2, a0); 1630 1631 __ li(a1, Operand(Smi::FromInt(NONE))); // PropertyAttributes. 1632 __ li(a0, Operand(Smi::FromInt(strict_mode))); 1633 __ Push(a1, a0); 1634 1635 // Do tail-call to runtime routine. 1636 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); 1637 } 1638 1639 1640 #undef __ 1641 1642 1643 Condition CompareIC::ComputeCondition(Token::Value op) { 1644 switch (op) { 1645 case Token::EQ_STRICT: 1646 case Token::EQ: 1647 return eq; 1648 case Token::LT: 1649 return lt; 1650 case Token::GT: 1651 return gt; 1652 case Token::LTE: 1653 return le; 1654 case Token::GTE: 1655 return ge; 1656 default: 1657 UNREACHABLE(); 1658 return kNoCondition; 1659 } 1660 } 1661 1662 1663 void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { 1664 HandleScope scope; 1665 Handle<Code> rewritten; 1666 State previous_state = GetState(); 1667 State state = TargetState(previous_state, false, x, y); 1668 if (state == GENERIC) { 1669 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, a1, a0); 1670 rewritten = stub.GetCode(); 1671 } else { 1672 ICCompareStub stub(op_, state); 1673 if (state == KNOWN_OBJECTS) { 1674 stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map())); 1675 } 1676 rewritten = stub.GetCode(); 1677 } 1678 set_target(*rewritten); 1679 1680 #ifdef DEBUG 1681 if (FLAG_trace_ic) { 1682 PrintF("[CompareIC (%s->%s)#%s]\n", 1683 GetStateName(previous_state), 1684 GetStateName(state), 1685 Token::Name(op_)); 1686 } 1687 #endif 1688 1689 // Activate inlined smi code. 1690 if (previous_state == UNINITIALIZED) { 1691 PatchInlinedSmiCode(address()); 1692 } 1693 } 1694 1695 1696 void PatchInlinedSmiCode(Address address) { 1697 Address andi_instruction_address = 1698 address + Assembler::kCallTargetAddressOffset; 1699 1700 // If the instruction following the call is not a andi at, rx, #yyy, nothing 1701 // was inlined. 1702 Instr instr = Assembler::instr_at(andi_instruction_address); 1703 if (!(Assembler::IsAndImmediate(instr) && 1704 Assembler::GetRt(instr) == (uint32_t)zero_reg.code())) { 1705 return; 1706 } 1707 1708 // The delta to the start of the map check instruction and the 1709 // condition code uses at the patched jump. 1710 int delta = Assembler::GetImmediate16(instr); 1711 delta += Assembler::GetRs(instr) * kImm16Mask; 1712 // If the delta is 0 the instruction is andi at, zero_reg, #0 which also 1713 // signals that nothing was inlined. 1714 if (delta == 0) { 1715 return; 1716 } 1717 1718 #ifdef DEBUG 1719 if (FLAG_trace_ic) { 1720 PrintF("[ patching ic at %p, andi=%p, delta=%d\n", 1721 address, andi_instruction_address, delta); 1722 } 1723 #endif 1724 1725 Address patch_address = 1726 andi_instruction_address - delta * Instruction::kInstrSize; 1727 Instr instr_at_patch = Assembler::instr_at(patch_address); 1728 Instr branch_instr = 1729 Assembler::instr_at(patch_address + Instruction::kInstrSize); 1730 ASSERT(Assembler::IsAndImmediate(instr_at_patch)); 1731 ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch)); 1732 ASSERT(Assembler::IsBranch(branch_instr)); 1733 if (Assembler::IsBeq(branch_instr)) { 1734 // This is patching a "jump if not smi" site to be active. 1735 // Changing: 1736 // andi at, rx, 0 1737 // Branch <target>, eq, at, Operand(zero_reg) 1738 // to: 1739 // andi at, rx, #kSmiTagMask 1740 // Branch <target>, ne, at, Operand(zero_reg) 1741 CodePatcher patcher(patch_address, 2); 1742 Register reg = Register::from_code(Assembler::GetRs(instr_at_patch)); 1743 patcher.masm()->andi(at, reg, kSmiTagMask); 1744 patcher.ChangeBranchCondition(ne); 1745 } else { 1746 ASSERT(Assembler::IsBne(branch_instr)); 1747 // This is patching a "jump if smi" site to be active. 1748 // Changing: 1749 // andi at, rx, 0 1750 // Branch <target>, ne, at, Operand(zero_reg) 1751 // to: 1752 // andi at, rx, #kSmiTagMask 1753 // Branch <target>, eq, at, Operand(zero_reg) 1754 CodePatcher patcher(patch_address, 2); 1755 Register reg = Register::from_code(Assembler::GetRs(instr_at_patch)); 1756 patcher.masm()->andi(at, reg, kSmiTagMask); 1757 patcher.ChangeBranchCondition(eq); 1758 } 1759 } 1760 1761 1762 } } // namespace v8::internal 1763 1764 #endif // V8_TARGET_ARCH_MIPS 1765