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