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