builtins-arm.cc revision e46be819fca9468a0cd4e74859ce0f778eb8ca60
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 503 // Set expected number of arguments to zero (not changing r0). 504 __ mov(r2, Operand(0)); 505 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 506 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 507 RelocInfo::CODE_TARGET); 508} 509 510 511static void Generate_JSConstructStubHelper(MacroAssembler* masm, 512 bool is_api_function) { 513 // Enter a construct frame. 514 __ EnterConstructFrame(); 515 516 // Preserve the two incoming parameters on the stack. 517 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); 518 __ push(r0); // Smi-tagged arguments count. 519 __ push(r1); // Constructor function. 520 521 // Use r7 for holding undefined which is used in several places below. 522 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex); 523 524 // Try to allocate the object without transitioning into C code. If any of the 525 // preconditions is not met, the code bails out to the runtime call. 526 Label rt_call, allocated; 527 if (FLAG_inline_new) { 528 Label undo_allocation; 529#ifdef ENABLE_DEBUGGER_SUPPORT 530 ExternalReference debug_step_in_fp = 531 ExternalReference::debug_step_in_fp_address(); 532 __ mov(r2, Operand(debug_step_in_fp)); 533 __ ldr(r2, MemOperand(r2)); 534 __ tst(r2, r2); 535 __ b(nz, &rt_call); 536#endif 537 538 // Load the initial map and verify that it is in fact a map. 539 // r1: constructor function 540 // r7: undefined 541 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); 542 __ tst(r2, Operand(kSmiTagMask)); 543 __ b(eq, &rt_call); 544 __ CompareObjectType(r2, r3, r4, MAP_TYPE); 545 __ b(ne, &rt_call); 546 547 // Check that the constructor is not constructing a JSFunction (see comments 548 // in Runtime_NewObject in runtime.cc). In which case the initial map's 549 // instance type would be JS_FUNCTION_TYPE. 550 // r1: constructor function 551 // r2: initial map 552 // r7: undefined 553 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE); 554 __ b(eq, &rt_call); 555 556 // Now allocate the JSObject on the heap. 557 // r1: constructor function 558 // r2: initial map 559 // r7: undefined 560 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset)); 561 __ AllocateInNewSpace(r3, r4, r5, r6, &rt_call, NO_ALLOCATION_FLAGS); 562 563 // Allocated the JSObject, now initialize the fields. Map is set to initial 564 // map and properties and elements are set to empty fixed array. 565 // r1: constructor function 566 // r2: initial map 567 // r3: object size 568 // r4: JSObject (not tagged) 569 // r7: undefined 570 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex); 571 __ mov(r5, r4); 572 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); 573 __ str(r2, MemOperand(r5, kPointerSize, PostIndex)); 574 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset); 575 __ str(r6, MemOperand(r5, kPointerSize, PostIndex)); 576 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset); 577 __ str(r6, MemOperand(r5, kPointerSize, PostIndex)); 578 579 // Fill all the in-object properties with undefined. 580 // r1: constructor function 581 // r2: initial map 582 // r3: object size (in words) 583 // r4: JSObject (not tagged) 584 // r5: First in-object property of JSObject (not tagged) 585 // r7: undefined 586 __ add(r6, r4, Operand(r3, LSL, kPointerSizeLog2)); // End of object. 587 ASSERT_EQ(3 * kPointerSize, JSObject::kHeaderSize); 588 { Label loop, entry; 589 __ b(&entry); 590 __ bind(&loop); 591 __ str(r7, MemOperand(r5, kPointerSize, PostIndex)); 592 __ bind(&entry); 593 __ cmp(r5, Operand(r6)); 594 __ b(lt, &loop); 595 } 596 597 // Add the object tag to make the JSObject real, so that we can continue and 598 // jump into the continuation code at any time from now on. Any failures 599 // need to undo the allocation, so that the heap is in a consistent state 600 // and verifiable. 601 __ add(r4, r4, Operand(kHeapObjectTag)); 602 603 // Check if a non-empty properties array is needed. Continue with allocated 604 // object if not fall through to runtime call if it is. 605 // r1: constructor function 606 // r4: JSObject 607 // r5: start of next object (not tagged) 608 // r7: undefined 609 __ ldrb(r3, FieldMemOperand(r2, Map::kUnusedPropertyFieldsOffset)); 610 // The field instance sizes contains both pre-allocated property fields and 611 // in-object properties. 612 __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset)); 613 __ and_(r6, 614 r0, 615 Operand(0x000000FF << Map::kPreAllocatedPropertyFieldsByte * 8)); 616 __ add(r3, r3, Operand(r6, LSR, Map::kPreAllocatedPropertyFieldsByte * 8)); 617 __ and_(r6, r0, Operand(0x000000FF << Map::kInObjectPropertiesByte * 8)); 618 __ sub(r3, r3, Operand(r6, LSR, Map::kInObjectPropertiesByte * 8), SetCC); 619 620 // Done if no extra properties are to be allocated. 621 __ b(eq, &allocated); 622 __ Assert(pl, "Property allocation count failed."); 623 624 // Scale the number of elements by pointer size and add the header for 625 // FixedArrays to the start of the next object calculation from above. 626 // r1: constructor 627 // r3: number of elements in properties array 628 // r4: JSObject 629 // r5: start of next object 630 // r7: undefined 631 __ add(r0, r3, Operand(FixedArray::kHeaderSize / kPointerSize)); 632 __ AllocateInNewSpace(r0, 633 r5, 634 r6, 635 r2, 636 &undo_allocation, 637 RESULT_CONTAINS_TOP); 638 639 // Initialize the FixedArray. 640 // r1: constructor 641 // r3: number of elements in properties array 642 // r4: JSObject 643 // r5: FixedArray (not tagged) 644 // r7: undefined 645 __ LoadRoot(r6, Heap::kFixedArrayMapRootIndex); 646 __ mov(r2, r5); 647 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); 648 __ str(r6, MemOperand(r2, kPointerSize, PostIndex)); 649 ASSERT_EQ(1 * kPointerSize, Array::kLengthOffset); 650 __ str(r3, MemOperand(r2, kPointerSize, PostIndex)); 651 652 // Initialize the fields to undefined. 653 // r1: constructor function 654 // r2: First element of FixedArray (not tagged) 655 // r3: number of elements in properties array 656 // r4: JSObject 657 // r5: FixedArray (not tagged) 658 // r7: undefined 659 __ add(r6, r2, Operand(r3, LSL, kPointerSizeLog2)); // End of object. 660 ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize); 661 { Label loop, entry; 662 __ b(&entry); 663 __ bind(&loop); 664 __ str(r7, MemOperand(r2, kPointerSize, PostIndex)); 665 __ bind(&entry); 666 __ cmp(r2, Operand(r6)); 667 __ b(lt, &loop); 668 } 669 670 // Store the initialized FixedArray into the properties field of 671 // the JSObject 672 // r1: constructor function 673 // r4: JSObject 674 // r5: FixedArray (not tagged) 675 __ add(r5, r5, Operand(kHeapObjectTag)); // Add the heap tag. 676 __ str(r5, FieldMemOperand(r4, JSObject::kPropertiesOffset)); 677 678 // Continue with JSObject being successfully allocated 679 // r1: constructor function 680 // r4: JSObject 681 __ jmp(&allocated); 682 683 // Undo the setting of the new top so that the heap is verifiable. For 684 // example, the map's unused properties potentially do not match the 685 // allocated objects unused properties. 686 // r4: JSObject (previous new top) 687 __ bind(&undo_allocation); 688 __ UndoAllocationInNewSpace(r4, r5); 689 } 690 691 // Allocate the new receiver object using the runtime call. 692 // r1: constructor function 693 __ bind(&rt_call); 694 __ push(r1); // argument for Runtime_NewObject 695 __ CallRuntime(Runtime::kNewObject, 1); 696 __ mov(r4, r0); 697 698 // Receiver for constructor call allocated. 699 // r4: JSObject 700 __ bind(&allocated); 701 __ push(r4); 702 703 // Push the function and the allocated receiver from the stack. 704 // sp[0]: receiver (newly allocated object) 705 // sp[1]: constructor function 706 // sp[2]: number of arguments (smi-tagged) 707 __ ldr(r1, MemOperand(sp, kPointerSize)); 708 __ push(r1); // Constructor function. 709 __ push(r4); // Receiver. 710 711 // Reload the number of arguments from the stack. 712 // r1: constructor function 713 // sp[0]: receiver 714 // sp[1]: constructor function 715 // sp[2]: receiver 716 // sp[3]: constructor function 717 // sp[4]: number of arguments (smi-tagged) 718 __ ldr(r3, MemOperand(sp, 4 * kPointerSize)); 719 720 // Setup pointer to last argument. 721 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); 722 723 // Setup number of arguments for function call below 724 __ mov(r0, Operand(r3, LSR, kSmiTagSize)); 725 726 // Copy arguments and receiver to the expression stack. 727 // r0: number of arguments 728 // r2: address of last argument (caller sp) 729 // r1: constructor function 730 // r3: number of arguments (smi-tagged) 731 // sp[0]: receiver 732 // sp[1]: constructor function 733 // sp[2]: receiver 734 // sp[3]: constructor function 735 // sp[4]: number of arguments (smi-tagged) 736 Label loop, entry; 737 __ b(&entry); 738 __ bind(&loop); 739 __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1)); 740 __ push(ip); 741 __ bind(&entry); 742 __ sub(r3, r3, Operand(2), SetCC); 743 __ b(ge, &loop); 744 745 // Call the function. 746 // r0: number of arguments 747 // r1: constructor function 748 if (is_api_function) { 749 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 750 Handle<Code> code = Handle<Code>( 751 Builtins::builtin(Builtins::HandleApiCallConstruct)); 752 ParameterCount expected(0); 753 __ InvokeCode(code, expected, expected, 754 RelocInfo::CODE_TARGET, CALL_FUNCTION); 755 } else { 756 ParameterCount actual(r0); 757 __ InvokeFunction(r1, actual, CALL_FUNCTION); 758 } 759 760 // Pop the function from the stack. 761 // sp[0]: constructor function 762 // sp[2]: receiver 763 // sp[3]: constructor function 764 // sp[4]: number of arguments (smi-tagged) 765 __ pop(); 766 767 // Restore context from the frame. 768 // r0: result 769 // sp[0]: receiver 770 // sp[1]: constructor function 771 // sp[2]: number of arguments (smi-tagged) 772 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 773 774 // If the result is an object (in the ECMA sense), we should get rid 775 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 776 // on page 74. 777 Label use_receiver, exit; 778 779 // If the result is a smi, it is *not* an object in the ECMA sense. 780 // r0: result 781 // sp[0]: receiver (newly allocated object) 782 // sp[1]: constructor function 783 // sp[2]: number of arguments (smi-tagged) 784 __ tst(r0, Operand(kSmiTagMask)); 785 __ b(eq, &use_receiver); 786 787 // If the type of the result (stored in its map) is less than 788 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. 789 __ CompareObjectType(r0, r3, r3, FIRST_JS_OBJECT_TYPE); 790 __ b(ge, &exit); 791 792 // Throw away the result of the constructor invocation and use the 793 // on-stack receiver as the result. 794 __ bind(&use_receiver); 795 __ ldr(r0, MemOperand(sp)); 796 797 // Remove receiver from the stack, remove caller arguments, and 798 // return. 799 __ bind(&exit); 800 // r0: result 801 // sp[0]: receiver (newly allocated object) 802 // sp[1]: constructor function 803 // sp[2]: number of arguments (smi-tagged) 804 __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); 805 __ LeaveConstructFrame(); 806 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1)); 807 __ add(sp, sp, Operand(kPointerSize)); 808 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2); 809 __ Jump(lr); 810} 811 812 813void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { 814 Generate_JSConstructStubHelper(masm, false); 815} 816 817 818void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { 819 Generate_JSConstructStubHelper(masm, true); 820} 821 822 823static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, 824 bool is_construct) { 825 // Called from Generate_JS_Entry 826 // r0: code entry 827 // r1: function 828 // r2: receiver 829 // r3: argc 830 // r4: argv 831 // r5-r7, cp may be clobbered 832 833 // Clear the context before we push it when entering the JS frame. 834 __ mov(cp, Operand(0)); 835 836 // Enter an internal frame. 837 __ EnterInternalFrame(); 838 839 // Set up the context from the function argument. 840 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 841 842 // Set up the roots register. 843 ExternalReference roots_address = ExternalReference::roots_address(); 844 __ mov(r10, Operand(roots_address)); 845 846 // Push the function and the receiver onto the stack. 847 __ push(r1); 848 __ push(r2); 849 850 // Copy arguments to the stack in a loop. 851 // r1: function 852 // r3: argc 853 // r4: argv, i.e. points to first arg 854 Label loop, entry; 855 __ add(r2, r4, Operand(r3, LSL, kPointerSizeLog2)); 856 // r2 points past last arg. 857 __ b(&entry); 858 __ bind(&loop); 859 __ ldr(r0, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter 860 __ ldr(r0, MemOperand(r0)); // dereference handle 861 __ push(r0); // push parameter 862 __ bind(&entry); 863 __ cmp(r4, Operand(r2)); 864 __ b(ne, &loop); 865 866 // Initialize all JavaScript callee-saved registers, since they will be seen 867 // by the garbage collector as part of handlers. 868 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); 869 __ mov(r5, Operand(r4)); 870 __ mov(r6, Operand(r4)); 871 __ mov(r7, Operand(r4)); 872 if (kR9Available == 1) { 873 __ mov(r9, Operand(r4)); 874 } 875 876 // Invoke the code and pass argc as r0. 877 __ mov(r0, Operand(r3)); 878 if (is_construct) { 879 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), 880 RelocInfo::CODE_TARGET); 881 } else { 882 ParameterCount actual(r0); 883 __ InvokeFunction(r1, actual, CALL_FUNCTION); 884 } 885 886 // Exit the JS frame and remove the parameters (except function), and return. 887 // Respect ABI stack constraint. 888 __ LeaveInternalFrame(); 889 __ Jump(lr); 890 891 // r0: result 892} 893 894 895void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 896 Generate_JSEntryTrampolineHelper(masm, false); 897} 898 899 900void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 901 Generate_JSEntryTrampolineHelper(masm, true); 902} 903 904 905void Builtins::Generate_FunctionCall(MacroAssembler* masm) { 906 // 1. Make sure we have at least one argument. 907 // r0: actual number of argument 908 { Label done; 909 __ tst(r0, Operand(r0)); 910 __ b(ne, &done); 911 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 912 __ push(r2); 913 __ add(r0, r0, Operand(1)); 914 __ bind(&done); 915 } 916 917 // 2. Get the function to call from the stack. 918 // r0: actual number of argument 919 { Label done, non_function, function; 920 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); 921 __ tst(r1, Operand(kSmiTagMask)); 922 __ b(eq, &non_function); 923 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); 924 __ b(eq, &function); 925 926 // Non-function called: Clear the function to force exception. 927 __ bind(&non_function); 928 __ mov(r1, Operand(0)); 929 __ b(&done); 930 931 // Change the context eagerly because it will be used below to get the 932 // right global object. 933 __ bind(&function); 934 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 935 936 __ bind(&done); 937 } 938 939 // 3. Make sure first argument is an object; convert if necessary. 940 // r0: actual number of arguments 941 // r1: function 942 { Label call_to_object, use_global_receiver, patch_receiver, done; 943 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 944 __ ldr(r2, MemOperand(r2, -kPointerSize)); 945 946 // r0: actual number of arguments 947 // r1: function 948 // r2: first argument 949 __ tst(r2, Operand(kSmiTagMask)); 950 __ b(eq, &call_to_object); 951 952 __ LoadRoot(r3, Heap::kNullValueRootIndex); 953 __ cmp(r2, r3); 954 __ b(eq, &use_global_receiver); 955 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 956 __ cmp(r2, r3); 957 __ b(eq, &use_global_receiver); 958 959 __ CompareObjectType(r2, r3, r3, FIRST_JS_OBJECT_TYPE); 960 __ b(lt, &call_to_object); 961 __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE)); 962 __ b(le, &done); 963 964 __ bind(&call_to_object); 965 __ EnterInternalFrame(); 966 967 // Store number of arguments and function across the call into the runtime. 968 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); 969 __ push(r0); 970 __ push(r1); 971 972 __ push(r2); 973 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); 974 __ mov(r2, r0); 975 976 // Restore number of arguments and function. 977 __ pop(r1); 978 __ pop(r0); 979 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); 980 981 __ LeaveInternalFrame(); 982 __ b(&patch_receiver); 983 984 // Use the global receiver object from the called function as the receiver. 985 __ bind(&use_global_receiver); 986 const int kGlobalIndex = 987 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 988 __ ldr(r2, FieldMemOperand(cp, kGlobalIndex)); 989 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset)); 990 __ ldr(r2, FieldMemOperand(r2, kGlobalIndex)); 991 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); 992 993 __ bind(&patch_receiver); 994 __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2)); 995 __ str(r2, MemOperand(r3, -kPointerSize)); 996 997 __ bind(&done); 998 } 999 1000 // 4. Shift stuff one slot down the stack 1001 // r0: actual number of arguments (including call() receiver) 1002 // r1: function 1003 { Label loop; 1004 // Calculate the copy start address (destination). Copy end address is sp. 1005 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 1006 __ add(r2, r2, Operand(kPointerSize)); // copy receiver too 1007 1008 __ bind(&loop); 1009 __ ldr(ip, MemOperand(r2, -kPointerSize)); 1010 __ str(ip, MemOperand(r2)); 1011 __ sub(r2, r2, Operand(kPointerSize)); 1012 __ cmp(r2, sp); 1013 __ b(ne, &loop); 1014 } 1015 1016 // 5. Adjust the actual number of arguments and remove the top element. 1017 // r0: actual number of arguments (including call() receiver) 1018 // r1: function 1019 __ sub(r0, r0, Operand(1)); 1020 __ add(sp, sp, Operand(kPointerSize)); 1021 1022 // 6. Get the code for the function or the non-function builtin. 1023 // If number of expected arguments matches, then call. Otherwise restart 1024 // the arguments adaptor stub. 1025 // r0: actual number of arguments 1026 // r1: function 1027 { Label invoke; 1028 __ tst(r1, r1); 1029 __ b(ne, &invoke); 1030 __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION 1031 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); 1032 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 1033 RelocInfo::CODE_TARGET); 1034 1035 __ bind(&invoke); 1036 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 1037 __ ldr(r2, 1038 FieldMemOperand(r3, 1039 SharedFunctionInfo::kFormalParameterCountOffset)); 1040 __ ldr(r3, 1041 MemOperand(r3, SharedFunctionInfo::kCodeOffset - kHeapObjectTag)); 1042 __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); 1043 __ cmp(r2, r0); // Check formal and actual parameter counts. 1044 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 1045 RelocInfo::CODE_TARGET, ne); 1046 1047 // 7. Jump to the code in r3 without checking arguments. 1048 ParameterCount expected(0); 1049 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION); 1050 } 1051} 1052 1053 1054void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 1055 const int kIndexOffset = -5 * kPointerSize; 1056 const int kLimitOffset = -4 * kPointerSize; 1057 const int kArgsOffset = 2 * kPointerSize; 1058 const int kRecvOffset = 3 * kPointerSize; 1059 const int kFunctionOffset = 4 * kPointerSize; 1060 1061 __ EnterInternalFrame(); 1062 1063 __ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function 1064 __ push(r0); 1065 __ ldr(r0, MemOperand(fp, kArgsOffset)); // get the args array 1066 __ push(r0); 1067 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS); 1068 1069 // Check the stack for overflow. We are not trying need to catch 1070 // interruptions (e.g. debug break and preemption) here, so the "real stack 1071 // limit" is checked. 1072 Label okay; 1073 __ LoadRoot(r2, Heap::kRealStackLimitRootIndex); 1074 // Make r2 the space we have left. The stack might already be overflowed 1075 // here which will cause r2 to become negative. 1076 __ sub(r2, sp, r2); 1077 // Check if the arguments will overflow the stack. 1078 __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1079 __ b(gt, &okay); // Signed comparison. 1080 1081 // Out of stack space. 1082 __ ldr(r1, MemOperand(fp, kFunctionOffset)); 1083 __ push(r1); 1084 __ push(r0); 1085 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS); 1086 // End of stack check. 1087 1088 // Push current limit and index. 1089 __ bind(&okay); 1090 __ push(r0); // limit 1091 __ mov(r1, Operand(0)); // initial index 1092 __ push(r1); 1093 1094 // Change context eagerly to get the right global object if necessary. 1095 __ ldr(r0, MemOperand(fp, kFunctionOffset)); 1096 __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset)); 1097 1098 // Compute the receiver. 1099 Label call_to_object, use_global_receiver, push_receiver; 1100 __ ldr(r0, MemOperand(fp, kRecvOffset)); 1101 __ tst(r0, Operand(kSmiTagMask)); 1102 __ b(eq, &call_to_object); 1103 __ LoadRoot(r1, Heap::kNullValueRootIndex); 1104 __ cmp(r0, r1); 1105 __ b(eq, &use_global_receiver); 1106 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); 1107 __ cmp(r0, r1); 1108 __ b(eq, &use_global_receiver); 1109 1110 // Check if the receiver is already a JavaScript object. 1111 // r0: receiver 1112 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE); 1113 __ b(lt, &call_to_object); 1114 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); 1115 __ b(le, &push_receiver); 1116 1117 // Convert the receiver to a regular object. 1118 // r0: receiver 1119 __ bind(&call_to_object); 1120 __ push(r0); 1121 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); 1122 __ b(&push_receiver); 1123 1124 // Use the current global receiver object as the receiver. 1125 __ bind(&use_global_receiver); 1126 const int kGlobalOffset = 1127 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 1128 __ ldr(r0, FieldMemOperand(cp, kGlobalOffset)); 1129 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset)); 1130 __ ldr(r0, FieldMemOperand(r0, kGlobalOffset)); 1131 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); 1132 1133 // Push the receiver. 1134 // r0: receiver 1135 __ bind(&push_receiver); 1136 __ push(r0); 1137 1138 // Copy all arguments from the array to the stack. 1139 Label entry, loop; 1140 __ ldr(r0, MemOperand(fp, kIndexOffset)); 1141 __ b(&entry); 1142 1143 // Load the current argument from the arguments array and push it to the 1144 // stack. 1145 // r0: current argument index 1146 __ bind(&loop); 1147 __ ldr(r1, MemOperand(fp, kArgsOffset)); 1148 __ push(r1); 1149 __ push(r0); 1150 1151 // Call the runtime to access the property in the arguments array. 1152 __ CallRuntime(Runtime::kGetProperty, 2); 1153 __ push(r0); 1154 1155 // Use inline caching to access the arguments. 1156 __ ldr(r0, MemOperand(fp, kIndexOffset)); 1157 __ add(r0, r0, Operand(1 << kSmiTagSize)); 1158 __ str(r0, MemOperand(fp, kIndexOffset)); 1159 1160 // Test if the copy loop has finished copying all the elements from the 1161 // arguments object. 1162 __ bind(&entry); 1163 __ ldr(r1, MemOperand(fp, kLimitOffset)); 1164 __ cmp(r0, r1); 1165 __ b(ne, &loop); 1166 1167 // Invoke the function. 1168 ParameterCount actual(r0); 1169 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); 1170 __ ldr(r1, MemOperand(fp, kFunctionOffset)); 1171 __ InvokeFunction(r1, actual, CALL_FUNCTION); 1172 1173 // Tear down the internal frame and remove function, receiver and args. 1174 __ LeaveInternalFrame(); 1175 __ add(sp, sp, Operand(3 * kPointerSize)); 1176 __ Jump(lr); 1177} 1178 1179 1180static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1181 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); 1182 __ mov(r4, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 1183 __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit()); 1184 __ add(fp, sp, Operand(3 * kPointerSize)); 1185} 1186 1187 1188static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { 1189 // ----------- S t a t e ------------- 1190 // -- r0 : result being passed through 1191 // ----------------------------------- 1192 // Get the number of arguments passed (as a smi), tear down the frame and 1193 // then tear down the parameters. 1194 __ ldr(r1, MemOperand(fp, -3 * kPointerSize)); 1195 __ mov(sp, fp); 1196 __ ldm(ia_w, sp, fp.bit() | lr.bit()); 1197 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); 1198 __ add(sp, sp, Operand(kPointerSize)); // adjust for receiver 1199} 1200 1201 1202void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { 1203 // ----------- S t a t e ------------- 1204 // -- r0 : actual number of arguments 1205 // -- r1 : function (passed through to callee) 1206 // -- r2 : expected number of arguments 1207 // -- r3 : code entry to call 1208 // ----------------------------------- 1209 1210 Label invoke, dont_adapt_arguments; 1211 1212 Label enough, too_few; 1213 __ cmp(r0, Operand(r2)); 1214 __ b(lt, &too_few); 1215 __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); 1216 __ b(eq, &dont_adapt_arguments); 1217 1218 { // Enough parameters: actual >= expected 1219 __ bind(&enough); 1220 EnterArgumentsAdaptorFrame(masm); 1221 1222 // Calculate copy start address into r0 and copy end address into r2. 1223 // r0: actual number of arguments as a smi 1224 // r1: function 1225 // r2: expected number of arguments 1226 // r3: code entry to call 1227 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1228 // adjust for return address and receiver 1229 __ add(r0, r0, Operand(2 * kPointerSize)); 1230 __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2)); 1231 1232 // Copy the arguments (including the receiver) to the new stack frame. 1233 // r0: copy start address 1234 // r1: function 1235 // r2: copy end address 1236 // r3: code entry to call 1237 1238 Label copy; 1239 __ bind(©); 1240 __ ldr(ip, MemOperand(r0, 0)); 1241 __ push(ip); 1242 __ cmp(r0, r2); // Compare before moving to next argument. 1243 __ sub(r0, r0, Operand(kPointerSize)); 1244 __ b(ne, ©); 1245 1246 __ b(&invoke); 1247 } 1248 1249 { // Too few parameters: Actual < expected 1250 __ bind(&too_few); 1251 EnterArgumentsAdaptorFrame(masm); 1252 1253 // Calculate copy start address into r0 and copy end address is fp. 1254 // r0: actual number of arguments as a smi 1255 // r1: function 1256 // r2: expected number of arguments 1257 // r3: code entry to call 1258 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1259 1260 // Copy the arguments (including the receiver) to the new stack frame. 1261 // r0: copy start address 1262 // r1: function 1263 // r2: expected number of arguments 1264 // r3: code entry to call 1265 Label copy; 1266 __ bind(©); 1267 // Adjust load for return address and receiver. 1268 __ ldr(ip, MemOperand(r0, 2 * kPointerSize)); 1269 __ push(ip); 1270 __ cmp(r0, fp); // Compare before moving to next argument. 1271 __ sub(r0, r0, Operand(kPointerSize)); 1272 __ b(ne, ©); 1273 1274 // Fill the remaining expected arguments with undefined. 1275 // r1: function 1276 // r2: expected number of arguments 1277 // r3: code entry to call 1278 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 1279 __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2)); 1280 __ sub(r2, r2, Operand(4 * kPointerSize)); // Adjust for frame. 1281 1282 Label fill; 1283 __ bind(&fill); 1284 __ push(ip); 1285 __ cmp(sp, r2); 1286 __ b(ne, &fill); 1287 } 1288 1289 // Call the entry point. 1290 __ bind(&invoke); 1291 __ Call(r3); 1292 1293 // Exit frame and return. 1294 LeaveArgumentsAdaptorFrame(masm); 1295 __ Jump(lr); 1296 1297 1298 // ------------------------------------------- 1299 // Dont adapt arguments. 1300 // ------------------------------------------- 1301 __ bind(&dont_adapt_arguments); 1302 __ Jump(r3); 1303} 1304 1305 1306#undef __ 1307 1308} } // namespace v8::internal 1309