OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 101 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
102 __ lw(result, | 102 __ lw(result, |
103 FieldMemOperand(result, GlobalObject::kNativeContextOffset)); | 103 FieldMemOperand(result, GlobalObject::kNativeContextOffset)); |
104 // Load the Array function from the native context. | 104 // Load the Array function from the native context. |
105 __ lw(result, | 105 __ lw(result, |
106 MemOperand(result, | 106 MemOperand(result, |
107 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); | 107 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); |
108 } | 108 } |
109 | 109 |
110 | 110 |
111 // Allocate an empty JSArray. The allocated array is put into the result | |
112 // register. An elements backing store is allocated with size initial_capacity | |
113 // and filled with the hole values. | |
114 static void AllocateEmptyJSArray(MacroAssembler* masm, | |
115 Register array_function, | |
116 Register result, | |
117 Register scratch1, | |
118 Register scratch2, | |
119 Register scratch3, | |
120 Label* gc_required) { | |
121 const int initial_capacity = JSArray::kPreallocatedArrayElements; | |
122 STATIC_ASSERT(initial_capacity >= 0); | |
123 __ LoadInitialArrayMap(array_function, scratch2, scratch1, false); | |
124 | |
125 // Allocate the JSArray object together with space for a fixed array with the | |
126 // requested elements. | |
127 int size = JSArray::kSize; | |
128 if (initial_capacity > 0) { | |
129 size += FixedArray::SizeFor(initial_capacity); | |
130 } | |
131 __ Allocate(size, result, scratch2, scratch3, gc_required, TAG_OBJECT); | |
132 | |
133 // Allocated the JSArray. Now initialize the fields except for the elements | |
134 // array. | |
135 // result: JSObject | |
136 // scratch1: initial map | |
137 // scratch2: start of next object | |
138 __ sw(scratch1, FieldMemOperand(result, JSObject::kMapOffset)); | |
139 __ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex); | |
140 __ sw(scratch1, FieldMemOperand(result, JSArray::kPropertiesOffset)); | |
141 // Field JSArray::kElementsOffset is initialized later. | |
142 __ mov(scratch3, zero_reg); | |
143 __ sw(scratch3, FieldMemOperand(result, JSArray::kLengthOffset)); | |
144 | |
145 if (initial_capacity == 0) { | |
146 __ sw(scratch1, FieldMemOperand(result, JSArray::kElementsOffset)); | |
147 return; | |
148 } | |
149 | |
150 // Calculate the location of the elements array and set elements array member | |
151 // of the JSArray. | |
152 // result: JSObject | |
153 // scratch2: start of next object | |
154 __ Addu(scratch1, result, Operand(JSArray::kSize)); | |
155 __ sw(scratch1, FieldMemOperand(result, JSArray::kElementsOffset)); | |
156 | |
157 // Clear the heap tag on the elements array. | |
158 __ And(scratch1, scratch1, Operand(~kHeapObjectTagMask)); | |
159 | |
160 // Initialize the FixedArray and fill it with holes. FixedArray length is | |
161 // stored as a smi. | |
162 // result: JSObject | |
163 // scratch1: elements array (untagged) | |
164 // scratch2: start of next object | |
165 __ LoadRoot(scratch3, Heap::kFixedArrayMapRootIndex); | |
166 STATIC_ASSERT(0 * kPointerSize == FixedArray::kMapOffset); | |
167 __ sw(scratch3, MemOperand(scratch1)); | |
168 __ Addu(scratch1, scratch1, kPointerSize); | |
169 __ li(scratch3, Operand(Smi::FromInt(initial_capacity))); | |
170 STATIC_ASSERT(1 * kPointerSize == FixedArray::kLengthOffset); | |
171 __ sw(scratch3, MemOperand(scratch1)); | |
172 __ Addu(scratch1, scratch1, kPointerSize); | |
173 | |
174 // Fill the FixedArray with the hole value. Inline the code if short. | |
175 STATIC_ASSERT(2 * kPointerSize == FixedArray::kHeaderSize); | |
176 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex); | |
177 static const int kLoopUnfoldLimit = 4; | |
178 if (initial_capacity <= kLoopUnfoldLimit) { | |
179 for (int i = 0; i < initial_capacity; i++) { | |
180 __ sw(scratch3, MemOperand(scratch1, i * kPointerSize)); | |
181 } | |
182 } else { | |
183 Label loop, entry; | |
184 __ Addu(scratch2, scratch1, Operand(initial_capacity * kPointerSize)); | |
185 __ Branch(&entry); | |
186 __ bind(&loop); | |
187 __ sw(scratch3, MemOperand(scratch1)); | |
188 __ Addu(scratch1, scratch1, kPointerSize); | |
189 __ bind(&entry); | |
190 __ Branch(&loop, lt, scratch1, Operand(scratch2)); | |
191 } | |
192 } | |
193 | |
194 | |
195 // Allocate a JSArray with the number of elements stored in a register. The | |
196 // register array_function holds the built-in Array function and the register | |
197 // array_size holds the size of the array as a smi. The allocated array is put | |
198 // into the result register and beginning and end of the FixedArray elements | |
199 // storage is put into registers elements_array_storage and elements_array_end | |
200 // (see below for when that is not the case). If the parameter fill_with_holes | |
201 // is true the allocated elements backing store is filled with the hole values | |
202 // otherwise it is left uninitialized. When the backing store is filled the | |
203 // register elements_array_storage is scratched. | |
204 static void AllocateJSArray(MacroAssembler* masm, | |
205 Register array_function, // Array function. | |
206 Register array_size, // As a smi, cannot be 0. | |
207 Register result, | |
208 Register elements_array_storage, | |
209 Register elements_array_end, | |
210 Register scratch1, | |
211 Register scratch2, | |
212 bool fill_with_hole, | |
213 Label* gc_required) { | |
214 // Load the initial map from the array function. | |
215 __ LoadInitialArrayMap(array_function, scratch2, | |
216 elements_array_storage, fill_with_hole); | |
217 | |
218 if (FLAG_debug_code) { // Assert that array size is not zero. | |
219 __ Assert( | |
220 ne, "array size is unexpectedly 0", array_size, Operand(zero_reg)); | |
221 } | |
222 | |
223 // Allocate the JSArray object together with space for a FixedArray with the | |
224 // requested number of elements. | |
225 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | |
226 __ li(elements_array_end, | |
227 (JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize); | |
228 __ sra(scratch1, array_size, kSmiTagSize); | |
229 __ Addu(elements_array_end, elements_array_end, scratch1); | |
230 __ Allocate(elements_array_end, | |
231 result, | |
232 scratch1, | |
233 scratch2, | |
234 gc_required, | |
235 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); | |
236 | |
237 // Allocated the JSArray. Now initialize the fields except for the elements | |
238 // array. | |
239 // result: JSObject | |
240 // elements_array_storage: initial map | |
241 // array_size: size of array (smi) | |
242 __ sw(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset)); | |
243 __ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex); | |
244 __ sw(elements_array_storage, | |
245 FieldMemOperand(result, JSArray::kPropertiesOffset)); | |
246 // Field JSArray::kElementsOffset is initialized later. | |
247 __ sw(array_size, FieldMemOperand(result, JSArray::kLengthOffset)); | |
248 | |
249 // Calculate the location of the elements array and set elements array member | |
250 // of the JSArray. | |
251 // result: JSObject | |
252 // array_size: size of array (smi) | |
253 __ Addu(elements_array_storage, result, Operand(JSArray::kSize)); | |
254 __ sw(elements_array_storage, | |
255 FieldMemOperand(result, JSArray::kElementsOffset)); | |
256 | |
257 // Clear the heap tag on the elements array. | |
258 __ And(elements_array_storage, | |
259 elements_array_storage, | |
260 Operand(~kHeapObjectTagMask)); | |
261 // Initialize the fixed array and fill it with holes. FixedArray length is | |
262 // stored as a smi. | |
263 // result: JSObject | |
264 // elements_array_storage: elements array (untagged) | |
265 // array_size: size of array (smi) | |
266 __ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex); | |
267 ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); | |
268 __ sw(scratch1, MemOperand(elements_array_storage)); | |
269 __ Addu(elements_array_storage, elements_array_storage, kPointerSize); | |
270 | |
271 // Length of the FixedArray is the number of pre-allocated elements if | |
272 // the actual JSArray has length 0 and the size of the JSArray for non-empty | |
273 // JSArrays. The length of a FixedArray is stored as a smi. | |
274 STATIC_ASSERT(kSmiTag == 0); | |
275 | |
276 ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); | |
277 __ sw(array_size, MemOperand(elements_array_storage)); | |
278 __ Addu(elements_array_storage, elements_array_storage, kPointerSize); | |
279 | |
280 // Calculate elements array and elements array end. | |
281 // result: JSObject | |
282 // elements_array_storage: elements array element storage | |
283 // array_size: smi-tagged size of elements array | |
284 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | |
285 __ sll(elements_array_end, array_size, kPointerSizeLog2 - kSmiTagSize); | |
286 __ Addu(elements_array_end, elements_array_storage, elements_array_end); | |
287 | |
288 // Fill the allocated FixedArray with the hole value if requested. | |
289 // result: JSObject | |
290 // elements_array_storage: elements array element storage | |
291 // elements_array_end: start of next object | |
292 if (fill_with_hole) { | |
293 Label loop, entry; | |
294 __ LoadRoot(scratch1, Heap::kTheHoleValueRootIndex); | |
295 __ Branch(&entry); | |
296 __ bind(&loop); | |
297 __ sw(scratch1, MemOperand(elements_array_storage)); | |
298 __ Addu(elements_array_storage, elements_array_storage, kPointerSize); | |
299 | |
300 __ bind(&entry); | |
301 __ Branch(&loop, lt, elements_array_storage, Operand(elements_array_end)); | |
302 } | |
303 } | |
304 | |
305 | |
306 // Create a new array for the built-in Array function. This function allocates | |
307 // the JSArray object and the FixedArray elements array and initializes these. | |
308 // If the Array cannot be constructed in native code the runtime is called. This | |
309 // function assumes the following state: | |
310 // a0: argc | |
311 // a1: constructor (built-in Array function) | |
312 // ra: return address | |
313 // sp[0]: last argument | |
314 // This function is used for both construct and normal calls of Array. The only | |
315 // difference between handling a construct call and a normal call is that for a | |
316 // construct call the constructor function in a1 needs to be preserved for | |
317 // entering the generic code. In both cases argc in a0 needs to be preserved. | |
318 // Both registers are preserved by this code so no need to differentiate between | |
319 // construct call and normal call. | |
320 void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code) { | |
321 Counters* counters = masm->isolate()->counters(); | |
322 Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array, | |
323 has_non_smi_element, finish, cant_transition_map, not_double; | |
324 | |
325 // Check for array construction with zero arguments or one. | |
326 __ Branch(&argc_one_or_more, ne, a0, Operand(zero_reg)); | |
327 // Handle construction of an empty array. | |
328 __ bind(&empty_array); | |
329 AllocateEmptyJSArray(masm, | |
330 a1, | |
331 a2, | |
332 a3, | |
333 t0, | |
334 t1, | |
335 call_generic_code); | |
336 __ IncrementCounter(counters->array_function_native(), 1, a3, t0); | |
337 // Set up return value, remove receiver from stack and return. | |
338 __ Addu(sp, sp, Operand(kPointerSize)); | |
339 __ Ret(USE_DELAY_SLOT); | |
340 __ mov(v0, a2); | |
341 | |
342 // Check for one argument. Bail out if argument is not smi or if it is | |
343 // negative. | |
344 __ bind(&argc_one_or_more); | |
345 __ Branch(&argc_two_or_more, ne, a0, Operand(1)); | |
346 | |
347 STATIC_ASSERT(kSmiTag == 0); | |
348 __ lw(a2, MemOperand(sp)); // Get the argument from the stack. | |
349 __ Branch(¬_empty_array, ne, a2, Operand(zero_reg)); | |
350 __ Drop(1); // Adjust stack. | |
351 __ mov(a0, zero_reg); // Treat this as a call with argc of zero. | |
352 __ Branch(&empty_array); | |
353 | |
354 __ bind(¬_empty_array); | |
355 __ And(a3, a2, Operand(kIntptrSignBit | kSmiTagMask)); | |
356 __ Branch(call_generic_code, eq, a3, Operand(zero_reg)); | |
357 | |
358 // Handle construction of an empty array of a certain size. Bail out if size | |
359 // is too large to actually allocate an elements array. | |
360 STATIC_ASSERT(kSmiTag == 0); | |
361 __ Branch(call_generic_code, Ugreater_equal, a2, | |
362 Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize)); | |
363 | |
364 // a0: argc | |
365 // a1: constructor | |
366 // a2: array_size (smi) | |
367 // sp[0]: argument | |
368 AllocateJSArray(masm, | |
369 a1, | |
370 a2, | |
371 a3, | |
372 t0, | |
373 t1, | |
374 t2, | |
375 t3, | |
376 true, | |
377 call_generic_code); | |
378 __ IncrementCounter(counters->array_function_native(), 1, a2, t0); | |
379 | |
380 // Set up return value, remove receiver and argument from stack and return. | |
381 __ Addu(sp, sp, Operand(2 * kPointerSize)); | |
382 __ Ret(USE_DELAY_SLOT); | |
383 __ mov(v0, a3); | |
384 | |
385 // Handle construction of an array from a list of arguments. | |
386 __ bind(&argc_two_or_more); | |
387 __ sll(a2, a0, kSmiTagSize); // Convert argc to a smi. | |
388 | |
389 // a0: argc | |
390 // a1: constructor | |
391 // a2: array_size (smi) | |
392 // sp[0]: last argument | |
393 AllocateJSArray(masm, | |
394 a1, | |
395 a2, | |
396 a3, | |
397 t0, | |
398 t1, | |
399 t2, | |
400 t3, | |
401 false, | |
402 call_generic_code); | |
403 __ IncrementCounter(counters->array_function_native(), 1, a2, t2); | |
404 | |
405 // Fill arguments as array elements. Copy from the top of the stack (last | |
406 // element) to the array backing store filling it backwards. Note: | |
407 // elements_array_end points after the backing store. | |
408 // a0: argc | |
409 // a3: JSArray | |
410 // t0: elements_array storage start (untagged) | |
411 // t1: elements_array_end (untagged) | |
412 // sp[0]: last argument | |
413 | |
414 Label loop, entry; | |
415 __ Branch(USE_DELAY_SLOT, &entry); | |
416 __ mov(t3, sp); | |
417 __ bind(&loop); | |
418 __ lw(a2, MemOperand(t3)); | |
419 if (FLAG_smi_only_arrays) { | |
420 __ JumpIfNotSmi(a2, &has_non_smi_element); | |
421 } | |
422 __ Addu(t3, t3, kPointerSize); | |
423 __ Addu(t1, t1, -kPointerSize); | |
424 __ sw(a2, MemOperand(t1)); | |
425 __ bind(&entry); | |
426 __ Branch(&loop, lt, t0, Operand(t1)); | |
427 | |
428 __ bind(&finish); | |
429 __ mov(sp, t3); | |
430 | |
431 // Remove caller arguments and receiver from the stack, setup return value and | |
432 // return. | |
433 // a0: argc | |
434 // a3: JSArray | |
435 // sp[0]: receiver | |
436 __ Addu(sp, sp, Operand(kPointerSize)); | |
437 __ Ret(USE_DELAY_SLOT); | |
438 __ mov(v0, a3); | |
439 | |
440 __ bind(&has_non_smi_element); | |
441 // Double values are handled by the runtime. | |
442 __ CheckMap( | |
443 a2, t5, Heap::kHeapNumberMapRootIndex, ¬_double, DONT_DO_SMI_CHECK); | |
444 __ bind(&cant_transition_map); | |
445 __ UndoAllocationInNewSpace(a3, t0); | |
446 __ Branch(call_generic_code); | |
447 | |
448 __ bind(¬_double); | |
449 // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS. | |
450 // a3: JSArray | |
451 __ lw(a2, FieldMemOperand(a3, HeapObject::kMapOffset)); | |
452 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | |
453 FAST_ELEMENTS, | |
454 a2, | |
455 t5, | |
456 &cant_transition_map); | |
457 __ sw(a2, FieldMemOperand(a3, HeapObject::kMapOffset)); | |
458 __ RecordWriteField(a3, | |
459 HeapObject::kMapOffset, | |
460 a2, | |
461 t5, | |
462 kRAHasNotBeenSaved, | |
463 kDontSaveFPRegs, | |
464 EMIT_REMEMBERED_SET, | |
465 OMIT_SMI_CHECK); | |
466 Label loop2; | |
467 __ bind(&loop2); | |
468 __ lw(a2, MemOperand(t3)); | |
469 __ Addu(t3, t3, kPointerSize); | |
470 __ Subu(t1, t1, kPointerSize); | |
471 __ sw(a2, MemOperand(t1)); | |
472 __ Branch(&loop2, lt, t0, Operand(t1)); | |
473 __ Branch(&finish); | |
474 } | |
475 | |
476 | |
477 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { | 111 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { |
478 // ----------- S t a t e ------------- | 112 // ----------- S t a t e ------------- |
479 // -- a0 : number of arguments | 113 // -- a0 : number of arguments |
480 // -- ra : return address | 114 // -- ra : return address |
481 // -- sp[...]: constructor arguments | 115 // -- sp[...]: constructor arguments |
482 // ----------------------------------- | 116 // ----------------------------------- |
483 Label generic_array_code, one_or_more_arguments, two_or_more_arguments; | 117 Label generic_array_code, one_or_more_arguments, two_or_more_arguments; |
484 | 118 |
485 // Get the InternalArray function. | 119 // Get the InternalArray function. |
486 GenerateLoadInternalArrayFunction(masm, a1); | 120 GenerateLoadInternalArrayFunction(masm, a1); |
487 | 121 |
488 if (FLAG_debug_code) { | 122 if (FLAG_debug_code) { |
489 // Initial map for the builtin InternalArray functions should be maps. | 123 // Initial map for the builtin InternalArray functions should be maps. |
490 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); | 124 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); |
491 __ And(t0, a2, Operand(kSmiTagMask)); | 125 __ And(t0, a2, Operand(kSmiTagMask)); |
492 __ Assert(ne, "Unexpected initial map for InternalArray function", | 126 __ Assert(ne, "Unexpected initial map for InternalArray function", |
493 t0, Operand(zero_reg)); | 127 t0, Operand(zero_reg)); |
494 __ GetObjectType(a2, a3, t0); | 128 __ GetObjectType(a2, a3, t0); |
495 __ Assert(eq, "Unexpected initial map for InternalArray function", | 129 __ Assert(eq, "Unexpected initial map for InternalArray function", |
496 t0, Operand(MAP_TYPE)); | 130 t0, Operand(MAP_TYPE)); |
497 } | 131 } |
498 | 132 |
499 // Run the native code for the InternalArray function called as a normal | 133 // Run the native code for the InternalArray function called as a normal |
500 // function. | 134 // function. |
501 if (FLAG_optimize_constructed_arrays) { | 135 // Tail call a stub. |
502 // Tail call a stub. | 136 InternalArrayConstructorStub stub(masm->isolate()); |
503 InternalArrayConstructorStub stub(masm->isolate()); | 137 __ TailCallStub(&stub); |
504 __ TailCallStub(&stub); | |
505 } else { | |
506 ArrayNativeCode(masm, &generic_array_code); | |
507 | |
508 // Jump to the generic array code if the specialized code cannot handle the | |
509 // construction. | |
510 __ bind(&generic_array_code); | |
511 Handle<Code> array_code = | |
512 masm->isolate()->builtins()->InternalArrayCodeGeneric(); | |
513 __ Jump(array_code, RelocInfo::CODE_TARGET); | |
514 } | |
515 } | 138 } |
516 | 139 |
517 | 140 |
518 void Builtins::Generate_ArrayCode(MacroAssembler* masm) { | 141 void Builtins::Generate_ArrayCode(MacroAssembler* masm) { |
519 // ----------- S t a t e ------------- | 142 // ----------- S t a t e ------------- |
520 // -- a0 : number of arguments | 143 // -- a0 : number of arguments |
521 // -- ra : return address | 144 // -- ra : return address |
522 // -- sp[...]: constructor arguments | 145 // -- sp[...]: constructor arguments |
523 // ----------------------------------- | 146 // ----------------------------------- |
524 Label generic_array_code; | 147 Label generic_array_code; |
525 | 148 |
526 // Get the Array function. | 149 // Get the Array function. |
527 GenerateLoadArrayFunction(masm, a1); | 150 GenerateLoadArrayFunction(masm, a1); |
528 | 151 |
529 if (FLAG_debug_code) { | 152 if (FLAG_debug_code) { |
530 // Initial map for the builtin Array functions should be maps. | 153 // Initial map for the builtin Array functions should be maps. |
531 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); | 154 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); |
532 __ And(t0, a2, Operand(kSmiTagMask)); | 155 __ And(t0, a2, Operand(kSmiTagMask)); |
533 __ Assert(ne, "Unexpected initial map for Array function (1)", | 156 __ Assert(ne, "Unexpected initial map for Array function (1)", |
534 t0, Operand(zero_reg)); | 157 t0, Operand(zero_reg)); |
535 __ GetObjectType(a2, a3, t0); | 158 __ GetObjectType(a2, a3, t0); |
536 __ Assert(eq, "Unexpected initial map for Array function (2)", | 159 __ Assert(eq, "Unexpected initial map for Array function (2)", |
537 t0, Operand(MAP_TYPE)); | 160 t0, Operand(MAP_TYPE)); |
538 } | 161 } |
539 | 162 |
540 // Run the native code for the Array function called as a normal function. | 163 // Run the native code for the Array function called as a normal function. |
541 if (FLAG_optimize_constructed_arrays) { | 164 // Tail call a stub. |
542 // Tail call a stub. | 165 Handle<Object> undefined_sentinel( |
543 Handle<Object> undefined_sentinel( | 166 masm->isolate()->heap()->undefined_value(), |
544 masm->isolate()->heap()->undefined_value(), | 167 masm->isolate()); |
545 masm->isolate()); | 168 __ li(a2, Operand(undefined_sentinel)); |
546 __ li(a2, Operand(undefined_sentinel)); | 169 ArrayConstructorStub stub(masm->isolate()); |
547 ArrayConstructorStub stub(masm->isolate()); | 170 __ TailCallStub(&stub); |
548 __ TailCallStub(&stub); | |
549 } else { | |
550 ArrayNativeCode(masm, &generic_array_code); | |
551 | |
552 // Jump to the generic array code if the specialized code cannot handle | |
553 // the construction. | |
554 __ bind(&generic_array_code); | |
555 Handle<Code> array_code = | |
556 masm->isolate()->builtins()->ArrayCodeGeneric(); | |
557 __ Jump(array_code, RelocInfo::CODE_TARGET); | |
558 } | |
559 } | 171 } |
560 | 172 |
561 | 173 |
562 void Builtins::Generate_CommonArrayConstructCode(MacroAssembler* masm) { | |
563 // ----------- S t a t e ------------- | |
564 // -- a0 : number of arguments | |
565 // -- a1 : constructor function | |
566 // -- a2 : type info cell | |
567 // -- ra : return address | |
568 // -- sp[...]: constructor arguments | |
569 // ----------------------------------- | |
570 | |
571 if (FLAG_debug_code) { | |
572 // The array construct code is only set for the builtin and internal | |
573 // Array functions which always have a map. | |
574 // Initial map for the builtin Array function should be a map. | |
575 __ lw(a3, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); | |
576 __ And(t0, a3, Operand(kSmiTagMask)); | |
577 __ Assert(ne, "Unexpected initial map for Array function (3)", | |
578 t0, Operand(zero_reg)); | |
579 __ GetObjectType(a3, a3, t0); | |
580 __ Assert(eq, "Unexpected initial map for Array function (4)", | |
581 t0, Operand(MAP_TYPE)); | |
582 } | |
583 Label generic_constructor; | |
584 // Run the native code for the Array function called as a constructor. | |
585 ArrayNativeCode(masm, &generic_constructor); | |
586 | |
587 // Jump to the generic construct code in case the specialized code cannot | |
588 // handle the construction. | |
589 __ bind(&generic_constructor); | |
590 Handle<Code> generic_construct_stub = | |
591 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
592 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | |
593 } | |
594 | |
595 | |
596 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { | 174 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { |
597 // ----------- S t a t e ------------- | 175 // ----------- S t a t e ------------- |
598 // -- a0 : number of arguments | 176 // -- a0 : number of arguments |
599 // -- a1 : constructor function | 177 // -- a1 : constructor function |
600 // -- ra : return address | 178 // -- ra : return address |
601 // -- sp[(argc - n - 1) * 4] : arg[n] (zero based) | 179 // -- sp[(argc - n - 1) * 4] : arg[n] (zero based) |
602 // -- sp[argc * 4] : receiver | 180 // -- sp[argc * 4] : receiver |
603 // ----------------------------------- | 181 // ----------------------------------- |
604 Counters* counters = masm->isolate()->counters(); | 182 Counters* counters = masm->isolate()->counters(); |
605 __ IncrementCounter(counters->string_ctor_calls(), 1, a2, a3); | 183 __ IncrementCounter(counters->string_ctor_calls(), 1, a2, a3); |
(...skipping 1331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1937 __ bind(&dont_adapt_arguments); | 1515 __ bind(&dont_adapt_arguments); |
1938 __ Jump(a3); | 1516 __ Jump(a3); |
1939 } | 1517 } |
1940 | 1518 |
1941 | 1519 |
1942 #undef __ | 1520 #undef __ |
1943 | 1521 |
1944 } } // namespace v8::internal | 1522 } } // namespace v8::internal |
1945 | 1523 |
1946 #endif // V8_TARGET_ARCH_MIPS | 1524 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |