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