builtins-arm.cc revision 402d937239b0e2fd11bf2f4fe972ad78aa9fd481
1// Copyright 2006-2009 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include "v8.h" 29 30#include "codegen-inl.h" 31#include "debug.h" 32#include "runtime.h" 33 34namespace v8 { 35namespace internal { 36 37 38#define __ ACCESS_MASM(masm) 39 40 41void Builtins::Generate_Adaptor(MacroAssembler* masm, 42 CFunctionId id, 43 BuiltinExtraArguments extra_args) { 44 // ----------- S t a t e ------------- 45 // -- r0 : number of arguments excluding receiver 46 // -- r1 : called function (only guaranteed when 47 // extra_args requires it) 48 // -- cp : context 49 // -- sp[0] : last argument 50 // -- ... 51 // -- sp[4 * (argc - 1)] : first argument (argc == r0) 52 // -- sp[4 * argc] : receiver 53 // ----------------------------------- 54 55 // Insert extra arguments. 56 int num_extra_args = 0; 57 if (extra_args == NEEDS_CALLED_FUNCTION) { 58 num_extra_args = 1; 59 __ push(r1); 60 } else { 61 ASSERT(extra_args == NO_EXTRA_ARGUMENTS); 62 } 63 64 // JumpToRuntime expects r0 to contain the number of arguments 65 // including the receiver and the extra arguments. 66 __ add(r0, r0, Operand(num_extra_args + 1)); 67 __ JumpToRuntime(ExternalReference(id)); 68} 69 70 71// Load the built-in Array function from the current context. 72static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) { 73 // Load the global context. 74 75 __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 76 __ ldr(result, 77 FieldMemOperand(result, GlobalObject::kGlobalContextOffset)); 78 // Load the Array function from the global context. 79 __ ldr(result, 80 MemOperand(result, 81 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); 82} 83 84 85// This constant has the same value as JSArray::kPreallocatedArrayElements and 86// if JSArray::kPreallocatedArrayElements is changed handling of loop unfolding 87// below should be reconsidered. 88static const int kLoopUnfoldLimit = 4; 89 90 91// Allocate an empty JSArray. The allocated array is put into the result 92// register. An elements backing store is allocated with size initial_capacity 93// and filled with the hole values. 94static void AllocateEmptyJSArray(MacroAssembler* masm, 95 Register array_function, 96 Register result, 97 Register scratch1, 98 Register scratch2, 99 Register scratch3, 100 int initial_capacity, 101 Label* gc_required) { 102 ASSERT(initial_capacity > 0); 103 // Load the initial map from the array function. 104 __ ldr(scratch1, FieldMemOperand(array_function, 105 JSFunction::kPrototypeOrInitialMapOffset)); 106 107 // Allocate the JSArray object together with space for a fixed array with the 108 // requested elements. 109 int size = JSArray::kSize + FixedArray::SizeFor(initial_capacity); 110 __ AllocateInNewSpace(size / kPointerSize, 111 result, 112 scratch2, 113 scratch3, 114 gc_required, 115 TAG_OBJECT); 116 117 // Allocated the JSArray. Now initialize the fields except for the elements 118 // array. 119 // result: JSObject 120 // scratch1: initial map 121 // scratch2: start of next object 122 __ str(scratch1, FieldMemOperand(result, JSObject::kMapOffset)); 123 __ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex); 124 __ str(scratch1, FieldMemOperand(result, JSArray::kPropertiesOffset)); 125 // Field JSArray::kElementsOffset is initialized later. 126 __ mov(scratch3, Operand(0)); 127 __ str(scratch3, FieldMemOperand(result, JSArray::kLengthOffset)); 128 129 // Calculate the location of the elements array and set elements array member 130 // of the JSArray. 131 // result: JSObject 132 // scratch2: start of next object 133 __ lea(scratch1, MemOperand(result, JSArray::kSize)); 134 __ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset)); 135 136 // Clear the heap tag on the elements array. 137 __ and_(scratch1, scratch1, Operand(~kHeapObjectTagMask)); 138 139 // Initialize the FixedArray and fill it with holes. FixedArray length is not 140 // stored as a smi. 141 // result: JSObject 142 // scratch1: elements array (untagged) 143 // scratch2: start of next object 144 __ LoadRoot(scratch3, Heap::kFixedArrayMapRootIndex); 145 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); 146 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 147 __ mov(scratch3, Operand(initial_capacity)); 148 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); 149 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 150 151 // Fill the FixedArray with the hole value. 152 ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize); 153 ASSERT(initial_capacity <= kLoopUnfoldLimit); 154 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex); 155 for (int i = 0; i < initial_capacity; i++) { 156 __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); 157 } 158} 159 160// Allocate a JSArray with the number of elements stored in a register. The 161// register array_function holds the built-in Array function and the register 162// array_size holds the size of the array as a smi. The allocated array is put 163// into the result register and beginning and end of the FixedArray elements 164// storage is put into registers elements_array_storage and elements_array_end 165// (see below for when that is not the case). If the parameter fill_with_holes 166// is true the allocated elements backing store is filled with the hole values 167// otherwise it is left uninitialized. When the backing store is filled the 168// register elements_array_storage is scratched. 169static void AllocateJSArray(MacroAssembler* masm, 170 Register array_function, // Array function. 171 Register array_size, // As a smi. 172 Register result, 173 Register elements_array_storage, 174 Register elements_array_end, 175 Register scratch1, 176 Register scratch2, 177 bool fill_with_hole, 178 Label* gc_required) { 179 Label not_empty, allocated; 180 181 // Load the initial map from the array function. 182 __ ldr(elements_array_storage, 183 FieldMemOperand(array_function, 184 JSFunction::kPrototypeOrInitialMapOffset)); 185 186 // Check whether an empty sized array is requested. 187 __ tst(array_size, array_size); 188 __ b(nz, ¬_empty); 189 190 // If an empty array is requested allocate a small elements array anyway. This 191 // keeps the code below free of special casing for the empty array. 192 int size = JSArray::kSize + 193 FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); 194 __ AllocateInNewSpace(size / kPointerSize, 195 result, 196 elements_array_end, 197 scratch1, 198 gc_required, 199 TAG_OBJECT); 200 __ jmp(&allocated); 201 202 // Allocate the JSArray object together with space for a FixedArray with the 203 // requested number of elements. 204 __ bind(¬_empty); 205 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 206 __ mov(elements_array_end, 207 Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize)); 208 __ add(elements_array_end, 209 elements_array_end, 210 Operand(array_size, ASR, kSmiTagSize)); 211 __ AllocateInNewSpace(elements_array_end, 212 result, 213 scratch1, 214 scratch2, 215 gc_required, 216 TAG_OBJECT); 217 218 // Allocated the JSArray. Now initialize the fields except for the elements 219 // array. 220 // result: JSObject 221 // elements_array_storage: initial map 222 // array_size: size of array (smi) 223 __ bind(&allocated); 224 __ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset)); 225 __ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex); 226 __ str(elements_array_storage, 227 FieldMemOperand(result, JSArray::kPropertiesOffset)); 228 // Field JSArray::kElementsOffset is initialized later. 229 __ str(array_size, FieldMemOperand(result, JSArray::kLengthOffset)); 230 231 // Calculate the location of the elements array and set elements array member 232 // of the JSArray. 233 // result: JSObject 234 // array_size: size of array (smi) 235 __ add(elements_array_storage, result, Operand(JSArray::kSize)); 236 __ str(elements_array_storage, 237 FieldMemOperand(result, JSArray::kElementsOffset)); 238 239 // Clear the heap tag on the elements array. 240 __ and_(elements_array_storage, 241 elements_array_storage, 242 Operand(~kHeapObjectTagMask)); 243 // Initialize the fixed array and fill it with holes. FixedArray length is not 244 // stored as a smi. 245 // result: JSObject 246 // elements_array_storage: elements array (untagged) 247 // array_size: size of array (smi) 248 ASSERT(kSmiTag == 0); 249 __ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex); 250 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); 251 __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex)); 252 // Convert array_size from smi to value. 253 __ mov(array_size, 254 Operand(array_size, ASR, kSmiTagSize)); 255 __ tst(array_size, array_size); 256 // Length of the FixedArray is the number of pre-allocated elements if 257 // the actual JSArray has length 0 and the size of the JSArray for non-empty 258 // JSArrays. The length of a FixedArray is not stored as a smi. 259 __ mov(array_size, Operand(JSArray::kPreallocatedArrayElements), LeaveCC, eq); 260 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); 261 __ str(array_size, 262 MemOperand(elements_array_storage, kPointerSize, PostIndex)); 263 264 // Calculate elements array and elements array end. 265 // result: JSObject 266 // elements_array_storage: elements array element storage 267 // array_size: size of elements array 268 __ add(elements_array_end, 269 elements_array_storage, 270 Operand(array_size, LSL, kPointerSizeLog2)); 271 272 // Fill the allocated FixedArray with the hole value if requested. 273 // result: JSObject 274 // elements_array_storage: elements array element storage 275 // elements_array_end: start of next object 276 if (fill_with_hole) { 277 Label loop, entry; 278 __ LoadRoot(scratch1, Heap::kTheHoleValueRootIndex); 279 __ jmp(&entry); 280 __ bind(&loop); 281 __ str(scratch1, 282 MemOperand(elements_array_storage, kPointerSize, PostIndex)); 283 __ bind(&entry); 284 __ cmp(elements_array_storage, elements_array_end); 285 __ b(lt, &loop); 286 } 287} 288 289// Create a new array for the built-in Array function. This function allocates 290// the JSArray object and the FixedArray elements array and initializes these. 291// If the Array cannot be constructed in native code the runtime is called. This 292// function assumes the following state: 293// r0: argc 294// r1: constructor (built-in Array function) 295// lr: return address 296// sp[0]: last argument 297// This function is used for both construct and normal calls of Array. The only 298// difference between handling a construct call and a normal call is that for a 299// construct call the constructor function in r1 needs to be preserved for 300// entering the generic code. In both cases argc in r0 needs to be preserved. 301// Both registers are preserved by this code so no need to differentiate between 302// construct call and normal call. 303static void ArrayNativeCode(MacroAssembler* masm, 304 Label* call_generic_code) { 305 Label argc_one_or_more, argc_two_or_more; 306 307 // Check for array construction with zero arguments or one. 308 __ cmp(r0, Operand(0)); 309 __ b(ne, &argc_one_or_more); 310 311 // Handle construction of an empty array. 312 AllocateEmptyJSArray(masm, 313 r1, 314 r2, 315 r3, 316 r4, 317 r5, 318 JSArray::kPreallocatedArrayElements, 319 call_generic_code); 320 __ IncrementCounter(&Counters::array_function_native, 1, r3, r4); 321 // Setup return value, remove receiver from stack and return. 322 __ mov(r0, r2); 323 __ add(sp, sp, Operand(kPointerSize)); 324 __ Jump(lr); 325 326 // Check for one argument. Bail out if argument is not smi or if it is 327 // negative. 328 __ bind(&argc_one_or_more); 329 __ cmp(r0, Operand(1)); 330 __ b(ne, &argc_two_or_more); 331 ASSERT(kSmiTag == 0); 332 __ ldr(r2, MemOperand(sp)); // Get the argument from the stack. 333 __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC); 334 __ b(ne, call_generic_code); 335 336 // Handle construction of an empty array of a certain size. Bail out if size 337 // is too large to actually allocate an elements array. 338 ASSERT(kSmiTag == 0); 339 __ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize)); 340 __ b(ge, call_generic_code); 341 342 // r0: argc 343 // r1: constructor 344 // r2: array_size (smi) 345 // sp[0]: argument 346 AllocateJSArray(masm, 347 r1, 348 r2, 349 r3, 350 r4, 351 r5, 352 r6, 353 r7, 354 true, 355 call_generic_code); 356 __ IncrementCounter(&Counters::array_function_native, 1, r2, r4); 357 // Setup return value, remove receiver and argument from stack and return. 358 __ mov(r0, r3); 359 __ add(sp, sp, Operand(2 * kPointerSize)); 360 __ Jump(lr); 361 362 // Handle construction of an array from a list of arguments. 363 __ bind(&argc_two_or_more); 364 __ mov(r2, Operand(r0, LSL, kSmiTagSize)); // Convet argc to a smi. 365 366 // r0: argc 367 // r1: constructor 368 // r2: array_size (smi) 369 // sp[0]: last argument 370 AllocateJSArray(masm, 371 r1, 372 r2, 373 r3, 374 r4, 375 r5, 376 r6, 377 r7, 378 false, 379 call_generic_code); 380 __ IncrementCounter(&Counters::array_function_native, 1, r2, r6); 381 382 // Fill arguments as array elements. Copy from the top of the stack (last 383 // element) to the array backing store filling it backwards. Note: 384 // elements_array_end points after the backing store therefore PreIndex is 385 // used when filling the backing store. 386 // r0: argc 387 // r3: JSArray 388 // r4: elements_array storage start (untagged) 389 // r5: elements_array_end (untagged) 390 // sp[0]: last argument 391 Label loop, entry; 392 __ jmp(&entry); 393 __ bind(&loop); 394 __ ldr(r2, MemOperand(sp, kPointerSize, PostIndex)); 395 __ str(r2, MemOperand(r5, -kPointerSize, PreIndex)); 396 __ bind(&entry); 397 __ cmp(r4, r5); 398 __ b(lt, &loop); 399 400 // Remove caller arguments and receiver from the stack, setup return value and 401 // return. 402 // r0: argc 403 // r3: JSArray 404 // sp[0]: receiver 405 __ add(sp, sp, Operand(kPointerSize)); 406 __ mov(r0, r3); 407 __ Jump(lr); 408} 409 410 411void Builtins::Generate_ArrayCode(MacroAssembler* masm) { 412 // ----------- S t a t e ------------- 413 // -- r0 : number of arguments 414 // -- lr : return address 415 // -- sp[...]: constructor arguments 416 // ----------------------------------- 417 Label generic_array_code, one_or_more_arguments, two_or_more_arguments; 418 419 // Get the Array function. 420 GenerateLoadArrayFunction(masm, r1); 421 422 if (FLAG_debug_code) { 423 // Initial map for the builtin Array function shoud be a map. 424 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); 425 __ tst(r2, Operand(kSmiTagMask)); 426 __ Assert(ne, "Unexpected initial map for Array function"); 427 __ CompareObjectType(r2, r3, r4, MAP_TYPE); 428 __ Assert(eq, "Unexpected initial map for Array function"); 429 } 430 431 // Run the native code for the Array function called as a normal function. 432 ArrayNativeCode(masm, &generic_array_code); 433 434 // Jump to the generic array code if the specialized code cannot handle 435 // the construction. 436 __ bind(&generic_array_code); 437 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric); 438 Handle<Code> array_code(code); 439 __ Jump(array_code, RelocInfo::CODE_TARGET); 440} 441 442 443void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) { 444 // ----------- S t a t e ------------- 445 // -- r0 : number of arguments 446 // -- r1 : constructor function 447 // -- lr : return address 448 // -- sp[...]: constructor arguments 449 // ----------------------------------- 450 Label generic_constructor; 451 452 if (FLAG_debug_code) { 453 // The array construct code is only set for the builtin Array function which 454 // always have a map. 455 GenerateLoadArrayFunction(masm, r2); 456 __ cmp(r1, r2); 457 __ Assert(eq, "Unexpected Array function"); 458 // Initial map for the builtin Array function should be a map. 459 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); 460 __ tst(r2, Operand(kSmiTagMask)); 461 __ Assert(ne, "Unexpected initial map for Array function"); 462 __ CompareObjectType(r2, r3, r4, MAP_TYPE); 463 __ Assert(eq, "Unexpected initial map for Array function"); 464 } 465 466 // Run the native code for the Array function called as a constructor. 467 ArrayNativeCode(masm, &generic_constructor); 468 469 // Jump to the generic construct code in case the specialized code cannot 470 // handle the construction. 471 __ bind(&generic_constructor); 472 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); 473 Handle<Code> generic_construct_stub(code); 474 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); 475} 476 477 478void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { 479 // ----------- S t a t e ------------- 480 // -- r0 : number of arguments 481 // -- r1 : constructor function 482 // -- lr : return address 483 // -- sp[...]: constructor arguments 484 // ----------------------------------- 485 486 Label non_function_call; 487 // Check that the function is not a smi. 488 __ tst(r1, Operand(kSmiTagMask)); 489 __ b(eq, &non_function_call); 490 // Check that the function is a JSFunction. 491 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); 492 __ b(ne, &non_function_call); 493 494 // Jump to the function-specific construct stub. 495 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 496 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kConstructStubOffset)); 497 __ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag)); 498 499 // r0: number of arguments 500 // r1: called object 501 __ bind(&non_function_call); 502 // CALL_NON_FUNCTION expects the non-function constructor as receiver 503 // (instead of the original receiver from the call site). The receiver is 504 // stack element argc. 505 __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); 506 // Set expected number of arguments to zero (not changing r0). 507 __ mov(r2, Operand(0)); 508 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 509 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 510 RelocInfo::CODE_TARGET); 511} 512 513 514static void Generate_JSConstructStubHelper(MacroAssembler* masm, 515 bool is_api_function) { 516 // Enter a construct frame. 517 __ EnterConstructFrame(); 518 519 // Preserve the two incoming parameters on the stack. 520 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); 521 __ push(r0); // Smi-tagged arguments count. 522 __ push(r1); // Constructor function. 523 524 // Use r7 for holding undefined which is used in several places below. 525 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex); 526 527 // Try to allocate the object without transitioning into C code. If any of the 528 // preconditions is not met, the code bails out to the runtime call. 529 Label rt_call, allocated; 530 if (FLAG_inline_new) { 531 Label undo_allocation; 532#ifdef ENABLE_DEBUGGER_SUPPORT 533 ExternalReference debug_step_in_fp = 534 ExternalReference::debug_step_in_fp_address(); 535 __ mov(r2, Operand(debug_step_in_fp)); 536 __ ldr(r2, MemOperand(r2)); 537 __ tst(r2, r2); 538 __ b(nz, &rt_call); 539#endif 540 541 // Load the initial map and verify that it is in fact a map. 542 // r1: constructor function 543 // r7: undefined 544 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); 545 __ tst(r2, Operand(kSmiTagMask)); 546 __ b(eq, &rt_call); 547 __ CompareObjectType(r2, r3, r4, MAP_TYPE); 548 __ b(ne, &rt_call); 549 550 // Check that the constructor is not constructing a JSFunction (see comments 551 // in Runtime_NewObject in runtime.cc). In which case the initial map's 552 // instance type would be JS_FUNCTION_TYPE. 553 // r1: constructor function 554 // r2: initial map 555 // r7: undefined 556 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE); 557 __ b(eq, &rt_call); 558 559 // Now allocate the JSObject on the heap. 560 // r1: constructor function 561 // r2: initial map 562 // r7: undefined 563 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset)); 564 __ AllocateInNewSpace(r3, r4, r5, r6, &rt_call, NO_ALLOCATION_FLAGS); 565 566 // Allocated the JSObject, now initialize the fields. Map is set to initial 567 // map and properties and elements are set to empty fixed array. 568 // r1: constructor function 569 // r2: initial map 570 // r3: object size 571 // r4: JSObject (not tagged) 572 // r7: undefined 573 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex); 574 __ mov(r5, r4); 575 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); 576 __ str(r2, MemOperand(r5, kPointerSize, PostIndex)); 577 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset); 578 __ str(r6, MemOperand(r5, kPointerSize, PostIndex)); 579 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset); 580 __ str(r6, MemOperand(r5, kPointerSize, PostIndex)); 581 582 // Fill all the in-object properties with undefined. 583 // r1: constructor function 584 // r2: initial map 585 // r3: object size (in words) 586 // r4: JSObject (not tagged) 587 // r5: First in-object property of JSObject (not tagged) 588 // r7: undefined 589 __ add(r6, r4, Operand(r3, LSL, kPointerSizeLog2)); // End of object. 590 ASSERT_EQ(3 * kPointerSize, JSObject::kHeaderSize); 591 { Label loop, entry; 592 __ b(&entry); 593 __ bind(&loop); 594 __ str(r7, MemOperand(r5, kPointerSize, PostIndex)); 595 __ bind(&entry); 596 __ cmp(r5, Operand(r6)); 597 __ b(lt, &loop); 598 } 599 600 // Add the object tag to make the JSObject real, so that we can continue and 601 // jump into the continuation code at any time from now on. Any failures 602 // need to undo the allocation, so that the heap is in a consistent state 603 // and verifiable. 604 __ add(r4, r4, Operand(kHeapObjectTag)); 605 606 // Check if a non-empty properties array is needed. Continue with allocated 607 // object if not fall through to runtime call if it is. 608 // r1: constructor function 609 // r4: JSObject 610 // r5: start of next object (not tagged) 611 // r7: undefined 612 __ ldrb(r3, FieldMemOperand(r2, Map::kUnusedPropertyFieldsOffset)); 613 // The field instance sizes contains both pre-allocated property fields and 614 // in-object properties. 615 __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset)); 616 __ and_(r6, 617 r0, 618 Operand(0x000000FF << Map::kPreAllocatedPropertyFieldsByte * 8)); 619 __ add(r3, r3, Operand(r6, LSR, Map::kPreAllocatedPropertyFieldsByte * 8)); 620 __ and_(r6, r0, Operand(0x000000FF << Map::kInObjectPropertiesByte * 8)); 621 __ sub(r3, r3, Operand(r6, LSR, Map::kInObjectPropertiesByte * 8), SetCC); 622 623 // Done if no extra properties are to be allocated. 624 __ b(eq, &allocated); 625 __ Assert(pl, "Property allocation count failed."); 626 627 // Scale the number of elements by pointer size and add the header for 628 // FixedArrays to the start of the next object calculation from above. 629 // r1: constructor 630 // r3: number of elements in properties array 631 // r4: JSObject 632 // r5: start of next object 633 // r7: undefined 634 __ add(r0, r3, Operand(FixedArray::kHeaderSize / kPointerSize)); 635 __ AllocateInNewSpace(r0, 636 r5, 637 r6, 638 r2, 639 &undo_allocation, 640 RESULT_CONTAINS_TOP); 641 642 // Initialize the FixedArray. 643 // r1: constructor 644 // r3: number of elements in properties array 645 // r4: JSObject 646 // r5: FixedArray (not tagged) 647 // r7: undefined 648 __ LoadRoot(r6, Heap::kFixedArrayMapRootIndex); 649 __ mov(r2, r5); 650 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); 651 __ str(r6, MemOperand(r2, kPointerSize, PostIndex)); 652 ASSERT_EQ(1 * kPointerSize, Array::kLengthOffset); 653 __ str(r3, MemOperand(r2, kPointerSize, PostIndex)); 654 655 // Initialize the fields to undefined. 656 // r1: constructor function 657 // r2: First element of FixedArray (not tagged) 658 // r3: number of elements in properties array 659 // r4: JSObject 660 // r5: FixedArray (not tagged) 661 // r7: undefined 662 __ add(r6, r2, Operand(r3, LSL, kPointerSizeLog2)); // End of object. 663 ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize); 664 { Label loop, entry; 665 __ b(&entry); 666 __ bind(&loop); 667 __ str(r7, MemOperand(r2, kPointerSize, PostIndex)); 668 __ bind(&entry); 669 __ cmp(r2, Operand(r6)); 670 __ b(lt, &loop); 671 } 672 673 // Store the initialized FixedArray into the properties field of 674 // the JSObject 675 // r1: constructor function 676 // r4: JSObject 677 // r5: FixedArray (not tagged) 678 __ add(r5, r5, Operand(kHeapObjectTag)); // Add the heap tag. 679 __ str(r5, FieldMemOperand(r4, JSObject::kPropertiesOffset)); 680 681 // Continue with JSObject being successfully allocated 682 // r1: constructor function 683 // r4: JSObject 684 __ jmp(&allocated); 685 686 // Undo the setting of the new top so that the heap is verifiable. For 687 // example, the map's unused properties potentially do not match the 688 // allocated objects unused properties. 689 // r4: JSObject (previous new top) 690 __ bind(&undo_allocation); 691 __ UndoAllocationInNewSpace(r4, r5); 692 } 693 694 // Allocate the new receiver object using the runtime call. 695 // r1: constructor function 696 __ bind(&rt_call); 697 __ push(r1); // argument for Runtime_NewObject 698 __ CallRuntime(Runtime::kNewObject, 1); 699 __ mov(r4, r0); 700 701 // Receiver for constructor call allocated. 702 // r4: JSObject 703 __ bind(&allocated); 704 __ push(r4); 705 706 // Push the function and the allocated receiver from the stack. 707 // sp[0]: receiver (newly allocated object) 708 // sp[1]: constructor function 709 // sp[2]: number of arguments (smi-tagged) 710 __ ldr(r1, MemOperand(sp, kPointerSize)); 711 __ push(r1); // Constructor function. 712 __ push(r4); // Receiver. 713 714 // Reload the number of arguments from the stack. 715 // r1: constructor function 716 // sp[0]: receiver 717 // sp[1]: constructor function 718 // sp[2]: receiver 719 // sp[3]: constructor function 720 // sp[4]: number of arguments (smi-tagged) 721 __ ldr(r3, MemOperand(sp, 4 * kPointerSize)); 722 723 // Setup pointer to last argument. 724 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); 725 726 // Setup number of arguments for function call below 727 __ mov(r0, Operand(r3, LSR, kSmiTagSize)); 728 729 // Copy arguments and receiver to the expression stack. 730 // r0: number of arguments 731 // r2: address of last argument (caller sp) 732 // r1: constructor function 733 // r3: number of arguments (smi-tagged) 734 // sp[0]: receiver 735 // sp[1]: constructor function 736 // sp[2]: receiver 737 // sp[3]: constructor function 738 // sp[4]: number of arguments (smi-tagged) 739 Label loop, entry; 740 __ b(&entry); 741 __ bind(&loop); 742 __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1)); 743 __ push(ip); 744 __ bind(&entry); 745 __ sub(r3, r3, Operand(2), SetCC); 746 __ b(ge, &loop); 747 748 // Call the function. 749 // r0: number of arguments 750 // r1: constructor function 751 if (is_api_function) { 752 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 753 Handle<Code> code = Handle<Code>( 754 Builtins::builtin(Builtins::HandleApiCallConstruct)); 755 ParameterCount expected(0); 756 __ InvokeCode(code, expected, expected, 757 RelocInfo::CODE_TARGET, CALL_FUNCTION); 758 } else { 759 ParameterCount actual(r0); 760 __ InvokeFunction(r1, actual, CALL_FUNCTION); 761 } 762 763 // Pop the function from the stack. 764 // sp[0]: constructor function 765 // sp[2]: receiver 766 // sp[3]: constructor function 767 // sp[4]: number of arguments (smi-tagged) 768 __ pop(); 769 770 // Restore context from the frame. 771 // r0: result 772 // sp[0]: receiver 773 // sp[1]: constructor function 774 // sp[2]: number of arguments (smi-tagged) 775 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 776 777 // If the result is an object (in the ECMA sense), we should get rid 778 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 779 // on page 74. 780 Label use_receiver, exit; 781 782 // If the result is a smi, it is *not* an object in the ECMA sense. 783 // r0: result 784 // sp[0]: receiver (newly allocated object) 785 // sp[1]: constructor function 786 // sp[2]: number of arguments (smi-tagged) 787 __ tst(r0, Operand(kSmiTagMask)); 788 __ b(eq, &use_receiver); 789 790 // If the type of the result (stored in its map) is less than 791 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. 792 __ CompareObjectType(r0, r3, r3, FIRST_JS_OBJECT_TYPE); 793 __ b(ge, &exit); 794 795 // Throw away the result of the constructor invocation and use the 796 // on-stack receiver as the result. 797 __ bind(&use_receiver); 798 __ ldr(r0, MemOperand(sp)); 799 800 // Remove receiver from the stack, remove caller arguments, and 801 // return. 802 __ bind(&exit); 803 // r0: result 804 // sp[0]: receiver (newly allocated object) 805 // sp[1]: constructor function 806 // sp[2]: number of arguments (smi-tagged) 807 __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); 808 __ LeaveConstructFrame(); 809 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1)); 810 __ add(sp, sp, Operand(kPointerSize)); 811 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2); 812 __ Jump(lr); 813} 814 815 816void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { 817 Generate_JSConstructStubHelper(masm, false); 818} 819 820 821void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { 822 Generate_JSConstructStubHelper(masm, true); 823} 824 825 826static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, 827 bool is_construct) { 828 // Called from Generate_JS_Entry 829 // r0: code entry 830 // r1: function 831 // r2: receiver 832 // r3: argc 833 // r4: argv 834 // r5-r7, cp may be clobbered 835 836 // Clear the context before we push it when entering the JS frame. 837 __ mov(cp, Operand(0)); 838 839 // Enter an internal frame. 840 __ EnterInternalFrame(); 841 842 // Set up the context from the function argument. 843 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 844 845 // Set up the roots register. 846 ExternalReference roots_address = ExternalReference::roots_address(); 847 __ mov(r10, Operand(roots_address)); 848 849 // Push the function and the receiver onto the stack. 850 __ push(r1); 851 __ push(r2); 852 853 // Copy arguments to the stack in a loop. 854 // r1: function 855 // r3: argc 856 // r4: argv, i.e. points to first arg 857 Label loop, entry; 858 __ add(r2, r4, Operand(r3, LSL, kPointerSizeLog2)); 859 // r2 points past last arg. 860 __ b(&entry); 861 __ bind(&loop); 862 __ ldr(r0, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter 863 __ ldr(r0, MemOperand(r0)); // dereference handle 864 __ push(r0); // push parameter 865 __ bind(&entry); 866 __ cmp(r4, Operand(r2)); 867 __ b(ne, &loop); 868 869 // Initialize all JavaScript callee-saved registers, since they will be seen 870 // by the garbage collector as part of handlers. 871 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); 872 __ mov(r5, Operand(r4)); 873 __ mov(r6, Operand(r4)); 874 __ mov(r7, Operand(r4)); 875 if (kR9Available == 1) { 876 __ mov(r9, Operand(r4)); 877 } 878 879 // Invoke the code and pass argc as r0. 880 __ mov(r0, Operand(r3)); 881 if (is_construct) { 882 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), 883 RelocInfo::CODE_TARGET); 884 } else { 885 ParameterCount actual(r0); 886 __ InvokeFunction(r1, actual, CALL_FUNCTION); 887 } 888 889 // Exit the JS frame and remove the parameters (except function), and return. 890 // Respect ABI stack constraint. 891 __ LeaveInternalFrame(); 892 __ Jump(lr); 893 894 // r0: result 895} 896 897 898void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 899 Generate_JSEntryTrampolineHelper(masm, false); 900} 901 902 903void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 904 Generate_JSEntryTrampolineHelper(masm, true); 905} 906 907 908void Builtins::Generate_FunctionCall(MacroAssembler* masm) { 909 // 1. Make sure we have at least one argument. 910 // r0: actual number of arguments 911 { Label done; 912 __ tst(r0, Operand(r0)); 913 __ b(ne, &done); 914 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 915 __ push(r2); 916 __ add(r0, r0, Operand(1)); 917 __ bind(&done); 918 } 919 920 // 2. Get the function to call (passed as receiver) from the stack, check 921 // if it is a function. 922 // r0: actual number of arguments 923 Label non_function; 924 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); 925 __ tst(r1, Operand(kSmiTagMask)); 926 __ b(eq, &non_function); 927 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); 928 __ b(ne, &non_function); 929 930 // 3a. Patch the first argument if necessary when calling a function. 931 // r0: actual number of arguments 932 // r1: function 933 Label shift_arguments; 934 { Label convert_to_object, use_global_receiver, patch_receiver; 935 // Change context eagerly in case we need the global receiver. 936 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 937 938 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 939 __ ldr(r2, MemOperand(r2, -kPointerSize)); 940 // r0: actual number of arguments 941 // r1: function 942 // r2: first argument 943 __ tst(r2, Operand(kSmiTagMask)); 944 __ b(eq, &convert_to_object); 945 946 __ LoadRoot(r3, Heap::kNullValueRootIndex); 947 __ cmp(r2, r3); 948 __ b(eq, &use_global_receiver); 949 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 950 __ cmp(r2, r3); 951 __ b(eq, &use_global_receiver); 952 953 __ CompareObjectType(r2, r3, r3, FIRST_JS_OBJECT_TYPE); 954 __ b(lt, &convert_to_object); 955 __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE)); 956 __ b(le, &shift_arguments); 957 958 __ bind(&convert_to_object); 959 __ EnterInternalFrame(); // In order to preserve argument count. 960 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); // Smi-tagged. 961 __ push(r0); 962 963 __ push(r2); 964 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); 965 __ mov(r2, r0); 966 967 __ pop(r0); 968 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); 969 __ LeaveInternalFrame(); 970 // Restore the function to r1. 971 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); 972 __ jmp(&patch_receiver); 973 974 // Use the global receiver object from the called function as the 975 // receiver. 976 __ bind(&use_global_receiver); 977 const int kGlobalIndex = 978 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 979 __ ldr(r2, FieldMemOperand(cp, kGlobalIndex)); 980 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset)); 981 __ ldr(r2, FieldMemOperand(r2, kGlobalIndex)); 982 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); 983 984 __ bind(&patch_receiver); 985 __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2)); 986 __ str(r2, MemOperand(r3, -kPointerSize)); 987 988 __ jmp(&shift_arguments); 989 } 990 991 // 3b. Patch the first argument when calling a non-function. The 992 // CALL_NON_FUNCTION builtin expects the non-function callee as 993 // receiver, so overwrite the first argument which will ultimately 994 // become the receiver. 995 // r0: actual number of arguments 996 // r1: function 997 __ bind(&non_function); 998 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 999 __ str(r1, MemOperand(r2, -kPointerSize)); 1000 // Clear r1 to indicate a non-function being called. 1001 __ mov(r1, Operand(0)); 1002 1003 // 4. Shift arguments and return address one slot down on the stack 1004 // (overwriting the original receiver). Adjust argument count to make 1005 // the original first argument the new receiver. 1006 // r0: actual number of arguments 1007 // r1: function 1008 __ bind(&shift_arguments); 1009 { Label loop; 1010 // Calculate the copy start address (destination). Copy end address is sp. 1011 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 1012 1013 __ bind(&loop); 1014 __ ldr(ip, MemOperand(r2, -kPointerSize)); 1015 __ str(ip, MemOperand(r2)); 1016 __ sub(r2, r2, Operand(kPointerSize)); 1017 __ cmp(r2, sp); 1018 __ b(ne, &loop); 1019 // Adjust the actual number of arguments and remove the top element 1020 // (which is a copy of the last argument). 1021 __ sub(r0, r0, Operand(1)); 1022 __ pop(); 1023 } 1024 1025 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin. 1026 // r0: actual number of arguments 1027 // r1: function 1028 { Label function; 1029 __ tst(r1, r1); 1030 __ b(ne, &function); 1031 __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION 1032 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); 1033 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 1034 RelocInfo::CODE_TARGET); 1035 __ bind(&function); 1036 } 1037 1038 // 5b. Get the code to call from the function and check that the number of 1039 // expected arguments matches what we're providing. If so, jump 1040 // (tail-call) to the code in register edx without checking arguments. 1041 // r0: actual number of arguments 1042 // r1: function 1043 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 1044 __ ldr(r2, 1045 FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset)); 1046 __ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset)); 1047 __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); 1048 __ cmp(r2, r0); // Check formal and actual parameter counts. 1049 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 1050 RelocInfo::CODE_TARGET, ne); 1051 1052 ParameterCount expected(0); 1053 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION); 1054} 1055 1056 1057void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 1058 const int kIndexOffset = -5 * kPointerSize; 1059 const int kLimitOffset = -4 * kPointerSize; 1060 const int kArgsOffset = 2 * kPointerSize; 1061 const int kRecvOffset = 3 * kPointerSize; 1062 const int kFunctionOffset = 4 * kPointerSize; 1063 1064 __ EnterInternalFrame(); 1065 1066 __ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function 1067 __ push(r0); 1068 __ ldr(r0, MemOperand(fp, kArgsOffset)); // get the args array 1069 __ push(r0); 1070 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS); 1071 1072 // Check the stack for overflow. We are not trying need to catch 1073 // interruptions (e.g. debug break and preemption) here, so the "real stack 1074 // limit" is checked. 1075 Label okay; 1076 __ LoadRoot(r2, Heap::kRealStackLimitRootIndex); 1077 // Make r2 the space we have left. The stack might already be overflowed 1078 // here which will cause r2 to become negative. 1079 __ sub(r2, sp, r2); 1080 // Check if the arguments will overflow the stack. 1081 __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1082 __ b(gt, &okay); // Signed comparison. 1083 1084 // Out of stack space. 1085 __ ldr(r1, MemOperand(fp, kFunctionOffset)); 1086 __ push(r1); 1087 __ push(r0); 1088 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS); 1089 // End of stack check. 1090 1091 // Push current limit and index. 1092 __ bind(&okay); 1093 __ push(r0); // limit 1094 __ mov(r1, Operand(0)); // initial index 1095 __ push(r1); 1096 1097 // Change context eagerly to get the right global object if necessary. 1098 __ ldr(r0, MemOperand(fp, kFunctionOffset)); 1099 __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset)); 1100 1101 // Compute the receiver. 1102 Label call_to_object, use_global_receiver, push_receiver; 1103 __ ldr(r0, MemOperand(fp, kRecvOffset)); 1104 __ tst(r0, Operand(kSmiTagMask)); 1105 __ b(eq, &call_to_object); 1106 __ LoadRoot(r1, Heap::kNullValueRootIndex); 1107 __ cmp(r0, r1); 1108 __ b(eq, &use_global_receiver); 1109 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); 1110 __ cmp(r0, r1); 1111 __ b(eq, &use_global_receiver); 1112 1113 // Check if the receiver is already a JavaScript object. 1114 // r0: receiver 1115 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE); 1116 __ b(lt, &call_to_object); 1117 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); 1118 __ b(le, &push_receiver); 1119 1120 // Convert the receiver to a regular object. 1121 // r0: receiver 1122 __ bind(&call_to_object); 1123 __ push(r0); 1124 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); 1125 __ b(&push_receiver); 1126 1127 // Use the current global receiver object as the receiver. 1128 __ bind(&use_global_receiver); 1129 const int kGlobalOffset = 1130 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 1131 __ ldr(r0, FieldMemOperand(cp, kGlobalOffset)); 1132 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset)); 1133 __ ldr(r0, FieldMemOperand(r0, kGlobalOffset)); 1134 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); 1135 1136 // Push the receiver. 1137 // r0: receiver 1138 __ bind(&push_receiver); 1139 __ push(r0); 1140 1141 // Copy all arguments from the array to the stack. 1142 Label entry, loop; 1143 __ ldr(r0, MemOperand(fp, kIndexOffset)); 1144 __ b(&entry); 1145 1146 // Load the current argument from the arguments array and push it to the 1147 // stack. 1148 // r0: current argument index 1149 __ bind(&loop); 1150 __ ldr(r1, MemOperand(fp, kArgsOffset)); 1151 __ push(r1); 1152 __ push(r0); 1153 1154 // Call the runtime to access the property in the arguments array. 1155 __ CallRuntime(Runtime::kGetProperty, 2); 1156 __ push(r0); 1157 1158 // Use inline caching to access the arguments. 1159 __ ldr(r0, MemOperand(fp, kIndexOffset)); 1160 __ add(r0, r0, Operand(1 << kSmiTagSize)); 1161 __ str(r0, MemOperand(fp, kIndexOffset)); 1162 1163 // Test if the copy loop has finished copying all the elements from the 1164 // arguments object. 1165 __ bind(&entry); 1166 __ ldr(r1, MemOperand(fp, kLimitOffset)); 1167 __ cmp(r0, r1); 1168 __ b(ne, &loop); 1169 1170 // Invoke the function. 1171 ParameterCount actual(r0); 1172 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); 1173 __ ldr(r1, MemOperand(fp, kFunctionOffset)); 1174 __ InvokeFunction(r1, actual, CALL_FUNCTION); 1175 1176 // Tear down the internal frame and remove function, receiver and args. 1177 __ LeaveInternalFrame(); 1178 __ add(sp, sp, Operand(3 * kPointerSize)); 1179 __ Jump(lr); 1180} 1181 1182 1183static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1184 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); 1185 __ mov(r4, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 1186 __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit()); 1187 __ add(fp, sp, Operand(3 * kPointerSize)); 1188} 1189 1190 1191static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { 1192 // ----------- S t a t e ------------- 1193 // -- r0 : result being passed through 1194 // ----------------------------------- 1195 // Get the number of arguments passed (as a smi), tear down the frame and 1196 // then tear down the parameters. 1197 __ ldr(r1, MemOperand(fp, -3 * kPointerSize)); 1198 __ mov(sp, fp); 1199 __ ldm(ia_w, sp, fp.bit() | lr.bit()); 1200 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); 1201 __ add(sp, sp, Operand(kPointerSize)); // adjust for receiver 1202} 1203 1204 1205void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { 1206 // ----------- S t a t e ------------- 1207 // -- r0 : actual number of arguments 1208 // -- r1 : function (passed through to callee) 1209 // -- r2 : expected number of arguments 1210 // -- r3 : code entry to call 1211 // ----------------------------------- 1212 1213 Label invoke, dont_adapt_arguments; 1214 1215 Label enough, too_few; 1216 __ cmp(r0, Operand(r2)); 1217 __ b(lt, &too_few); 1218 __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); 1219 __ b(eq, &dont_adapt_arguments); 1220 1221 { // Enough parameters: actual >= expected 1222 __ bind(&enough); 1223 EnterArgumentsAdaptorFrame(masm); 1224 1225 // Calculate copy start address into r0 and copy end address into r2. 1226 // r0: actual number of arguments as a smi 1227 // r1: function 1228 // r2: expected number of arguments 1229 // r3: code entry to call 1230 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1231 // adjust for return address and receiver 1232 __ add(r0, r0, Operand(2 * kPointerSize)); 1233 __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2)); 1234 1235 // Copy the arguments (including the receiver) to the new stack frame. 1236 // r0: copy start address 1237 // r1: function 1238 // r2: copy end address 1239 // r3: code entry to call 1240 1241 Label copy; 1242 __ bind(©); 1243 __ ldr(ip, MemOperand(r0, 0)); 1244 __ push(ip); 1245 __ cmp(r0, r2); // Compare before moving to next argument. 1246 __ sub(r0, r0, Operand(kPointerSize)); 1247 __ b(ne, ©); 1248 1249 __ b(&invoke); 1250 } 1251 1252 { // Too few parameters: Actual < expected 1253 __ bind(&too_few); 1254 EnterArgumentsAdaptorFrame(masm); 1255 1256 // Calculate copy start address into r0 and copy end address is fp. 1257 // r0: actual number of arguments as a smi 1258 // r1: function 1259 // r2: expected number of arguments 1260 // r3: code entry to call 1261 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1262 1263 // Copy the arguments (including the receiver) to the new stack frame. 1264 // r0: copy start address 1265 // r1: function 1266 // r2: expected number of arguments 1267 // r3: code entry to call 1268 Label copy; 1269 __ bind(©); 1270 // Adjust load for return address and receiver. 1271 __ ldr(ip, MemOperand(r0, 2 * kPointerSize)); 1272 __ push(ip); 1273 __ cmp(r0, fp); // Compare before moving to next argument. 1274 __ sub(r0, r0, Operand(kPointerSize)); 1275 __ b(ne, ©); 1276 1277 // Fill the remaining expected arguments with undefined. 1278 // r1: function 1279 // r2: expected number of arguments 1280 // r3: code entry to call 1281 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 1282 __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2)); 1283 __ sub(r2, r2, Operand(4 * kPointerSize)); // Adjust for frame. 1284 1285 Label fill; 1286 __ bind(&fill); 1287 __ push(ip); 1288 __ cmp(sp, r2); 1289 __ b(ne, &fill); 1290 } 1291 1292 // Call the entry point. 1293 __ bind(&invoke); 1294 __ Call(r3); 1295 1296 // Exit frame and return. 1297 LeaveArgumentsAdaptorFrame(masm); 1298 __ Jump(lr); 1299 1300 1301 // ------------------------------------------- 1302 // Dont adapt arguments. 1303 // ------------------------------------------- 1304 __ bind(&dont_adapt_arguments); 1305 __ Jump(r3); 1306} 1307 1308 1309#undef __ 1310 1311} } // namespace v8::internal 1312