1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #if defined(V8_TARGET_ARCH_ARM) 31 32 #include "codegen.h" 33 #include "debug.h" 34 #include "deoptimizer.h" 35 #include "full-codegen.h" 36 #include "runtime.h" 37 38 namespace v8 { 39 namespace internal { 40 41 42 #define __ ACCESS_MASM(masm) 43 44 45 void Builtins::Generate_Adaptor(MacroAssembler* masm, 46 CFunctionId id, 47 BuiltinExtraArguments extra_args) { 48 // ----------- S t a t e ------------- 49 // -- r0 : number of arguments excluding receiver 50 // -- r1 : called function (only guaranteed when 51 // extra_args requires it) 52 // -- cp : context 53 // -- sp[0] : last argument 54 // -- ... 55 // -- sp[4 * (argc - 1)] : first argument (argc == r0) 56 // -- sp[4 * argc] : receiver 57 // ----------------------------------- 58 59 // Insert extra arguments. 60 int num_extra_args = 0; 61 if (extra_args == NEEDS_CALLED_FUNCTION) { 62 num_extra_args = 1; 63 __ push(r1); 64 } else { 65 ASSERT(extra_args == NO_EXTRA_ARGUMENTS); 66 } 67 68 // JumpToExternalReference expects r0 to contain the number of arguments 69 // including the receiver and the extra arguments. 70 __ add(r0, r0, Operand(num_extra_args + 1)); 71 __ JumpToExternalReference(ExternalReference(id, masm->isolate())); 72 } 73 74 75 // Load the built-in InternalArray function from the current context. 76 static void GenerateLoadInternalArrayFunction(MacroAssembler* masm, 77 Register result) { 78 // Load the global context. 79 80 __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 81 __ ldr(result, 82 FieldMemOperand(result, GlobalObject::kGlobalContextOffset)); 83 // Load the InternalArray function from the global context. 84 __ ldr(result, 85 MemOperand(result, 86 Context::SlotOffset( 87 Context::INTERNAL_ARRAY_FUNCTION_INDEX))); 88 } 89 90 91 // Load the built-in Array function from the current context. 92 static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) { 93 // Load the global context. 94 95 __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 96 __ ldr(result, 97 FieldMemOperand(result, GlobalObject::kGlobalContextOffset)); 98 // Load the Array function from the global context. 99 __ ldr(result, 100 MemOperand(result, 101 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); 102 } 103 104 105 // Allocate an empty JSArray. The allocated array is put into the result 106 // register. An elements backing store is allocated with size initial_capacity 107 // and filled with the hole values. 108 static void AllocateEmptyJSArray(MacroAssembler* masm, 109 Register array_function, 110 Register result, 111 Register scratch1, 112 Register scratch2, 113 Register scratch3, 114 Label* gc_required) { 115 const int initial_capacity = JSArray::kPreallocatedArrayElements; 116 STATIC_ASSERT(initial_capacity >= 0); 117 __ LoadInitialArrayMap(array_function, scratch2, scratch1); 118 119 // Allocate the JSArray object together with space for a fixed array with the 120 // requested elements. 121 int size = JSArray::kSize; 122 if (initial_capacity > 0) { 123 size += FixedArray::SizeFor(initial_capacity); 124 } 125 __ AllocateInNewSpace(size, 126 result, 127 scratch2, 128 scratch3, 129 gc_required, 130 TAG_OBJECT); 131 132 // Allocated the JSArray. Now initialize the fields except for the elements 133 // array. 134 // result: JSObject 135 // scratch1: initial map 136 // scratch2: start of next object 137 __ str(scratch1, FieldMemOperand(result, JSObject::kMapOffset)); 138 __ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex); 139 __ str(scratch1, FieldMemOperand(result, JSArray::kPropertiesOffset)); 140 // Field JSArray::kElementsOffset is initialized later. 141 __ mov(scratch3, Operand(0, RelocInfo::NONE)); 142 __ str(scratch3, FieldMemOperand(result, JSArray::kLengthOffset)); 143 144 if (initial_capacity == 0) { 145 __ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset)); 146 return; 147 } 148 149 // Calculate the location of the elements array and set elements array member 150 // of the JSArray. 151 // result: JSObject 152 // scratch2: start of next object 153 __ add(scratch1, result, Operand(JSArray::kSize)); 154 __ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset)); 155 156 // Clear the heap tag on the elements array. 157 __ sub(scratch1, scratch1, Operand(kHeapObjectTag)); 158 159 // Initialize the FixedArray and fill it with holes. FixedArray length is 160 // stored as a smi. 161 // result: JSObject 162 // scratch1: elements array (untagged) 163 // scratch2: start of next object 164 __ LoadRoot(scratch3, Heap::kFixedArrayMapRootIndex); 165 STATIC_ASSERT(0 * kPointerSize == FixedArray::kMapOffset); 166 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 167 __ mov(scratch3, Operand(Smi::FromInt(initial_capacity))); 168 STATIC_ASSERT(1 * kPointerSize == FixedArray::kLengthOffset); 169 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 170 171 // Fill the FixedArray with the hole value. Inline the code if short. 172 STATIC_ASSERT(2 * kPointerSize == FixedArray::kHeaderSize); 173 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex); 174 static const int kLoopUnfoldLimit = 4; 175 if (initial_capacity <= kLoopUnfoldLimit) { 176 for (int i = 0; i < initial_capacity; i++) { 177 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 178 } 179 } else { 180 Label loop, entry; 181 __ add(scratch2, scratch1, Operand(initial_capacity * kPointerSize)); 182 __ b(&entry); 183 __ bind(&loop); 184 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 185 __ bind(&entry); 186 __ cmp(scratch1, scratch2); 187 __ b(lt, &loop); 188 } 189 } 190 191 // Allocate a JSArray with the number of elements stored in a register. The 192 // register array_function holds the built-in Array function and the register 193 // array_size holds the size of the array as a smi. The allocated array is put 194 // into the result register and beginning and end of the FixedArray elements 195 // storage is put into registers elements_array_storage and elements_array_end 196 // (see below for when that is not the case). If the parameter fill_with_holes 197 // is true the allocated elements backing store is filled with the hole values 198 // otherwise it is left uninitialized. When the backing store is filled the 199 // register elements_array_storage is scratched. 200 static void AllocateJSArray(MacroAssembler* masm, 201 Register array_function, // Array function. 202 Register array_size, // As a smi, cannot be 0. 203 Register result, 204 Register elements_array_storage, 205 Register elements_array_end, 206 Register scratch1, 207 Register scratch2, 208 bool fill_with_hole, 209 Label* gc_required) { 210 // Load the initial map from the array function. 211 __ LoadInitialArrayMap(array_function, scratch2, elements_array_storage); 212 213 if (FLAG_debug_code) { // Assert that array size is not zero. 214 __ tst(array_size, array_size); 215 __ Assert(ne, "array size is unexpectedly 0"); 216 } 217 218 // Allocate the JSArray object together with space for a FixedArray with the 219 // requested number of elements. 220 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 221 __ mov(elements_array_end, 222 Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize)); 223 __ add(elements_array_end, 224 elements_array_end, 225 Operand(array_size, ASR, kSmiTagSize)); 226 __ AllocateInNewSpace( 227 elements_array_end, 228 result, 229 scratch1, 230 scratch2, 231 gc_required, 232 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); 233 234 // Allocated the JSArray. Now initialize the fields except for the elements 235 // array. 236 // result: JSObject 237 // elements_array_storage: initial map 238 // array_size: size of array (smi) 239 __ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset)); 240 __ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex); 241 __ str(elements_array_storage, 242 FieldMemOperand(result, JSArray::kPropertiesOffset)); 243 // Field JSArray::kElementsOffset is initialized later. 244 __ str(array_size, FieldMemOperand(result, JSArray::kLengthOffset)); 245 246 // Calculate the location of the elements array and set elements array member 247 // of the JSArray. 248 // result: JSObject 249 // array_size: size of array (smi) 250 __ add(elements_array_storage, result, Operand(JSArray::kSize)); 251 __ str(elements_array_storage, 252 FieldMemOperand(result, JSArray::kElementsOffset)); 253 254 // Clear the heap tag on the elements array. 255 STATIC_ASSERT(kSmiTag == 0); 256 __ sub(elements_array_storage, 257 elements_array_storage, 258 Operand(kHeapObjectTag)); 259 // Initialize the fixed array and fill it with holes. FixedArray length is 260 // stored as a smi. 261 // result: JSObject 262 // elements_array_storage: elements array (untagged) 263 // array_size: size of array (smi) 264 __ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex); 265 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); 266 __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex)); 267 STATIC_ASSERT(kSmiTag == 0); 268 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); 269 __ str(array_size, 270 MemOperand(elements_array_storage, kPointerSize, PostIndex)); 271 272 // Calculate elements array and elements array end. 273 // result: JSObject 274 // elements_array_storage: elements array element storage 275 // array_size: smi-tagged size of elements array 276 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); 277 __ add(elements_array_end, 278 elements_array_storage, 279 Operand(array_size, LSL, kPointerSizeLog2 - kSmiTagSize)); 280 281 // Fill the allocated FixedArray with the hole value if requested. 282 // result: JSObject 283 // elements_array_storage: elements array element storage 284 // elements_array_end: start of next object 285 if (fill_with_hole) { 286 Label loop, entry; 287 __ LoadRoot(scratch1, Heap::kTheHoleValueRootIndex); 288 __ jmp(&entry); 289 __ bind(&loop); 290 __ str(scratch1, 291 MemOperand(elements_array_storage, kPointerSize, PostIndex)); 292 __ bind(&entry); 293 __ cmp(elements_array_storage, elements_array_end); 294 __ b(lt, &loop); 295 } 296 } 297 298 // Create a new array for the built-in Array function. This function allocates 299 // the JSArray object and the FixedArray elements array and initializes these. 300 // If the Array cannot be constructed in native code the runtime is called. This 301 // function assumes the following state: 302 // r0: argc 303 // r1: constructor (built-in Array function) 304 // lr: return address 305 // sp[0]: last argument 306 // This function is used for both construct and normal calls of Array. The only 307 // difference between handling a construct call and a normal call is that for a 308 // construct call the constructor function in r1 needs to be preserved for 309 // entering the generic code. In both cases argc in r0 needs to be preserved. 310 // Both registers are preserved by this code so no need to differentiate between 311 // construct call and normal call. 312 static void ArrayNativeCode(MacroAssembler* masm, 313 Label* call_generic_code) { 314 Counters* counters = masm->isolate()->counters(); 315 Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array, 316 has_non_smi_element, finish, cant_transition_map, not_double; 317 318 // Check for array construction with zero arguments or one. 319 __ cmp(r0, Operand(0, RelocInfo::NONE)); 320 __ b(ne, &argc_one_or_more); 321 322 // Handle construction of an empty array. 323 __ bind(&empty_array); 324 AllocateEmptyJSArray(masm, 325 r1, 326 r2, 327 r3, 328 r4, 329 r5, 330 call_generic_code); 331 __ IncrementCounter(counters->array_function_native(), 1, r3, r4); 332 // Set up return value, remove receiver from stack and return. 333 __ mov(r0, r2); 334 __ add(sp, sp, Operand(kPointerSize)); 335 __ Jump(lr); 336 337 // Check for one argument. Bail out if argument is not smi or if it is 338 // negative. 339 __ bind(&argc_one_or_more); 340 __ cmp(r0, Operand(1)); 341 __ b(ne, &argc_two_or_more); 342 STATIC_ASSERT(kSmiTag == 0); 343 __ ldr(r2, MemOperand(sp)); // Get the argument from the stack. 344 __ tst(r2, r2); 345 __ b(ne, ¬_empty_array); 346 __ Drop(1); // Adjust stack. 347 __ mov(r0, Operand(0)); // Treat this as a call with argc of zero. 348 __ b(&empty_array); 349 350 __ bind(¬_empty_array); 351 __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC); 352 __ b(ne, call_generic_code); 353 354 // Handle construction of an empty array of a certain size. Bail out if size 355 // is too large to actually allocate an elements array. 356 STATIC_ASSERT(kSmiTag == 0); 357 __ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize)); 358 __ b(ge, call_generic_code); 359 360 // r0: argc 361 // r1: constructor 362 // r2: array_size (smi) 363 // sp[0]: argument 364 AllocateJSArray(masm, 365 r1, 366 r2, 367 r3, 368 r4, 369 r5, 370 r6, 371 r7, 372 true, 373 call_generic_code); 374 __ IncrementCounter(counters->array_function_native(), 1, r2, r4); 375 // Set up return value, remove receiver and argument from stack and return. 376 __ mov(r0, r3); 377 __ add(sp, sp, Operand(2 * kPointerSize)); 378 __ Jump(lr); 379 380 // Handle construction of an array from a list of arguments. 381 __ bind(&argc_two_or_more); 382 __ mov(r2, Operand(r0, LSL, kSmiTagSize)); // Convet argc to a smi. 383 384 // r0: argc 385 // r1: constructor 386 // r2: array_size (smi) 387 // sp[0]: last argument 388 AllocateJSArray(masm, 389 r1, 390 r2, 391 r3, 392 r4, 393 r5, 394 r6, 395 r7, 396 false, 397 call_generic_code); 398 __ IncrementCounter(counters->array_function_native(), 1, r2, r6); 399 400 // Fill arguments as array elements. Copy from the top of the stack (last 401 // element) to the array backing store filling it backwards. Note: 402 // elements_array_end points after the backing store therefore PreIndex is 403 // used when filling the backing store. 404 // r0: argc 405 // r3: JSArray 406 // r4: elements_array storage start (untagged) 407 // r5: elements_array_end (untagged) 408 // sp[0]: last argument 409 Label loop, entry; 410 __ mov(r7, sp); 411 __ jmp(&entry); 412 __ bind(&loop); 413 __ ldr(r2, MemOperand(r7, kPointerSize, PostIndex)); 414 if (FLAG_smi_only_arrays) { 415 __ JumpIfNotSmi(r2, &has_non_smi_element); 416 } 417 __ str(r2, MemOperand(r5, -kPointerSize, PreIndex)); 418 __ bind(&entry); 419 __ cmp(r4, r5); 420 __ b(lt, &loop); 421 422 __ bind(&finish); 423 __ mov(sp, r7); 424 425 // Remove caller arguments and receiver from the stack, setup return value and 426 // return. 427 // r0: argc 428 // r3: JSArray 429 // sp[0]: receiver 430 __ add(sp, sp, Operand(kPointerSize)); 431 __ mov(r0, r3); 432 __ Jump(lr); 433 434 __ bind(&has_non_smi_element); 435 // Double values are handled by the runtime. 436 __ CheckMap( 437 r2, r9, Heap::kHeapNumberMapRootIndex, ¬_double, DONT_DO_SMI_CHECK); 438 __ bind(&cant_transition_map); 439 __ UndoAllocationInNewSpace(r3, r4); 440 __ b(call_generic_code); 441 442 __ bind(¬_double); 443 // Transition FAST_SMI_ONLY_ELEMENTS to FAST_ELEMENTS. 444 // r3: JSArray 445 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); 446 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS, 447 FAST_ELEMENTS, 448 r2, 449 r9, 450 &cant_transition_map); 451 __ str(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); 452 __ RecordWriteField(r3, 453 HeapObject::kMapOffset, 454 r2, 455 r9, 456 kLRHasNotBeenSaved, 457 kDontSaveFPRegs, 458 EMIT_REMEMBERED_SET, 459 OMIT_SMI_CHECK); 460 Label loop2; 461 __ sub(r7, r7, Operand(kPointerSize)); 462 __ bind(&loop2); 463 __ ldr(r2, MemOperand(r7, kPointerSize, PostIndex)); 464 __ str(r2, MemOperand(r5, -kPointerSize, PreIndex)); 465 __ cmp(r4, r5); 466 __ b(lt, &loop2); 467 __ b(&finish); 468 } 469 470 471 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { 472 // ----------- S t a t e ------------- 473 // -- r0 : number of arguments 474 // -- lr : return address 475 // -- sp[...]: constructor arguments 476 // ----------------------------------- 477 Label generic_array_code, one_or_more_arguments, two_or_more_arguments; 478 479 // Get the InternalArray function. 480 GenerateLoadInternalArrayFunction(masm, r1); 481 482 if (FLAG_debug_code) { 483 // Initial map for the builtin InternalArray functions should be maps. 484 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); 485 __ tst(r2, Operand(kSmiTagMask)); 486 __ Assert(ne, "Unexpected initial map for InternalArray function"); 487 __ CompareObjectType(r2, r3, r4, MAP_TYPE); 488 __ Assert(eq, "Unexpected initial map for InternalArray function"); 489 } 490 491 // Run the native code for the InternalArray function called as a normal 492 // function. 493 ArrayNativeCode(masm, &generic_array_code); 494 495 // Jump to the generic array code if the specialized code cannot handle the 496 // construction. 497 __ bind(&generic_array_code); 498 499 Handle<Code> array_code = 500 masm->isolate()->builtins()->InternalArrayCodeGeneric(); 501 __ Jump(array_code, RelocInfo::CODE_TARGET); 502 } 503 504 505 void Builtins::Generate_ArrayCode(MacroAssembler* masm) { 506 // ----------- S t a t e ------------- 507 // -- r0 : number of arguments 508 // -- lr : return address 509 // -- sp[...]: constructor arguments 510 // ----------------------------------- 511 Label generic_array_code, one_or_more_arguments, two_or_more_arguments; 512 513 // Get the Array function. 514 GenerateLoadArrayFunction(masm, r1); 515 516 if (FLAG_debug_code) { 517 // Initial map for the builtin Array functions should be maps. 518 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); 519 __ tst(r2, Operand(kSmiTagMask)); 520 __ Assert(ne, "Unexpected initial map for Array function"); 521 __ CompareObjectType(r2, r3, r4, MAP_TYPE); 522 __ Assert(eq, "Unexpected initial map for Array function"); 523 } 524 525 // Run the native code for the Array function called as a normal function. 526 ArrayNativeCode(masm, &generic_array_code); 527 528 // Jump to the generic array code if the specialized code cannot handle 529 // the construction. 530 __ bind(&generic_array_code); 531 532 Handle<Code> array_code = 533 masm->isolate()->builtins()->ArrayCodeGeneric(); 534 __ Jump(array_code, RelocInfo::CODE_TARGET); 535 } 536 537 538 void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) { 539 // ----------- S t a t e ------------- 540 // -- r0 : number of arguments 541 // -- r1 : constructor function 542 // -- lr : return address 543 // -- sp[...]: constructor arguments 544 // ----------------------------------- 545 Label generic_constructor; 546 547 if (FLAG_debug_code) { 548 // The array construct code is only set for the builtin and internal 549 // Array functions which always have a map. 550 // Initial map for the builtin Array function should be a map. 551 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); 552 __ tst(r2, Operand(kSmiTagMask)); 553 __ Assert(ne, "Unexpected initial map for Array function"); 554 __ CompareObjectType(r2, r3, r4, MAP_TYPE); 555 __ Assert(eq, "Unexpected initial map for Array function"); 556 } 557 558 // Run the native code for the Array function called as a constructor. 559 ArrayNativeCode(masm, &generic_constructor); 560 561 // Jump to the generic construct code in case the specialized code cannot 562 // handle the construction. 563 __ bind(&generic_constructor); 564 Handle<Code> generic_construct_stub = 565 masm->isolate()->builtins()->JSConstructStubGeneric(); 566 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); 567 } 568 569 570 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { 571 // ----------- S t a t e ------------- 572 // -- r0 : number of arguments 573 // -- r1 : constructor function 574 // -- lr : return address 575 // -- sp[(argc - n - 1) * 4] : arg[n] (zero based) 576 // -- sp[argc * 4] : receiver 577 // ----------------------------------- 578 Counters* counters = masm->isolate()->counters(); 579 __ IncrementCounter(counters->string_ctor_calls(), 1, r2, r3); 580 581 Register function = r1; 582 if (FLAG_debug_code) { 583 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, r2); 584 __ cmp(function, Operand(r2)); 585 __ Assert(eq, "Unexpected String function"); 586 } 587 588 // Load the first arguments in r0 and get rid of the rest. 589 Label no_arguments; 590 __ cmp(r0, Operand(0, RelocInfo::NONE)); 591 __ b(eq, &no_arguments); 592 // First args = sp[(argc - 1) * 4]. 593 __ sub(r0, r0, Operand(1)); 594 __ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex)); 595 // sp now point to args[0], drop args[0] + receiver. 596 __ Drop(2); 597 598 Register argument = r2; 599 Label not_cached, argument_is_string; 600 NumberToStringStub::GenerateLookupNumberStringCache( 601 masm, 602 r0, // Input. 603 argument, // Result. 604 r3, // Scratch. 605 r4, // Scratch. 606 r5, // Scratch. 607 false, // Is it a Smi? 608 ¬_cached); 609 __ IncrementCounter(counters->string_ctor_cached_number(), 1, r3, r4); 610 __ bind(&argument_is_string); 611 612 // ----------- S t a t e ------------- 613 // -- r2 : argument converted to string 614 // -- r1 : constructor function 615 // -- lr : return address 616 // ----------------------------------- 617 618 Label gc_required; 619 __ AllocateInNewSpace(JSValue::kSize, 620 r0, // Result. 621 r3, // Scratch. 622 r4, // Scratch. 623 &gc_required, 624 TAG_OBJECT); 625 626 // Initialising the String Object. 627 Register map = r3; 628 __ LoadGlobalFunctionInitialMap(function, map, r4); 629 if (FLAG_debug_code) { 630 __ ldrb(r4, FieldMemOperand(map, Map::kInstanceSizeOffset)); 631 __ cmp(r4, Operand(JSValue::kSize >> kPointerSizeLog2)); 632 __ Assert(eq, "Unexpected string wrapper instance size"); 633 __ ldrb(r4, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset)); 634 __ cmp(r4, Operand(0, RelocInfo::NONE)); 635 __ Assert(eq, "Unexpected unused properties of string wrapper"); 636 } 637 __ str(map, FieldMemOperand(r0, HeapObject::kMapOffset)); 638 639 __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex); 640 __ str(r3, FieldMemOperand(r0, JSObject::kPropertiesOffset)); 641 __ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset)); 642 643 __ str(argument, FieldMemOperand(r0, JSValue::kValueOffset)); 644 645 // Ensure the object is fully initialized. 646 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); 647 648 __ Ret(); 649 650 // The argument was not found in the number to string cache. Check 651 // if it's a string already before calling the conversion builtin. 652 Label convert_argument; 653 __ bind(¬_cached); 654 __ JumpIfSmi(r0, &convert_argument); 655 656 // Is it a String? 657 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); 658 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset)); 659 STATIC_ASSERT(kNotStringTag != 0); 660 __ tst(r3, Operand(kIsNotStringMask)); 661 __ b(ne, &convert_argument); 662 __ mov(argument, r0); 663 __ IncrementCounter(counters->string_ctor_conversions(), 1, r3, r4); 664 __ b(&argument_is_string); 665 666 // Invoke the conversion builtin and put the result into r2. 667 __ bind(&convert_argument); 668 __ push(function); // Preserve the function. 669 __ IncrementCounter(counters->string_ctor_conversions(), 1, r3, r4); 670 { 671 FrameScope scope(masm, StackFrame::INTERNAL); 672 __ push(r0); 673 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION); 674 } 675 __ pop(function); 676 __ mov(argument, r0); 677 __ b(&argument_is_string); 678 679 // Load the empty string into r2, remove the receiver from the 680 // stack, and jump back to the case where the argument is a string. 681 __ bind(&no_arguments); 682 __ LoadRoot(argument, Heap::kEmptyStringRootIndex); 683 __ Drop(1); 684 __ b(&argument_is_string); 685 686 // At this point the argument is already a string. Call runtime to 687 // create a string wrapper. 688 __ bind(&gc_required); 689 __ IncrementCounter(counters->string_ctor_gc_required(), 1, r3, r4); 690 { 691 FrameScope scope(masm, StackFrame::INTERNAL); 692 __ push(argument); 693 __ CallRuntime(Runtime::kNewStringWrapper, 1); 694 } 695 __ Ret(); 696 } 697 698 699 static void Generate_JSConstructStubHelper(MacroAssembler* masm, 700 bool is_api_function, 701 bool count_constructions) { 702 // ----------- S t a t e ------------- 703 // -- r0 : number of arguments 704 // -- r1 : constructor function 705 // -- lr : return address 706 // -- sp[...]: constructor arguments 707 // ----------------------------------- 708 709 // Should never count constructions for api objects. 710 ASSERT(!is_api_function || !count_constructions); 711 712 Isolate* isolate = masm->isolate(); 713 714 // Enter a construct frame. 715 { 716 FrameScope scope(masm, StackFrame::CONSTRUCT); 717 718 // Preserve the two incoming parameters on the stack. 719 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); 720 __ push(r0); // Smi-tagged arguments count. 721 __ push(r1); // Constructor function. 722 723 // Try to allocate the object without transitioning into C code. If any of 724 // the preconditions is not met, the code bails out to the runtime call. 725 Label rt_call, allocated; 726 if (FLAG_inline_new) { 727 Label undo_allocation; 728 #ifdef ENABLE_DEBUGGER_SUPPORT 729 ExternalReference debug_step_in_fp = 730 ExternalReference::debug_step_in_fp_address(isolate); 731 __ mov(r2, Operand(debug_step_in_fp)); 732 __ ldr(r2, MemOperand(r2)); 733 __ tst(r2, r2); 734 __ b(ne, &rt_call); 735 #endif 736 737 // Load the initial map and verify that it is in fact a map. 738 // r1: constructor function 739 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); 740 __ JumpIfSmi(r2, &rt_call); 741 __ CompareObjectType(r2, r3, r4, MAP_TYPE); 742 __ b(ne, &rt_call); 743 744 // Check that the constructor is not constructing a JSFunction (see 745 // comments in Runtime_NewObject in runtime.cc). In which case the 746 // initial map's instance type would be JS_FUNCTION_TYPE. 747 // r1: constructor function 748 // r2: initial map 749 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE); 750 __ b(eq, &rt_call); 751 752 if (count_constructions) { 753 Label allocate; 754 // Decrease generous allocation count. 755 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 756 MemOperand constructor_count = 757 FieldMemOperand(r3, SharedFunctionInfo::kConstructionCountOffset); 758 __ ldrb(r4, constructor_count); 759 __ sub(r4, r4, Operand(1), SetCC); 760 __ strb(r4, constructor_count); 761 __ b(ne, &allocate); 762 763 __ Push(r1, r2); 764 765 __ push(r1); // constructor 766 // The call will replace the stub, so the countdown is only done once. 767 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); 768 769 __ pop(r2); 770 __ pop(r1); 771 772 __ bind(&allocate); 773 } 774 775 // Now allocate the JSObject on the heap. 776 // r1: constructor function 777 // r2: initial map 778 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset)); 779 __ AllocateInNewSpace(r3, r4, r5, r6, &rt_call, SIZE_IN_WORDS); 780 781 // Allocated the JSObject, now initialize the fields. Map is set to 782 // initial map and properties and elements are set to empty fixed array. 783 // r1: constructor function 784 // r2: initial map 785 // r3: object size 786 // r4: JSObject (not tagged) 787 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex); 788 __ mov(r5, r4); 789 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); 790 __ str(r2, MemOperand(r5, kPointerSize, PostIndex)); 791 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset); 792 __ str(r6, MemOperand(r5, kPointerSize, PostIndex)); 793 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset); 794 __ str(r6, MemOperand(r5, kPointerSize, PostIndex)); 795 796 // Fill all the in-object properties with the appropriate filler. 797 // r1: constructor function 798 // r2: initial map 799 // r3: object size (in words) 800 // r4: JSObject (not tagged) 801 // r5: First in-object property of JSObject (not tagged) 802 __ add(r6, r4, Operand(r3, LSL, kPointerSizeLog2)); // End of object. 803 ASSERT_EQ(3 * kPointerSize, JSObject::kHeaderSize); 804 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex); 805 if (count_constructions) { 806 __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset)); 807 __ Ubfx(r0, r0, Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte, 808 kBitsPerByte); 809 __ add(r0, r5, Operand(r0, LSL, kPointerSizeLog2)); 810 // r0: offset of first field after pre-allocated fields 811 if (FLAG_debug_code) { 812 __ cmp(r0, r6); 813 __ Assert(le, "Unexpected number of pre-allocated property fields."); 814 } 815 __ InitializeFieldsWithFiller(r5, r0, r7); 816 // To allow for truncation. 817 __ LoadRoot(r7, Heap::kOnePointerFillerMapRootIndex); 818 } 819 __ InitializeFieldsWithFiller(r5, r6, r7); 820 821 // Add the object tag to make the JSObject real, so that we can continue 822 // and jump into the continuation code at any time from now on. Any 823 // failures need to undo the allocation, so that the heap is in a 824 // consistent state and verifiable. 825 __ add(r4, r4, Operand(kHeapObjectTag)); 826 827 // Check if a non-empty properties array is needed. Continue with 828 // allocated object if not fall through to runtime call if it is. 829 // r1: constructor function 830 // r4: JSObject 831 // r5: start of next object (not tagged) 832 __ ldrb(r3, FieldMemOperand(r2, Map::kUnusedPropertyFieldsOffset)); 833 // The field instance sizes contains both pre-allocated property fields 834 // and in-object properties. 835 __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset)); 836 __ Ubfx(r6, r0, Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte, 837 kBitsPerByte); 838 __ add(r3, r3, Operand(r6)); 839 __ Ubfx(r6, r0, Map::kInObjectPropertiesByte * kBitsPerByte, 840 kBitsPerByte); 841 __ sub(r3, r3, Operand(r6), SetCC); 842 843 // Done if no extra properties are to be allocated. 844 __ b(eq, &allocated); 845 __ Assert(pl, "Property allocation count failed."); 846 847 // Scale the number of elements by pointer size and add the header for 848 // FixedArrays to the start of the next object calculation from above. 849 // r1: constructor 850 // r3: number of elements in properties array 851 // r4: JSObject 852 // r5: start of next object 853 __ add(r0, r3, Operand(FixedArray::kHeaderSize / kPointerSize)); 854 __ AllocateInNewSpace( 855 r0, 856 r5, 857 r6, 858 r2, 859 &undo_allocation, 860 static_cast<AllocationFlags>(RESULT_CONTAINS_TOP | SIZE_IN_WORDS)); 861 862 // Initialize the FixedArray. 863 // r1: constructor 864 // r3: number of elements in properties array 865 // r4: JSObject 866 // r5: FixedArray (not tagged) 867 __ LoadRoot(r6, Heap::kFixedArrayMapRootIndex); 868 __ mov(r2, r5); 869 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); 870 __ str(r6, MemOperand(r2, kPointerSize, PostIndex)); 871 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); 872 __ mov(r0, Operand(r3, LSL, kSmiTagSize)); 873 __ str(r0, MemOperand(r2, kPointerSize, PostIndex)); 874 875 // Initialize the fields to undefined. 876 // r1: constructor function 877 // r2: First element of FixedArray (not tagged) 878 // r3: number of elements in properties array 879 // r4: JSObject 880 // r5: FixedArray (not tagged) 881 __ add(r6, r2, Operand(r3, LSL, kPointerSizeLog2)); // End of object. 882 ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize); 883 { Label loop, entry; 884 if (count_constructions) { 885 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex); 886 } else if (FLAG_debug_code) { 887 __ LoadRoot(r8, Heap::kUndefinedValueRootIndex); 888 __ cmp(r7, r8); 889 __ Assert(eq, "Undefined value not loaded."); 890 } 891 __ b(&entry); 892 __ bind(&loop); 893 __ str(r7, MemOperand(r2, kPointerSize, PostIndex)); 894 __ bind(&entry); 895 __ cmp(r2, r6); 896 __ b(lt, &loop); 897 } 898 899 // Store the initialized FixedArray into the properties field of 900 // the JSObject 901 // r1: constructor function 902 // r4: JSObject 903 // r5: FixedArray (not tagged) 904 __ add(r5, r5, Operand(kHeapObjectTag)); // Add the heap tag. 905 __ str(r5, FieldMemOperand(r4, JSObject::kPropertiesOffset)); 906 907 // Continue with JSObject being successfully allocated 908 // r1: constructor function 909 // r4: JSObject 910 __ jmp(&allocated); 911 912 // Undo the setting of the new top so that the heap is verifiable. For 913 // example, the map's unused properties potentially do not match the 914 // allocated objects unused properties. 915 // r4: JSObject (previous new top) 916 __ bind(&undo_allocation); 917 __ UndoAllocationInNewSpace(r4, r5); 918 } 919 920 // Allocate the new receiver object using the runtime call. 921 // r1: constructor function 922 __ bind(&rt_call); 923 __ push(r1); // argument for Runtime_NewObject 924 __ CallRuntime(Runtime::kNewObject, 1); 925 __ mov(r4, r0); 926 927 // Receiver for constructor call allocated. 928 // r4: JSObject 929 __ bind(&allocated); 930 __ push(r4); 931 __ push(r4); 932 933 // Reload the number of arguments and the constructor from the stack. 934 // sp[0]: receiver 935 // sp[1]: receiver 936 // sp[2]: constructor function 937 // sp[3]: number of arguments (smi-tagged) 938 __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); 939 __ ldr(r3, MemOperand(sp, 3 * kPointerSize)); 940 941 // Set up pointer to last argument. 942 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); 943 944 // Set up number of arguments for function call below 945 __ mov(r0, Operand(r3, LSR, kSmiTagSize)); 946 947 // Copy arguments and receiver to the expression stack. 948 // r0: number of arguments 949 // r1: constructor function 950 // r2: address of last argument (caller sp) 951 // r3: number of arguments (smi-tagged) 952 // sp[0]: receiver 953 // sp[1]: receiver 954 // sp[2]: constructor function 955 // sp[3]: number of arguments (smi-tagged) 956 Label loop, entry; 957 __ b(&entry); 958 __ bind(&loop); 959 __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1)); 960 __ push(ip); 961 __ bind(&entry); 962 __ sub(r3, r3, Operand(2), SetCC); 963 __ b(ge, &loop); 964 965 // Call the function. 966 // r0: number of arguments 967 // r1: constructor function 968 if (is_api_function) { 969 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 970 Handle<Code> code = 971 masm->isolate()->builtins()->HandleApiCallConstruct(); 972 ParameterCount expected(0); 973 __ InvokeCode(code, expected, expected, 974 RelocInfo::CODE_TARGET, CALL_FUNCTION, CALL_AS_METHOD); 975 } else { 976 ParameterCount actual(r0); 977 __ InvokeFunction(r1, actual, CALL_FUNCTION, 978 NullCallWrapper(), CALL_AS_METHOD); 979 } 980 981 // Store offset of return address for deoptimizer. 982 if (!is_api_function && !count_constructions) { 983 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); 984 } 985 986 // Restore context from the frame. 987 // r0: result 988 // sp[0]: receiver 989 // sp[1]: constructor function 990 // sp[2]: number of arguments (smi-tagged) 991 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 992 993 // If the result is an object (in the ECMA sense), we should get rid 994 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 995 // on page 74. 996 Label use_receiver, exit; 997 998 // If the result is a smi, it is *not* an object in the ECMA sense. 999 // r0: result 1000 // sp[0]: receiver (newly allocated object) 1001 // sp[1]: constructor function 1002 // sp[2]: number of arguments (smi-tagged) 1003 __ JumpIfSmi(r0, &use_receiver); 1004 1005 // If the type of the result (stored in its map) is less than 1006 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. 1007 __ CompareObjectType(r0, r3, r3, FIRST_SPEC_OBJECT_TYPE); 1008 __ b(ge, &exit); 1009 1010 // Throw away the result of the constructor invocation and use the 1011 // on-stack receiver as the result. 1012 __ bind(&use_receiver); 1013 __ ldr(r0, MemOperand(sp)); 1014 1015 // Remove receiver from the stack, remove caller arguments, and 1016 // return. 1017 __ bind(&exit); 1018 // r0: result 1019 // sp[0]: receiver (newly allocated object) 1020 // sp[1]: constructor function 1021 // sp[2]: number of arguments (smi-tagged) 1022 __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); 1023 1024 // Leave construct frame. 1025 } 1026 1027 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1)); 1028 __ add(sp, sp, Operand(kPointerSize)); 1029 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, r1, r2); 1030 __ Jump(lr); 1031 } 1032 1033 1034 void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) { 1035 Generate_JSConstructStubHelper(masm, false, true); 1036 } 1037 1038 1039 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { 1040 Generate_JSConstructStubHelper(masm, false, false); 1041 } 1042 1043 1044 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { 1045 Generate_JSConstructStubHelper(masm, true, false); 1046 } 1047 1048 1049 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, 1050 bool is_construct) { 1051 // Called from Generate_JS_Entry 1052 // r0: code entry 1053 // r1: function 1054 // r2: receiver 1055 // r3: argc 1056 // r4: argv 1057 // r5-r7, cp may be clobbered 1058 1059 // Clear the context before we push it when entering the internal frame. 1060 __ mov(cp, Operand(0, RelocInfo::NONE)); 1061 1062 // Enter an internal frame. 1063 { 1064 FrameScope scope(masm, StackFrame::INTERNAL); 1065 1066 // Set up the context from the function argument. 1067 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 1068 1069 __ InitializeRootRegister(); 1070 1071 // Push the function and the receiver onto the stack. 1072 __ push(r1); 1073 __ push(r2); 1074 1075 // Copy arguments to the stack in a loop. 1076 // r1: function 1077 // r3: argc 1078 // r4: argv, i.e. points to first arg 1079 Label loop, entry; 1080 __ add(r2, r4, Operand(r3, LSL, kPointerSizeLog2)); 1081 // r2 points past last arg. 1082 __ b(&entry); 1083 __ bind(&loop); 1084 __ ldr(r0, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter 1085 __ ldr(r0, MemOperand(r0)); // dereference handle 1086 __ push(r0); // push parameter 1087 __ bind(&entry); 1088 __ cmp(r4, r2); 1089 __ b(ne, &loop); 1090 1091 // Initialize all JavaScript callee-saved registers, since they will be seen 1092 // by the garbage collector as part of handlers. 1093 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); 1094 __ mov(r5, Operand(r4)); 1095 __ mov(r6, Operand(r4)); 1096 __ mov(r7, Operand(r4)); 1097 if (kR9Available == 1) { 1098 __ mov(r9, Operand(r4)); 1099 } 1100 1101 // Invoke the code and pass argc as r0. 1102 __ mov(r0, Operand(r3)); 1103 if (is_construct) { 1104 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); 1105 __ CallStub(&stub); 1106 } else { 1107 ParameterCount actual(r0); 1108 __ InvokeFunction(r1, actual, CALL_FUNCTION, 1109 NullCallWrapper(), CALL_AS_METHOD); 1110 } 1111 // Exit the JS frame and remove the parameters (except function), and 1112 // return. 1113 // Respect ABI stack constraint. 1114 } 1115 __ Jump(lr); 1116 1117 // r0: result 1118 } 1119 1120 1121 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 1122 Generate_JSEntryTrampolineHelper(masm, false); 1123 } 1124 1125 1126 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 1127 Generate_JSEntryTrampolineHelper(masm, true); 1128 } 1129 1130 1131 void Builtins::Generate_LazyCompile(MacroAssembler* masm) { 1132 // Enter an internal frame. 1133 { 1134 FrameScope scope(masm, StackFrame::INTERNAL); 1135 1136 // Preserve the function. 1137 __ push(r1); 1138 // Push call kind information. 1139 __ push(r5); 1140 1141 // Push the function on the stack as the argument to the runtime function. 1142 __ push(r1); 1143 __ CallRuntime(Runtime::kLazyCompile, 1); 1144 // Calculate the entry point. 1145 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); 1146 1147 // Restore call kind information. 1148 __ pop(r5); 1149 // Restore saved function. 1150 __ pop(r1); 1151 1152 // Tear down internal frame. 1153 } 1154 1155 // Do a tail-call of the compiled function. 1156 __ Jump(r2); 1157 } 1158 1159 1160 void Builtins::Generate_LazyRecompile(MacroAssembler* masm) { 1161 // Enter an internal frame. 1162 { 1163 FrameScope scope(masm, StackFrame::INTERNAL); 1164 1165 // Preserve the function. 1166 __ push(r1); 1167 // Push call kind information. 1168 __ push(r5); 1169 1170 // Push the function on the stack as the argument to the runtime function. 1171 __ push(r1); 1172 __ CallRuntime(Runtime::kLazyRecompile, 1); 1173 // Calculate the entry point. 1174 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); 1175 1176 // Restore call kind information. 1177 __ pop(r5); 1178 // Restore saved function. 1179 __ pop(r1); 1180 1181 // Tear down internal frame. 1182 } 1183 1184 // Do a tail-call of the compiled function. 1185 __ Jump(r2); 1186 } 1187 1188 1189 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, 1190 Deoptimizer::BailoutType type) { 1191 { 1192 FrameScope scope(masm, StackFrame::INTERNAL); 1193 // Pass the function and deoptimization type to the runtime system. 1194 __ mov(r0, Operand(Smi::FromInt(static_cast<int>(type)))); 1195 __ push(r0); 1196 __ CallRuntime(Runtime::kNotifyDeoptimized, 1); 1197 } 1198 1199 // Get the full codegen state from the stack and untag it -> r6. 1200 __ ldr(r6, MemOperand(sp, 0 * kPointerSize)); 1201 __ SmiUntag(r6); 1202 // Switch on the state. 1203 Label with_tos_register, unknown_state; 1204 __ cmp(r6, Operand(FullCodeGenerator::NO_REGISTERS)); 1205 __ b(ne, &with_tos_register); 1206 __ add(sp, sp, Operand(1 * kPointerSize)); // Remove state. 1207 __ Ret(); 1208 1209 __ bind(&with_tos_register); 1210 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); 1211 __ cmp(r6, Operand(FullCodeGenerator::TOS_REG)); 1212 __ b(ne, &unknown_state); 1213 __ add(sp, sp, Operand(2 * kPointerSize)); // Remove state. 1214 __ Ret(); 1215 1216 __ bind(&unknown_state); 1217 __ stop("no cases left"); 1218 } 1219 1220 1221 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { 1222 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER); 1223 } 1224 1225 1226 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) { 1227 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY); 1228 } 1229 1230 1231 void Builtins::Generate_NotifyOSR(MacroAssembler* masm) { 1232 // For now, we are relying on the fact that Runtime::NotifyOSR 1233 // doesn't do any garbage collection which allows us to save/restore 1234 // the registers without worrying about which of them contain 1235 // pointers. This seems a bit fragile. 1236 __ stm(db_w, sp, kJSCallerSaved | kCalleeSaved | lr.bit() | fp.bit()); 1237 { 1238 FrameScope scope(masm, StackFrame::INTERNAL); 1239 __ CallRuntime(Runtime::kNotifyOSR, 0); 1240 } 1241 __ ldm(ia_w, sp, kJSCallerSaved | kCalleeSaved | lr.bit() | fp.bit()); 1242 __ Ret(); 1243 } 1244 1245 1246 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) { 1247 CpuFeatures::TryForceFeatureScope scope(VFP3); 1248 if (!CpuFeatures::IsSupported(VFP3)) { 1249 __ Abort("Unreachable code: Cannot optimize without VFP3 support."); 1250 return; 1251 } 1252 1253 // Lookup the function in the JavaScript frame and push it as an 1254 // argument to the on-stack replacement function. 1255 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1256 { 1257 FrameScope scope(masm, StackFrame::INTERNAL); 1258 __ push(r0); 1259 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1); 1260 } 1261 1262 // If the result was -1 it means that we couldn't optimize the 1263 // function. Just return and continue in the unoptimized version. 1264 Label skip; 1265 __ cmp(r0, Operand(Smi::FromInt(-1))); 1266 __ b(ne, &skip); 1267 __ Ret(); 1268 1269 __ bind(&skip); 1270 // Untag the AST id and push it on the stack. 1271 __ SmiUntag(r0); 1272 __ push(r0); 1273 1274 // Generate the code for doing the frame-to-frame translation using 1275 // the deoptimizer infrastructure. 1276 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR); 1277 generator.Generate(); 1278 } 1279 1280 1281 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { 1282 // 1. Make sure we have at least one argument. 1283 // r0: actual number of arguments 1284 { Label done; 1285 __ cmp(r0, Operand(0)); 1286 __ b(ne, &done); 1287 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 1288 __ push(r2); 1289 __ add(r0, r0, Operand(1)); 1290 __ bind(&done); 1291 } 1292 1293 // 2. Get the function to call (passed as receiver) from the stack, check 1294 // if it is a function. 1295 // r0: actual number of arguments 1296 Label slow, non_function; 1297 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); 1298 __ JumpIfSmi(r1, &non_function); 1299 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); 1300 __ b(ne, &slow); 1301 1302 // 3a. Patch the first argument if necessary when calling a function. 1303 // r0: actual number of arguments 1304 // r1: function 1305 Label shift_arguments; 1306 __ mov(r4, Operand(0, RelocInfo::NONE)); // indicate regular JS_FUNCTION 1307 { Label convert_to_object, use_global_receiver, patch_receiver; 1308 // Change context eagerly in case we need the global receiver. 1309 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 1310 1311 // Do not transform the receiver for strict mode functions. 1312 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 1313 __ ldr(r3, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset)); 1314 __ tst(r3, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + 1315 kSmiTagSize))); 1316 __ b(ne, &shift_arguments); 1317 1318 // Do not transform the receiver for native (Compilerhints already in r3). 1319 __ tst(r3, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); 1320 __ b(ne, &shift_arguments); 1321 1322 // Compute the receiver in non-strict mode. 1323 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 1324 __ ldr(r2, MemOperand(r2, -kPointerSize)); 1325 // r0: actual number of arguments 1326 // r1: function 1327 // r2: first argument 1328 __ JumpIfSmi(r2, &convert_to_object); 1329 1330 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 1331 __ cmp(r2, r3); 1332 __ b(eq, &use_global_receiver); 1333 __ LoadRoot(r3, Heap::kNullValueRootIndex); 1334 __ cmp(r2, r3); 1335 __ b(eq, &use_global_receiver); 1336 1337 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); 1338 __ CompareObjectType(r2, r3, r3, FIRST_SPEC_OBJECT_TYPE); 1339 __ b(ge, &shift_arguments); 1340 1341 __ bind(&convert_to_object); 1342 1343 { 1344 // Enter an internal frame in order to preserve argument count. 1345 FrameScope scope(masm, StackFrame::INTERNAL); 1346 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); // Smi-tagged. 1347 __ push(r0); 1348 1349 __ push(r2); 1350 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 1351 __ mov(r2, r0); 1352 1353 __ pop(r0); 1354 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); 1355 1356 // Exit the internal frame. 1357 } 1358 1359 // Restore the function to r1, and the flag to r4. 1360 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); 1361 __ mov(r4, Operand(0, RelocInfo::NONE)); 1362 __ jmp(&patch_receiver); 1363 1364 // Use the global receiver object from the called function as the 1365 // receiver. 1366 __ bind(&use_global_receiver); 1367 const int kGlobalIndex = 1368 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 1369 __ ldr(r2, FieldMemOperand(cp, kGlobalIndex)); 1370 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset)); 1371 __ ldr(r2, FieldMemOperand(r2, kGlobalIndex)); 1372 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); 1373 1374 __ bind(&patch_receiver); 1375 __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2)); 1376 __ str(r2, MemOperand(r3, -kPointerSize)); 1377 1378 __ jmp(&shift_arguments); 1379 } 1380 1381 // 3b. Check for function proxy. 1382 __ bind(&slow); 1383 __ mov(r4, Operand(1, RelocInfo::NONE)); // indicate function proxy 1384 __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE)); 1385 __ b(eq, &shift_arguments); 1386 __ bind(&non_function); 1387 __ mov(r4, Operand(2, RelocInfo::NONE)); // indicate non-function 1388 1389 // 3c. Patch the first argument when calling a non-function. The 1390 // CALL_NON_FUNCTION builtin expects the non-function callee as 1391 // receiver, so overwrite the first argument which will ultimately 1392 // become the receiver. 1393 // r0: actual number of arguments 1394 // r1: function 1395 // r4: call type (0: JS function, 1: function proxy, 2: non-function) 1396 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 1397 __ str(r1, MemOperand(r2, -kPointerSize)); 1398 1399 // 4. Shift arguments and return address one slot down on the stack 1400 // (overwriting the original receiver). Adjust argument count to make 1401 // the original first argument the new receiver. 1402 // r0: actual number of arguments 1403 // r1: function 1404 // r4: call type (0: JS function, 1: function proxy, 2: non-function) 1405 __ bind(&shift_arguments); 1406 { Label loop; 1407 // Calculate the copy start address (destination). Copy end address is sp. 1408 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 1409 1410 __ bind(&loop); 1411 __ ldr(ip, MemOperand(r2, -kPointerSize)); 1412 __ str(ip, MemOperand(r2)); 1413 __ sub(r2, r2, Operand(kPointerSize)); 1414 __ cmp(r2, sp); 1415 __ b(ne, &loop); 1416 // Adjust the actual number of arguments and remove the top element 1417 // (which is a copy of the last argument). 1418 __ sub(r0, r0, Operand(1)); 1419 __ pop(); 1420 } 1421 1422 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin, 1423 // or a function proxy via CALL_FUNCTION_PROXY. 1424 // r0: actual number of arguments 1425 // r1: function 1426 // r4: call type (0: JS function, 1: function proxy, 2: non-function) 1427 { Label function, non_proxy; 1428 __ tst(r4, r4); 1429 __ b(eq, &function); 1430 // Expected number of arguments is 0 for CALL_NON_FUNCTION. 1431 __ mov(r2, Operand(0, RelocInfo::NONE)); 1432 __ SetCallKind(r5, CALL_AS_METHOD); 1433 __ cmp(r4, Operand(1)); 1434 __ b(ne, &non_proxy); 1435 1436 __ push(r1); // re-add proxy object as additional argument 1437 __ add(r0, r0, Operand(1)); 1438 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY); 1439 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 1440 RelocInfo::CODE_TARGET); 1441 1442 __ bind(&non_proxy); 1443 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); 1444 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 1445 RelocInfo::CODE_TARGET); 1446 __ bind(&function); 1447 } 1448 1449 // 5b. Get the code to call from the function and check that the number of 1450 // expected arguments matches what we're providing. If so, jump 1451 // (tail-call) to the code in register edx without checking arguments. 1452 // r0: actual number of arguments 1453 // r1: function 1454 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 1455 __ ldr(r2, 1456 FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset)); 1457 __ mov(r2, Operand(r2, ASR, kSmiTagSize)); 1458 __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); 1459 __ SetCallKind(r5, CALL_AS_METHOD); 1460 __ cmp(r2, r0); // Check formal and actual parameter counts. 1461 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 1462 RelocInfo::CODE_TARGET, 1463 ne); 1464 1465 ParameterCount expected(0); 1466 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION, 1467 NullCallWrapper(), CALL_AS_METHOD); 1468 } 1469 1470 1471 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 1472 const int kIndexOffset = -5 * kPointerSize; 1473 const int kLimitOffset = -4 * kPointerSize; 1474 const int kArgsOffset = 2 * kPointerSize; 1475 const int kRecvOffset = 3 * kPointerSize; 1476 const int kFunctionOffset = 4 * kPointerSize; 1477 1478 { 1479 FrameScope frame_scope(masm, StackFrame::INTERNAL); 1480 1481 __ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function 1482 __ push(r0); 1483 __ ldr(r0, MemOperand(fp, kArgsOffset)); // get the args array 1484 __ push(r0); 1485 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); 1486 1487 // Check the stack for overflow. We are not trying to catch 1488 // interruptions (e.g. debug break and preemption) here, so the "real stack 1489 // limit" is checked. 1490 Label okay; 1491 __ LoadRoot(r2, Heap::kRealStackLimitRootIndex); 1492 // Make r2 the space we have left. The stack might already be overflowed 1493 // here which will cause r2 to become negative. 1494 __ sub(r2, sp, r2); 1495 // Check if the arguments will overflow the stack. 1496 __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1497 __ b(gt, &okay); // Signed comparison. 1498 1499 // Out of stack space. 1500 __ ldr(r1, MemOperand(fp, kFunctionOffset)); 1501 __ push(r1); 1502 __ push(r0); 1503 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); 1504 // End of stack check. 1505 1506 // Push current limit and index. 1507 __ bind(&okay); 1508 __ push(r0); // limit 1509 __ mov(r1, Operand(0, RelocInfo::NONE)); // initial index 1510 __ push(r1); 1511 1512 // Get the receiver. 1513 __ ldr(r0, MemOperand(fp, kRecvOffset)); 1514 1515 // Check that the function is a JS function (otherwise it must be a proxy). 1516 Label push_receiver; 1517 __ ldr(r1, MemOperand(fp, kFunctionOffset)); 1518 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); 1519 __ b(ne, &push_receiver); 1520 1521 // Change context eagerly to get the right global object if necessary. 1522 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 1523 // Load the shared function info while the function is still in r1. 1524 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 1525 1526 // Compute the receiver. 1527 // Do not transform the receiver for strict mode functions. 1528 Label call_to_object, use_global_receiver; 1529 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset)); 1530 __ tst(r2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + 1531 kSmiTagSize))); 1532 __ b(ne, &push_receiver); 1533 1534 // Do not transform the receiver for strict mode functions. 1535 __ tst(r2, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); 1536 __ b(ne, &push_receiver); 1537 1538 // Compute the receiver in non-strict mode. 1539 __ JumpIfSmi(r0, &call_to_object); 1540 __ LoadRoot(r1, Heap::kNullValueRootIndex); 1541 __ cmp(r0, r1); 1542 __ b(eq, &use_global_receiver); 1543 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); 1544 __ cmp(r0, r1); 1545 __ b(eq, &use_global_receiver); 1546 1547 // Check if the receiver is already a JavaScript object. 1548 // r0: receiver 1549 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); 1550 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE); 1551 __ b(ge, &push_receiver); 1552 1553 // Convert the receiver to a regular object. 1554 // r0: receiver 1555 __ bind(&call_to_object); 1556 __ push(r0); 1557 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 1558 __ b(&push_receiver); 1559 1560 // Use the current global receiver object as the receiver. 1561 __ bind(&use_global_receiver); 1562 const int kGlobalOffset = 1563 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 1564 __ ldr(r0, FieldMemOperand(cp, kGlobalOffset)); 1565 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset)); 1566 __ ldr(r0, FieldMemOperand(r0, kGlobalOffset)); 1567 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); 1568 1569 // Push the receiver. 1570 // r0: receiver 1571 __ bind(&push_receiver); 1572 __ push(r0); 1573 1574 // Copy all arguments from the array to the stack. 1575 Label entry, loop; 1576 __ ldr(r0, MemOperand(fp, kIndexOffset)); 1577 __ b(&entry); 1578 1579 // Load the current argument from the arguments array and push it to the 1580 // stack. 1581 // r0: current argument index 1582 __ bind(&loop); 1583 __ ldr(r1, MemOperand(fp, kArgsOffset)); 1584 __ push(r1); 1585 __ push(r0); 1586 1587 // Call the runtime to access the property in the arguments array. 1588 __ CallRuntime(Runtime::kGetProperty, 2); 1589 __ push(r0); 1590 1591 // Use inline caching to access the arguments. 1592 __ ldr(r0, MemOperand(fp, kIndexOffset)); 1593 __ add(r0, r0, Operand(1 << kSmiTagSize)); 1594 __ str(r0, MemOperand(fp, kIndexOffset)); 1595 1596 // Test if the copy loop has finished copying all the elements from the 1597 // arguments object. 1598 __ bind(&entry); 1599 __ ldr(r1, MemOperand(fp, kLimitOffset)); 1600 __ cmp(r0, r1); 1601 __ b(ne, &loop); 1602 1603 // Invoke the function. 1604 Label call_proxy; 1605 ParameterCount actual(r0); 1606 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); 1607 __ ldr(r1, MemOperand(fp, kFunctionOffset)); 1608 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); 1609 __ b(ne, &call_proxy); 1610 __ InvokeFunction(r1, actual, CALL_FUNCTION, 1611 NullCallWrapper(), CALL_AS_METHOD); 1612 1613 frame_scope.GenerateLeaveFrame(); 1614 __ add(sp, sp, Operand(3 * kPointerSize)); 1615 __ Jump(lr); 1616 1617 // Invoke the function proxy. 1618 __ bind(&call_proxy); 1619 __ push(r1); // add function proxy as last argument 1620 __ add(r0, r0, Operand(1)); 1621 __ mov(r2, Operand(0, RelocInfo::NONE)); 1622 __ SetCallKind(r5, CALL_AS_METHOD); 1623 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY); 1624 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 1625 RelocInfo::CODE_TARGET); 1626 1627 // Tear down the internal frame and remove function, receiver and args. 1628 } 1629 __ add(sp, sp, Operand(3 * kPointerSize)); 1630 __ Jump(lr); 1631 } 1632 1633 1634 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1635 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); 1636 __ mov(r4, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 1637 __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit()); 1638 __ add(fp, sp, Operand(3 * kPointerSize)); 1639 } 1640 1641 1642 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { 1643 // ----------- S t a t e ------------- 1644 // -- r0 : result being passed through 1645 // ----------------------------------- 1646 // Get the number of arguments passed (as a smi), tear down the frame and 1647 // then tear down the parameters. 1648 __ ldr(r1, MemOperand(fp, -3 * kPointerSize)); 1649 __ mov(sp, fp); 1650 __ ldm(ia_w, sp, fp.bit() | lr.bit()); 1651 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); 1652 __ add(sp, sp, Operand(kPointerSize)); // adjust for receiver 1653 } 1654 1655 1656 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { 1657 // ----------- S t a t e ------------- 1658 // -- r0 : actual number of arguments 1659 // -- r1 : function (passed through to callee) 1660 // -- r2 : expected number of arguments 1661 // -- r3 : code entry to call 1662 // -- r5 : call kind information 1663 // ----------------------------------- 1664 1665 Label invoke, dont_adapt_arguments; 1666 1667 Label enough, too_few; 1668 __ cmp(r0, r2); 1669 __ b(lt, &too_few); 1670 __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); 1671 __ b(eq, &dont_adapt_arguments); 1672 1673 { // Enough parameters: actual >= expected 1674 __ bind(&enough); 1675 EnterArgumentsAdaptorFrame(masm); 1676 1677 // Calculate copy start address into r0 and copy end address into r2. 1678 // r0: actual number of arguments as a smi 1679 // r1: function 1680 // r2: expected number of arguments 1681 // r3: code entry to call 1682 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1683 // adjust for return address and receiver 1684 __ add(r0, r0, Operand(2 * kPointerSize)); 1685 __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2)); 1686 1687 // Copy the arguments (including the receiver) to the new stack frame. 1688 // r0: copy start address 1689 // r1: function 1690 // r2: copy end address 1691 // r3: code entry to call 1692 1693 Label copy; 1694 __ bind(©); 1695 __ ldr(ip, MemOperand(r0, 0)); 1696 __ push(ip); 1697 __ cmp(r0, r2); // Compare before moving to next argument. 1698 __ sub(r0, r0, Operand(kPointerSize)); 1699 __ b(ne, ©); 1700 1701 __ b(&invoke); 1702 } 1703 1704 { // Too few parameters: Actual < expected 1705 __ bind(&too_few); 1706 EnterArgumentsAdaptorFrame(masm); 1707 1708 // Calculate copy start address into r0 and copy end address is fp. 1709 // r0: actual number of arguments as a smi 1710 // r1: function 1711 // r2: expected number of arguments 1712 // r3: code entry to call 1713 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1714 1715 // Copy the arguments (including the receiver) to the new stack frame. 1716 // r0: copy start address 1717 // r1: function 1718 // r2: expected number of arguments 1719 // r3: code entry to call 1720 Label copy; 1721 __ bind(©); 1722 // Adjust load for return address and receiver. 1723 __ ldr(ip, MemOperand(r0, 2 * kPointerSize)); 1724 __ push(ip); 1725 __ cmp(r0, fp); // Compare before moving to next argument. 1726 __ sub(r0, r0, Operand(kPointerSize)); 1727 __ b(ne, ©); 1728 1729 // Fill the remaining expected arguments with undefined. 1730 // r1: function 1731 // r2: expected number of arguments 1732 // r3: code entry to call 1733 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 1734 __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2)); 1735 __ sub(r2, r2, Operand(4 * kPointerSize)); // Adjust for frame. 1736 1737 Label fill; 1738 __ bind(&fill); 1739 __ push(ip); 1740 __ cmp(sp, r2); 1741 __ b(ne, &fill); 1742 } 1743 1744 // Call the entry point. 1745 __ bind(&invoke); 1746 __ Call(r3); 1747 1748 // Store offset of return address for deoptimizer. 1749 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset()); 1750 1751 // Exit frame and return. 1752 LeaveArgumentsAdaptorFrame(masm); 1753 __ Jump(lr); 1754 1755 1756 // ------------------------------------------- 1757 // Dont adapt arguments. 1758 // ------------------------------------------- 1759 __ bind(&dont_adapt_arguments); 1760 __ Jump(r3); 1761 } 1762 1763 1764 #undef __ 1765 1766 } } // namespace v8::internal 1767 1768 #endif // V8_TARGET_ARCH_ARM 1769