stub-cache-mips.cc revision 257744e915dfc84d6d07a6b2accf8402d9ffc708
1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include "v8.h" 29 30#if defined(V8_TARGET_ARCH_MIPS) 31 32#include "ic-inl.h" 33#include "codegen.h" 34#include "stub-cache.h" 35 36namespace v8 { 37namespace internal { 38 39#define __ ACCESS_MASM(masm) 40 41 42static void ProbeTable(Isolate* isolate, 43 MacroAssembler* masm, 44 Code::Flags flags, 45 StubCache::Table table, 46 Register name, 47 Register offset, 48 Register scratch, 49 Register scratch2) { 50 ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); 51 ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); 52 53 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address()); 54 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address()); 55 56 // Check the relative positions of the address fields. 57 ASSERT(value_off_addr > key_off_addr); 58 ASSERT((value_off_addr - key_off_addr) % 4 == 0); 59 ASSERT((value_off_addr - key_off_addr) < (256 * 4)); 60 61 Label miss; 62 Register offsets_base_addr = scratch; 63 64 // Check that the key in the entry matches the name. 65 __ li(offsets_base_addr, Operand(key_offset)); 66 __ sll(scratch2, offset, 1); 67 __ addu(scratch2, offsets_base_addr, scratch2); 68 __ lw(scratch2, MemOperand(scratch2)); 69 __ Branch(&miss, ne, name, Operand(scratch2)); 70 71 // Get the code entry from the cache. 72 __ Addu(offsets_base_addr, offsets_base_addr, 73 Operand(value_off_addr - key_off_addr)); 74 __ sll(scratch2, offset, 1); 75 __ addu(scratch2, offsets_base_addr, scratch2); 76 __ lw(scratch2, MemOperand(scratch2)); 77 78 // Check that the flags match what we're looking for. 79 __ lw(scratch2, FieldMemOperand(scratch2, Code::kFlagsOffset)); 80 __ And(scratch2, scratch2, Operand(~Code::kFlagsNotUsedInLookup)); 81 __ Branch(&miss, ne, scratch2, Operand(flags)); 82 83 // Re-load code entry from cache. 84 __ sll(offset, offset, 1); 85 __ addu(offset, offset, offsets_base_addr); 86 __ lw(offset, MemOperand(offset)); 87 88 // Jump to the first instruction in the code stub. 89 __ Addu(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag)); 90 __ Jump(offset); 91 92 // Miss: fall through. 93 __ bind(&miss); 94} 95 96 97// Helper function used to check that the dictionary doesn't contain 98// the property. This function may return false negatives, so miss_label 99// must always call a backup property check that is complete. 100// This function is safe to call if the receiver has fast properties. 101// Name must be a symbol and receiver must be a heap object. 102MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup( 103 MacroAssembler* masm, 104 Label* miss_label, 105 Register receiver, 106 String* name, 107 Register scratch0, 108 Register scratch1) { 109 ASSERT(name->IsSymbol()); 110 Counters* counters = masm->isolate()->counters(); 111 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); 112 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); 113 114 Label done; 115 116 const int kInterceptorOrAccessCheckNeededMask = 117 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); 118 119 // Bail out if the receiver has a named interceptor or requires access checks. 120 Register map = scratch1; 121 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); 122 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); 123 __ And(at, scratch0, Operand(kInterceptorOrAccessCheckNeededMask)); 124 __ Branch(miss_label, ne, at, Operand(zero_reg)); 125 126 127 // Check that receiver is a JSObject. 128 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); 129 __ Branch(miss_label, lt, scratch0, Operand(FIRST_JS_OBJECT_TYPE)); 130 131 // Load properties array. 132 Register properties = scratch0; 133 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); 134 // Check that the properties array is a dictionary. 135 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset)); 136 Register tmp = properties; 137 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); 138 __ Branch(miss_label, ne, map, Operand(tmp)); 139 140 // Restore the temporarily used register. 141 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); 142 143 MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup( 144 masm, 145 miss_label, 146 &done, 147 receiver, 148 properties, 149 name, 150 scratch1); 151 if (result->IsFailure()) return result; 152 153 __ bind(&done); 154 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); 155 156 return result; 157} 158 159 160void StubCache::GenerateProbe(MacroAssembler* masm, 161 Code::Flags flags, 162 Register receiver, 163 Register name, 164 Register scratch, 165 Register extra, 166 Register extra2) { 167 Isolate* isolate = masm->isolate(); 168 Label miss; 169 170 // Make sure that code is valid. The shifting code relies on the 171 // entry size being 8. 172 ASSERT(sizeof(Entry) == 8); 173 174 // Make sure the flags does not name a specific type. 175 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); 176 177 // Make sure that there are no register conflicts. 178 ASSERT(!scratch.is(receiver)); 179 ASSERT(!scratch.is(name)); 180 ASSERT(!extra.is(receiver)); 181 ASSERT(!extra.is(name)); 182 ASSERT(!extra.is(scratch)); 183 ASSERT(!extra2.is(receiver)); 184 ASSERT(!extra2.is(name)); 185 ASSERT(!extra2.is(scratch)); 186 ASSERT(!extra2.is(extra)); 187 188 // Check scratch, extra and extra2 registers are valid. 189 ASSERT(!scratch.is(no_reg)); 190 ASSERT(!extra.is(no_reg)); 191 ASSERT(!extra2.is(no_reg)); 192 193 // Check that the receiver isn't a smi. 194 __ JumpIfSmi(receiver, &miss, t0); 195 196 // Get the map of the receiver and compute the hash. 197 __ lw(scratch, FieldMemOperand(name, String::kHashFieldOffset)); 198 __ lw(t8, FieldMemOperand(receiver, HeapObject::kMapOffset)); 199 __ Addu(scratch, scratch, Operand(t8)); 200 __ Xor(scratch, scratch, Operand(flags)); 201 __ And(scratch, 202 scratch, 203 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize)); 204 205 // Probe the primary table. 206 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra, extra2); 207 208 // Primary miss: Compute hash for secondary probe. 209 __ Subu(scratch, scratch, Operand(name)); 210 __ Addu(scratch, scratch, Operand(flags)); 211 __ And(scratch, 212 scratch, 213 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize)); 214 215 // Probe the secondary table. 216 ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra, extra2); 217 218 // Cache miss: Fall-through and let caller handle the miss by 219 // entering the runtime system. 220 __ bind(&miss); 221} 222 223 224void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, 225 int index, 226 Register prototype) { 227 // Load the global or builtins object from the current context. 228 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 229 // Load the global context from the global or builtins object. 230 __ lw(prototype, 231 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset)); 232 // Load the function from the global context. 233 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index))); 234 // Load the initial map. The global functions all have initial maps. 235 __ lw(prototype, 236 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset)); 237 // Load the prototype from the initial map. 238 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); 239} 240 241 242void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( 243 MacroAssembler* masm, int index, Register prototype, Label* miss) { 244 Isolate* isolate = masm->isolate(); 245 // Check we're still in the same context. 246 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 247 ASSERT(!prototype.is(at)); 248 __ li(at, isolate->global()); 249 __ Branch(miss, ne, prototype, Operand(at)); 250 // Get the global function with the given index. 251 JSFunction* function = 252 JSFunction::cast(isolate->global_context()->get(index)); 253 // Load its initial map. The global functions all have initial maps. 254 __ li(prototype, Handle<Map>(function->initial_map())); 255 // Load the prototype from the initial map. 256 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); 257} 258 259 260// Load a fast property out of a holder object (src). In-object properties 261// are loaded directly otherwise the property is loaded from the properties 262// fixed array. 263void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, 264 Register dst, Register src, 265 JSObject* holder, int index) { 266 // Adjust for the number of properties stored in the holder. 267 index -= holder->map()->inobject_properties(); 268 if (index < 0) { 269 // Get the property straight out of the holder. 270 int offset = holder->map()->instance_size() + (index * kPointerSize); 271 __ lw(dst, FieldMemOperand(src, offset)); 272 } else { 273 // Calculate the offset into the properties array. 274 int offset = index * kPointerSize + FixedArray::kHeaderSize; 275 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset)); 276 __ lw(dst, FieldMemOperand(dst, offset)); 277 } 278} 279 280 281void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, 282 Register receiver, 283 Register scratch, 284 Label* miss_label) { 285 // Check that the receiver isn't a smi. 286 __ And(scratch, receiver, Operand(kSmiTagMask)); 287 __ Branch(miss_label, eq, scratch, Operand(zero_reg)); 288 289 // Check that the object is a JS array. 290 __ GetObjectType(receiver, scratch, scratch); 291 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE)); 292 293 // Load length directly from the JS array. 294 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 295 __ Ret(); 296} 297 298 299// Generate code to check if an object is a string. If the object is a 300// heap object, its map's instance type is left in the scratch1 register. 301// If this is not needed, scratch1 and scratch2 may be the same register. 302static void GenerateStringCheck(MacroAssembler* masm, 303 Register receiver, 304 Register scratch1, 305 Register scratch2, 306 Label* smi, 307 Label* non_string_object) { 308 // Check that the receiver isn't a smi. 309 __ JumpIfSmi(receiver, smi, t0); 310 311 // Check that the object is a string. 312 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); 313 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); 314 __ And(scratch2, scratch1, Operand(kIsNotStringMask)); 315 // The cast is to resolve the overload for the argument of 0x0. 316 __ Branch(non_string_object, 317 ne, 318 scratch2, 319 Operand(static_cast<int32_t>(kStringTag))); 320} 321 322 323// Generate code to load the length from a string object and return the length. 324// If the receiver object is not a string or a wrapped string object the 325// execution continues at the miss label. The register containing the 326// receiver is potentially clobbered. 327void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, 328 Register receiver, 329 Register scratch1, 330 Register scratch2, 331 Label* miss, 332 bool support_wrappers) { 333 Label check_wrapper; 334 335 // Check if the object is a string leaving the instance type in the 336 // scratch1 register. 337 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, 338 support_wrappers ? &check_wrapper : miss); 339 340 // Load length directly from the string. 341 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset)); 342 __ Ret(); 343 344 if (support_wrappers) { 345 // Check if the object is a JSValue wrapper. 346 __ bind(&check_wrapper); 347 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE)); 348 349 // Unwrap the value and check if the wrapped value is a string. 350 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset)); 351 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss); 352 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset)); 353 __ Ret(); 354 } 355} 356 357 358void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, 359 Register receiver, 360 Register scratch1, 361 Register scratch2, 362 Label* miss_label) { 363 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); 364 __ mov(v0, scratch1); 365 __ Ret(); 366} 367 368 369// Generate StoreField code, value is passed in a0 register. 370// After executing generated code, the receiver_reg and name_reg 371// may be clobbered. 372void StubCompiler::GenerateStoreField(MacroAssembler* masm, 373 JSObject* object, 374 int index, 375 Map* transition, 376 Register receiver_reg, 377 Register name_reg, 378 Register scratch, 379 Label* miss_label) { 380 // a0 : value. 381 Label exit; 382 383 // Check that the receiver isn't a smi. 384 __ JumpIfSmi(receiver_reg, miss_label, scratch); 385 386 // Check that the map of the receiver hasn't changed. 387 __ lw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); 388 __ Branch(miss_label, ne, scratch, Operand(Handle<Map>(object->map()))); 389 390 // Perform global security token check if needed. 391 if (object->IsJSGlobalProxy()) { 392 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); 393 } 394 395 // Stub never generated for non-global objects that require access 396 // checks. 397 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); 398 399 // Perform map transition for the receiver if necessary. 400 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) { 401 // The properties must be extended before we can store the value. 402 // We jump to a runtime call that extends the properties array. 403 __ push(receiver_reg); 404 __ li(a2, Operand(Handle<Map>(transition))); 405 __ Push(a2, a0); 406 __ TailCallExternalReference( 407 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), 408 masm->isolate()), 409 3, 1); 410 return; 411 } 412 413 if (transition != NULL) { 414 // Update the map of the object; no write barrier updating is 415 // needed because the map is never in new space. 416 __ li(t0, Operand(Handle<Map>(transition))); 417 __ sw(t0, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); 418 } 419 420 // Adjust for the number of properties stored in the object. Even in the 421 // face of a transition we can use the old map here because the size of the 422 // object and the number of in-object properties is not going to change. 423 index -= object->map()->inobject_properties(); 424 425 if (index < 0) { 426 // Set the property straight into the object. 427 int offset = object->map()->instance_size() + (index * kPointerSize); 428 __ sw(a0, FieldMemOperand(receiver_reg, offset)); 429 430 // Skip updating write barrier if storing a smi. 431 __ JumpIfSmi(a0, &exit, scratch); 432 433 // Update the write barrier for the array address. 434 // Pass the now unused name_reg as a scratch register. 435 __ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch); 436 } else { 437 // Write to the properties array. 438 int offset = index * kPointerSize + FixedArray::kHeaderSize; 439 // Get the properties array. 440 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); 441 __ sw(a0, FieldMemOperand(scratch, offset)); 442 443 // Skip updating write barrier if storing a smi. 444 __ JumpIfSmi(a0, &exit); 445 446 // Update the write barrier for the array address. 447 // Ok to clobber receiver_reg and name_reg, since we return. 448 __ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg); 449 } 450 451 // Return the value (register v0). 452 __ bind(&exit); 453 __ mov(v0, a0); 454 __ Ret(); 455} 456 457 458void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { 459 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); 460 Code* code = NULL; 461 if (kind == Code::LOAD_IC) { 462 code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss); 463 } else { 464 code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss); 465 } 466 467 Handle<Code> ic(code); 468 __ Jump(ic, RelocInfo::CODE_TARGET); 469} 470 471 472static void GenerateCallFunction(MacroAssembler* masm, 473 Object* object, 474 const ParameterCount& arguments, 475 Label* miss) { 476 // ----------- S t a t e ------------- 477 // -- a0: receiver 478 // -- a1: function to call 479 // ----------------------------------- 480 // Check that the function really is a function. 481 __ JumpIfSmi(a1, miss); 482 __ GetObjectType(a1, a3, a3); 483 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE)); 484 485 // Patch the receiver on the stack with the global proxy if 486 // necessary. 487 if (object->IsGlobalObject()) { 488 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset)); 489 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize)); 490 } 491 492 // Invoke the function. 493 __ InvokeFunction(a1, arguments, JUMP_FUNCTION); 494} 495 496 497static void PushInterceptorArguments(MacroAssembler* masm, 498 Register receiver, 499 Register holder, 500 Register name, 501 JSObject* holder_obj) { 502 __ push(name); 503 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); 504 ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor)); 505 Register scratch = name; 506 __ li(scratch, Operand(Handle<Object>(interceptor))); 507 __ Push(scratch, receiver, holder); 508 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset)); 509 __ push(scratch); 510} 511 512 513static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, 514 Register receiver, 515 Register holder, 516 Register name, 517 JSObject* holder_obj) { 518 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); 519 520 ExternalReference ref = 521 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), 522 masm->isolate()); 523 __ li(a0, Operand(5)); 524 __ li(a1, Operand(ref)); 525 526 CEntryStub stub(1); 527 __ CallStub(&stub); 528} 529 530 531static const int kFastApiCallArguments = 3; 532 533 534// Reserves space for the extra arguments to FastHandleApiCall in the 535// caller's frame. 536// 537// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall. 538static void ReserveSpaceForFastApiCall(MacroAssembler* masm, 539 Register scratch) { 540 ASSERT(Smi::FromInt(0) == 0); 541 for (int i = 0; i < kFastApiCallArguments; i++) { 542 __ push(zero_reg); 543 } 544} 545 546 547// Undoes the effects of ReserveSpaceForFastApiCall. 548static void FreeSpaceForFastApiCall(MacroAssembler* masm) { 549 __ Drop(kFastApiCallArguments); 550} 551 552 553static MaybeObject* GenerateFastApiDirectCall(MacroAssembler* masm, 554 const CallOptimization& optimization, 555 int argc) { 556 // ----------- S t a t e ------------- 557 // -- sp[0] : holder (set by CheckPrototypes) 558 // -- sp[4] : callee js function 559 // -- sp[8] : call data 560 // -- sp[12] : last js argument 561 // -- ... 562 // -- sp[(argc + 3) * 4] : first js argument 563 // -- sp[(argc + 4) * 4] : receiver 564 // ----------------------------------- 565 // Get the function and setup the context. 566 JSFunction* function = optimization.constant_function(); 567 __ li(t1, Operand(Handle<JSFunction>(function))); 568 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset)); 569 570 // Pass the additional arguments FastHandleApiCall expects. 571 Object* call_data = optimization.api_call_info()->data(); 572 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); 573 if (masm->isolate()->heap()->InNewSpace(call_data)) { 574 __ li(a0, api_call_info_handle); 575 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset)); 576 } else { 577 __ li(t2, Operand(Handle<Object>(call_data))); 578 } 579 580 // Store js function and call data. 581 __ sw(t1, MemOperand(sp, 1 * kPointerSize)); 582 __ sw(t2, MemOperand(sp, 2 * kPointerSize)); 583 584 // a2 points to call data as expected by Arguments 585 // (refer to layout above). 586 __ Addu(a2, sp, Operand(2 * kPointerSize)); 587 588 Object* callback = optimization.api_call_info()->callback(); 589 Address api_function_address = v8::ToCData<Address>(callback); 590 ApiFunction fun(api_function_address); 591 592 const int kApiStackSpace = 4; 593 594 __ EnterExitFrame(false, kApiStackSpace); 595 596 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a 597 // struct from the function (which is currently the case). This means we pass 598 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn 599 // will handle setting up a0. 600 601 // a1 = v8::Arguments& 602 // Arguments is built at sp + 1 (sp is a reserved spot for ra). 603 __ Addu(a1, sp, kPointerSize); 604 605 // v8::Arguments::implicit_args = data 606 __ sw(a2, MemOperand(a1, 0 * kPointerSize)); 607 // v8::Arguments::values = last argument 608 __ Addu(t0, a2, Operand(argc * kPointerSize)); 609 __ sw(t0, MemOperand(a1, 1 * kPointerSize)); 610 // v8::Arguments::length_ = argc 611 __ li(t0, Operand(argc)); 612 __ sw(t0, MemOperand(a1, 2 * kPointerSize)); 613 // v8::Arguments::is_construct_call = 0 614 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize)); 615 616 // Emitting a stub call may try to allocate (if the code is not 617 // already generated). Do not allow the assembler to perform a 618 // garbage collection but instead return the allocation failure 619 // object. 620 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1; 621 ExternalReference ref = 622 ExternalReference(&fun, 623 ExternalReference::DIRECT_API_CALL, 624 masm->isolate()); 625 return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace); 626} 627 628class CallInterceptorCompiler BASE_EMBEDDED { 629 public: 630 CallInterceptorCompiler(StubCompiler* stub_compiler, 631 const ParameterCount& arguments, 632 Register name) 633 : stub_compiler_(stub_compiler), 634 arguments_(arguments), 635 name_(name) {} 636 637 MaybeObject* Compile(MacroAssembler* masm, 638 JSObject* object, 639 JSObject* holder, 640 String* name, 641 LookupResult* lookup, 642 Register receiver, 643 Register scratch1, 644 Register scratch2, 645 Register scratch3, 646 Label* miss) { 647 ASSERT(holder->HasNamedInterceptor()); 648 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); 649 650 // Check that the receiver isn't a smi. 651 __ JumpIfSmi(receiver, miss); 652 653 CallOptimization optimization(lookup); 654 655 if (optimization.is_constant_call()) { 656 return CompileCacheable(masm, 657 object, 658 receiver, 659 scratch1, 660 scratch2, 661 scratch3, 662 holder, 663 lookup, 664 name, 665 optimization, 666 miss); 667 } else { 668 CompileRegular(masm, 669 object, 670 receiver, 671 scratch1, 672 scratch2, 673 scratch3, 674 name, 675 holder, 676 miss); 677 return masm->isolate()->heap()->undefined_value(); 678 } 679 } 680 681 private: 682 MaybeObject* CompileCacheable(MacroAssembler* masm, 683 JSObject* object, 684 Register receiver, 685 Register scratch1, 686 Register scratch2, 687 Register scratch3, 688 JSObject* interceptor_holder, 689 LookupResult* lookup, 690 String* name, 691 const CallOptimization& optimization, 692 Label* miss_label) { 693 ASSERT(optimization.is_constant_call()); 694 ASSERT(!lookup->holder()->IsGlobalObject()); 695 696 Counters* counters = masm->isolate()->counters(); 697 698 int depth1 = kInvalidProtoDepth; 699 int depth2 = kInvalidProtoDepth; 700 bool can_do_fast_api_call = false; 701 if (optimization.is_simple_api_call() && 702 !lookup->holder()->IsGlobalObject()) { 703 depth1 = 704 optimization.GetPrototypeDepthOfExpectedType(object, 705 interceptor_holder); 706 if (depth1 == kInvalidProtoDepth) { 707 depth2 = 708 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, 709 lookup->holder()); 710 } 711 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || 712 (depth2 != kInvalidProtoDepth); 713 } 714 715 __ IncrementCounter(counters->call_const_interceptor(), 1, 716 scratch1, scratch2); 717 718 if (can_do_fast_api_call) { 719 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1, 720 scratch1, scratch2); 721 ReserveSpaceForFastApiCall(masm, scratch1); 722 } 723 724 // Check that the maps from receiver to interceptor's holder 725 // haven't changed and thus we can invoke interceptor. 726 Label miss_cleanup; 727 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; 728 Register holder = 729 stub_compiler_->CheckPrototypes(object, receiver, 730 interceptor_holder, scratch1, 731 scratch2, scratch3, name, depth1, miss); 732 733 // Invoke an interceptor and if it provides a value, 734 // branch to |regular_invoke|. 735 Label regular_invoke; 736 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, 737 ®ular_invoke); 738 739 // Interceptor returned nothing for this property. Try to use cached 740 // constant function. 741 742 // Check that the maps from interceptor's holder to constant function's 743 // holder haven't changed and thus we can use cached constant function. 744 if (interceptor_holder != lookup->holder()) { 745 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, 746 lookup->holder(), scratch1, 747 scratch2, scratch3, name, depth2, miss); 748 } else { 749 // CheckPrototypes has a side effect of fetching a 'holder' 750 // for API (object which is instanceof for the signature). It's 751 // safe to omit it here, as if present, it should be fetched 752 // by the previous CheckPrototypes. 753 ASSERT(depth2 == kInvalidProtoDepth); 754 } 755 756 // Invoke function. 757 if (can_do_fast_api_call) { 758 MaybeObject* result = GenerateFastApiDirectCall(masm, 759 optimization, 760 arguments_.immediate()); 761 if (result->IsFailure()) return result; 762 } else { 763 __ InvokeFunction(optimization.constant_function(), arguments_, 764 JUMP_FUNCTION); 765 } 766 767 // Deferred code for fast API call case---clean preallocated space. 768 if (can_do_fast_api_call) { 769 __ bind(&miss_cleanup); 770 FreeSpaceForFastApiCall(masm); 771 __ Branch(miss_label); 772 } 773 774 // Invoke a regular function. 775 __ bind(®ular_invoke); 776 if (can_do_fast_api_call) { 777 FreeSpaceForFastApiCall(masm); 778 } 779 780 return masm->isolate()->heap()->undefined_value(); 781 } 782 783 void CompileRegular(MacroAssembler* masm, 784 JSObject* object, 785 Register receiver, 786 Register scratch1, 787 Register scratch2, 788 Register scratch3, 789 String* name, 790 JSObject* interceptor_holder, 791 Label* miss_label) { 792 Register holder = 793 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, 794 scratch1, scratch2, scratch3, name, 795 miss_label); 796 797 // Call a runtime function to load the interceptor property. 798 __ EnterInternalFrame(); 799 // Save the name_ register across the call. 800 __ push(name_); 801 802 PushInterceptorArguments(masm, 803 receiver, 804 holder, 805 name_, 806 interceptor_holder); 807 808 __ CallExternalReference( 809 ExternalReference( 810 IC_Utility(IC::kLoadPropertyWithInterceptorForCall), 811 masm->isolate()), 812 5); 813 814 // Restore the name_ register. 815 __ pop(name_); 816 __ LeaveInternalFrame(); 817 } 818 819 void LoadWithInterceptor(MacroAssembler* masm, 820 Register receiver, 821 Register holder, 822 JSObject* holder_obj, 823 Register scratch, 824 Label* interceptor_succeeded) { 825 __ EnterInternalFrame(); 826 827 __ Push(holder, name_); 828 829 CompileCallLoadPropertyWithInterceptor(masm, 830 receiver, 831 holder, 832 name_, 833 holder_obj); 834 835 __ pop(name_); // Restore the name. 836 __ pop(receiver); // Restore the holder. 837 __ LeaveInternalFrame(); 838 839 // If interceptor returns no-result sentinel, call the constant function. 840 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex); 841 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch)); 842 } 843 844 StubCompiler* stub_compiler_; 845 const ParameterCount& arguments_; 846 Register name_; 847}; 848 849 850 851// Generate code to check that a global property cell is empty. Create 852// the property cell at compilation time if no cell exists for the 853// property. 854MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell( 855 MacroAssembler* masm, 856 GlobalObject* global, 857 String* name, 858 Register scratch, 859 Label* miss) { 860 Object* probe; 861 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name); 862 if (!maybe_probe->ToObject(&probe)) return maybe_probe; 863 } 864 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); 865 ASSERT(cell->value()->IsTheHole()); 866 __ li(scratch, Operand(Handle<Object>(cell))); 867 __ lw(scratch, 868 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); 869 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); 870 __ Branch(miss, ne, scratch, Operand(at)); 871 return cell; 872} 873 874 875// Calls GenerateCheckPropertyCell for each global object in the prototype chain 876// from object to (but not including) holder. 877MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells( 878 MacroAssembler* masm, 879 JSObject* object, 880 JSObject* holder, 881 String* name, 882 Register scratch, 883 Label* miss) { 884 JSObject* current = object; 885 while (current != holder) { 886 if (current->IsGlobalObject()) { 887 // Returns a cell or a failure. 888 MaybeObject* result = GenerateCheckPropertyCell( 889 masm, 890 GlobalObject::cast(current), 891 name, 892 scratch, 893 miss); 894 if (result->IsFailure()) return result; 895 } 896 ASSERT(current->IsJSObject()); 897 current = JSObject::cast(current->GetPrototype()); 898 } 899 return NULL; 900} 901 902 903// Convert and store int passed in register ival to IEEE 754 single precision 904// floating point value at memory location (dst + 4 * wordoffset) 905// If FPU is available use it for conversion. 906static void StoreIntAsFloat(MacroAssembler* masm, 907 Register dst, 908 Register wordoffset, 909 Register ival, 910 Register fval, 911 Register scratch1, 912 Register scratch2) { 913 if (CpuFeatures::IsSupported(FPU)) { 914 CpuFeatures::Scope scope(FPU); 915 __ mtc1(ival, f0); 916 __ cvt_s_w(f0, f0); 917 __ sll(scratch1, wordoffset, 2); 918 __ addu(scratch1, dst, scratch1); 919 __ swc1(f0, MemOperand(scratch1, 0)); 920 } else { 921 // FPU is not available, do manual conversions. 922 923 Label not_special, done; 924 // Move sign bit from source to destination. This works because the sign 925 // bit in the exponent word of the double has the same position and polarity 926 // as the 2's complement sign bit in a Smi. 927 ASSERT(kBinary32SignMask == 0x80000000u); 928 929 __ And(fval, ival, Operand(kBinary32SignMask)); 930 // Negate value if it is negative. 931 __ subu(scratch1, zero_reg, ival); 932 __ movn(ival, scratch1, fval); 933 934 // We have -1, 0 or 1, which we treat specially. Register ival contains 935 // absolute value: it is either equal to 1 (special case of -1 and 1), 936 // greater than 1 (not a special case) or less than 1 (special case of 0). 937 __ Branch(¬_special, gt, ival, Operand(1)); 938 939 // For 1 or -1 we need to or in the 0 exponent (biased). 940 static const uint32_t exponent_word_for_1 = 941 kBinary32ExponentBias << kBinary32ExponentShift; 942 943 __ Xor(scratch1, ival, Operand(1)); 944 __ li(scratch2, exponent_word_for_1); 945 __ or_(scratch2, fval, scratch2); 946 __ movz(fval, scratch2, scratch1); // Only if ival is equal to 1. 947 __ Branch(&done); 948 949 __ bind(¬_special); 950 // Count leading zeros. 951 // Gets the wrong answer for 0, but we already checked for that case above. 952 Register zeros = scratch2; 953 __ clz(zeros, ival); 954 955 // Compute exponent and or it into the exponent register. 956 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias); 957 __ subu(scratch1, scratch1, zeros); 958 959 __ sll(scratch1, scratch1, kBinary32ExponentShift); 960 __ or_(fval, fval, scratch1); 961 962 // Shift up the source chopping the top bit off. 963 __ Addu(zeros, zeros, Operand(1)); 964 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0. 965 __ sllv(ival, ival, zeros); 966 // And the top (top 20 bits). 967 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits); 968 __ or_(fval, fval, scratch1); 969 970 __ bind(&done); 971 972 __ sll(scratch1, wordoffset, 2); 973 __ addu(scratch1, dst, scratch1); 974 __ sw(fval, MemOperand(scratch1, 0)); 975 } 976} 977 978 979// Convert unsigned integer with specified number of leading zeroes in binary 980// representation to IEEE 754 double. 981// Integer to convert is passed in register hiword. 982// Resulting double is returned in registers hiword:loword. 983// This functions does not work correctly for 0. 984static void GenerateUInt2Double(MacroAssembler* masm, 985 Register hiword, 986 Register loword, 987 Register scratch, 988 int leading_zeroes) { 989 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1; 990 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits; 991 992 const int mantissa_shift_for_hi_word = 993 meaningful_bits - HeapNumber::kMantissaBitsInTopWord; 994 995 const int mantissa_shift_for_lo_word = 996 kBitsPerInt - mantissa_shift_for_hi_word; 997 998 __ li(scratch, biased_exponent << HeapNumber::kExponentShift); 999 if (mantissa_shift_for_hi_word > 0) { 1000 __ sll(loword, hiword, mantissa_shift_for_lo_word); 1001 __ srl(hiword, hiword, mantissa_shift_for_hi_word); 1002 __ or_(hiword, scratch, hiword); 1003 } else { 1004 __ mov(loword, zero_reg); 1005 __ sll(hiword, hiword, mantissa_shift_for_hi_word); 1006 __ or_(hiword, scratch, hiword); 1007 } 1008 1009 // If least significant bit of biased exponent was not 1 it was corrupted 1010 // by most significant bit of mantissa so we should fix that. 1011 if (!(biased_exponent & 1)) { 1012 __ li(scratch, 1 << HeapNumber::kExponentShift); 1013 __ nor(scratch, scratch, scratch); 1014 __ and_(hiword, hiword, scratch); 1015 } 1016} 1017 1018 1019#undef __ 1020#define __ ACCESS_MASM(masm()) 1021 1022 1023Register StubCompiler::CheckPrototypes(JSObject* object, 1024 Register object_reg, 1025 JSObject* holder, 1026 Register holder_reg, 1027 Register scratch1, 1028 Register scratch2, 1029 String* name, 1030 int save_at_depth, 1031 Label* miss) { 1032 // Make sure there's no overlap between holder and object registers. 1033 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); 1034 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) 1035 && !scratch2.is(scratch1)); 1036 1037 // Keep track of the current object in register reg. 1038 Register reg = object_reg; 1039 int depth = 0; 1040 1041 if (save_at_depth == depth) { 1042 __ sw(reg, MemOperand(sp)); 1043 } 1044 1045 // Check the maps in the prototype chain. 1046 // Traverse the prototype chain from the object and do map checks. 1047 JSObject* current = object; 1048 while (current != holder) { 1049 depth++; 1050 1051 // Only global objects and objects that do not require access 1052 // checks are allowed in stubs. 1053 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); 1054 1055 ASSERT(current->GetPrototype()->IsJSObject()); 1056 JSObject* prototype = JSObject::cast(current->GetPrototype()); 1057 if (!current->HasFastProperties() && 1058 !current->IsJSGlobalObject() && 1059 !current->IsJSGlobalProxy()) { 1060 if (!name->IsSymbol()) { 1061 MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name); 1062 Object* lookup_result = NULL; // Initialization to please compiler. 1063 if (!maybe_lookup_result->ToObject(&lookup_result)) { 1064 set_failure(Failure::cast(maybe_lookup_result)); 1065 return reg; 1066 } 1067 name = String::cast(lookup_result); 1068 } 1069 ASSERT(current->property_dictionary()->FindEntry(name) == 1070 StringDictionary::kNotFound); 1071 1072 MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(), 1073 miss, 1074 reg, 1075 name, 1076 scratch1, 1077 scratch2); 1078 if (negative_lookup->IsFailure()) { 1079 set_failure(Failure::cast(negative_lookup)); 1080 return reg; 1081 } 1082 1083 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); 1084 reg = holder_reg; // From now the object is in holder_reg. 1085 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); 1086 } else if (heap()->InNewSpace(prototype)) { 1087 // Get the map of the current object. 1088 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); 1089 1090 // Branch on the result of the map check. 1091 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map()))); 1092 1093 // Check access rights to the global object. This has to happen 1094 // after the map check so that we know that the object is 1095 // actually a global object. 1096 if (current->IsJSGlobalProxy()) { 1097 __ CheckAccessGlobalProxy(reg, scratch1, miss); 1098 // Restore scratch register to be the map of the object. In the 1099 // new space case below, we load the prototype from the map in 1100 // the scratch register. 1101 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); 1102 } 1103 1104 reg = holder_reg; // From now the object is in holder_reg. 1105 // The prototype is in new space; we cannot store a reference 1106 // to it in the code. Load it from the map. 1107 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); 1108 } else { 1109 // Check the map of the current object. 1110 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); 1111 // Branch on the result of the map check. 1112 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map()))); 1113 // Check access rights to the global object. This has to happen 1114 // after the map check so that we know that the object is 1115 // actually a global object. 1116 if (current->IsJSGlobalProxy()) { 1117 __ CheckAccessGlobalProxy(reg, scratch1, miss); 1118 } 1119 // The prototype is in old space; load it directly. 1120 reg = holder_reg; // From now the object is in holder_reg. 1121 __ li(reg, Operand(Handle<JSObject>(prototype))); 1122 } 1123 1124 if (save_at_depth == depth) { 1125 __ sw(reg, MemOperand(sp)); 1126 } 1127 1128 // Go to the next object in the prototype chain. 1129 current = prototype; 1130 } 1131 1132 // Check the holder map. 1133 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); 1134 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map()))); 1135 1136 // Log the check depth. 1137 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1)); 1138 // Perform security check for access to the global object. 1139 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); 1140 if (holder->IsJSGlobalProxy()) { 1141 __ CheckAccessGlobalProxy(reg, scratch1, miss); 1142 }; 1143 1144 // If we've skipped any global objects, it's not enough to verify 1145 // that their maps haven't changed. We also need to check that the 1146 // property cell for the property is still empty. 1147 1148 MaybeObject* result = GenerateCheckPropertyCells(masm(), 1149 object, 1150 holder, 1151 name, 1152 scratch1, 1153 miss); 1154 if (result->IsFailure()) set_failure(Failure::cast(result)); 1155 1156 // Return the register containing the holder. 1157 return reg; 1158} 1159 1160 1161void StubCompiler::GenerateLoadField(JSObject* object, 1162 JSObject* holder, 1163 Register receiver, 1164 Register scratch1, 1165 Register scratch2, 1166 Register scratch3, 1167 int index, 1168 String* name, 1169 Label* miss) { 1170 // Check that the receiver isn't a smi. 1171 __ And(scratch1, receiver, Operand(kSmiTagMask)); 1172 __ Branch(miss, eq, scratch1, Operand(zero_reg)); 1173 1174 // Check that the maps haven't changed. 1175 Register reg = 1176 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3, 1177 name, miss); 1178 GenerateFastPropertyLoad(masm(), v0, reg, holder, index); 1179 __ Ret(); 1180} 1181 1182 1183void StubCompiler::GenerateLoadConstant(JSObject* object, 1184 JSObject* holder, 1185 Register receiver, 1186 Register scratch1, 1187 Register scratch2, 1188 Register scratch3, 1189 Object* value, 1190 String* name, 1191 Label* miss) { 1192 // Check that the receiver isn't a smi. 1193 __ JumpIfSmi(receiver, miss, scratch1); 1194 1195 // Check that the maps haven't changed. 1196 Register reg = 1197 CheckPrototypes(object, receiver, holder, 1198 scratch1, scratch2, scratch3, name, miss); 1199 1200 // Return the constant value. 1201 __ li(v0, Operand(Handle<Object>(value))); 1202 __ Ret(); 1203} 1204 1205 1206MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, 1207 JSObject* holder, 1208 Register receiver, 1209 Register name_reg, 1210 Register scratch1, 1211 Register scratch2, 1212 Register scratch3, 1213 AccessorInfo* callback, 1214 String* name, 1215 Label* miss) { 1216 // Check that the receiver isn't a smi. 1217 __ JumpIfSmi(receiver, miss, scratch1); 1218 1219 // Check that the maps haven't changed. 1220 Register reg = 1221 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3, 1222 name, miss); 1223 1224 // Build AccessorInfo::args_ list on the stack and push property name below 1225 // the exit frame to make GC aware of them and store pointers to them. 1226 __ push(receiver); 1227 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_ 1228 Handle<AccessorInfo> callback_handle(callback); 1229 if (heap()->InNewSpace(callback_handle->data())) { 1230 __ li(scratch3, callback_handle); 1231 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset)); 1232 } else { 1233 __ li(scratch3, Handle<Object>(callback_handle->data())); 1234 } 1235 __ Push(reg, scratch3, name_reg); 1236 __ mov(a2, scratch2); // Saved in case scratch2 == a1. 1237 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String> 1238 1239 Address getter_address = v8::ToCData<Address>(callback->getter()); 1240 ApiFunction fun(getter_address); 1241 1242 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a 1243 // struct from the function (which is currently the case). This means we pass 1244 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn 1245 // will handle setting up a0. 1246 1247 const int kApiStackSpace = 1; 1248 1249 __ EnterExitFrame(false, kApiStackSpace); 1250 // Create AccessorInfo instance on the stack above the exit frame with 1251 // scratch2 (internal::Object **args_) as the data. 1252 __ sw(a2, MemOperand(sp, kPointerSize)); 1253 // a2 (second argument - see note above) = AccessorInfo& 1254 __ Addu(a2, sp, kPointerSize); 1255 1256 // Emitting a stub call may try to allocate (if the code is not 1257 // already generated). Do not allow the assembler to perform a 1258 // garbage collection but instead return the allocation failure 1259 // object. 1260 ExternalReference ref = 1261 ExternalReference(&fun, 1262 ExternalReference::DIRECT_GETTER_CALL, 1263 masm()->isolate()); 1264 // 4 args - will be freed later by LeaveExitFrame. 1265 return masm()->TryCallApiFunctionAndReturn(ref, 4); 1266} 1267 1268 1269void StubCompiler::GenerateLoadInterceptor(JSObject* object, 1270 JSObject* interceptor_holder, 1271 LookupResult* lookup, 1272 Register receiver, 1273 Register name_reg, 1274 Register scratch1, 1275 Register scratch2, 1276 Register scratch3, 1277 String* name, 1278 Label* miss) { 1279 ASSERT(interceptor_holder->HasNamedInterceptor()); 1280 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); 1281 1282 // Check that the receiver isn't a smi. 1283 __ JumpIfSmi(receiver, miss); 1284 1285 // So far the most popular follow ups for interceptor loads are FIELD 1286 // and CALLBACKS, so inline only them, other cases may be added 1287 // later. 1288 bool compile_followup_inline = false; 1289 if (lookup->IsProperty() && lookup->IsCacheable()) { 1290 if (lookup->type() == FIELD) { 1291 compile_followup_inline = true; 1292 } else if (lookup->type() == CALLBACKS && 1293 lookup->GetCallbackObject()->IsAccessorInfo() && 1294 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) { 1295 compile_followup_inline = true; 1296 } 1297 } 1298 1299 if (compile_followup_inline) { 1300 // Compile the interceptor call, followed by inline code to load the 1301 // property from further up the prototype chain if the call fails. 1302 // Check that the maps haven't changed. 1303 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, 1304 scratch1, scratch2, scratch3, 1305 name, miss); 1306 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); 1307 1308 // Save necessary data before invoking an interceptor. 1309 // Requires a frame to make GC aware of pushed pointers. 1310 __ EnterInternalFrame(); 1311 1312 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { 1313 // CALLBACKS case needs a receiver to be passed into C++ callback. 1314 __ Push(receiver, holder_reg, name_reg); 1315 } else { 1316 __ Push(holder_reg, name_reg); 1317 } 1318 1319 // Invoke an interceptor. Note: map checks from receiver to 1320 // interceptor's holder has been compiled before (see a caller 1321 // of this method). 1322 CompileCallLoadPropertyWithInterceptor(masm(), 1323 receiver, 1324 holder_reg, 1325 name_reg, 1326 interceptor_holder); 1327 1328 // Check if interceptor provided a value for property. If it's 1329 // the case, return immediately. 1330 Label interceptor_failed; 1331 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); 1332 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1)); 1333 __ LeaveInternalFrame(); 1334 __ Ret(); 1335 1336 __ bind(&interceptor_failed); 1337 __ pop(name_reg); 1338 __ pop(holder_reg); 1339 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { 1340 __ pop(receiver); 1341 } 1342 1343 __ LeaveInternalFrame(); 1344 1345 // Check that the maps from interceptor's holder to lookup's holder 1346 // haven't changed. And load lookup's holder into |holder| register. 1347 if (interceptor_holder != lookup->holder()) { 1348 holder_reg = CheckPrototypes(interceptor_holder, 1349 holder_reg, 1350 lookup->holder(), 1351 scratch1, 1352 scratch2, 1353 scratch3, 1354 name, 1355 miss); 1356 } 1357 1358 if (lookup->type() == FIELD) { 1359 // We found FIELD property in prototype chain of interceptor's holder. 1360 // Retrieve a field from field's holder. 1361 GenerateFastPropertyLoad(masm(), v0, holder_reg, 1362 lookup->holder(), lookup->GetFieldIndex()); 1363 __ Ret(); 1364 } else { 1365 // We found CALLBACKS property in prototype chain of interceptor's 1366 // holder. 1367 ASSERT(lookup->type() == CALLBACKS); 1368 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); 1369 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); 1370 ASSERT(callback != NULL); 1371 ASSERT(callback->getter() != NULL); 1372 1373 // Tail call to runtime. 1374 // Important invariant in CALLBACKS case: the code above must be 1375 // structured to never clobber |receiver| register. 1376 __ li(scratch2, Handle<AccessorInfo>(callback)); 1377 // holder_reg is either receiver or scratch1. 1378 if (!receiver.is(holder_reg)) { 1379 ASSERT(scratch1.is(holder_reg)); 1380 __ Push(receiver, holder_reg); 1381 __ lw(scratch3, 1382 FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); 1383 __ Push(scratch3, scratch2, name_reg); 1384 } else { 1385 __ push(receiver); 1386 __ lw(scratch3, 1387 FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); 1388 __ Push(holder_reg, scratch3, scratch2, name_reg); 1389 } 1390 1391 ExternalReference ref = 1392 ExternalReference(IC_Utility(IC::kLoadCallbackProperty), 1393 masm()->isolate()); 1394 __ TailCallExternalReference(ref, 5, 1); 1395 } 1396 } else { // !compile_followup_inline 1397 // Call the runtime system to load the interceptor. 1398 // Check that the maps haven't changed. 1399 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, 1400 scratch1, scratch2, scratch3, 1401 name, miss); 1402 PushInterceptorArguments(masm(), receiver, holder_reg, 1403 name_reg, interceptor_holder); 1404 1405 ExternalReference ref = ExternalReference( 1406 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate()); 1407 __ TailCallExternalReference(ref, 5, 1); 1408 } 1409} 1410 1411 1412void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { 1413 if (kind_ == Code::KEYED_CALL_IC) { 1414 __ Branch(miss, ne, a2, Operand(Handle<String>(name))); 1415 } 1416} 1417 1418 1419void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, 1420 JSObject* holder, 1421 String* name, 1422 Label* miss) { 1423 ASSERT(holder->IsGlobalObject()); 1424 1425 // Get the number of arguments. 1426 const int argc = arguments().immediate(); 1427 1428 // Get the receiver from the stack. 1429 __ lw(a0, MemOperand(sp, argc * kPointerSize)); 1430 1431 // If the object is the holder then we know that it's a global 1432 // object which can only happen for contextual calls. In this case, 1433 // the receiver cannot be a smi. 1434 if (object != holder) { 1435 __ JumpIfSmi(a0, miss); 1436 } 1437 1438 // Check that the maps haven't changed. 1439 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss); 1440} 1441 1442 1443void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, 1444 JSFunction* function, 1445 Label* miss) { 1446 // Get the value from the cell. 1447 __ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell))); 1448 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset)); 1449 1450 // Check that the cell contains the same function. 1451 if (heap()->InNewSpace(function)) { 1452 // We can't embed a pointer to a function in new space so we have 1453 // to verify that the shared function info is unchanged. This has 1454 // the nice side effect that multiple closures based on the same 1455 // function can all use this call IC. Before we load through the 1456 // function, we have to verify that it still is a function. 1457 __ JumpIfSmi(a1, miss); 1458 __ GetObjectType(a1, a3, a3); 1459 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE)); 1460 1461 // Check the shared function info. Make sure it hasn't changed. 1462 __ li(a3, Handle<SharedFunctionInfo>(function->shared())); 1463 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); 1464 __ Branch(miss, ne, t0, Operand(a3)); 1465 } else { 1466 __ Branch(miss, ne, a1, Operand(Handle<JSFunction>(function))); 1467 } 1468} 1469 1470 1471MaybeObject* CallStubCompiler::GenerateMissBranch() { 1472 MaybeObject* maybe_obj = 1473 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), 1474 kind_, 1475 extra_ic_state_); 1476 Object* obj; 1477 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1478 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); 1479 return obj; 1480} 1481 1482 1483MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, 1484 JSObject* holder, 1485 int index, 1486 String* name) { 1487 // ----------- S t a t e ------------- 1488 // -- a2 : name 1489 // -- ra : return address 1490 // ----------------------------------- 1491 Label miss; 1492 1493 GenerateNameCheck(name, &miss); 1494 1495 const int argc = arguments().immediate(); 1496 1497 // Get the receiver of the function from the stack into a0. 1498 __ lw(a0, MemOperand(sp, argc * kPointerSize)); 1499 // Check that the receiver isn't a smi. 1500 __ JumpIfSmi(a0, &miss, t0); 1501 1502 // Do the right check and compute the holder register. 1503 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss); 1504 GenerateFastPropertyLoad(masm(), a1, reg, holder, index); 1505 1506 GenerateCallFunction(masm(), object, arguments(), &miss); 1507 1508 // Handle call cache miss. 1509 __ bind(&miss); 1510 MaybeObject* maybe_result = GenerateMissBranch(); 1511 if (maybe_result->IsFailure()) return maybe_result; 1512 1513 // Return the generated code. 1514 return GetCode(FIELD, name); 1515} 1516 1517 1518MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, 1519 JSObject* holder, 1520 JSGlobalPropertyCell* cell, 1521 JSFunction* function, 1522 String* name) { 1523 // ----------- S t a t e ------------- 1524 // -- a2 : name 1525 // -- ra : return address 1526 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) 1527 // -- ... 1528 // -- sp[argc * 4] : receiver 1529 // ----------------------------------- 1530 1531 // If object is not an array, bail out to regular call. 1532 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value(); 1533 1534 Label miss; 1535 1536 GenerateNameCheck(name, &miss); 1537 1538 Register receiver = a1; 1539 1540 // Get the receiver from the stack. 1541 const int argc = arguments().immediate(); 1542 __ lw(receiver, MemOperand(sp, argc * kPointerSize)); 1543 1544 // Check that the receiver isn't a smi. 1545 __ JumpIfSmi(receiver, &miss); 1546 1547 // Check that the maps haven't changed. 1548 CheckPrototypes(JSObject::cast(object), receiver, 1549 holder, a3, v0, t0, name, &miss); 1550 1551 if (argc == 0) { 1552 // Nothing to do, just return the length. 1553 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1554 __ Drop(argc + 1); 1555 __ Ret(); 1556 } else { 1557 Label call_builtin; 1558 1559 Register elements = a3; 1560 Register end_elements = t1; 1561 1562 // Get the elements array of the object. 1563 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); 1564 1565 // Check that the elements are in fast mode and writable. 1566 __ CheckMap(elements, 1567 v0, 1568 Heap::kFixedArrayMapRootIndex, 1569 &call_builtin, 1570 DONT_DO_SMI_CHECK); 1571 1572 if (argc == 1) { // Otherwise fall through to call the builtin. 1573 Label exit, with_write_barrier, attempt_to_grow_elements; 1574 1575 // Get the array's length into v0 and calculate new length. 1576 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1577 STATIC_ASSERT(kSmiTagSize == 1); 1578 STATIC_ASSERT(kSmiTag == 0); 1579 __ Addu(v0, v0, Operand(Smi::FromInt(argc))); 1580 1581 // Get the element's length. 1582 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); 1583 1584 // Check if we could survive without allocation. 1585 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0)); 1586 1587 // Save new length. 1588 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1589 1590 // Push the element. 1591 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize)); 1592 // We may need a register containing the address end_elements below, 1593 // so write back the value in end_elements. 1594 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize); 1595 __ Addu(end_elements, elements, end_elements); 1596 const int kEndElementsOffset = 1597 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize; 1598 __ sw(t0, MemOperand(end_elements, kEndElementsOffset)); 1599 __ Addu(end_elements, end_elements, kPointerSize); 1600 1601 // Check for a smi. 1602 __ JumpIfNotSmi(t0, &with_write_barrier); 1603 __ bind(&exit); 1604 __ Drop(argc + 1); 1605 __ Ret(); 1606 1607 __ bind(&with_write_barrier); 1608 __ InNewSpace(elements, t0, eq, &exit); 1609 __ RecordWriteHelper(elements, end_elements, t0); 1610 __ Drop(argc + 1); 1611 __ Ret(); 1612 1613 __ bind(&attempt_to_grow_elements); 1614 // v0: array's length + 1. 1615 // t0: elements' length. 1616 1617 if (!FLAG_inline_new) { 1618 __ Branch(&call_builtin); 1619 } 1620 1621 ExternalReference new_space_allocation_top = 1622 ExternalReference::new_space_allocation_top_address( 1623 masm()->isolate()); 1624 ExternalReference new_space_allocation_limit = 1625 ExternalReference::new_space_allocation_limit_address( 1626 masm()->isolate()); 1627 1628 const int kAllocationDelta = 4; 1629 // Load top and check if it is the end of elements. 1630 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize); 1631 __ Addu(end_elements, elements, end_elements); 1632 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset)); 1633 __ li(t3, Operand(new_space_allocation_top)); 1634 __ lw(t2, MemOperand(t3)); 1635 __ Branch(&call_builtin, ne, end_elements, Operand(t2)); 1636 1637 __ li(t5, Operand(new_space_allocation_limit)); 1638 __ lw(t5, MemOperand(t5)); 1639 __ Addu(t2, t2, Operand(kAllocationDelta * kPointerSize)); 1640 __ Branch(&call_builtin, hi, t2, Operand(t5)); 1641 1642 // We fit and could grow elements. 1643 // Update new_space_allocation_top. 1644 __ sw(t2, MemOperand(t3)); 1645 // Push the argument. 1646 __ lw(t2, MemOperand(sp, (argc - 1) * kPointerSize)); 1647 __ sw(t2, MemOperand(end_elements)); 1648 // Fill the rest with holes. 1649 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex); 1650 for (int i = 1; i < kAllocationDelta; i++) { 1651 __ sw(t2, MemOperand(end_elements, i * kPointerSize)); 1652 } 1653 1654 // Update elements' and array's sizes. 1655 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1656 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta))); 1657 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); 1658 1659 // Elements are in new space, so write barrier is not required. 1660 __ Drop(argc + 1); 1661 __ Ret(); 1662 } 1663 __ bind(&call_builtin); 1664 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush, 1665 masm()->isolate()), 1666 argc + 1, 1667 1); 1668 } 1669 1670 // Handle call cache miss. 1671 __ bind(&miss); 1672 MaybeObject* maybe_result = GenerateMissBranch(); 1673 if (maybe_result->IsFailure()) return maybe_result; 1674 1675 // Return the generated code. 1676 return GetCode(function); 1677} 1678 1679 1680MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, 1681 JSObject* holder, 1682 JSGlobalPropertyCell* cell, 1683 JSFunction* function, 1684 String* name) { 1685 // ----------- S t a t e ------------- 1686 // -- a2 : name 1687 // -- ra : return address 1688 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) 1689 // -- ... 1690 // -- sp[argc * 4] : receiver 1691 // ----------------------------------- 1692 1693 // If object is not an array, bail out to regular call. 1694 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value(); 1695 1696 Label miss, return_undefined, call_builtin; 1697 1698 Register receiver = a1; 1699 Register elements = a3; 1700 1701 GenerateNameCheck(name, &miss); 1702 1703 // Get the receiver from the stack. 1704 const int argc = arguments().immediate(); 1705 __ lw(receiver, MemOperand(sp, argc * kPointerSize)); 1706 1707 // Check that the receiver isn't a smi. 1708 __ JumpIfSmi(receiver, &miss); 1709 1710 // Check that the maps haven't changed. 1711 CheckPrototypes(JSObject::cast(object), 1712 receiver, holder, elements, t0, v0, name, &miss); 1713 1714 // Get the elements array of the object. 1715 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); 1716 1717 // Check that the elements are in fast mode and writable. 1718 __ CheckMap(elements, 1719 v0, 1720 Heap::kFixedArrayMapRootIndex, 1721 &call_builtin, 1722 DONT_DO_SMI_CHECK); 1723 1724 // Get the array's length into t0 and calculate new length. 1725 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1726 __ Subu(t0, t0, Operand(Smi::FromInt(1))); 1727 __ Branch(&return_undefined, lt, t0, Operand(zero_reg)); 1728 1729 // Get the last element. 1730 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex); 1731 STATIC_ASSERT(kSmiTagSize == 1); 1732 STATIC_ASSERT(kSmiTag == 0); 1733 // We can't address the last element in one operation. Compute the more 1734 // expensive shift first, and use an offset later on. 1735 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize); 1736 __ Addu(elements, elements, t1); 1737 __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag)); 1738 __ Branch(&call_builtin, eq, v0, Operand(t2)); 1739 1740 // Set the array's length. 1741 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); 1742 1743 // Fill with the hole. 1744 __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag)); 1745 __ Drop(argc + 1); 1746 __ Ret(); 1747 1748 __ bind(&return_undefined); 1749 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); 1750 __ Drop(argc + 1); 1751 __ Ret(); 1752 1753 __ bind(&call_builtin); 1754 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop, 1755 masm()->isolate()), 1756 argc + 1, 1757 1); 1758 1759 // Handle call cache miss. 1760 __ bind(&miss); 1761 MaybeObject* maybe_result = GenerateMissBranch(); 1762 if (maybe_result->IsFailure()) return maybe_result; 1763 1764 // Return the generated code. 1765 return GetCode(function); 1766} 1767 1768 1769MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( 1770 Object* object, 1771 JSObject* holder, 1772 JSGlobalPropertyCell* cell, 1773 JSFunction* function, 1774 String* name) { 1775 // ----------- S t a t e ------------- 1776 // -- a2 : function name 1777 // -- ra : return address 1778 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) 1779 // -- ... 1780 // -- sp[argc * 4] : receiver 1781 // ----------------------------------- 1782 1783 // If object is not a string, bail out to regular call. 1784 if (!object->IsString() || cell != NULL) return heap()->undefined_value(); 1785 1786 const int argc = arguments().immediate(); 1787 1788 Label miss; 1789 Label name_miss; 1790 Label index_out_of_range; 1791 1792 Label* index_out_of_range_label = &index_out_of_range; 1793 1794 if (kind_ == Code::CALL_IC && 1795 (CallICBase::StringStubState::decode(extra_ic_state_) == 1796 DEFAULT_STRING_STUB)) { 1797 index_out_of_range_label = &miss; 1798 } 1799 1800 GenerateNameCheck(name, &name_miss); 1801 1802 // Check that the maps starting from the prototype haven't changed. 1803 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1804 Context::STRING_FUNCTION_INDEX, 1805 v0, 1806 &miss); 1807 ASSERT(object != holder); 1808 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder, 1809 a1, a3, t0, name, &miss); 1810 1811 Register receiver = a1; 1812 Register index = t1; 1813 Register scratch = a3; 1814 Register result = v0; 1815 __ lw(receiver, MemOperand(sp, argc * kPointerSize)); 1816 if (argc > 0) { 1817 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize)); 1818 } else { 1819 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 1820 } 1821 1822 StringCharCodeAtGenerator char_code_at_generator(receiver, 1823 index, 1824 scratch, 1825 result, 1826 &miss, // When not a string. 1827 &miss, // When not a number. 1828 index_out_of_range_label, 1829 STRING_INDEX_IS_NUMBER); 1830 char_code_at_generator.GenerateFast(masm()); 1831 __ Drop(argc + 1); 1832 __ Ret(); 1833 1834 StubRuntimeCallHelper call_helper; 1835 char_code_at_generator.GenerateSlow(masm(), call_helper); 1836 1837 if (index_out_of_range.is_linked()) { 1838 __ bind(&index_out_of_range); 1839 __ LoadRoot(v0, Heap::kNanValueRootIndex); 1840 __ Drop(argc + 1); 1841 __ Ret(); 1842 } 1843 1844 __ bind(&miss); 1845 // Restore function name in a2. 1846 __ li(a2, Handle<String>(name)); 1847 __ bind(&name_miss); 1848 MaybeObject* maybe_result = GenerateMissBranch(); 1849 if (maybe_result->IsFailure()) return maybe_result; 1850 1851 // Return the generated code. 1852 return GetCode(function); 1853} 1854 1855 1856MaybeObject* CallStubCompiler::CompileStringCharAtCall( 1857 Object* object, 1858 JSObject* holder, 1859 JSGlobalPropertyCell* cell, 1860 JSFunction* function, 1861 String* name) { 1862 // ----------- S t a t e ------------- 1863 // -- a2 : function name 1864 // -- ra : return address 1865 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) 1866 // -- ... 1867 // -- sp[argc * 4] : receiver 1868 // ----------------------------------- 1869 1870 // If object is not a string, bail out to regular call. 1871 if (!object->IsString() || cell != NULL) return heap()->undefined_value(); 1872 1873 const int argc = arguments().immediate(); 1874 1875 Label miss; 1876 Label name_miss; 1877 Label index_out_of_range; 1878 Label* index_out_of_range_label = &index_out_of_range; 1879 1880 if (kind_ == Code::CALL_IC && 1881 (CallICBase::StringStubState::decode(extra_ic_state_) == 1882 DEFAULT_STRING_STUB)) { 1883 index_out_of_range_label = &miss; 1884 } 1885 1886 GenerateNameCheck(name, &name_miss); 1887 1888 // Check that the maps starting from the prototype haven't changed. 1889 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1890 Context::STRING_FUNCTION_INDEX, 1891 v0, 1892 &miss); 1893 ASSERT(object != holder); 1894 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder, 1895 a1, a3, t0, name, &miss); 1896 1897 Register receiver = v0; 1898 Register index = t1; 1899 Register scratch1 = a1; 1900 Register scratch2 = a3; 1901 Register result = v0; 1902 __ lw(receiver, MemOperand(sp, argc * kPointerSize)); 1903 if (argc > 0) { 1904 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize)); 1905 } else { 1906 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 1907 } 1908 1909 StringCharAtGenerator char_at_generator(receiver, 1910 index, 1911 scratch1, 1912 scratch2, 1913 result, 1914 &miss, // When not a string. 1915 &miss, // When not a number. 1916 index_out_of_range_label, 1917 STRING_INDEX_IS_NUMBER); 1918 char_at_generator.GenerateFast(masm()); 1919 __ Drop(argc + 1); 1920 __ Ret(); 1921 1922 StubRuntimeCallHelper call_helper; 1923 char_at_generator.GenerateSlow(masm(), call_helper); 1924 1925 if (index_out_of_range.is_linked()) { 1926 __ bind(&index_out_of_range); 1927 __ LoadRoot(v0, Heap::kEmptyStringRootIndex); 1928 __ Drop(argc + 1); 1929 __ Ret(); 1930 } 1931 1932 __ bind(&miss); 1933 // Restore function name in a2. 1934 __ li(a2, Handle<String>(name)); 1935 __ bind(&name_miss); 1936 MaybeObject* maybe_result = GenerateMissBranch(); 1937 if (maybe_result->IsFailure()) return maybe_result; 1938 1939 // Return the generated code. 1940 return GetCode(function); 1941} 1942 1943 1944MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( 1945 Object* object, 1946 JSObject* holder, 1947 JSGlobalPropertyCell* cell, 1948 JSFunction* function, 1949 String* name) { 1950 // ----------- S t a t e ------------- 1951 // -- a2 : function name 1952 // -- ra : return address 1953 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) 1954 // -- ... 1955 // -- sp[argc * 4] : receiver 1956 // ----------------------------------- 1957 1958 const int argc = arguments().immediate(); 1959 1960 // If the object is not a JSObject or we got an unexpected number of 1961 // arguments, bail out to the regular call. 1962 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); 1963 1964 Label miss; 1965 GenerateNameCheck(name, &miss); 1966 1967 if (cell == NULL) { 1968 __ lw(a1, MemOperand(sp, 1 * kPointerSize)); 1969 1970 STATIC_ASSERT(kSmiTag == 0); 1971 __ JumpIfSmi(a1, &miss); 1972 1973 CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name, 1974 &miss); 1975 } else { 1976 ASSERT(cell->value() == function); 1977 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); 1978 GenerateLoadFunctionFromCell(cell, function, &miss); 1979 } 1980 1981 // Load the char code argument. 1982 Register code = a1; 1983 __ lw(code, MemOperand(sp, 0 * kPointerSize)); 1984 1985 // Check the code is a smi. 1986 Label slow; 1987 STATIC_ASSERT(kSmiTag == 0); 1988 __ JumpIfNotSmi(code, &slow); 1989 1990 // Convert the smi code to uint16. 1991 __ And(code, code, Operand(Smi::FromInt(0xffff))); 1992 1993 StringCharFromCodeGenerator char_from_code_generator(code, v0); 1994 char_from_code_generator.GenerateFast(masm()); 1995 __ Drop(argc + 1); 1996 __ Ret(); 1997 1998 StubRuntimeCallHelper call_helper; 1999 char_from_code_generator.GenerateSlow(masm(), call_helper); 2000 2001 // Tail call the full function. We do not have to patch the receiver 2002 // because the function makes no use of it. 2003 __ bind(&slow); 2004 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 2005 2006 __ bind(&miss); 2007 // a2: function name. 2008 MaybeObject* maybe_result = GenerateMissBranch(); 2009 if (maybe_result->IsFailure()) return maybe_result; 2010 2011 // Return the generated code. 2012 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); 2013} 2014 2015 2016MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object, 2017 JSObject* holder, 2018 JSGlobalPropertyCell* cell, 2019 JSFunction* function, 2020 String* name) { 2021 // ----------- S t a t e ------------- 2022 // -- a2 : function name 2023 // -- ra : return address 2024 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) 2025 // -- ... 2026 // -- sp[argc * 4] : receiver 2027 // ----------------------------------- 2028 2029 if (!CpuFeatures::IsSupported(FPU)) 2030 return heap()->undefined_value(); 2031 CpuFeatures::Scope scope_fpu(FPU); 2032 2033 const int argc = arguments().immediate(); 2034 2035 // If the object is not a JSObject or we got an unexpected number of 2036 // arguments, bail out to the regular call. 2037 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); 2038 2039 Label miss, slow; 2040 GenerateNameCheck(name, &miss); 2041 2042 if (cell == NULL) { 2043 __ lw(a1, MemOperand(sp, 1 * kPointerSize)); 2044 2045 STATIC_ASSERT(kSmiTag == 0); 2046 __ JumpIfSmi(a1, &miss); 2047 2048 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name, 2049 &miss); 2050 } else { 2051 ASSERT(cell->value() == function); 2052 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); 2053 GenerateLoadFunctionFromCell(cell, function, &miss); 2054 } 2055 2056 // Load the (only) argument into v0. 2057 __ lw(v0, MemOperand(sp, 0 * kPointerSize)); 2058 2059 // If the argument is a smi, just return. 2060 STATIC_ASSERT(kSmiTag == 0); 2061 __ And(t0, v0, Operand(kSmiTagMask)); 2062 __ Drop(argc + 1, eq, t0, Operand(zero_reg)); 2063 __ Ret(eq, t0, Operand(zero_reg)); 2064 2065 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK); 2066 2067 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return; 2068 2069 // If fpu is enabled, we use the floor instruction. 2070 2071 // Load the HeapNumber value. 2072 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); 2073 2074 // Backup FCSR. 2075 __ cfc1(a3, FCSR); 2076 // Clearing FCSR clears the exception mask with no side-effects. 2077 __ ctc1(zero_reg, FCSR); 2078 // Convert the argument to an integer. 2079 __ floor_w_d(f0, f0); 2080 2081 // Start checking for special cases. 2082 // Get the argument exponent and clear the sign bit. 2083 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize)); 2084 __ And(t2, t1, Operand(~HeapNumber::kSignMask)); 2085 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord); 2086 2087 // Retrieve FCSR and check for fpu errors. 2088 __ cfc1(t5, FCSR); 2089 __ srl(t5, t5, kFCSRFlagShift); 2090 // Flag 1 marks an inaccurate but still good result so we ignore it. 2091 __ And(t5, t5, Operand(kFCSRFlagMask ^ 1)); 2092 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg)); 2093 2094 // Check for NaN, Infinity, and -Infinity. 2095 // They are invariant through a Math.Floor call, so just 2096 // return the original argument. 2097 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask 2098 >> HeapNumber::kMantissaBitsInTopWord)); 2099 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg)); 2100 // We had an overflow or underflow in the conversion. Check if we 2101 // have a big exponent. 2102 // If greater or equal, the argument is already round and in v0. 2103 __ Branch(&restore_fcsr_and_return, ge, t3, 2104 Operand(HeapNumber::kMantissaBits)); 2105 __ Branch(&wont_fit_smi); 2106 2107 __ bind(&no_fpu_error); 2108 // Move the result back to v0. 2109 __ mfc1(v0, f0); 2110 // Check if the result fits into a smi. 2111 __ Addu(a1, v0, Operand(0x40000000)); 2112 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg)); 2113 // Tag the result. 2114 STATIC_ASSERT(kSmiTag == 0); 2115 __ sll(v0, v0, kSmiTagSize); 2116 2117 // Check for -0. 2118 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg)); 2119 // t1 already holds the HeapNumber exponent. 2120 __ And(t0, t1, Operand(HeapNumber::kSignMask)); 2121 // If our HeapNumber is negative it was -0, so load its address and return. 2122 // Else v0 is loaded with 0, so we can also just return. 2123 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg)); 2124 __ lw(v0, MemOperand(sp, 0 * kPointerSize)); 2125 2126 __ bind(&restore_fcsr_and_return); 2127 // Restore FCSR and return. 2128 __ ctc1(a3, FCSR); 2129 2130 __ Drop(argc + 1); 2131 __ Ret(); 2132 2133 __ bind(&wont_fit_smi); 2134 // Restore FCSR and fall to slow case. 2135 __ ctc1(a3, FCSR); 2136 2137 __ bind(&slow); 2138 // Tail call the full function. We do not have to patch the receiver 2139 // because the function makes no use of it. 2140 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 2141 2142 __ bind(&miss); 2143 // a2: function name. 2144 MaybeObject* obj = GenerateMissBranch(); 2145 if (obj->IsFailure()) return obj; 2146 2147 // Return the generated code. 2148 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); 2149} 2150 2151 2152MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, 2153 JSObject* holder, 2154 JSGlobalPropertyCell* cell, 2155 JSFunction* function, 2156 String* name) { 2157 // ----------- S t a t e ------------- 2158 // -- a2 : function name 2159 // -- ra : return address 2160 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) 2161 // -- ... 2162 // -- sp[argc * 4] : receiver 2163 // ----------------------------------- 2164 2165 const int argc = arguments().immediate(); 2166 2167 // If the object is not a JSObject or we got an unexpected number of 2168 // arguments, bail out to the regular call. 2169 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); 2170 2171 Label miss; 2172 GenerateNameCheck(name, &miss); 2173 2174 if (cell == NULL) { 2175 __ lw(a1, MemOperand(sp, 1 * kPointerSize)); 2176 2177 STATIC_ASSERT(kSmiTag == 0); 2178 __ JumpIfSmi(a1, &miss); 2179 2180 CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name, 2181 &miss); 2182 } else { 2183 ASSERT(cell->value() == function); 2184 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); 2185 GenerateLoadFunctionFromCell(cell, function, &miss); 2186 } 2187 2188 // Load the (only) argument into v0. 2189 __ lw(v0, MemOperand(sp, 0 * kPointerSize)); 2190 2191 // Check if the argument is a smi. 2192 Label not_smi; 2193 STATIC_ASSERT(kSmiTag == 0); 2194 __ JumpIfNotSmi(v0, ¬_smi); 2195 2196 // Do bitwise not or do nothing depending on the sign of the 2197 // argument. 2198 __ sra(t0, v0, kBitsPerInt - 1); 2199 __ Xor(a1, v0, t0); 2200 2201 // Add 1 or do nothing depending on the sign of the argument. 2202 __ Subu(v0, a1, t0); 2203 2204 // If the result is still negative, go to the slow case. 2205 // This only happens for the most negative smi. 2206 Label slow; 2207 __ Branch(&slow, lt, v0, Operand(zero_reg)); 2208 2209 // Smi case done. 2210 __ Drop(argc + 1); 2211 __ Ret(); 2212 2213 // Check if the argument is a heap number and load its exponent and 2214 // sign. 2215 __ bind(¬_smi); 2216 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK); 2217 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset)); 2218 2219 // Check the sign of the argument. If the argument is positive, 2220 // just return it. 2221 Label negative_sign; 2222 __ And(t0, a1, Operand(HeapNumber::kSignMask)); 2223 __ Branch(&negative_sign, ne, t0, Operand(zero_reg)); 2224 __ Drop(argc + 1); 2225 __ Ret(); 2226 2227 // If the argument is negative, clear the sign, and return a new 2228 // number. 2229 __ bind(&negative_sign); 2230 __ Xor(a1, a1, Operand(HeapNumber::kSignMask)); 2231 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset)); 2232 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex); 2233 __ AllocateHeapNumber(v0, t0, t1, t2, &slow); 2234 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset)); 2235 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset)); 2236 __ Drop(argc + 1); 2237 __ Ret(); 2238 2239 // Tail call the full function. We do not have to patch the receiver 2240 // because the function makes no use of it. 2241 __ bind(&slow); 2242 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 2243 2244 __ bind(&miss); 2245 // a2: function name. 2246 MaybeObject* maybe_result = GenerateMissBranch(); 2247 if (maybe_result->IsFailure()) return maybe_result; 2248 2249 // Return the generated code. 2250 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); 2251} 2252 2253 2254MaybeObject* CallStubCompiler::CompileFastApiCall( 2255 const CallOptimization& optimization, 2256 Object* object, 2257 JSObject* holder, 2258 JSGlobalPropertyCell* cell, 2259 JSFunction* function, 2260 String* name) { 2261 2262 Counters* counters = isolate()->counters(); 2263 2264 ASSERT(optimization.is_simple_api_call()); 2265 // Bail out if object is a global object as we don't want to 2266 // repatch it to global receiver. 2267 if (object->IsGlobalObject()) return heap()->undefined_value(); 2268 if (cell != NULL) return heap()->undefined_value(); 2269 if (!object->IsJSObject()) return heap()->undefined_value(); 2270 int depth = optimization.GetPrototypeDepthOfExpectedType( 2271 JSObject::cast(object), holder); 2272 if (depth == kInvalidProtoDepth) return heap()->undefined_value(); 2273 2274 Label miss, miss_before_stack_reserved; 2275 2276 GenerateNameCheck(name, &miss_before_stack_reserved); 2277 2278 // Get the receiver from the stack. 2279 const int argc = arguments().immediate(); 2280 __ lw(a1, MemOperand(sp, argc * kPointerSize)); 2281 2282 // Check that the receiver isn't a smi. 2283 __ JumpIfSmi(a1, &miss_before_stack_reserved); 2284 2285 __ IncrementCounter(counters->call_const(), 1, a0, a3); 2286 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3); 2287 2288 ReserveSpaceForFastApiCall(masm(), a0); 2289 2290 // Check that the maps haven't changed and find a Holder as a side effect. 2291 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name, 2292 depth, &miss); 2293 2294 MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc); 2295 if (result->IsFailure()) return result; 2296 2297 __ bind(&miss); 2298 FreeSpaceForFastApiCall(masm()); 2299 2300 __ bind(&miss_before_stack_reserved); 2301 MaybeObject* maybe_result = GenerateMissBranch(); 2302 if (maybe_result->IsFailure()) return maybe_result; 2303 2304 // Return the generated code. 2305 return GetCode(function); 2306} 2307 2308 2309MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, 2310 JSObject* holder, 2311 JSFunction* function, 2312 String* name, 2313 CheckType check) { 2314 // ----------- S t a t e ------------- 2315 // -- a2 : name 2316 // -- ra : return address 2317 // ----------------------------------- 2318 if (HasCustomCallGenerator(function)) { 2319 MaybeObject* maybe_result = CompileCustomCall( 2320 object, holder, NULL, function, name); 2321 Object* result; 2322 if (!maybe_result->ToObject(&result)) return maybe_result; 2323 // Undefined means bail out to regular compiler. 2324 if (!result->IsUndefined()) return result; 2325 } 2326 2327 Label miss; 2328 2329 GenerateNameCheck(name, &miss); 2330 2331 // Get the receiver from the stack. 2332 const int argc = arguments().immediate(); 2333 __ lw(a1, MemOperand(sp, argc * kPointerSize)); 2334 2335 // Check that the receiver isn't a smi. 2336 if (check != NUMBER_CHECK) { 2337 __ And(t1, a1, Operand(kSmiTagMask)); 2338 __ Branch(&miss, eq, t1, Operand(zero_reg)); 2339 } 2340 2341 // Make sure that it's okay not to patch the on stack receiver 2342 // unless we're doing a receiver map check. 2343 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); 2344 2345 SharedFunctionInfo* function_info = function->shared(); 2346 switch (check) { 2347 case RECEIVER_MAP_CHECK: 2348 __ IncrementCounter(masm()->isolate()->counters()->call_const(), 2349 1, a0, a3); 2350 2351 // Check that the maps haven't changed. 2352 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name, 2353 &miss); 2354 2355 // Patch the receiver on the stack with the global proxy if 2356 // necessary. 2357 if (object->IsGlobalObject()) { 2358 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset)); 2359 __ sw(a3, MemOperand(sp, argc * kPointerSize)); 2360 } 2361 break; 2362 2363 case STRING_CHECK: 2364 if (!function->IsBuiltin() && !function_info->strict_mode()) { 2365 // Calling non-strict non-builtins with a value as the receiver 2366 // requires boxing. 2367 __ jmp(&miss); 2368 } else { 2369 // Check that the object is a two-byte string or a symbol. 2370 __ GetObjectType(a1, a3, a3); 2371 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE)); 2372 // Check that the maps starting from the prototype haven't changed. 2373 GenerateDirectLoadGlobalFunctionPrototype( 2374 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss); 2375 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3, 2376 a1, t0, name, &miss); 2377 } 2378 break; 2379 2380 case NUMBER_CHECK: { 2381 if (!function->IsBuiltin() && !function_info->strict_mode()) { 2382 // Calling non-strict non-builtins with a value as the receiver 2383 // requires boxing. 2384 __ jmp(&miss); 2385 } else { 2386 Label fast; 2387 // Check that the object is a smi or a heap number. 2388 __ And(t1, a1, Operand(kSmiTagMask)); 2389 __ Branch(&fast, eq, t1, Operand(zero_reg)); 2390 __ GetObjectType(a1, a0, a0); 2391 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE)); 2392 __ bind(&fast); 2393 // Check that the maps starting from the prototype haven't changed. 2394 GenerateDirectLoadGlobalFunctionPrototype( 2395 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss); 2396 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3, 2397 a1, t0, name, &miss); 2398 } 2399 break; 2400 } 2401 2402 case BOOLEAN_CHECK: { 2403 if (!function->IsBuiltin() && !function_info->strict_mode()) { 2404 // Calling non-strict non-builtins with a value as the receiver 2405 // requires boxing. 2406 __ jmp(&miss); 2407 } else { 2408 Label fast; 2409 // Check that the object is a boolean. 2410 __ LoadRoot(t0, Heap::kTrueValueRootIndex); 2411 __ Branch(&fast, eq, a1, Operand(t0)); 2412 __ LoadRoot(t0, Heap::kFalseValueRootIndex); 2413 __ Branch(&miss, ne, a1, Operand(t0)); 2414 __ bind(&fast); 2415 // Check that the maps starting from the prototype haven't changed. 2416 GenerateDirectLoadGlobalFunctionPrototype( 2417 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss); 2418 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3, 2419 a1, t0, name, &miss); 2420 } 2421 break; 2422 } 2423 2424 default: 2425 UNREACHABLE(); 2426 } 2427 2428 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 2429 2430 // Handle call cache miss. 2431 __ bind(&miss); 2432 2433 MaybeObject* maybe_result = GenerateMissBranch(); 2434 if (maybe_result->IsFailure()) return maybe_result; 2435 2436 // Return the generated code. 2437 return GetCode(function); 2438} 2439 2440 2441MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, 2442 JSObject* holder, 2443 String* name) { 2444 // ----------- S t a t e ------------- 2445 // -- a2 : name 2446 // -- ra : return address 2447 // ----------------------------------- 2448 2449 Label miss; 2450 2451 GenerateNameCheck(name, &miss); 2452 2453 // Get the number of arguments. 2454 const int argc = arguments().immediate(); 2455 2456 LookupResult lookup; 2457 LookupPostInterceptor(holder, name, &lookup); 2458 2459 // Get the receiver from the stack. 2460 __ lw(a1, MemOperand(sp, argc * kPointerSize)); 2461 2462 CallInterceptorCompiler compiler(this, arguments(), a2); 2463 MaybeObject* result = compiler.Compile(masm(), 2464 object, 2465 holder, 2466 name, 2467 &lookup, 2468 a1, 2469 a3, 2470 t0, 2471 a0, 2472 &miss); 2473 if (result->IsFailure()) { 2474 return result; 2475 } 2476 2477 // Move returned value, the function to call, to a1. 2478 __ mov(a1, v0); 2479 // Restore receiver. 2480 __ lw(a0, MemOperand(sp, argc * kPointerSize)); 2481 2482 GenerateCallFunction(masm(), object, arguments(), &miss); 2483 2484 // Handle call cache miss. 2485 __ bind(&miss); 2486 MaybeObject* maybe_result = GenerateMissBranch(); 2487 if (maybe_result->IsFailure()) return maybe_result; 2488 2489 // Return the generated code. 2490 return GetCode(INTERCEPTOR, name); 2491} 2492 2493 2494MaybeObject* CallStubCompiler::CompileCallGlobal( 2495 JSObject* object, 2496 GlobalObject* holder, 2497 JSGlobalPropertyCell* cell, 2498 JSFunction* function, 2499 String* name, 2500 Code::ExtraICState extra_ic_state) { 2501 // ----------- S t a t e ------------- 2502 // -- a2 : name 2503 // -- ra : return address 2504 // ----------------------------------- 2505 2506 if (HasCustomCallGenerator(function)) { 2507 MaybeObject* maybe_result = CompileCustomCall( 2508 object, holder, cell, function, name); 2509 Object* result; 2510 if (!maybe_result->ToObject(&result)) return maybe_result; 2511 // Undefined means bail out to regular compiler. 2512 if (!result->IsUndefined()) return result; 2513 } 2514 2515 Label miss; 2516 2517 GenerateNameCheck(name, &miss); 2518 2519 // Get the number of arguments. 2520 const int argc = arguments().immediate(); 2521 2522 GenerateGlobalReceiverCheck(object, holder, name, &miss); 2523 GenerateLoadFunctionFromCell(cell, function, &miss); 2524 2525 // Patch the receiver on the stack with the global proxy if 2526 // necessary. 2527 if (object->IsGlobalObject()) { 2528 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset)); 2529 __ sw(a3, MemOperand(sp, argc * kPointerSize)); 2530 } 2531 2532 // Setup the context (function already in r1). 2533 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); 2534 2535 // Jump to the cached code (tail call). 2536 Counters* counters = masm()->isolate()->counters(); 2537 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0); 2538 ASSERT(function->is_compiled()); 2539 Handle<Code> code(function->code()); 2540 ParameterCount expected(function->shared()->formal_parameter_count()); 2541 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state) 2542 ? CALL_AS_FUNCTION 2543 : CALL_AS_METHOD; 2544 if (V8::UseCrankshaft()) { 2545 UNIMPLEMENTED_MIPS(); 2546 } else { 2547 __ InvokeCode(code, expected, arguments(), RelocInfo::CODE_TARGET, 2548 JUMP_FUNCTION, call_kind); 2549 } 2550 2551 // Handle call cache miss. 2552 __ bind(&miss); 2553 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3); 2554 MaybeObject* maybe_result = GenerateMissBranch(); 2555 if (maybe_result->IsFailure()) return maybe_result; 2556 2557 // Return the generated code. 2558 return GetCode(NORMAL, name); 2559} 2560 2561 2562MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object, 2563 int index, 2564 Map* transition, 2565 String* name) { 2566 // ----------- S t a t e ------------- 2567 // -- a0 : value 2568 // -- a1 : receiver 2569 // -- a2 : name 2570 // -- ra : return address 2571 // ----------------------------------- 2572 Label miss; 2573 2574 // Name register might be clobbered. 2575 GenerateStoreField(masm(), 2576 object, 2577 index, 2578 transition, 2579 a1, a2, a3, 2580 &miss); 2581 __ bind(&miss); 2582 __ li(a2, Operand(Handle<String>(name))); // Restore name. 2583 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss(); 2584 __ Jump(ic, RelocInfo::CODE_TARGET); 2585 2586 // Return the generated code. 2587 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); 2588} 2589 2590 2591MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, 2592 AccessorInfo* callback, 2593 String* name) { 2594 // ----------- S t a t e ------------- 2595 // -- a0 : value 2596 // -- a1 : receiver 2597 // -- a2 : name 2598 // -- ra : return address 2599 // ----------------------------------- 2600 Label miss; 2601 2602 // Check that the object isn't a smi. 2603 __ JumpIfSmi(a1, &miss); 2604 2605 // Check that the map of the object hasn't changed. 2606 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset)); 2607 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map()))); 2608 2609 // Perform global security token check if needed. 2610 if (object->IsJSGlobalProxy()) { 2611 __ CheckAccessGlobalProxy(a1, a3, &miss); 2612 } 2613 2614 // Stub never generated for non-global objects that require access 2615 // checks. 2616 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); 2617 2618 __ push(a1); // Receiver. 2619 __ li(a3, Operand(Handle<AccessorInfo>(callback))); // Callback info. 2620 __ Push(a3, a2, a0); 2621 2622 // Do tail-call to the runtime system. 2623 ExternalReference store_callback_property = 2624 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), 2625 masm()->isolate()); 2626 __ TailCallExternalReference(store_callback_property, 4, 1); 2627 2628 // Handle store cache miss. 2629 __ bind(&miss); 2630 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss(); 2631 __ Jump(ic, RelocInfo::CODE_TARGET); 2632 2633 // Return the generated code. 2634 return GetCode(CALLBACKS, name); 2635} 2636 2637 2638MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, 2639 String* name) { 2640 // ----------- S t a t e ------------- 2641 // -- a0 : value 2642 // -- a1 : receiver 2643 // -- a2 : name 2644 // -- ra : return address 2645 // ----------------------------------- 2646 Label miss; 2647 2648 // Check that the object isn't a smi. 2649 __ JumpIfSmi(a1, &miss); 2650 2651 // Check that the map of the object hasn't changed. 2652 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset)); 2653 __ Branch(&miss, ne, a3, Operand(Handle<Map>(receiver->map()))); 2654 2655 // Perform global security token check if needed. 2656 if (receiver->IsJSGlobalProxy()) { 2657 __ CheckAccessGlobalProxy(a1, a3, &miss); 2658 } 2659 2660 // Stub is never generated for non-global objects that require access 2661 // checks. 2662 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); 2663 2664 __ Push(a1, a2, a0); // Receiver, name, value. 2665 2666 __ li(a0, Operand(Smi::FromInt(strict_mode_))); 2667 __ push(a0); // Strict mode. 2668 2669 // Do tail-call to the runtime system. 2670 ExternalReference store_ic_property = 2671 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), 2672 masm()->isolate()); 2673 __ TailCallExternalReference(store_ic_property, 4, 1); 2674 2675 // Handle store cache miss. 2676 __ bind(&miss); 2677 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss(); 2678 __ Jump(ic, RelocInfo::CODE_TARGET); 2679 2680 // Return the generated code. 2681 return GetCode(INTERCEPTOR, name); 2682} 2683 2684 2685MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, 2686 JSGlobalPropertyCell* cell, 2687 String* name) { 2688 // ----------- S t a t e ------------- 2689 // -- a0 : value 2690 // -- a1 : receiver 2691 // -- a2 : name 2692 // -- ra : return address 2693 // ----------------------------------- 2694 Label miss; 2695 2696 // Check that the map of the global has not changed. 2697 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset)); 2698 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map()))); 2699 2700 // Check that the value in the cell is not the hole. If it is, this 2701 // cell could have been deleted and reintroducing the global needs 2702 // to update the property details in the property dictionary of the 2703 // global object. We bail out to the runtime system to do that. 2704 __ li(t0, Operand(Handle<JSGlobalPropertyCell>(cell))); 2705 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex); 2706 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset)); 2707 __ Branch(&miss, eq, t1, Operand(t2)); 2708 2709 // Store the value in the cell. 2710 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset)); 2711 __ mov(v0, a0); // Stored value must be returned in v0. 2712 Counters* counters = masm()->isolate()->counters(); 2713 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3); 2714 __ Ret(); 2715 2716 // Handle store cache miss. 2717 __ bind(&miss); 2718 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3); 2719 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss(); 2720 __ Jump(ic, RelocInfo::CODE_TARGET); 2721 2722 // Return the generated code. 2723 return GetCode(NORMAL, name); 2724} 2725 2726 2727MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, 2728 JSObject* object, 2729 JSObject* last) { 2730 // ----------- S t a t e ------------- 2731 // -- a0 : receiver 2732 // -- ra : return address 2733 // ----------------------------------- 2734 Label miss; 2735 2736 // Check that the receiver is not a smi. 2737 __ JumpIfSmi(a0, &miss); 2738 2739 // Check the maps of the full prototype chain. 2740 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss); 2741 2742 // If the last object in the prototype chain is a global object, 2743 // check that the global property cell is empty. 2744 if (last->IsGlobalObject()) { 2745 MaybeObject* cell = GenerateCheckPropertyCell(masm(), 2746 GlobalObject::cast(last), 2747 name, 2748 a1, 2749 &miss); 2750 if (cell->IsFailure()) { 2751 miss.Unuse(); 2752 return cell; 2753 } 2754 } 2755 2756 // Return undefined if maps of the full prototype chain is still the same. 2757 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); 2758 __ Ret(); 2759 2760 __ bind(&miss); 2761 GenerateLoadMiss(masm(), Code::LOAD_IC); 2762 2763 // Return the generated code. 2764 return GetCode(NONEXISTENT, heap()->empty_string()); 2765} 2766 2767 2768MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object, 2769 JSObject* holder, 2770 int index, 2771 String* name) { 2772 // ----------- S t a t e ------------- 2773 // -- a0 : receiver 2774 // -- a2 : name 2775 // -- ra : return address 2776 // ----------------------------------- 2777 Label miss; 2778 2779 __ mov(v0, a0); 2780 2781 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss); 2782 __ bind(&miss); 2783 GenerateLoadMiss(masm(), Code::LOAD_IC); 2784 2785 // Return the generated code. 2786 return GetCode(FIELD, name); 2787} 2788 2789 2790MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, 2791 JSObject* object, 2792 JSObject* holder, 2793 AccessorInfo* callback) { 2794 // ----------- S t a t e ------------- 2795 // -- a0 : receiver 2796 // -- a2 : name 2797 // -- ra : return address 2798 // ----------------------------------- 2799 Label miss; 2800 2801 MaybeObject* result = GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, 2802 callback, name, &miss); 2803 if (result->IsFailure()) { 2804 miss.Unuse(); 2805 return result; 2806 } 2807 2808 __ bind(&miss); 2809 GenerateLoadMiss(masm(), Code::LOAD_IC); 2810 2811 // Return the generated code. 2812 return GetCode(CALLBACKS, name); 2813} 2814 2815 2816MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object, 2817 JSObject* holder, 2818 Object* value, 2819 String* name) { 2820 // ----------- S t a t e ------------- 2821 // -- a0 : receiver 2822 // -- a2 : name 2823 // -- ra : return address 2824 // ----------------------------------- 2825 Label miss; 2826 2827 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss); 2828 __ bind(&miss); 2829 GenerateLoadMiss(masm(), Code::LOAD_IC); 2830 2831 // Return the generated code. 2832 return GetCode(CONSTANT_FUNCTION, name); 2833} 2834 2835 2836MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object, 2837 JSObject* holder, 2838 String* name) { 2839 // ----------- S t a t e ------------- 2840 // -- a0 : receiver 2841 // -- a2 : name 2842 // -- ra : return address 2843 // -- [sp] : receiver 2844 // ----------------------------------- 2845 Label miss; 2846 2847 LookupResult lookup; 2848 LookupPostInterceptor(holder, name, &lookup); 2849 GenerateLoadInterceptor(object, 2850 holder, 2851 &lookup, 2852 a0, 2853 a2, 2854 a3, 2855 a1, 2856 t0, 2857 name, 2858 &miss); 2859 __ bind(&miss); 2860 GenerateLoadMiss(masm(), Code::LOAD_IC); 2861 2862 // Return the generated code. 2863 return GetCode(INTERCEPTOR, name); 2864} 2865 2866 2867MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, 2868 GlobalObject* holder, 2869 JSGlobalPropertyCell* cell, 2870 String* name, 2871 bool is_dont_delete) { 2872 // ----------- S t a t e ------------- 2873 // -- a0 : receiver 2874 // -- a2 : name 2875 // -- ra : return address 2876 // ----------------------------------- 2877 Label miss; 2878 2879 // If the object is the holder then we know that it's a global 2880 // object which can only happen for contextual calls. In this case, 2881 // the receiver cannot be a smi. 2882 if (object != holder) { 2883 __ And(t0, a0, Operand(kSmiTagMask)); 2884 __ Branch(&miss, eq, t0, Operand(zero_reg)); 2885 } 2886 2887 // Check that the map of the global has not changed. 2888 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss); 2889 2890 // Get the value from the cell. 2891 __ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell))); 2892 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset)); 2893 2894 // Check for deleted property if property can actually be deleted. 2895 if (!is_dont_delete) { 2896 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); 2897 __ Branch(&miss, eq, t0, Operand(at)); 2898 } 2899 2900 __ mov(v0, t0); 2901 Counters* counters = masm()->isolate()->counters(); 2902 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3); 2903 __ Ret(); 2904 2905 __ bind(&miss); 2906 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3); 2907 GenerateLoadMiss(masm(), Code::LOAD_IC); 2908 2909 // Return the generated code. 2910 return GetCode(NORMAL, name); 2911} 2912 2913 2914MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, 2915 JSObject* receiver, 2916 JSObject* holder, 2917 int index) { 2918 // ----------- S t a t e ------------- 2919 // -- ra : return address 2920 // -- a0 : key 2921 // -- a1 : receiver 2922 // ----------------------------------- 2923 Label miss; 2924 2925 // Check the key is the cached one. 2926 __ Branch(&miss, ne, a0, Operand(Handle<String>(name))); 2927 2928 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss); 2929 __ bind(&miss); 2930 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2931 2932 return GetCode(FIELD, name); 2933} 2934 2935 2936MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( 2937 String* name, 2938 JSObject* receiver, 2939 JSObject* holder, 2940 AccessorInfo* callback) { 2941 // ----------- S t a t e ------------- 2942 // -- ra : return address 2943 // -- a0 : key 2944 // -- a1 : receiver 2945 // ----------------------------------- 2946 Label miss; 2947 2948 // Check the key is the cached one. 2949 __ Branch(&miss, ne, a0, Operand(Handle<String>(name))); 2950 2951 MaybeObject* result = GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, 2952 t0, callback, name, &miss); 2953 if (result->IsFailure()) { 2954 miss.Unuse(); 2955 return result; 2956 } 2957 2958 __ bind(&miss); 2959 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2960 2961 return GetCode(CALLBACKS, name); 2962} 2963 2964 2965MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, 2966 JSObject* receiver, 2967 JSObject* holder, 2968 Object* value) { 2969 // ----------- S t a t e ------------- 2970 // -- ra : return address 2971 // -- a0 : key 2972 // -- a1 : receiver 2973 // ----------------------------------- 2974 Label miss; 2975 2976 // Check the key is the cached one. 2977 __ Branch(&miss, ne, a0, Operand(Handle<String>(name))); 2978 2979 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss); 2980 __ bind(&miss); 2981 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2982 2983 // Return the generated code. 2984 return GetCode(CONSTANT_FUNCTION, name); 2985} 2986 2987 2988MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, 2989 JSObject* holder, 2990 String* name) { 2991 // ----------- S t a t e ------------- 2992 // -- ra : return address 2993 // -- a0 : key 2994 // -- a1 : receiver 2995 // ----------------------------------- 2996 Label miss; 2997 2998 // Check the key is the cached one. 2999 __ Branch(&miss, ne, a0, Operand(Handle<String>(name))); 3000 3001 LookupResult lookup; 3002 LookupPostInterceptor(holder, name, &lookup); 3003 GenerateLoadInterceptor(receiver, 3004 holder, 3005 &lookup, 3006 a1, 3007 a0, 3008 a2, 3009 a3, 3010 t0, 3011 name, 3012 &miss); 3013 __ bind(&miss); 3014 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 3015 3016 return GetCode(INTERCEPTOR, name); 3017} 3018 3019 3020MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { 3021 // ----------- S t a t e ------------- 3022 // -- ra : return address 3023 // -- a0 : key 3024 // -- a1 : receiver 3025 // ----------------------------------- 3026 Label miss; 3027 3028 // Check the key is the cached one. 3029 __ Branch(&miss, ne, a0, Operand(Handle<String>(name))); 3030 3031 GenerateLoadArrayLength(masm(), a1, a2, &miss); 3032 __ bind(&miss); 3033 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 3034 3035 return GetCode(CALLBACKS, name); 3036} 3037 3038 3039MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { 3040 // ----------- S t a t e ------------- 3041 // -- ra : return address 3042 // -- a0 : key 3043 // -- a1 : receiver 3044 // ----------------------------------- 3045 Label miss; 3046 3047 Counters* counters = masm()->isolate()->counters(); 3048 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3); 3049 3050 // Check the key is the cached one. 3051 __ Branch(&miss, ne, a0, Operand(Handle<String>(name))); 3052 3053 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true); 3054 __ bind(&miss); 3055 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3); 3056 3057 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 3058 3059 return GetCode(CALLBACKS, name); 3060} 3061 3062 3063MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { 3064 // ----------- S t a t e ------------- 3065 // -- ra : return address 3066 // -- a0 : key 3067 // -- a1 : receiver 3068 // ----------------------------------- 3069 Label miss; 3070 3071 Counters* counters = masm()->isolate()->counters(); 3072 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3); 3073 3074 // Check the name hasn't changed. 3075 __ Branch(&miss, ne, a0, Operand(Handle<String>(name))); 3076 3077 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss); 3078 __ bind(&miss); 3079 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3); 3080 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 3081 3082 return GetCode(CALLBACKS, name); 3083} 3084 3085 3086MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) { 3087 // ----------- S t a t e ------------- 3088 // -- ra : return address 3089 // -- a0 : key 3090 // -- a1 : receiver 3091 // ----------------------------------- 3092 MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode(); 3093 Code* stub; 3094 if (!maybe_stub->To(&stub)) return maybe_stub; 3095 __ DispatchMap(a1, 3096 a2, 3097 Handle<Map>(receiver_map), 3098 Handle<Code>(stub), 3099 DO_SMI_CHECK); 3100 3101 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss(); 3102 __ Jump(ic, RelocInfo::CODE_TARGET); 3103 3104 // Return the generated code. 3105 return GetCode(NORMAL, NULL); 3106} 3107 3108 3109MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic( 3110 MapList* receiver_maps, 3111 CodeList* handler_ics) { 3112 // ----------- S t a t e ------------- 3113 // -- ra : return address 3114 // -- a0 : key 3115 // -- a1 : receiver 3116 // ----------------------------------- 3117 Label miss; 3118 __ JumpIfSmi(a1, &miss); 3119 3120 int receiver_count = receiver_maps->length(); 3121 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset)); 3122 for (int current = 0; current < receiver_count; ++current) { 3123 Handle<Map> map(receiver_maps->at(current)); 3124 Handle<Code> code(handler_ics->at(current)); 3125 __ Jump(code, RelocInfo::CODE_TARGET, eq, a2, Operand(map)); 3126 } 3127 3128 __ bind(&miss); 3129 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss(); 3130 __ Jump(miss_ic, RelocInfo::CODE_TARGET); 3131 3132 // Return the generated code. 3133 return GetCode(NORMAL, NULL, MEGAMORPHIC); 3134} 3135 3136 3137MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, 3138 int index, 3139 Map* transition, 3140 String* name) { 3141 // ----------- S t a t e ------------- 3142 // -- a0 : value 3143 // -- a1 : key 3144 // -- a2 : receiver 3145 // -- ra : return address 3146 // ----------------------------------- 3147 3148 Label miss; 3149 3150 Counters* counters = masm()->isolate()->counters(); 3151 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0); 3152 3153 // Check that the name has not changed. 3154 __ Branch(&miss, ne, a1, Operand(Handle<String>(name))); 3155 3156 // a3 is used as scratch register. a1 and a2 keep their values if a jump to 3157 // the miss label is generated. 3158 GenerateStoreField(masm(), 3159 object, 3160 index, 3161 transition, 3162 a2, a1, a3, 3163 &miss); 3164 __ bind(&miss); 3165 3166 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0); 3167 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss(); 3168 __ Jump(ic, RelocInfo::CODE_TARGET); 3169 3170 // Return the generated code. 3171 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); 3172} 3173 3174 3175MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement( 3176 Map* receiver_map) { 3177 // ----------- S t a t e ------------- 3178 // -- a0 : value 3179 // -- a1 : key 3180 // -- a2 : receiver 3181 // -- ra : return address 3182 // -- a3 : scratch 3183 // ----------------------------------- 3184 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; 3185 MaybeObject* maybe_stub = 3186 KeyedStoreFastElementStub(is_js_array).TryGetCode(); 3187 Code* stub; 3188 if (!maybe_stub->To(&stub)) return maybe_stub; 3189 __ DispatchMap(a2, 3190 a3, 3191 Handle<Map>(receiver_map), 3192 Handle<Code>(stub), 3193 DO_SMI_CHECK); 3194 3195 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); 3196 __ Jump(ic, RelocInfo::CODE_TARGET); 3197 3198 // Return the generated code. 3199 return GetCode(NORMAL, NULL); 3200} 3201 3202 3203MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic( 3204 MapList* receiver_maps, 3205 CodeList* handler_ics) { 3206 // ----------- S t a t e ------------- 3207 // -- a0 : value 3208 // -- a1 : key 3209 // -- a2 : receiver 3210 // -- ra : return address 3211 // -- a3 : scratch 3212 // ----------------------------------- 3213 Label miss; 3214 __ JumpIfSmi(a2, &miss); 3215 3216 int receiver_count = receiver_maps->length(); 3217 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset)); 3218 for (int current = 0; current < receiver_count; ++current) { 3219 Handle<Map> map(receiver_maps->at(current)); 3220 Handle<Code> code(handler_ics->at(current)); 3221 __ Jump(code, RelocInfo::CODE_TARGET, eq, a3, Operand(map)); 3222 } 3223 3224 __ bind(&miss); 3225 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss(); 3226 __ Jump(miss_ic, RelocInfo::CODE_TARGET); 3227 3228 // Return the generated code. 3229 return GetCode(NORMAL, NULL, MEGAMORPHIC); 3230} 3231 3232 3233MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { 3234 // a0 : argc 3235 // a1 : constructor 3236 // ra : return address 3237 // [sp] : last argument 3238 Label generic_stub_call; 3239 3240 // Use t7 for holding undefined which is used in several places below. 3241 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex); 3242 3243#ifdef ENABLE_DEBUGGER_SUPPORT 3244 // Check to see whether there are any break points in the function code. If 3245 // there are jump to the generic constructor stub which calls the actual 3246 // code for the function thereby hitting the break points. 3247 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); 3248 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset)); 3249 __ Branch(&generic_stub_call, ne, a2, Operand(t7)); 3250#endif 3251 3252 // Load the initial map and verify that it is in fact a map. 3253 // a1: constructor function 3254 // t7: undefined 3255 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); 3256 __ And(t0, a2, Operand(kSmiTagMask)); 3257 __ Branch(&generic_stub_call, eq, t0, Operand(zero_reg)); 3258 __ GetObjectType(a2, a3, t0); 3259 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE)); 3260 3261#ifdef DEBUG 3262 // Cannot construct functions this way. 3263 // a0: argc 3264 // a1: constructor function 3265 // a2: initial map 3266 // t7: undefined 3267 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset)); 3268 __ Check(ne, "Function constructed by construct stub.", 3269 a3, Operand(JS_FUNCTION_TYPE)); 3270#endif 3271 3272 // Now allocate the JSObject in new space. 3273 // a0: argc 3274 // a1: constructor function 3275 // a2: initial map 3276 // t7: undefined 3277 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset)); 3278 __ AllocateInNewSpace(a3, 3279 t4, 3280 t5, 3281 t6, 3282 &generic_stub_call, 3283 SIZE_IN_WORDS); 3284 3285 // Allocated the JSObject, now initialize the fields. Map is set to initial 3286 // map and properties and elements are set to empty fixed array. 3287 // a0: argc 3288 // a1: constructor function 3289 // a2: initial map 3290 // a3: object size (in words) 3291 // t4: JSObject (not tagged) 3292 // t7: undefined 3293 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex); 3294 __ mov(t5, t4); 3295 __ sw(a2, MemOperand(t5, JSObject::kMapOffset)); 3296 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset)); 3297 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset)); 3298 __ Addu(t5, t5, Operand(3 * kPointerSize)); 3299 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); 3300 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset); 3301 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset); 3302 3303 3304 // Calculate the location of the first argument. The stack contains only the 3305 // argc arguments. 3306 __ sll(a1, a0, kPointerSizeLog2); 3307 __ Addu(a1, a1, sp); 3308 3309 // Fill all the in-object properties with undefined. 3310 // a0: argc 3311 // a1: first argument 3312 // a3: object size (in words) 3313 // t4: JSObject (not tagged) 3314 // t5: First in-object property of JSObject (not tagged) 3315 // t7: undefined 3316 // Fill the initialized properties with a constant value or a passed argument 3317 // depending on the this.x = ...; assignment in the function. 3318 SharedFunctionInfo* shared = function->shared(); 3319 for (int i = 0; i < shared->this_property_assignments_count(); i++) { 3320 if (shared->IsThisPropertyAssignmentArgument(i)) { 3321 Label not_passed, next; 3322 // Check if the argument assigned to the property is actually passed. 3323 int arg_number = shared->GetThisPropertyAssignmentArgument(i); 3324 __ Branch(¬_passed, less_equal, a0, Operand(arg_number)); 3325 // Argument passed - find it on the stack. 3326 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize)); 3327 __ sw(a2, MemOperand(t5)); 3328 __ Addu(t5, t5, kPointerSize); 3329 __ jmp(&next); 3330 __ bind(¬_passed); 3331 // Set the property to undefined. 3332 __ sw(t7, MemOperand(t5)); 3333 __ Addu(t5, t5, Operand(kPointerSize)); 3334 __ bind(&next); 3335 } else { 3336 // Set the property to the constant value. 3337 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i)); 3338 __ li(a2, Operand(constant)); 3339 __ sw(a2, MemOperand(t5)); 3340 __ Addu(t5, t5, kPointerSize); 3341 } 3342 } 3343 3344 // Fill the unused in-object property fields with undefined. 3345 ASSERT(function->has_initial_map()); 3346 for (int i = shared->this_property_assignments_count(); 3347 i < function->initial_map()->inobject_properties(); 3348 i++) { 3349 __ sw(t7, MemOperand(t5)); 3350 __ Addu(t5, t5, kPointerSize); 3351 } 3352 3353 // a0: argc 3354 // t4: JSObject (not tagged) 3355 // Move argc to a1 and the JSObject to return to v0 and tag it. 3356 __ mov(a1, a0); 3357 __ mov(v0, t4); 3358 __ Or(v0, v0, Operand(kHeapObjectTag)); 3359 3360 // v0: JSObject 3361 // a1: argc 3362 // Remove caller arguments and receiver from the stack and return. 3363 __ sll(t0, a1, kPointerSizeLog2); 3364 __ Addu(sp, sp, t0); 3365 __ Addu(sp, sp, Operand(kPointerSize)); 3366 Counters* counters = masm()->isolate()->counters(); 3367 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2); 3368 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2); 3369 __ Ret(); 3370 3371 // Jump to the generic stub in case the specialized code cannot handle the 3372 // construction. 3373 __ bind(&generic_stub_call); 3374 Handle<Code> generic_construct_stub = 3375 masm()->isolate()->builtins()->JSConstructStubGeneric(); 3376 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); 3377 3378 // Return the generated code. 3379 return GetCode(); 3380} 3381 3382 3383MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad( 3384 JSObject*receiver, ExternalArrayType array_type) { 3385 // ----------- S t a t e ------------- 3386 // -- ra : return address 3387 // -- a0 : key 3388 // -- a1 : receiver 3389 // ----------------------------------- 3390 MaybeObject* maybe_stub = 3391 KeyedLoadExternalArrayStub(array_type).TryGetCode(); 3392 Code* stub; 3393 if (!maybe_stub->To(&stub)) return maybe_stub; 3394 __ DispatchMap(a1, 3395 a2, 3396 Handle<Map>(receiver->map()), 3397 Handle<Code>(stub), 3398 DO_SMI_CHECK); 3399 3400 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss(); 3401 __ Jump(ic, RelocInfo::CODE_TARGET); 3402 3403 // Return the generated code. 3404 return GetCode(); 3405} 3406 3407 3408MaybeObject* ExternalArrayStoreStubCompiler::CompileStore( 3409 JSObject* receiver, ExternalArrayType array_type) { 3410 // ----------- S t a t e ------------- 3411 // -- a0 : value 3412 // -- a1 : name 3413 // -- a2 : receiver 3414 // -- ra : return address 3415 // ----------------------------------- 3416 MaybeObject* maybe_stub = 3417 KeyedStoreExternalArrayStub(array_type).TryGetCode(); 3418 Code* stub; 3419 if (!maybe_stub->To(&stub)) return maybe_stub; 3420 __ DispatchMap(a2, 3421 a3, 3422 Handle<Map>(receiver->map()), 3423 Handle<Code>(stub), 3424 DO_SMI_CHECK); 3425 3426 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); 3427 __ Jump(ic, RelocInfo::CODE_TARGET); 3428 3429 return GetCode(); 3430} 3431 3432 3433#undef __ 3434#define __ ACCESS_MASM(masm) 3435 3436 3437static bool IsElementTypeSigned(ExternalArrayType array_type) { 3438 switch (array_type) { 3439 case kExternalByteArray: 3440 case kExternalShortArray: 3441 case kExternalIntArray: 3442 return true; 3443 3444 case kExternalUnsignedByteArray: 3445 case kExternalUnsignedShortArray: 3446 case kExternalUnsignedIntArray: 3447 return false; 3448 3449 default: 3450 UNREACHABLE(); 3451 return false; 3452 } 3453} 3454 3455 3456void KeyedLoadStubCompiler::GenerateLoadExternalArray( 3457 MacroAssembler* masm, 3458 ExternalArrayType array_type) { 3459 // ---------- S t a t e -------------- 3460 // -- ra : return address 3461 // -- a0 : key 3462 // -- a1 : receiver 3463 // ----------------------------------- 3464 Label miss_force_generic, slow, failed_allocation; 3465 3466 Register key = a0; 3467 Register receiver = a1; 3468 3469 // This stub is meant to be tail-jumped to, the receiver must already 3470 // have been verified by the caller to not be a smi. 3471 3472 // Check that the key is a smi. 3473 __ JumpIfNotSmi(key, &miss_force_generic); 3474 3475 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset)); 3476 // a3: elements array 3477 3478 // Check that the index is in range. 3479 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset)); 3480 __ sra(t2, key, kSmiTagSize); 3481 // Unsigned comparison catches both negative and too-large values. 3482 __ Branch(&miss_force_generic, Uless, t1, Operand(t2)); 3483 3484 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset)); 3485 // a3: base pointer of external storage 3486 3487 // We are not untagging smi key and instead work with it 3488 // as if it was premultiplied by 2. 3489 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); 3490 3491 Register value = a2; 3492 switch (array_type) { 3493 case kExternalByteArray: 3494 __ srl(t2, key, 1); 3495 __ addu(t3, a3, t2); 3496 __ lb(value, MemOperand(t3, 0)); 3497 break; 3498 case kExternalPixelArray: 3499 case kExternalUnsignedByteArray: 3500 __ srl(t2, key, 1); 3501 __ addu(t3, a3, t2); 3502 __ lbu(value, MemOperand(t3, 0)); 3503 break; 3504 case kExternalShortArray: 3505 __ addu(t3, a3, key); 3506 __ lh(value, MemOperand(t3, 0)); 3507 break; 3508 case kExternalUnsignedShortArray: 3509 __ addu(t3, a3, key); 3510 __ lhu(value, MemOperand(t3, 0)); 3511 break; 3512 case kExternalIntArray: 3513 case kExternalUnsignedIntArray: 3514 __ sll(t2, key, 1); 3515 __ addu(t3, a3, t2); 3516 __ lw(value, MemOperand(t3, 0)); 3517 break; 3518 case kExternalFloatArray: 3519 __ sll(t3, t2, 2); 3520 __ addu(t3, a3, t3); 3521 if (CpuFeatures::IsSupported(FPU)) { 3522 CpuFeatures::Scope scope(FPU); 3523 __ lwc1(f0, MemOperand(t3, 0)); 3524 } else { 3525 __ lw(value, MemOperand(t3, 0)); 3526 } 3527 break; 3528 case kExternalDoubleArray: 3529 __ sll(t2, key, 2); 3530 __ addu(t3, a3, t2); 3531 if (CpuFeatures::IsSupported(FPU)) { 3532 CpuFeatures::Scope scope(FPU); 3533 __ ldc1(f0, MemOperand(t3, 0)); 3534 } else { 3535 // t3: pointer to the beginning of the double we want to load. 3536 __ lw(a2, MemOperand(t3, 0)); 3537 __ lw(a3, MemOperand(t3, Register::kSizeInBytes)); 3538 } 3539 break; 3540 default: 3541 UNREACHABLE(); 3542 break; 3543 } 3544 3545 // For integer array types: 3546 // a2: value 3547 // For float array type: 3548 // f0: value (if FPU is supported) 3549 // a2: value (if FPU is not supported) 3550 // For double array type: 3551 // f0: value (if FPU is supported) 3552 // a2/a3: value (if FPU is not supported) 3553 3554 if (array_type == kExternalIntArray) { 3555 // For the Int and UnsignedInt array types, we need to see whether 3556 // the value can be represented in a Smi. If not, we need to convert 3557 // it to a HeapNumber. 3558 Label box_int; 3559 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result. 3560 __ Branch(&box_int, lt, t3, Operand(zero_reg)); 3561 // Tag integer as smi and return it. 3562 __ sll(v0, value, kSmiTagSize); 3563 __ Ret(); 3564 3565 __ bind(&box_int); 3566 // Allocate a HeapNumber for the result and perform int-to-double 3567 // conversion. 3568 // The arm version uses a temporary here to save r0, but we don't need to 3569 // (a0 is not modified). 3570 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex); 3571 __ AllocateHeapNumber(v0, a3, t0, t1, &slow); 3572 3573 if (CpuFeatures::IsSupported(FPU)) { 3574 CpuFeatures::Scope scope(FPU); 3575 __ mtc1(value, f0); 3576 __ cvt_d_w(f0, f0); 3577 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag)); 3578 __ Ret(); 3579 } else { 3580 Register dst1 = t2; 3581 Register dst2 = t3; 3582 FloatingPointHelper::Destination dest = 3583 FloatingPointHelper::kCoreRegisters; 3584 FloatingPointHelper::ConvertIntToDouble(masm, 3585 value, 3586 dest, 3587 f0, 3588 dst1, 3589 dst2, 3590 t1, 3591 f2); 3592 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset)); 3593 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset)); 3594 __ Ret(); 3595 } 3596 } else if (array_type == kExternalUnsignedIntArray) { 3597 // The test is different for unsigned int values. Since we need 3598 // the value to be in the range of a positive smi, we can't 3599 // handle either of the top two bits being set in the value. 3600 if (CpuFeatures::IsSupported(FPU)) { 3601 CpuFeatures::Scope scope(FPU); 3602 Label pl_box_int; 3603 __ And(t2, value, Operand(0xC0000000)); 3604 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg)); 3605 3606 // It can fit in an Smi. 3607 // Tag integer as smi and return it. 3608 __ sll(v0, value, kSmiTagSize); 3609 __ Ret(); 3610 3611 __ bind(&pl_box_int); 3612 // Allocate a HeapNumber for the result and perform int-to-double 3613 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all 3614 // registers - also when jumping due to exhausted young space. 3615 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); 3616 __ AllocateHeapNumber(v0, t2, t3, t6, &slow); 3617 3618 // This is replaced by a macro: 3619 // __ mtc1(value, f0); // LS 32-bits. 3620 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero. 3621 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit. 3622 3623 __ Cvt_d_uw(f0, value); 3624 3625 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag)); 3626 3627 __ Ret(); 3628 } else { 3629 // Check whether unsigned integer fits into smi. 3630 Label box_int_0, box_int_1, done; 3631 __ And(t2, value, Operand(0x80000000)); 3632 __ Branch(&box_int_0, ne, t2, Operand(zero_reg)); 3633 __ And(t2, value, Operand(0x40000000)); 3634 __ Branch(&box_int_1, ne, t2, Operand(zero_reg)); 3635 3636 // Tag integer as smi and return it. 3637 __ sll(v0, value, kSmiTagSize); 3638 __ Ret(); 3639 3640 Register hiword = value; // a2. 3641 Register loword = a3; 3642 3643 __ bind(&box_int_0); 3644 // Integer does not have leading zeros. 3645 GenerateUInt2Double(masm, hiword, loword, t0, 0); 3646 __ Branch(&done); 3647 3648 __ bind(&box_int_1); 3649 // Integer has one leading zero. 3650 GenerateUInt2Double(masm, hiword, loword, t0, 1); 3651 3652 3653 __ bind(&done); 3654 // Integer was converted to double in registers hiword:loword. 3655 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber 3656 // clobbers all registers - also when jumping due to exhausted young 3657 // space. 3658 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); 3659 __ AllocateHeapNumber(t2, t3, t5, t6, &slow); 3660 3661 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset)); 3662 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset)); 3663 3664 __ mov(v0, t2); 3665 __ Ret(); 3666 } 3667 } else if (array_type == kExternalFloatArray) { 3668 // For the floating-point array type, we need to always allocate a 3669 // HeapNumber. 3670 if (CpuFeatures::IsSupported(FPU)) { 3671 CpuFeatures::Scope scope(FPU); 3672 // Allocate a HeapNumber for the result. Don't use a0 and a1 as 3673 // AllocateHeapNumber clobbers all registers - also when jumping due to 3674 // exhausted young space. 3675 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); 3676 __ AllocateHeapNumber(v0, t3, t5, t6, &slow); 3677 // The float (single) value is already in fpu reg f0 (if we use float). 3678 __ cvt_d_s(f0, f0); 3679 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag)); 3680 __ Ret(); 3681 } else { 3682 // Allocate a HeapNumber for the result. Don't use a0 and a1 as 3683 // AllocateHeapNumber clobbers all registers - also when jumping due to 3684 // exhausted young space. 3685 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); 3686 __ AllocateHeapNumber(v0, t3, t5, t6, &slow); 3687 // FPU is not available, do manual single to double conversion. 3688 3689 // a2: floating point value (binary32). 3690 // v0: heap number for result 3691 3692 // Extract mantissa to t4. 3693 __ And(t4, value, Operand(kBinary32MantissaMask)); 3694 3695 // Extract exponent to t5. 3696 __ srl(t5, value, kBinary32MantissaBits); 3697 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits)); 3698 3699 Label exponent_rebiased; 3700 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg)); 3701 3702 __ li(t0, 0x7ff); 3703 __ Xor(t1, t5, Operand(0xFF)); 3704 __ movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff. 3705 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff)); 3706 3707 // Rebias exponent. 3708 __ Addu(t5, 3709 t5, 3710 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias)); 3711 3712 __ bind(&exponent_rebiased); 3713 __ And(a2, value, Operand(kBinary32SignMask)); 3714 value = no_reg; 3715 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord); 3716 __ or_(a2, a2, t0); 3717 3718 // Shift mantissa. 3719 static const int kMantissaShiftForHiWord = 3720 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord; 3721 3722 static const int kMantissaShiftForLoWord = 3723 kBitsPerInt - kMantissaShiftForHiWord; 3724 3725 __ srl(t0, t4, kMantissaShiftForHiWord); 3726 __ or_(a2, a2, t0); 3727 __ sll(a0, t4, kMantissaShiftForLoWord); 3728 3729 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset)); 3730 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset)); 3731 __ Ret(); 3732 } 3733 3734 } else if (array_type == kExternalDoubleArray) { 3735 if (CpuFeatures::IsSupported(FPU)) { 3736 CpuFeatures::Scope scope(FPU); 3737 // Allocate a HeapNumber for the result. Don't use a0 and a1 as 3738 // AllocateHeapNumber clobbers all registers - also when jumping due to 3739 // exhausted young space. 3740 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); 3741 __ AllocateHeapNumber(v0, t3, t5, t6, &slow); 3742 // The double value is already in f0 3743 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); 3744 __ Ret(); 3745 } else { 3746 // Allocate a HeapNumber for the result. Don't use a0 and a1 as 3747 // AllocateHeapNumber clobbers all registers - also when jumping due to 3748 // exhausted young space. 3749 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); 3750 __ AllocateHeapNumber(v0, t3, t5, t6, &slow); 3751 3752 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset)); 3753 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset)); 3754 __ Ret(); 3755 } 3756 3757 } else { 3758 // Tag integer as smi and return it. 3759 __ sll(v0, value, kSmiTagSize); 3760 __ Ret(); 3761 } 3762 3763 // Slow case, key and receiver still in a0 and a1. 3764 __ bind(&slow); 3765 __ IncrementCounter( 3766 masm->isolate()->counters()->keyed_load_external_array_slow(), 3767 1, a2, a3); 3768 3769 // ---------- S t a t e -------------- 3770 // -- ra : return address 3771 // -- a0 : key 3772 // -- a1 : receiver 3773 // ----------------------------------- 3774 3775 __ Push(a1, a0); 3776 3777 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); 3778 3779 __ bind(&miss_force_generic); 3780 Code* stub = masm->isolate()->builtins()->builtin( 3781 Builtins::kKeyedLoadIC_MissForceGeneric); 3782 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET); 3783} 3784 3785 3786void KeyedStoreStubCompiler::GenerateStoreExternalArray( 3787 MacroAssembler* masm, 3788 ExternalArrayType array_type) { 3789 // ---------- S t a t e -------------- 3790 // -- a0 : value 3791 // -- a1 : key 3792 // -- a2 : receiver 3793 // -- ra : return address 3794 // ----------------------------------- 3795 3796 Label slow, check_heap_number, miss_force_generic; 3797 3798 // Register usage. 3799 Register value = a0; 3800 Register key = a1; 3801 Register receiver = a2; 3802 // a3 mostly holds the elements array or the destination external array. 3803 3804 // This stub is meant to be tail-jumped to, the receiver must already 3805 // have been verified by the caller to not be a smi. 3806 3807 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset)); 3808 3809 // Check that the key is a smi. 3810 __ JumpIfNotSmi(key, &miss_force_generic); 3811 3812 // Check that the index is in range. 3813 __ SmiUntag(t0, key); 3814 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset)); 3815 // Unsigned comparison catches both negative and too-large values. 3816 __ Branch(&miss_force_generic, Ugreater_equal, t0, Operand(t1)); 3817 3818 // Handle both smis and HeapNumbers in the fast path. Go to the 3819 // runtime for all other kinds of values. 3820 // a3: external array. 3821 // t0: key (integer). 3822 3823 if (array_type == kExternalPixelArray) { 3824 // Double to pixel conversion is only implemented in the runtime for now. 3825 __ JumpIfNotSmi(value, &slow); 3826 } else { 3827 __ JumpIfNotSmi(value, &check_heap_number); 3828 } 3829 __ SmiUntag(t1, value); 3830 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset)); 3831 3832 // a3: base pointer of external storage. 3833 // t0: key (integer). 3834 // t1: value (integer). 3835 3836 switch (array_type) { 3837 case kExternalPixelArray: { 3838 // Clamp the value to [0..255]. 3839 // v0 is used as a scratch register here. 3840 Label done; 3841 __ li(v0, Operand(255)); 3842 // Normal branch: nop in delay slot. 3843 __ Branch(&done, gt, t1, Operand(v0)); 3844 // Use delay slot in this branch. 3845 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg)); 3846 __ mov(v0, zero_reg); // In delay slot. 3847 __ mov(v0, t1); // Value is in range 0..255. 3848 __ bind(&done); 3849 __ mov(t1, v0); 3850 __ addu(t8, a3, t0); 3851 __ sb(t1, MemOperand(t8, 0)); 3852 } 3853 break; 3854 case kExternalByteArray: 3855 case kExternalUnsignedByteArray: 3856 __ addu(t8, a3, t0); 3857 __ sb(t1, MemOperand(t8, 0)); 3858 break; 3859 case kExternalShortArray: 3860 case kExternalUnsignedShortArray: 3861 __ sll(t8, t0, 1); 3862 __ addu(t8, a3, t8); 3863 __ sh(t1, MemOperand(t8, 0)); 3864 break; 3865 case kExternalIntArray: 3866 case kExternalUnsignedIntArray: 3867 __ sll(t8, t0, 2); 3868 __ addu(t8, a3, t8); 3869 __ sw(t1, MemOperand(t8, 0)); 3870 break; 3871 case kExternalFloatArray: 3872 // Perform int-to-float conversion and store to memory. 3873 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4); 3874 break; 3875 case kExternalDoubleArray: 3876 __ sll(t8, t0, 3); 3877 __ addu(a3, a3, t8); 3878 // a3: effective address of the double element 3879 FloatingPointHelper::Destination destination; 3880 if (CpuFeatures::IsSupported(FPU)) { 3881 destination = FloatingPointHelper::kFPURegisters; 3882 } else { 3883 destination = FloatingPointHelper::kCoreRegisters; 3884 } 3885 FloatingPointHelper::ConvertIntToDouble( 3886 masm, t1, destination, 3887 f0, t2, t3, // These are: double_dst, dst1, dst2. 3888 t0, f2); // These are: scratch2, single_scratch. 3889 if (destination == FloatingPointHelper::kFPURegisters) { 3890 CpuFeatures::Scope scope(FPU); 3891 __ sdc1(f0, MemOperand(a3, 0)); 3892 } else { 3893 __ sw(t2, MemOperand(a3, 0)); 3894 __ sw(t3, MemOperand(a3, Register::kSizeInBytes)); 3895 } 3896 break; 3897 default: 3898 UNREACHABLE(); 3899 break; 3900 } 3901 3902 // Entry registers are intact, a0 holds the value which is the return value. 3903 __ mov(v0, value); 3904 __ Ret(); 3905 3906 if (array_type != kExternalPixelArray) { 3907 // a3: external array. 3908 // t0: index (integer). 3909 __ bind(&check_heap_number); 3910 __ GetObjectType(value, t1, t2); 3911 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE)); 3912 3913 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset)); 3914 3915 // a3: base pointer of external storage. 3916 // t0: key (integer). 3917 3918 // The WebGL specification leaves the behavior of storing NaN and 3919 // +/-Infinity into integer arrays basically undefined. For more 3920 // reproducible behavior, convert these to zero. 3921 3922 if (CpuFeatures::IsSupported(FPU)) { 3923 CpuFeatures::Scope scope(FPU); 3924 3925 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset)); 3926 3927 if (array_type == kExternalFloatArray) { 3928 __ cvt_s_d(f0, f0); 3929 __ sll(t8, t0, 2); 3930 __ addu(t8, a3, t8); 3931 __ swc1(f0, MemOperand(t8, 0)); 3932 } else if (array_type == kExternalDoubleArray) { 3933 __ sll(t8, t0, 3); 3934 __ addu(t8, a3, t8); 3935 __ sdc1(f0, MemOperand(t8, 0)); 3936 } else { 3937 Label done; 3938 3939 // Need to perform float-to-int conversion. 3940 // Test whether exponent equal to 0x7FF (infinity or NaN). 3941 3942 __ mfc1(t3, f1); // Move exponent word of double to t3 (as raw bits). 3943 __ li(t1, Operand(0x7FF00000)); 3944 __ And(t3, t3, Operand(t1)); 3945 __ Branch(USE_DELAY_SLOT, &done, eq, t3, Operand(t1)); 3946 __ mov(t3, zero_reg); // In delay slot. 3947 3948 // Not infinity or NaN simply convert to int. 3949 if (IsElementTypeSigned(array_type)) { 3950 __ trunc_w_d(f0, f0); 3951 __ mfc1(t3, f0); 3952 } else { 3953 __ Trunc_uw_d(f0, t3); 3954 } 3955 3956 // t3: HeapNumber converted to integer 3957 __ bind(&done); 3958 switch (array_type) { 3959 case kExternalByteArray: 3960 case kExternalUnsignedByteArray: 3961 __ addu(t8, a3, t0); 3962 __ sb(t3, MemOperand(t8, 0)); 3963 break; 3964 case kExternalShortArray: 3965 case kExternalUnsignedShortArray: 3966 __ sll(t8, t0, 1); 3967 __ addu(t8, a3, t8); 3968 __ sh(t3, MemOperand(t8, 0)); 3969 break; 3970 case kExternalIntArray: 3971 case kExternalUnsignedIntArray: 3972 __ sll(t8, t0, 2); 3973 __ addu(t8, a3, t8); 3974 __ sw(t3, MemOperand(t8, 0)); 3975 break; 3976 default: 3977 UNREACHABLE(); 3978 break; 3979 } 3980 } 3981 3982 // Entry registers are intact, a0 holds the value 3983 // which is the return value. 3984 __ mov(v0, value); 3985 __ Ret(); 3986 } else { 3987 // FPU is not available, do manual conversions. 3988 3989 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset)); 3990 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset)); 3991 3992 if (array_type == kExternalFloatArray) { 3993 Label done, nan_or_infinity_or_zero; 3994 static const int kMantissaInHiWordShift = 3995 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord; 3996 3997 static const int kMantissaInLoWordShift = 3998 kBitsPerInt - kMantissaInHiWordShift; 3999 4000 // Test for all special exponent values: zeros, subnormal numbers, NaNs 4001 // and infinities. All these should be converted to 0. 4002 __ li(t5, HeapNumber::kExponentMask); 4003 __ and_(t6, t3, t5); 4004 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg)); 4005 4006 __ xor_(t1, t6, t5); 4007 __ li(t2, kBinary32ExponentMask); 4008 __ movz(t6, t2, t1); // Only if t6 is equal to t5. 4009 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5)); 4010 4011 // Rebias exponent. 4012 __ srl(t6, t6, HeapNumber::kExponentShift); 4013 __ Addu(t6, 4014 t6, 4015 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias)); 4016 4017 __ li(t1, Operand(kBinary32MaxExponent)); 4018 __ Slt(t1, t1, t6); 4019 __ And(t2, t3, Operand(HeapNumber::kSignMask)); 4020 __ Or(t2, t2, Operand(kBinary32ExponentMask)); 4021 __ movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent. 4022 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent)); 4023 4024 __ Slt(t1, t6, Operand(kBinary32MinExponent)); 4025 __ And(t2, t3, Operand(HeapNumber::kSignMask)); 4026 __ movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent. 4027 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent)); 4028 4029 __ And(t7, t3, Operand(HeapNumber::kSignMask)); 4030 __ And(t3, t3, Operand(HeapNumber::kMantissaMask)); 4031 __ sll(t3, t3, kMantissaInHiWordShift); 4032 __ or_(t7, t7, t3); 4033 __ srl(t4, t4, kMantissaInLoWordShift); 4034 __ or_(t7, t7, t4); 4035 __ sll(t6, t6, kBinary32ExponentShift); 4036 __ or_(t3, t7, t6); 4037 4038 __ bind(&done); 4039 __ sll(t9, a1, 2); 4040 __ addu(t9, a2, t9); 4041 __ sw(t3, MemOperand(t9, 0)); 4042 4043 // Entry registers are intact, a0 holds the value which is the return 4044 // value. 4045 __ mov(v0, value); 4046 __ Ret(); 4047 4048 __ bind(&nan_or_infinity_or_zero); 4049 __ And(t7, t3, Operand(HeapNumber::kSignMask)); 4050 __ And(t3, t3, Operand(HeapNumber::kMantissaMask)); 4051 __ or_(t6, t6, t7); 4052 __ sll(t3, t3, kMantissaInHiWordShift); 4053 __ or_(t6, t6, t3); 4054 __ srl(t4, t4, kMantissaInLoWordShift); 4055 __ or_(t3, t6, t4); 4056 __ Branch(&done); 4057 } else if (array_type == kExternalDoubleArray) { 4058 __ sll(t8, t0, 3); 4059 __ addu(t8, a3, t8); 4060 // t8: effective address of destination element. 4061 __ sw(t4, MemOperand(t8, 0)); 4062 __ sw(t3, MemOperand(t8, Register::kSizeInBytes)); 4063 __ Ret(); 4064 } else { 4065 bool is_signed_type = IsElementTypeSigned(array_type); 4066 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt; 4067 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000; 4068 4069 Label done, sign; 4070 4071 // Test for all special exponent values: zeros, subnormal numbers, NaNs 4072 // and infinities. All these should be converted to 0. 4073 __ li(t5, HeapNumber::kExponentMask); 4074 __ and_(t6, t3, t5); 4075 __ movz(t3, zero_reg, t6); // Only if t6 is equal to zero. 4076 __ Branch(&done, eq, t6, Operand(zero_reg)); 4077 4078 __ xor_(t2, t6, t5); 4079 __ movz(t3, zero_reg, t2); // Only if t6 is equal to t5. 4080 __ Branch(&done, eq, t6, Operand(t5)); 4081 4082 // Unbias exponent. 4083 __ srl(t6, t6, HeapNumber::kExponentShift); 4084 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias)); 4085 // If exponent is negative then result is 0. 4086 __ slt(t2, t6, zero_reg); 4087 __ movn(t3, zero_reg, t2); // Only if exponent is negative. 4088 __ Branch(&done, lt, t6, Operand(zero_reg)); 4089 4090 // If exponent is too big then result is minimal value. 4091 __ slti(t1, t6, meaningfull_bits - 1); 4092 __ li(t2, min_value); 4093 __ movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1. 4094 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1)); 4095 4096 __ And(t5, t3, Operand(HeapNumber::kSignMask)); 4097 __ And(t3, t3, Operand(HeapNumber::kMantissaMask)); 4098 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord)); 4099 4100 __ li(t9, HeapNumber::kMantissaBitsInTopWord); 4101 __ subu(t6, t9, t6); 4102 __ slt(t1, t6, zero_reg); 4103 __ srlv(t2, t3, t6); 4104 __ movz(t3, t2, t1); // Only if t6 is positive. 4105 __ Branch(&sign, ge, t6, Operand(zero_reg)); 4106 4107 __ subu(t6, zero_reg, t6); 4108 __ sllv(t3, t3, t6); 4109 __ li(t9, meaningfull_bits); 4110 __ subu(t6, t9, t6); 4111 __ srlv(t4, t4, t6); 4112 __ or_(t3, t3, t4); 4113 4114 __ bind(&sign); 4115 __ subu(t2, t3, zero_reg); 4116 __ movz(t3, t2, t5); // Only if t5 is zero. 4117 4118 __ bind(&done); 4119 4120 // Result is in t3. 4121 // This switch block should be exactly the same as above (FPU mode). 4122 switch (array_type) { 4123 case kExternalByteArray: 4124 case kExternalUnsignedByteArray: 4125 __ addu(t8, a3, t0); 4126 __ sb(t3, MemOperand(t8, 0)); 4127 break; 4128 case kExternalShortArray: 4129 case kExternalUnsignedShortArray: 4130 __ sll(t8, t0, 1); 4131 __ addu(t8, a3, t8); 4132 __ sh(t3, MemOperand(t8, 0)); 4133 break; 4134 case kExternalIntArray: 4135 case kExternalUnsignedIntArray: 4136 __ sll(t8, t0, 2); 4137 __ addu(t8, a3, t8); 4138 __ sw(t3, MemOperand(t8, 0)); 4139 break; 4140 default: 4141 UNREACHABLE(); 4142 break; 4143 } 4144 } 4145 } 4146 } 4147 4148 // Slow case, key and receiver still in a0 and a1. 4149 __ bind(&slow); 4150 __ IncrementCounter( 4151 masm->isolate()->counters()->keyed_load_external_array_slow(), 4152 1, a2, a3); 4153 // Entry registers are intact. 4154 // ---------- S t a t e -------------- 4155 // -- ra : return address 4156 // -- a0 : key 4157 // -- a1 : receiver 4158 // ----------------------------------- 4159 Handle<Code> slow_ic = 4160 masm->isolate()->builtins()->KeyedStoreIC_Slow(); 4161 __ Jump(slow_ic, RelocInfo::CODE_TARGET); 4162 4163 // Miss case, call the runtime. 4164 __ bind(&miss_force_generic); 4165 4166 // ---------- S t a t e -------------- 4167 // -- ra : return address 4168 // -- a0 : key 4169 // -- a1 : receiver 4170 // ----------------------------------- 4171 4172 Handle<Code> miss_ic = 4173 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); 4174 __ Jump(miss_ic, RelocInfo::CODE_TARGET); 4175} 4176 4177 4178void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { 4179 // ----------- S t a t e ------------- 4180 // -- ra : return address 4181 // -- a0 : key 4182 // -- a1 : receiver 4183 // ----------------------------------- 4184 Label miss_force_generic; 4185 4186 // This stub is meant to be tail-jumped to, the receiver must already 4187 // have been verified by the caller to not be a smi. 4188 4189 // Check that the key is a smi. 4190 __ JumpIfNotSmi(a0, &miss_force_generic); 4191 4192 // Get the elements array. 4193 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset)); 4194 __ AssertFastElements(a2); 4195 4196 // Check that the key is within bounds. 4197 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset)); 4198 __ Branch(&miss_force_generic, hs, a0, Operand(a3)); 4199 4200 // Load the result and make sure it's not the hole. 4201 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 4202 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); 4203 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize); 4204 __ Addu(t0, t0, a3); 4205 __ lw(t0, MemOperand(t0)); 4206 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex); 4207 __ Branch(&miss_force_generic, eq, t0, Operand(t1)); 4208 __ mov(v0, t0); 4209 __ Ret(); 4210 4211 __ bind(&miss_force_generic); 4212 Code* stub = masm->isolate()->builtins()->builtin( 4213 Builtins::kKeyedLoadIC_MissForceGeneric); 4214 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET); 4215} 4216 4217 4218void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, 4219 bool is_js_array) { 4220 // ----------- S t a t e ------------- 4221 // -- a0 : value 4222 // -- a1 : key 4223 // -- a2 : receiver 4224 // -- ra : return address 4225 // -- a3 : scratch 4226 // -- a4 : scratch (elements) 4227 // ----------------------------------- 4228 Label miss_force_generic; 4229 4230 Register value_reg = a0; 4231 Register key_reg = a1; 4232 Register receiver_reg = a2; 4233 Register scratch = a3; 4234 Register elements_reg = t0; 4235 Register scratch2 = t1; 4236 Register scratch3 = t2; 4237 4238 // This stub is meant to be tail-jumped to, the receiver must already 4239 // have been verified by the caller to not be a smi. 4240 4241 // Check that the key is a smi. 4242 __ JumpIfNotSmi(a0, &miss_force_generic); 4243 4244 // Get the elements array and make sure it is a fast element array, not 'cow'. 4245 __ lw(elements_reg, 4246 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); 4247 __ CheckMap(elements_reg, 4248 scratch, 4249 Heap::kFixedArrayMapRootIndex, 4250 &miss_force_generic, 4251 DONT_DO_SMI_CHECK); 4252 4253 // Check that the key is within bounds. 4254 if (is_js_array) { 4255 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); 4256 } else { 4257 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); 4258 } 4259 // Compare smis. 4260 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch)); 4261 4262 __ Addu(scratch, 4263 elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 4264 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); 4265 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize); 4266 __ Addu(scratch3, scratch2, scratch); 4267 __ sw(value_reg, MemOperand(scratch3)); 4268 __ RecordWrite(scratch, Operand(scratch2), receiver_reg , elements_reg); 4269 4270 // value_reg (a0) is preserved. 4271 // Done. 4272 __ Ret(); 4273 4274 __ bind(&miss_force_generic); 4275 Handle<Code> ic = 4276 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); 4277 __ Jump(ic, RelocInfo::CODE_TARGET); 4278} 4279 4280 4281#undef __ 4282 4283} } // namespace v8::internal 4284 4285#endif // V8_TARGET_ARCH_MIPS 4286