blob: 4420102eb095218815a3fbbe3c789d9637e39a21 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_IA32)
31
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000032#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000033#include "deoptimizer.h"
34#include "full-codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036namespace v8 {
37namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
39
ager@chromium.org65dad4b2009-04-23 08:48:43 +000040#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
42
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000043void Builtins::Generate_Adaptor(MacroAssembler* masm,
44 CFunctionId id,
45 BuiltinExtraArguments extra_args) {
46 // ----------- S t a t e -------------
47 // -- eax : number of arguments excluding receiver
48 // -- edi : called function (only guaranteed when
49 // extra_args requires it)
50 // -- esi : context
51 // -- esp[0] : return address
52 // -- esp[4] : last argument
53 // -- ...
54 // -- esp[4 * argc] : first argument (argc == eax)
55 // -- esp[4 * (argc +1)] : receiver
56 // -----------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000057
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000058 // Insert extra arguments.
59 int num_extra_args = 0;
60 if (extra_args == NEEDS_CALLED_FUNCTION) {
61 num_extra_args = 1;
62 Register scratch = ebx;
63 __ pop(scratch); // Save return address.
64 __ push(edi);
65 __ push(scratch); // Restore return address.
66 } else {
67 ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
68 }
69
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000070 // JumpToExternalReference expects eax to contain the number of arguments
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000071 // including the receiver and the extra arguments.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000072 __ add(eax, Immediate(num_extra_args + 1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000073 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074}
75
76
yangguo@chromium.org304cc332012-07-24 07:59:48 +000077static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
78 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
79 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kCodeOffset));
80 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
81 __ jmp(eax);
82}
83
84
85void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
86 GenerateTailCallToSharedCode(masm);
87}
88
89
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000090void Builtins::Generate_InstallRecompiledCode(MacroAssembler* masm) {
91 {
92 FrameScope scope(masm, StackFrame::INTERNAL);
93
94 // Push a copy of the function.
95 __ push(edi);
96 // Push call kind information.
97 __ push(ecx);
98
99 __ push(edi); // Function is also the parameter to the runtime call.
100 __ CallRuntime(Runtime::kInstallRecompiledCode, 1);
101
102 // Restore call kind information.
103 __ pop(ecx);
104 // Restore receiver.
105 __ pop(edi);
106
107 // Tear down internal frame.
108 }
109
110 // Do a tail-call of the compiled function.
111 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
112 __ jmp(eax);
113}
114
115
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000116void Builtins::Generate_ParallelRecompile(MacroAssembler* masm) {
117 {
118 FrameScope scope(masm, StackFrame::INTERNAL);
119
120 // Push a copy of the function onto the stack.
121 __ push(edi);
122 // Push call kind information.
123 __ push(ecx);
124
125 __ push(edi); // Function is also the parameter to the runtime call.
126 __ CallRuntime(Runtime::kParallelRecompile, 1);
127
128 // Restore call kind information.
129 __ pop(ecx);
130 // Restore receiver.
131 __ pop(edi);
132
133 // Tear down internal frame.
134 }
135
136 GenerateTailCallToSharedCode(masm);
137}
138
139
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000140static void Generate_JSConstructStubHelper(MacroAssembler* masm,
141 bool is_api_function,
142 bool count_constructions) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000143 // ----------- S t a t e -------------
144 // -- eax: number of arguments
145 // -- edi: constructor function
146 // -----------------------------------
147
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000148 // Should never count constructions for api objects.
149 ASSERT(!is_api_function || !count_constructions);
150
ager@chromium.org7c537e22008-10-16 08:43:32 +0000151 // Enter a construct frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000152 {
153 FrameScope scope(masm, StackFrame::CONSTRUCT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000154
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000155 // Store a smi-tagged arguments count on the stack.
156 __ SmiTag(eax);
157 __ push(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000159 // Push the function to invoke on the stack.
160 __ push(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000162 // Try to allocate the object without transitioning into C code. If any of
163 // the preconditions is not met, the code bails out to the runtime call.
164 Label rt_call, allocated;
165 if (FLAG_inline_new) {
166 Label undo_allocation;
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000167#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000168 ExternalReference debug_step_in_fp =
169 ExternalReference::debug_step_in_fp_address(masm->isolate());
170 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
171 __ j(not_equal, &rt_call);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000172#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000174 // Verified that the constructor is a JSFunction.
175 // Load the initial map and verify that it is in fact a map.
176 // edi: constructor
177 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
178 // Will both indicate a NULL and a Smi
179 __ JumpIfSmi(eax, &rt_call);
180 // edi: constructor
181 // eax: initial map (if proven valid below)
182 __ CmpObjectType(eax, MAP_TYPE, ebx);
183 __ j(not_equal, &rt_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000184
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000185 // Check that the constructor is not constructing a JSFunction (see
186 // comments in Runtime_NewObject in runtime.cc). In which case the
187 // initial map's instance type would be JS_FUNCTION_TYPE.
188 // edi: constructor
189 // eax: initial map
190 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
191 __ j(equal, &rt_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000193 if (count_constructions) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000194 Label allocate;
195 // Decrease generous allocation count.
196 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
197 __ dec_b(FieldOperand(ecx,
198 SharedFunctionInfo::kConstructionCountOffset));
199 __ j(not_zero, &allocate);
200
201 __ push(eax);
202 __ push(edi);
203
204 __ push(edi); // constructor
205 // The call will replace the stub, so the countdown is only done once.
206 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
207
208 __ pop(edi);
209 __ pop(eax);
210
211 __ bind(&allocate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000212 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000213
214 // Now allocate the JSObject on the heap.
215 // edi: constructor
216 // eax: initial map
217 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
218 __ shl(edi, kPointerSizeLog2);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000219 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000220 // Allocated the JSObject, now initialize the fields.
221 // eax: initial map
222 // ebx: JSObject
223 // edi: start of next object
224 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
225 Factory* factory = masm->isolate()->factory();
226 __ mov(ecx, factory->empty_fixed_array());
227 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
228 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
229 // Set extra fields in the newly allocated object.
230 // eax: initial map
231 // ebx: JSObject
232 // edi: start of next object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000234 __ mov(edx, factory->undefined_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000235 if (count_constructions) {
236 __ movzx_b(esi,
237 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
238 __ lea(esi,
239 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
240 // esi: offset of first field after pre-allocated fields
241 if (FLAG_debug_code) {
242 __ cmp(esi, edi);
243 __ Assert(less_equal,
244 "Unexpected number of pre-allocated property fields.");
245 }
246 __ InitializeFieldsWithFiller(ecx, esi, edx);
247 __ mov(edx, factory->one_pointer_filler_map());
248 }
249 __ InitializeFieldsWithFiller(ecx, edi, edx);
250
251 // Add the object tag to make the JSObject real, so that we can continue
252 // and jump into the continuation code at any time from now on. Any
253 // failures need to undo the allocation, so that the heap is in a
254 // consistent state and verifiable.
255 // eax: initial map
256 // ebx: JSObject
257 // edi: start of next object
258 __ or_(ebx, Immediate(kHeapObjectTag));
259
260 // Check if a non-empty properties array is needed.
261 // Allocate and initialize a FixedArray if it is.
262 // eax: initial map
263 // ebx: JSObject
264 // edi: start of next object
265 // Calculate the total number of properties described by the map.
266 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
267 __ movzx_b(ecx,
268 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
269 __ add(edx, ecx);
270 // Calculate unused properties past the end of the in-object properties.
271 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
272 __ sub(edx, ecx);
273 // Done if no extra properties are to be allocated.
274 __ j(zero, &allocated);
275 __ Assert(positive, "Property allocation count failed.");
276
277 // Scale the number of elements by pointer size and add the header for
278 // FixedArrays to the start of the next object calculation from above.
279 // ebx: JSObject
280 // edi: start of next object (will be start of FixedArray)
281 // edx: number of elements in properties array
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000282 __ Allocate(FixedArray::kHeaderSize,
283 times_pointer_size,
284 edx,
285 REGISTER_VALUE_IS_INT32,
286 edi,
287 ecx,
288 no_reg,
289 &undo_allocation,
290 RESULT_CONTAINS_TOP);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000291
292 // Initialize the FixedArray.
293 // ebx: JSObject
294 // edi: FixedArray
295 // edx: number of elements
296 // ecx: start of next object
297 __ mov(eax, factory->fixed_array_map());
298 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
299 __ SmiTag(edx);
300 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
301
302 // Initialize the fields to undefined.
303 // ebx: JSObject
304 // edi: FixedArray
305 // ecx: start of next object
306 { Label loop, entry;
307 __ mov(edx, factory->undefined_value());
308 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
309 __ jmp(&entry);
310 __ bind(&loop);
311 __ mov(Operand(eax, 0), edx);
312 __ add(eax, Immediate(kPointerSize));
313 __ bind(&entry);
314 __ cmp(eax, ecx);
315 __ j(below, &loop);
316 }
317
318 // Store the initialized FixedArray into the properties field of
319 // the JSObject
320 // ebx: JSObject
321 // edi: FixedArray
322 __ or_(edi, Immediate(kHeapObjectTag)); // add the heap tag
323 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
324
325
326 // Continue with JSObject being successfully allocated
327 // ebx: JSObject
328 __ jmp(&allocated);
329
330 // Undo the setting of the new top so that the heap is verifiable. For
331 // example, the map's unused properties potentially do not match the
332 // allocated objects unused properties.
333 // ebx: JSObject (previous new top)
334 __ bind(&undo_allocation);
335 __ UndoAllocationInNewSpace(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 }
337
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000338 // Allocate the new receiver object using the runtime call.
339 __ bind(&rt_call);
340 // Must restore edi (constructor) before calling runtime.
341 __ mov(edi, Operand(esp, 0));
342 // edi: function (constructor)
343 __ push(edi);
344 __ CallRuntime(Runtime::kNewObject, 1);
345 __ mov(ebx, eax); // store result in ebx
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000347 // New object allocated.
348 // ebx: newly allocated object
349 __ bind(&allocated);
350 // Retrieve the function from the stack.
351 __ pop(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000353 // Retrieve smi-tagged arguments count from the stack.
354 __ mov(eax, Operand(esp, 0));
355 __ SmiUntag(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000356
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000357 // Push the allocated receiver to the stack. We need two copies
358 // because we may have to return the original one and the calling
359 // conventions dictate that the called function pops the receiver.
360 __ push(ebx);
361 __ push(ebx);
362
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000363 // Set up pointer to last argument.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000364 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
365
366 // Copy arguments and receiver to the expression stack.
367 Label loop, entry;
368 __ mov(ecx, eax);
369 __ jmp(&entry);
370 __ bind(&loop);
371 __ push(Operand(ebx, ecx, times_4, 0));
372 __ bind(&entry);
373 __ dec(ecx);
374 __ j(greater_equal, &loop);
375
376 // Call the function.
377 if (is_api_function) {
378 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
379 Handle<Code> code =
380 masm->isolate()->builtins()->HandleApiCallConstruct();
381 ParameterCount expected(0);
382 __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
383 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
384 } else {
385 ParameterCount actual(eax);
386 __ InvokeFunction(edi, actual, CALL_FUNCTION,
387 NullCallWrapper(), CALL_AS_METHOD);
388 }
389
ulan@chromium.org967e2702012-02-28 09:49:15 +0000390 // Store offset of return address for deoptimizer.
391 if (!is_api_function && !count_constructions) {
392 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
393 }
394
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000395 // Restore context from the frame.
396 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
397
398 // If the result is an object (in the ECMA sense), we should get rid
399 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
400 // on page 74.
401 Label use_receiver, exit;
402
403 // If the result is a smi, it is *not* an object in the ECMA sense.
404 __ JumpIfSmi(eax, &use_receiver);
405
406 // If the type of the result (stored in its map) is less than
407 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
408 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
409 __ j(above_equal, &exit);
410
411 // Throw away the result of the constructor invocation and use the
412 // on-stack receiver as the result.
413 __ bind(&use_receiver);
414 __ mov(eax, Operand(esp, 0));
415
416 // Restore the arguments count and leave the construct frame.
417 __ bind(&exit);
418 __ mov(ebx, Operand(esp, kPointerSize)); // Get arguments count.
419
420 // Leave construct frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000421 }
422
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000423 // Remove caller arguments from the stack and return.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000424 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425 __ pop(ecx);
426 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
427 __ push(ecx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000428 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 __ ret(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430}
431
432
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000433void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
434 Generate_JSConstructStubHelper(masm, false, true);
435}
436
437
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000438void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000439 Generate_JSConstructStubHelper(masm, false, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000440}
441
442
443void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000444 Generate_JSConstructStubHelper(masm, true, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000445}
446
447
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000448static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
449 bool is_construct) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000450 // Clear the context before we push it when entering the internal frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000451 __ Set(esi, Immediate(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000453 {
454 FrameScope scope(masm, StackFrame::INTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000456 // Load the previous frame pointer (ebx) to access C arguments
457 __ mov(ebx, Operand(ebp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000458
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000459 // Get the function from the frame and setup the context.
460 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
461 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000463 // Push the function and the receiver onto the stack.
464 __ push(ecx);
465 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000467 // Load the number of arguments and setup pointer to the arguments.
468 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
469 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000471 // Copy arguments to the stack in a loop.
472 Label loop, entry;
473 __ Set(ecx, Immediate(0));
474 __ jmp(&entry);
475 __ bind(&loop);
476 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
477 __ push(Operand(edx, 0)); // dereference handle
478 __ inc(ecx);
479 __ bind(&entry);
480 __ cmp(ecx, eax);
481 __ j(not_equal, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000483 // Get the function from the stack and call it.
484 // kPointerSize for the receiver.
485 __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000487 // Invoke the code.
488 if (is_construct) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000489 // No type feedback cell is available
490 Handle<Object> undefined_sentinel(
491 masm->isolate()->heap()->undefined_value(), masm->isolate());
492 __ mov(ebx, Immediate(undefined_sentinel));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000493 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
494 __ CallStub(&stub);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000495 } else {
496 ParameterCount actual(eax);
497 __ InvokeFunction(edi, actual, CALL_FUNCTION,
498 NullCallWrapper(), CALL_AS_METHOD);
499 }
500
501 // Exit the internal frame. Notice that this also removes the empty.
502 // context and the function left on the stack by the code
503 // invocation.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000505 __ ret(kPointerSize); // Remove receiver.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000506}
507
508
509void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
510 Generate_JSEntryTrampolineHelper(masm, false);
511}
512
513
514void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
515 Generate_JSEntryTrampolineHelper(masm, true);
516}
517
518
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000519void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000520 {
521 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000522
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000523 // Push a copy of the function.
524 __ push(edi);
525 // Push call kind information.
526 __ push(ecx);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000527
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000528 __ push(edi); // Function is also the parameter to the runtime call.
529 __ CallRuntime(Runtime::kLazyCompile, 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000530
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000531 // Restore call kind information.
532 __ pop(ecx);
533 // Restore receiver.
534 __ pop(edi);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000535
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000536 // Tear down internal frame.
537 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000538
539 // Do a tail-call of the compiled function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000540 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000541 __ jmp(eax);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000542}
543
544
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000545void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000546 {
547 FrameScope scope(masm, StackFrame::INTERNAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000548
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000549 // Push a copy of the function onto the stack.
550 __ push(edi);
551 // Push call kind information.
552 __ push(ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000553
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000554 __ push(edi); // Function is also the parameter to the runtime call.
555 __ CallRuntime(Runtime::kLazyRecompile, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000556
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000557 // Restore call kind information.
558 __ pop(ecx);
559 // Restore receiver.
560 __ pop(edi);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000561
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000562 // Tear down internal frame.
563 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000564
565 // Do a tail-call of the compiled function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000566 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000567 __ jmp(eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000568}
569
570
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000571static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
572 // For now, we are relying on the fact that make_code_young doesn't do any
573 // garbage collection which allows us to save/restore the registers without
574 // worrying about which of them contain pointers. We also don't build an
575 // internal frame to make the code faster, since we shouldn't have to do stack
576 // crawls in MakeCodeYoung. This seems a bit fragile.
577
578 // Re-execute the code that was patched back to the young age when
579 // the stub returns.
580 __ sub(Operand(esp, 0), Immediate(5));
581 __ pushad();
582 __ mov(eax, Operand(esp, 8 * kPointerSize));
583 {
584 FrameScope scope(masm, StackFrame::MANUAL);
585 __ PrepareCallCFunction(1, ebx);
586 __ mov(Operand(esp, 0), eax);
587 __ CallCFunction(
588 ExternalReference::get_make_code_young_function(masm->isolate()), 1);
589 }
590 __ popad();
591 __ ret(0);
592}
593
594#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
595void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
596 MacroAssembler* masm) { \
597 GenerateMakeCodeYoungAgainCommon(masm); \
598} \
599void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
600 MacroAssembler* masm) { \
601 GenerateMakeCodeYoungAgainCommon(masm); \
602}
603CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
604#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
605
606
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000607void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000608 // Enter an internal frame.
609 {
610 FrameScope scope(masm, StackFrame::INTERNAL);
611
612 // Preserve registers across notification, this is important for compiled
613 // stubs that tail call the runtime on deopts passing their parameters in
614 // registers.
615 __ pushad();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000616 __ CallRuntime(Runtime::kNotifyStubFailure, 0);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000617 __ popad();
618 // Tear down internal frame.
619 }
620
621 __ pop(MemOperand(esp, 0)); // Ignore state offset
622 __ ret(0); // Return to IC Miss stub, continuation still on stack.
623}
624
625
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000626static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
627 Deoptimizer::BailoutType type) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000628 {
629 FrameScope scope(masm, StackFrame::INTERNAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000630
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000631 // Pass deoptimization type to the runtime system.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000632 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
633 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000634
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000635 // Tear down internal frame.
636 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000637
638 // Get the full codegen state from the stack and untag it.
639 __ mov(ecx, Operand(esp, 1 * kPointerSize));
640 __ SmiUntag(ecx);
641
642 // Switch on the state.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000643 Label not_no_registers, not_tos_eax;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000644 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000645 __ j(not_equal, &not_no_registers, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000646 __ ret(1 * kPointerSize); // Remove state.
647
648 __ bind(&not_no_registers);
649 __ mov(eax, Operand(esp, 2 * kPointerSize));
650 __ cmp(ecx, FullCodeGenerator::TOS_REG);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000651 __ j(not_equal, &not_tos_eax, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000652 __ ret(2 * kPointerSize); // Remove state, eax.
653
654 __ bind(&not_tos_eax);
655 __ Abort("no cases left");
656}
657
658
659void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
660 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
661}
662
663
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000664void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
665 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
666}
667
668
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000669void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
670 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
671}
672
673
674void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
675 // TODO(kasperl): Do we need to save/restore the XMM registers too?
ulan@chromium.org750145a2013-03-07 15:14:13 +0000676 // TODO(mvstanton): We should save these regs, do this in a future
677 // checkin.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000678
679 // For now, we are relying on the fact that Runtime::NotifyOSR
680 // doesn't do any garbage collection which allows us to save/restore
681 // the registers without worrying about which of them contain
682 // pointers. This seems a bit fragile.
683 __ pushad();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000684 {
685 FrameScope scope(masm, StackFrame::INTERNAL);
686 __ CallRuntime(Runtime::kNotifyOSR, 0);
687 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000688 __ popad();
689 __ ret(0);
690}
691
692
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000693void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000694 Factory* factory = masm->isolate()->factory();
695
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000696 // 1. Make sure we have at least one argument.
697 { Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000698 __ test(eax, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000699 __ j(not_zero, &done);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000700 __ pop(ebx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000701 __ push(Immediate(factory->undefined_value()));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000702 __ push(ebx);
703 __ inc(eax);
704 __ bind(&done);
705 }
706
ager@chromium.org5c838252010-02-19 08:53:10 +0000707 // 2. Get the function to call (passed as receiver) from the stack, check
708 // if it is a function.
lrn@chromium.org34e60782011-09-15 07:25:40 +0000709 Label slow, non_function;
ager@chromium.org5c838252010-02-19 08:53:10 +0000710 // 1 ~ return address.
711 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000712 __ JumpIfSmi(edi, &non_function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000713 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000714 __ j(not_equal, &slow);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000715
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000716
ager@chromium.org5c838252010-02-19 08:53:10 +0000717 // 3a. Patch the first argument if necessary when calling a function.
718 Label shift_arguments;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000719 __ Set(edx, Immediate(0)); // indicate regular JS_FUNCTION
ager@chromium.org5c838252010-02-19 08:53:10 +0000720 { Label convert_to_object, use_global_receiver, patch_receiver;
721 // Change context eagerly in case we need the global receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000722 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
723
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000724 // Do not transform the receiver for strict mode functions.
725 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
726 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
727 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
728 __ j(not_equal, &shift_arguments);
729
lrn@chromium.org1c092762011-05-09 09:42:16 +0000730 // Do not transform the receiver for natives (shared already in ebx).
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000731 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
732 1 << SharedFunctionInfo::kNativeBitWithinByte);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +0000733 __ j(not_equal, &shift_arguments);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000734
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000735 // Compute the receiver in non-strict mode.
ager@chromium.org5c838252010-02-19 08:53:10 +0000736 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000737
738 // Call ToObject on the receiver if it is not an object, or use the
739 // global object if it is null or undefined.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000740 __ JumpIfSmi(ebx, &convert_to_object);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000741 __ cmp(ebx, factory->null_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000742 __ j(equal, &use_global_receiver);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000743 __ cmp(ebx, factory->undefined_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000744 __ j(equal, &use_global_receiver);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000745 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
746 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000747 __ j(above_equal, &shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000748
ager@chromium.org5c838252010-02-19 08:53:10 +0000749 __ bind(&convert_to_object);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000750
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000751 { // In order to preserve argument count.
752 FrameScope scope(masm, StackFrame::INTERNAL);
753 __ SmiTag(eax);
754 __ push(eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000755
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000756 __ push(ebx);
757 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
758 __ mov(ebx, eax);
759 __ Set(edx, Immediate(0)); // restore
760
761 __ pop(eax);
762 __ SmiUntag(eax);
763 }
764
ager@chromium.org5c838252010-02-19 08:53:10 +0000765 // Restore the function to edi.
766 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000767 __ jmp(&patch_receiver);
768
ager@chromium.org5c838252010-02-19 08:53:10 +0000769 // Use the global receiver object from the called function as the
770 // receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000771 __ bind(&use_global_receiver);
772 const int kGlobalIndex =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000773 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000774 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000775 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
ager@chromium.org3811b432009-10-28 14:53:37 +0000776 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000777 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000778
779 __ bind(&patch_receiver);
780 __ mov(Operand(esp, eax, times_4, 0), ebx);
781
ager@chromium.org5c838252010-02-19 08:53:10 +0000782 __ jmp(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000783 }
784
lrn@chromium.org34e60782011-09-15 07:25:40 +0000785 // 3b. Check for function proxy.
786 __ bind(&slow);
787 __ Set(edx, Immediate(1)); // indicate function proxy
788 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
789 __ j(equal, &shift_arguments);
790 __ bind(&non_function);
791 __ Set(edx, Immediate(2)); // indicate non-function
792
793 // 3c. Patch the first argument when calling a non-function. The
ager@chromium.org5c838252010-02-19 08:53:10 +0000794 // CALL_NON_FUNCTION builtin expects the non-function callee as
795 // receiver, so overwrite the first argument which will ultimately
796 // become the receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +0000797 __ mov(Operand(esp, eax, times_4, 0), edi);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000798
ager@chromium.org5c838252010-02-19 08:53:10 +0000799 // 4. Shift arguments and return address one slot down on the stack
800 // (overwriting the original receiver). Adjust argument count to make
801 // the original first argument the new receiver.
802 __ bind(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000803 { Label loop;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000804 __ mov(ecx, eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000805 __ bind(&loop);
806 __ mov(ebx, Operand(esp, ecx, times_4, 0));
807 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
808 __ dec(ecx);
ager@chromium.org5c838252010-02-19 08:53:10 +0000809 __ j(not_sign, &loop); // While non-negative (to copy return address).
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000810 __ pop(ebx); // Discard copy of return address.
811 __ dec(eax); // One fewer argument (first argument is new receiver).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000812 }
813
lrn@chromium.org34e60782011-09-15 07:25:40 +0000814 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
815 // or a function proxy via CALL_FUNCTION_PROXY.
816 { Label function, non_proxy;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000817 __ test(edx, edx);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000818 __ j(zero, &function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000819 __ Set(ebx, Immediate(0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000820 __ cmp(edx, Immediate(1));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000821 __ j(not_equal, &non_proxy);
822
823 __ pop(edx); // return address
824 __ push(edi); // re-add proxy object as additional argument
825 __ push(edx);
826 __ inc(eax);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000827 __ SetCallKind(ecx, CALL_AS_FUNCTION);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000828 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
829 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
830 RelocInfo::CODE_TARGET);
831
832 __ bind(&non_proxy);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000833 __ SetCallKind(ecx, CALL_AS_METHOD);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000834 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000835 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
836 RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000837 __ bind(&function);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000838 }
839
ager@chromium.org5c838252010-02-19 08:53:10 +0000840 // 5b. Get the code to call from the function and check that the number of
841 // expected arguments matches what we're providing. If so, jump
842 // (tail-call) to the code in register edx without checking arguments.
843 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
844 __ mov(ebx,
845 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000846 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000847 __ SmiUntag(ebx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000848 __ SetCallKind(ecx, CALL_AS_METHOD);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000849 __ cmp(eax, ebx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000850 __ j(not_equal,
851 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
ager@chromium.org5c838252010-02-19 08:53:10 +0000852
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000853 ParameterCount expected(0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000854 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper(),
855 CALL_AS_METHOD);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000856}
857
858
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
lrn@chromium.org34e60782011-09-15 07:25:40 +0000860 static const int kArgumentsOffset = 2 * kPointerSize;
861 static const int kReceiverOffset = 3 * kPointerSize;
862 static const int kFunctionOffset = 4 * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000863 {
864 FrameScope frame_scope(masm, StackFrame::INTERNAL);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000865
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000866 __ push(Operand(ebp, kFunctionOffset)); // push this
867 __ push(Operand(ebp, kArgumentsOffset)); // push arguments
868 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000870 // Check the stack for overflow. We are not trying to catch
871 // interruptions (e.g. debug break and preemption) here, so the "real stack
872 // limit" is checked.
873 Label okay;
874 ExternalReference real_stack_limit =
875 ExternalReference::address_of_real_stack_limit(masm->isolate());
876 __ mov(edi, Operand::StaticVariable(real_stack_limit));
877 // Make ecx the space we have left. The stack might already be overflowed
878 // here which will cause ecx to become negative.
879 __ mov(ecx, esp);
880 __ sub(ecx, edi);
881 // Make edx the space we need for the array when it is unrolled onto the
882 // stack.
883 __ mov(edx, eax);
884 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
885 // Check if the arguments will overflow the stack.
886 __ cmp(ecx, edx);
887 __ j(greater, &okay); // Signed comparison.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000889 // Out of stack space.
890 __ push(Operand(ebp, 4 * kPointerSize)); // push this
891 __ push(eax);
892 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
893 __ bind(&okay);
894 // End of stack check.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000895
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000896 // Push current index and limit.
897 const int kLimitOffset =
898 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
899 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
900 __ push(eax); // limit
901 __ push(Immediate(0)); // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000903 // Get the receiver.
904 __ mov(ebx, Operand(ebp, kReceiverOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000906 // Check that the function is a JS function (otherwise it must be a proxy).
907 Label push_receiver;
908 __ mov(edi, Operand(ebp, kFunctionOffset));
909 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
910 __ j(not_equal, &push_receiver);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000911
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000912 // Change context eagerly to get the right global object if necessary.
913 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000914
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 // Compute the receiver.
916 // Do not transform the receiver for strict mode functions.
917 Label call_to_object, use_global_receiver;
918 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
919 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
920 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
921 __ j(not_equal, &push_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000922
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000923 Factory* factory = masm->isolate()->factory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000924
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000925 // Do not transform the receiver for natives (shared already in ecx).
926 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
927 1 << SharedFunctionInfo::kNativeBitWithinByte);
928 __ j(not_equal, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000929
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000930 // Compute the receiver in non-strict mode.
931 // Call ToObject on the receiver if it is not an object, or use the
932 // global object if it is null or undefined.
933 __ JumpIfSmi(ebx, &call_to_object);
934 __ cmp(ebx, factory->null_value());
935 __ j(equal, &use_global_receiver);
936 __ cmp(ebx, factory->undefined_value());
937 __ j(equal, &use_global_receiver);
938 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
939 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
940 __ j(above_equal, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000941
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000942 __ bind(&call_to_object);
943 __ push(ebx);
944 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
945 __ mov(ebx, eax);
946 __ jmp(&push_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000948 // Use the current global receiver object as the receiver.
949 __ bind(&use_global_receiver);
950 const int kGlobalOffset =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000951 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000952 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000953 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000954 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
955 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000957 // Push the receiver.
958 __ bind(&push_receiver);
959 __ push(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000961 // Copy all arguments from the array to the stack.
962 Label entry, loop;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000963 __ mov(ecx, Operand(ebp, kIndexOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000964 __ jmp(&entry);
965 __ bind(&loop);
966 __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000967
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000968 // Use inline caching to speed up access to arguments.
969 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
970 __ call(ic, RelocInfo::CODE_TARGET);
971 // It is important that we do not have a test instruction after the
972 // call. A test instruction after the call is used to indicate that
973 // we have generated an inline version of the keyed load. In this
974 // case, we know that we are not generating a test instruction next.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000975
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000976 // Push the nth argument.
977 __ push(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000978
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000979 // Update the index on the stack and in register eax.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000980 __ mov(ecx, Operand(ebp, kIndexOffset));
981 __ add(ecx, Immediate(1 << kSmiTagSize));
982 __ mov(Operand(ebp, kIndexOffset), ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000984 __ bind(&entry);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000985 __ cmp(ecx, Operand(ebp, kLimitOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000986 __ j(not_equal, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000988 // Invoke the function.
989 Label call_proxy;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000990 __ mov(eax, ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000991 ParameterCount actual(eax);
992 __ SmiUntag(eax);
993 __ mov(edi, Operand(ebp, kFunctionOffset));
994 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
995 __ j(not_equal, &call_proxy);
996 __ InvokeFunction(edi, actual, CALL_FUNCTION,
997 NullCallWrapper(), CALL_AS_METHOD);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000999 frame_scope.GenerateLeaveFrame();
1000 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001002 // Invoke the function proxy.
1003 __ bind(&call_proxy);
1004 __ push(edi); // add function proxy as last argument
1005 __ inc(eax);
1006 __ Set(ebx, Immediate(0));
1007 __ SetCallKind(ecx, CALL_AS_METHOD);
1008 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
1009 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1010 RelocInfo::CODE_TARGET);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001011
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001012 // Leave internal frame.
1013 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001014 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015}
1016
1017
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001018// Allocate an empty JSArray. The allocated array is put into the result
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001019// register. If the parameter initial_capacity is larger than zero an elements
1020// backing store is allocated with this size and filled with the hole values.
1021// Otherwise the elements backing store is set to the empty FixedArray.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001022static void AllocateEmptyJSArray(MacroAssembler* masm,
1023 Register array_function,
1024 Register result,
1025 Register scratch1,
1026 Register scratch2,
1027 Register scratch3,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001028 Label* gc_required) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001029 const int initial_capacity = JSArray::kPreallocatedArrayElements;
1030 STATIC_ASSERT(initial_capacity >= 0);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001031
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001032 __ LoadInitialArrayMap(array_function, scratch2, scratch1, false);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001033
1034 // Allocate the JSArray object together with space for a fixed array with the
1035 // requested elements.
1036 int size = JSArray::kSize;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001037 if (initial_capacity > 0) {
1038 size += FixedArray::SizeFor(initial_capacity);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001039 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001040 __ Allocate(size, result, scratch2, scratch3, gc_required, TAG_OBJECT);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001041
1042 // Allocated the JSArray. Now initialize the fields except for the elements
1043 // array.
1044 // result: JSObject
1045 // scratch1: initial map
1046 // scratch2: start of next object
1047 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001048 Factory* factory = masm->isolate()->factory();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001049 __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001050 factory->empty_fixed_array());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001051 // Field JSArray::kElementsOffset is initialized later.
1052 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
1053
1054 // If no storage is requested for the elements array just set the empty
1055 // fixed array.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001056 if (initial_capacity == 0) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001057 __ mov(FieldOperand(result, JSArray::kElementsOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001058 factory->empty_fixed_array());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001059 return;
1060 }
1061
1062 // Calculate the location of the elements array and set elements array member
1063 // of the JSArray.
1064 // result: JSObject
1065 // scratch2: start of next object
1066 __ lea(scratch1, Operand(result, JSArray::kSize));
1067 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
1068
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001069 // Initialize the FixedArray and fill it with holes. FixedArray length is
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001070 // stored as a smi.
1071 // result: JSObject
1072 // scratch1: elements array
1073 // scratch2: start of next object
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001074 __ mov(FieldOperand(scratch1, FixedArray::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001075 factory->fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001076 __ mov(FieldOperand(scratch1, FixedArray::kLengthOffset),
1077 Immediate(Smi::FromInt(initial_capacity)));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001078
1079 // Fill the FixedArray with the hole value. Inline the code if short.
1080 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
1081 static const int kLoopUnfoldLimit = 4;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001082 if (initial_capacity <= kLoopUnfoldLimit) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001083 // Use a scratch register here to have only one reloc info when unfolding
1084 // the loop.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001085 __ mov(scratch3, factory->the_hole_value());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001086 for (int i = 0; i < initial_capacity; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001087 __ mov(FieldOperand(scratch1,
1088 FixedArray::kHeaderSize + i * kPointerSize),
1089 scratch3);
1090 }
1091 } else {
1092 Label loop, entry;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001093 __ mov(scratch2, Immediate(initial_capacity));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001094 __ jmp(&entry);
1095 __ bind(&loop);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001096 __ mov(FieldOperand(scratch1,
1097 scratch2,
1098 times_pointer_size,
1099 FixedArray::kHeaderSize),
1100 factory->the_hole_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001101 __ bind(&entry);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001102 __ dec(scratch2);
1103 __ j(not_sign, &loop);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001104 }
1105}
1106
1107
1108// Allocate a JSArray with the number of elements stored in a register. The
1109// register array_function holds the built-in Array function and the register
1110// array_size holds the size of the array as a smi. The allocated array is put
1111// into the result register and beginning and end of the FixedArray elements
1112// storage is put into registers elements_array and elements_array_end (see
1113// below for when that is not the case). If the parameter fill_with_holes is
1114// true the allocated elements backing store is filled with the hole values
1115// otherwise it is left uninitialized. When the backing store is filled the
1116// register elements_array is scratched.
1117static void AllocateJSArray(MacroAssembler* masm,
1118 Register array_function, // Array function.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001119 Register array_size, // As a smi, cannot be 0.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001120 Register result,
1121 Register elements_array,
1122 Register elements_array_end,
1123 Register scratch,
1124 bool fill_with_hole,
1125 Label* gc_required) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001126 ASSERT(scratch.is(edi)); // rep stos destination
1127 ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001128 ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001129
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001130 __ LoadInitialArrayMap(array_function, scratch,
1131 elements_array, fill_with_hole);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001132
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001133 // Allocate the JSArray object together with space for a FixedArray with the
1134 // requested elements.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001135 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001136 __ Allocate(JSArray::kSize + FixedArray::kHeaderSize,
1137 times_pointer_size,
1138 array_size,
1139 REGISTER_VALUE_IS_SMI,
1140 result,
1141 elements_array_end,
1142 scratch,
1143 gc_required,
1144 TAG_OBJECT);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001145
1146 // Allocated the JSArray. Now initialize the fields except for the elements
1147 // array.
1148 // result: JSObject
1149 // elements_array: initial map
1150 // elements_array_end: start of next object
1151 // array_size: size of array (smi)
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001152 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001153 Factory* factory = masm->isolate()->factory();
1154 __ mov(elements_array, factory->empty_fixed_array());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001155 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
1156 // Field JSArray::kElementsOffset is initialized later.
1157 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
1158
1159 // Calculate the location of the elements array and set elements array member
1160 // of the JSArray.
1161 // result: JSObject
1162 // elements_array_end: start of next object
1163 // array_size: size of array (smi)
1164 __ lea(elements_array, Operand(result, JSArray::kSize));
1165 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
1166
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001167 // Initialize the fixed array. FixedArray length is stored as a smi.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001168 // result: JSObject
1169 // elements_array: elements array
1170 // elements_array_end: start of next object
1171 // array_size: size of array (smi)
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001172 __ mov(FieldOperand(elements_array, FixedArray::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001173 factory->fixed_array_map());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001174 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
1175 // same.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001176 __ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001177
1178 // Fill the allocated FixedArray with the hole value if requested.
1179 // result: JSObject
1180 // elements_array: elements array
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001181 if (fill_with_hole) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001182 __ SmiUntag(array_size);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001183 __ lea(edi, Operand(elements_array,
1184 FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001185 __ mov(eax, factory->the_hole_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001186 __ cld();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001187 // Do not use rep stos when filling less than kRepStosThreshold
1188 // words.
1189 const int kRepStosThreshold = 16;
1190 Label loop, entry, done;
1191 __ cmp(ecx, kRepStosThreshold);
1192 __ j(below, &loop); // Note: ecx > 0.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001193 __ rep_stos();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001194 __ jmp(&done);
1195 __ bind(&loop);
1196 __ stos();
1197 __ bind(&entry);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001198 __ cmp(edi, elements_array_end);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001199 __ j(below, &loop);
1200 __ bind(&done);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001201 }
1202}
1203
1204
1205// Create a new array for the built-in Array function. This function allocates
1206// the JSArray object and the FixedArray elements array and initializes these.
1207// If the Array cannot be constructed in native code the runtime is called. This
1208// function assumes the following state:
1209// edi: constructor (built-in Array function)
1210// eax: argc
1211// esp[0]: return address
1212// esp[4]: last argument
1213// This function is used for both construct and normal calls of Array. Whether
1214// it is a construct call or not is indicated by the construct_call parameter.
1215// The only difference between handling a construct call and a normal call is
1216// that for a construct call the constructor function in edi needs to be
1217// preserved for entering the generic code. In both cases argc in eax needs to
1218// be preserved.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001219void ArrayNativeCode(MacroAssembler* masm,
1220 bool construct_call,
1221 Label* call_generic_code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001222 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001223 empty_array, not_empty_array, finish, cant_transition_map, not_double;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001224
1225 // Push the constructor and argc. No need to tag argc as a smi, as there will
1226 // be no garbage collection with this on the stack.
1227 int push_count = 0;
1228 if (construct_call) {
1229 push_count++;
1230 __ push(edi);
1231 }
1232 push_count++;
1233 __ push(eax);
1234
1235 // Check for array construction with zero arguments.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001236 __ test(eax, eax);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001237 __ j(not_zero, &argc_one_or_more);
1238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001239 __ bind(&empty_array);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001240 // Handle construction of an empty array.
1241 AllocateEmptyJSArray(masm,
1242 edi,
1243 eax,
1244 ebx,
1245 ecx,
1246 edi,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001247 &prepare_generic_code_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001248 __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001249 __ pop(ebx);
1250 if (construct_call) {
1251 __ pop(edi);
1252 }
1253 __ ret(kPointerSize);
1254
1255 // Check for one argument. Bail out if argument is not smi or if it is
1256 // negative.
1257 __ bind(&argc_one_or_more);
1258 __ cmp(eax, 1);
1259 __ j(not_equal, &argc_two_or_more);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001260 STATIC_ASSERT(kSmiTag == 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001261 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001262 __ test(ecx, ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001263 __ j(not_zero, &not_empty_array);
1264
1265 // The single argument passed is zero, so we jump to the code above used to
1266 // handle the case of no arguments passed. To adapt the stack for that we move
1267 // the return address and the pushed constructor (if pushed) one stack slot up
1268 // thereby removing the passed argument. Argc is also on the stack - at the
1269 // bottom - and it needs to be changed from 1 to 0 to have the call into the
1270 // runtime system work in case a GC is required.
1271 for (int i = push_count; i > 0; i--) {
1272 __ mov(eax, Operand(esp, i * kPointerSize));
1273 __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
1274 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001275 __ Drop(2); // Drop two stack slots.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001276 __ push(Immediate(0)); // Treat this as a call with argc of zero.
1277 __ jmp(&empty_array);
1278
1279 __ bind(&not_empty_array);
1280 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001281 __ j(not_zero, &prepare_generic_code_call);
1282
1283 // Handle construction of an empty array of a certain size. Get the size from
1284 // the stack and bail out if size is to large to actually allocate an elements
1285 // array.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001286 __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001287 __ j(greater_equal, &prepare_generic_code_call);
1288
1289 // edx: array_size (smi)
1290 // edi: constructor
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001291 // esp[0]: argc (cannot be 0 here)
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001292 // esp[4]: constructor (only if construct_call)
1293 // esp[8]: return address
1294 // esp[C]: argument
1295 AllocateJSArray(masm,
1296 edi,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001297 ecx,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001298 ebx,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001299 eax,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001300 edx,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001301 edi,
1302 true,
1303 &prepare_generic_code_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001304 Counters* counters = masm->isolate()->counters();
1305 __ IncrementCounter(counters->array_function_native(), 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001306 __ mov(eax, ebx);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001307 __ pop(ebx);
1308 if (construct_call) {
1309 __ pop(edi);
1310 }
1311 __ ret(2 * kPointerSize);
1312
1313 // Handle construction of an array from a list of arguments.
1314 __ bind(&argc_two_or_more);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001315 STATIC_ASSERT(kSmiTag == 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001316 __ SmiTag(eax); // Convet argc to a smi.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001317 // eax: array_size (smi)
1318 // edi: constructor
1319 // esp[0] : argc
1320 // esp[4]: constructor (only if construct_call)
1321 // esp[8] : return address
1322 // esp[C] : last argument
1323 AllocateJSArray(masm,
1324 edi,
1325 eax,
1326 ebx,
1327 ecx,
1328 edx,
1329 edi,
1330 false,
1331 &prepare_generic_code_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001332 __ IncrementCounter(counters->array_function_native(), 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001333 __ push(ebx);
1334 __ mov(ebx, Operand(esp, kPointerSize));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001335 // ebx: argc
1336 // edx: elements_array_end (untagged)
1337 // esp[0]: JSArray
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001338 // esp[4]: argc
1339 // esp[8]: constructor (only if construct_call)
1340 // esp[12]: return address
1341 // esp[16]: last argument
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001342
1343 // Location of the last argument
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001344 int last_arg_offset = (construct_call ? 4 : 3) * kPointerSize;
1345 __ lea(edi, Operand(esp, last_arg_offset));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001346
1347 // Location of the first array element (Parameter fill_with_holes to
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001348 // AllocateJSArray is false, so the FixedArray is returned in ecx).
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001349 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
1350
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001351 Label has_non_smi_element;
1352
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001353 // ebx: argc
1354 // edx: location of the first array element
1355 // edi: location of the last argument
1356 // esp[0]: JSArray
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001357 // esp[4]: argc
1358 // esp[8]: constructor (only if construct_call)
1359 // esp[12]: return address
1360 // esp[16]: last argument
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001361 Label loop, entry;
1362 __ mov(ecx, ebx);
1363 __ jmp(&entry);
1364 __ bind(&loop);
1365 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001366 if (FLAG_smi_only_arrays) {
1367 __ JumpIfNotSmi(eax, &has_non_smi_element);
1368 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001369 __ mov(Operand(edx, 0), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001370 __ add(edx, Immediate(kPointerSize));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001371 __ bind(&entry);
1372 __ dec(ecx);
1373 __ j(greater_equal, &loop);
1374
1375 // Remove caller arguments from the stack and return.
1376 // ebx: argc
1377 // esp[0]: JSArray
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001378 // esp[4]: argc
1379 // esp[8]: constructor (only if construct_call)
1380 // esp[12]: return address
1381 // esp[16]: last argument
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001382 __ bind(&finish);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001383 __ mov(ecx, Operand(esp, last_arg_offset - kPointerSize));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001384 __ pop(eax);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001385 __ pop(ebx);
1386 __ lea(esp, Operand(esp, ebx, times_pointer_size,
1387 last_arg_offset - kPointerSize));
1388 __ jmp(ecx);
1389
1390 __ bind(&has_non_smi_element);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001391 // Double values are handled by the runtime.
1392 __ CheckMap(eax,
1393 masm->isolate()->factory()->heap_number_map(),
1394 &not_double,
1395 DONT_DO_SMI_CHECK);
1396 __ bind(&cant_transition_map);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001397 // Throw away the array that's only been partially constructed.
1398 __ pop(eax);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001399 __ UndoAllocationInNewSpace(eax);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001400 __ jmp(&prepare_generic_code_call);
1401
1402 __ bind(&not_double);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001403 // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001404 __ mov(ebx, Operand(esp, 0));
1405 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
1406 __ LoadTransitionedArrayMapConditional(
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001407 FAST_SMI_ELEMENTS,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001408 FAST_ELEMENTS,
1409 edi,
1410 eax,
1411 &cant_transition_map);
1412 __ mov(FieldOperand(ebx, HeapObject::kMapOffset), edi);
1413 __ RecordWriteField(ebx, HeapObject::kMapOffset, edi, eax,
1414 kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
1415
1416 // Prepare to re-enter the loop
1417 __ lea(edi, Operand(esp, last_arg_offset));
1418
1419 // Finish the array initialization loop.
1420 Label loop2;
1421 __ bind(&loop2);
1422 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1423 __ mov(Operand(edx, 0), eax);
1424 __ add(edx, Immediate(kPointerSize));
1425 __ dec(ecx);
1426 __ j(greater_equal, &loop2);
1427 __ jmp(&finish);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001428
1429 // Restore argc and constructor before running the generic code.
1430 __ bind(&prepare_generic_code_call);
1431 __ pop(eax);
1432 if (construct_call) {
1433 __ pop(edi);
1434 }
1435 __ jmp(call_generic_code);
1436}
1437
1438
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001439void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1440 // ----------- S t a t e -------------
1441 // -- eax : argc
1442 // -- esp[0] : return address
1443 // -- esp[4] : last argument
1444 // -----------------------------------
1445 Label generic_array_code;
1446
1447 // Get the InternalArray function.
1448 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1449
1450 if (FLAG_debug_code) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001451 // Initial map for the builtin InternalArray function should be a map.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001452 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1453 // Will both indicate a NULL and a Smi.
1454 __ test(ebx, Immediate(kSmiTagMask));
1455 __ Assert(not_zero, "Unexpected initial map for InternalArray function");
1456 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1457 __ Assert(equal, "Unexpected initial map for InternalArray function");
1458 }
1459
1460 // Run the native code for the InternalArray function called as a normal
1461 // function.
1462 ArrayNativeCode(masm, false, &generic_array_code);
1463
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001464 // Jump to the generic internal array code in case the specialized code cannot
1465 // handle the construction.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001466 __ bind(&generic_array_code);
1467 Handle<Code> array_code =
1468 masm->isolate()->builtins()->InternalArrayCodeGeneric();
1469 __ jmp(array_code, RelocInfo::CODE_TARGET);
1470}
1471
1472
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001473void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1474 // ----------- S t a t e -------------
1475 // -- eax : argc
1476 // -- esp[0] : return address
1477 // -- esp[4] : last argument
1478 // -----------------------------------
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001479 Label generic_array_code;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001480
1481 // Get the Array function.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001482 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001483
1484 if (FLAG_debug_code) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001485 // Initial map for the builtin Array function should be a map.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001486 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1487 // Will both indicate a NULL and a Smi.
1488 __ test(ebx, Immediate(kSmiTagMask));
1489 __ Assert(not_zero, "Unexpected initial map for Array function");
1490 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1491 __ Assert(equal, "Unexpected initial map for Array function");
1492 }
1493
1494 // Run the native code for the Array function called as a normal function.
1495 ArrayNativeCode(masm, false, &generic_array_code);
1496
1497 // Jump to the generic array code in case the specialized code cannot handle
1498 // the construction.
1499 __ bind(&generic_array_code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001500 Handle<Code> array_code =
1501 masm->isolate()->builtins()->ArrayCodeGeneric();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001502 __ jmp(array_code, RelocInfo::CODE_TARGET);
1503}
1504
1505
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001506void Builtins::Generate_CommonArrayConstructCode(MacroAssembler* masm) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001507 // ----------- S t a t e -------------
1508 // -- eax : argc
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001509 // -- ebx : type info cell
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001510 // -- edi : constructor
1511 // -- esp[0] : return address
1512 // -- esp[4] : last argument
1513 // -----------------------------------
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001514 if (FLAG_debug_code) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001515 // The array construct code is only set for the global and natives
1516 // builtin Array functions which always have maps.
1517
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001518 // Initial map for the builtin Array function should be a map.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001519 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001520 // Will both indicate a NULL and a Smi.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001521 __ test(ecx, Immediate(kSmiTagMask));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001522 __ Assert(not_zero, "Unexpected initial map for Array function");
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001523 __ CmpObjectType(ecx, MAP_TYPE, ecx);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001524 __ Assert(equal, "Unexpected initial map for Array function");
1525 }
1526
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001527 Label generic_constructor;
1528 // Run the native code for the Array function called as constructor.
1529 ArrayNativeCode(masm, true, &generic_constructor);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001530
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001531 // Jump to the generic construct code in case the specialized code cannot
1532 // handle the construction.
1533 __ bind(&generic_constructor);
1534 Handle<Code> generic_construct_stub =
1535 masm->isolate()->builtins()->JSConstructStubGeneric();
1536 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001537}
1538
1539
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001540void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1541 // ----------- S t a t e -------------
1542 // -- eax : number of arguments
1543 // -- edi : constructor function
1544 // -- esp[0] : return address
1545 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1546 // -- esp[(argc + 1) * 4] : receiver
1547 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001548 Counters* counters = masm->isolate()->counters();
1549 __ IncrementCounter(counters->string_ctor_calls(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001550
1551 if (FLAG_debug_code) {
1552 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001553 __ cmp(edi, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001554 __ Assert(equal, "Unexpected String function");
1555 }
1556
1557 // Load the first argument into eax and get rid of the rest
1558 // (including the receiver).
1559 Label no_arguments;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001560 __ test(eax, eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001561 __ j(zero, &no_arguments);
1562 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1563 __ pop(ecx);
1564 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1565 __ push(ecx);
1566 __ mov(eax, ebx);
1567
1568 // Lookup the argument in the number to string cache.
1569 Label not_cached, argument_is_string;
1570 NumberToStringStub::GenerateLookupNumberStringCache(
1571 masm,
1572 eax, // Input.
1573 ebx, // Result.
1574 ecx, // Scratch 1.
1575 edx, // Scratch 2.
1576 false, // Input is known to be smi?
1577 &not_cached);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001578 __ IncrementCounter(counters->string_ctor_cached_number(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001579 __ bind(&argument_is_string);
1580 // ----------- S t a t e -------------
1581 // -- ebx : argument converted to string
1582 // -- edi : constructor function
1583 // -- esp[0] : return address
1584 // -----------------------------------
1585
1586 // Allocate a JSValue and put the tagged pointer into eax.
1587 Label gc_required;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001588 __ Allocate(JSValue::kSize,
1589 eax, // Result.
1590 ecx, // New allocation top (we ignore it).
1591 no_reg,
1592 &gc_required,
1593 TAG_OBJECT);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001594
1595 // Set the map.
1596 __ LoadGlobalFunctionInitialMap(edi, ecx);
1597 if (FLAG_debug_code) {
1598 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1599 JSValue::kSize >> kPointerSizeLog2);
1600 __ Assert(equal, "Unexpected string wrapper instance size");
1601 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1602 __ Assert(equal, "Unexpected unused properties of string wrapper");
1603 }
1604 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1605
1606 // Set properties and elements.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001607 Factory* factory = masm->isolate()->factory();
1608 __ Set(ecx, Immediate(factory->empty_fixed_array()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001609 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1610 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1611
1612 // Set the value.
1613 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1614
1615 // Ensure the object is fully initialized.
1616 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1617
1618 // We're done. Return.
1619 __ ret(0);
1620
1621 // The argument was not found in the number to string cache. Check
1622 // if it's a string already before calling the conversion builtin.
1623 Label convert_argument;
1624 __ bind(&not_cached);
1625 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001626 __ JumpIfSmi(eax, &convert_argument);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001627 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1628 __ j(NegateCondition(is_string), &convert_argument);
1629 __ mov(ebx, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001630 __ IncrementCounter(counters->string_ctor_string_value(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001631 __ jmp(&argument_is_string);
1632
1633 // Invoke the conversion builtin and put the result into ebx.
1634 __ bind(&convert_argument);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001635 __ IncrementCounter(counters->string_ctor_conversions(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001636 {
1637 FrameScope scope(masm, StackFrame::INTERNAL);
1638 __ push(edi); // Preserve the function.
1639 __ push(eax);
1640 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1641 __ pop(edi);
1642 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001643 __ mov(ebx, eax);
1644 __ jmp(&argument_is_string);
1645
1646 // Load the empty string into ebx, remove the receiver from the
1647 // stack, and jump back to the case where the argument is a string.
1648 __ bind(&no_arguments);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001649 __ Set(ebx, Immediate(factory->empty_string()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001650 __ pop(ecx);
1651 __ lea(esp, Operand(esp, kPointerSize));
1652 __ push(ecx);
1653 __ jmp(&argument_is_string);
1654
1655 // At this point the argument is already a string. Call runtime to
1656 // create a string wrapper.
1657 __ bind(&gc_required);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001658 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001659 {
1660 FrameScope scope(masm, StackFrame::INTERNAL);
1661 __ push(ebx);
1662 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1663 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001664 __ ret(0);
1665}
1666
1667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001668static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1669 __ push(ebp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001670 __ mov(ebp, esp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671
1672 // Store the arguments adaptor context sentinel.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001673 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001674
1675 // Push the function on the stack.
1676 __ push(edi);
1677
danno@chromium.org40cb8782011-05-25 07:58:50 +00001678 // Preserve the number of arguments on the stack. Must preserve eax,
1679 // ebx and ecx because these registers are used when copying the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 // arguments and the receiver.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001681 STATIC_ASSERT(kSmiTagSize == 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001682 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1683 __ push(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001684}
1685
1686
ager@chromium.org7c537e22008-10-16 08:43:32 +00001687static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001688 // Retrieve the number of arguments from the stack.
1689 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1690
1691 // Leave the frame.
1692 __ leave();
1693
1694 // Remove caller arguments from the stack.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001695 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696 __ pop(ecx);
1697 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1698 __ push(ecx);
1699}
1700
1701
1702void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1703 // ----------- S t a t e -------------
1704 // -- eax : actual number of arguments
1705 // -- ebx : expected number of arguments
danno@chromium.org40cb8782011-05-25 07:58:50 +00001706 // -- ecx : call kind information
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001707 // -- edx : code entry to call
1708 // -----------------------------------
1709
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001710 Label invoke, dont_adapt_arguments;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001711 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001712
1713 Label enough, too_few;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001714 __ cmp(eax, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001715 __ j(less, &too_few);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001716 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1717 __ j(equal, &dont_adapt_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718
1719 { // Enough parameters: Actual >= expected.
1720 __ bind(&enough);
1721 EnterArgumentsAdaptorFrame(masm);
1722
1723 // Copy receiver and all expected arguments.
1724 const int offset = StandardFrameConstants::kCallerSPOffset;
1725 __ lea(eax, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001726 __ mov(edi, -1); // account for receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727
1728 Label copy;
1729 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001730 __ inc(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001731 __ push(Operand(eax, 0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001732 __ sub(eax, Immediate(kPointerSize));
1733 __ cmp(edi, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001734 __ j(less, &copy);
1735 __ jmp(&invoke);
1736 }
1737
1738 { // Too few parameters: Actual < expected.
1739 __ bind(&too_few);
1740 EnterArgumentsAdaptorFrame(masm);
1741
1742 // Copy receiver and all actual arguments.
1743 const int offset = StandardFrameConstants::kCallerSPOffset;
1744 __ lea(edi, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001745 // ebx = expected - actual.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001746 __ sub(ebx, eax);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001747 // eax = -actual - 1
1748 __ neg(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001749 __ sub(eax, Immediate(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001750
1751 Label copy;
1752 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001753 __ inc(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754 __ push(Operand(edi, 0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001755 __ sub(edi, Immediate(kPointerSize));
1756 __ test(eax, eax);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001757 __ j(not_zero, &copy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758
1759 // Fill remaining expected arguments with undefined values.
1760 Label fill;
1761 __ bind(&fill);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001762 __ inc(eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001763 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001764 __ cmp(eax, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001765 __ j(less, &fill);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001766 }
1767
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001768 // Call the entry point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001769 __ bind(&invoke);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001770 // Restore function pointer.
1771 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001772 __ call(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001773
ulan@chromium.org967e2702012-02-28 09:49:15 +00001774 // Store offset of return address for deoptimizer.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001775 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
ulan@chromium.org967e2702012-02-28 09:49:15 +00001776
ager@chromium.org7c537e22008-10-16 08:43:32 +00001777 // Leave frame and return.
1778 LeaveArgumentsAdaptorFrame(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001779 __ ret(0);
1780
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001781 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001782 // Dont adapt arguments.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001783 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001784 __ bind(&dont_adapt_arguments);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001785 __ jmp(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001786}
1787
1788
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001789void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001790 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001791
1792 // Pass the function to optimize as the argument to the on-stack
1793 // replacement runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001794 {
1795 FrameScope scope(masm, StackFrame::INTERNAL);
1796 __ push(eax);
1797 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1798 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001799
1800 // If the result was -1 it means that we couldn't optimize the
1801 // function. Just return and continue in the unoptimized version.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001802 Label skip;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001803 __ cmp(eax, Immediate(Smi::FromInt(-1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001804 __ j(not_equal, &skip, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001805 __ ret(0);
1806
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001807 __ bind(&skip);
1808 // Untag the AST id and push it on the stack.
1809 __ SmiUntag(eax);
1810 __ push(eax);
1811
1812 // Generate the code for doing the frame-to-frame translation using
1813 // the deoptimizer infrastructure.
1814 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1815 generator.Generate();
1816}
1817
1818
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001819#undef __
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001820}
1821} // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001822
1823#endif // V8_TARGET_ARCH_IA32