blob: 01785bb53e25400eda7668ffd94fb3e12088a374 [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
90void Builtins::Generate_ParallelRecompile(MacroAssembler* masm) {
91 {
92 FrameScope scope(masm, StackFrame::INTERNAL);
93
94 // Push a copy of the function onto the stack.
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::kParallelRecompile, 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 GenerateTailCallToSharedCode(masm);
111}
112
113
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000114static void Generate_JSConstructStubHelper(MacroAssembler* masm,
115 bool is_api_function,
116 bool count_constructions) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000117 // ----------- S t a t e -------------
118 // -- eax: number of arguments
119 // -- edi: constructor function
120 // -----------------------------------
121
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000122 // Should never count constructions for api objects.
123 ASSERT(!is_api_function || !count_constructions);
124
ager@chromium.org7c537e22008-10-16 08:43:32 +0000125 // Enter a construct frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000126 {
127 FrameScope scope(masm, StackFrame::CONSTRUCT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000129 // Store a smi-tagged arguments count on the stack.
130 __ SmiTag(eax);
131 __ push(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000133 // Push the function to invoke on the stack.
134 __ push(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000135
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000136 // Try to allocate the object without transitioning into C code. If any of
137 // the preconditions is not met, the code bails out to the runtime call.
138 Label rt_call, allocated;
139 if (FLAG_inline_new) {
140 Label undo_allocation;
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000141#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000142 ExternalReference debug_step_in_fp =
143 ExternalReference::debug_step_in_fp_address(masm->isolate());
144 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
145 __ j(not_equal, &rt_call);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000146#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000147
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000148 // Verified that the constructor is a JSFunction.
149 // Load the initial map and verify that it is in fact a map.
150 // edi: constructor
151 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
152 // Will both indicate a NULL and a Smi
153 __ JumpIfSmi(eax, &rt_call);
154 // edi: constructor
155 // eax: initial map (if proven valid below)
156 __ CmpObjectType(eax, MAP_TYPE, ebx);
157 __ j(not_equal, &rt_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000159 // Check that the constructor is not constructing a JSFunction (see
160 // comments in Runtime_NewObject in runtime.cc). In which case the
161 // initial map's instance type would be JS_FUNCTION_TYPE.
162 // edi: constructor
163 // eax: initial map
164 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
165 __ j(equal, &rt_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000167 if (count_constructions) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000168 Label allocate;
169 // Decrease generous allocation count.
170 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
171 __ dec_b(FieldOperand(ecx,
172 SharedFunctionInfo::kConstructionCountOffset));
173 __ j(not_zero, &allocate);
174
175 __ push(eax);
176 __ push(edi);
177
178 __ push(edi); // constructor
179 // The call will replace the stub, so the countdown is only done once.
180 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
181
182 __ pop(edi);
183 __ pop(eax);
184
185 __ bind(&allocate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000186 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000187
188 // Now allocate the JSObject on the heap.
189 // edi: constructor
190 // eax: initial map
191 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
192 __ shl(edi, kPointerSizeLog2);
193 __ AllocateInNewSpace(
194 edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
195 // Allocated the JSObject, now initialize the fields.
196 // eax: initial map
197 // ebx: JSObject
198 // edi: start of next object
199 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
200 Factory* factory = masm->isolate()->factory();
201 __ mov(ecx, factory->empty_fixed_array());
202 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
203 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
204 // Set extra fields in the newly allocated object.
205 // eax: initial map
206 // ebx: JSObject
207 // edi: start of next object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000209 __ mov(edx, factory->undefined_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000210 if (count_constructions) {
211 __ movzx_b(esi,
212 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
213 __ lea(esi,
214 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
215 // esi: offset of first field after pre-allocated fields
216 if (FLAG_debug_code) {
217 __ cmp(esi, edi);
218 __ Assert(less_equal,
219 "Unexpected number of pre-allocated property fields.");
220 }
221 __ InitializeFieldsWithFiller(ecx, esi, edx);
222 __ mov(edx, factory->one_pointer_filler_map());
223 }
224 __ InitializeFieldsWithFiller(ecx, edi, edx);
225
226 // Add the object tag to make the JSObject real, so that we can continue
227 // and jump into the continuation code at any time from now on. Any
228 // failures need to undo the allocation, so that the heap is in a
229 // consistent state and verifiable.
230 // eax: initial map
231 // ebx: JSObject
232 // edi: start of next object
233 __ or_(ebx, Immediate(kHeapObjectTag));
234
235 // Check if a non-empty properties array is needed.
236 // Allocate and initialize a FixedArray if it is.
237 // eax: initial map
238 // ebx: JSObject
239 // edi: start of next object
240 // Calculate the total number of properties described by the map.
241 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
242 __ movzx_b(ecx,
243 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
244 __ add(edx, ecx);
245 // Calculate unused properties past the end of the in-object properties.
246 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
247 __ sub(edx, ecx);
248 // Done if no extra properties are to be allocated.
249 __ j(zero, &allocated);
250 __ Assert(positive, "Property allocation count failed.");
251
252 // Scale the number of elements by pointer size and add the header for
253 // FixedArrays to the start of the next object calculation from above.
254 // ebx: JSObject
255 // edi: start of next object (will be start of FixedArray)
256 // edx: number of elements in properties array
257 __ AllocateInNewSpace(FixedArray::kHeaderSize,
258 times_pointer_size,
259 edx,
260 edi,
261 ecx,
262 no_reg,
263 &undo_allocation,
264 RESULT_CONTAINS_TOP);
265
266 // Initialize the FixedArray.
267 // ebx: JSObject
268 // edi: FixedArray
269 // edx: number of elements
270 // ecx: start of next object
271 __ mov(eax, factory->fixed_array_map());
272 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
273 __ SmiTag(edx);
274 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
275
276 // Initialize the fields to undefined.
277 // ebx: JSObject
278 // edi: FixedArray
279 // ecx: start of next object
280 { Label loop, entry;
281 __ mov(edx, factory->undefined_value());
282 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
283 __ jmp(&entry);
284 __ bind(&loop);
285 __ mov(Operand(eax, 0), edx);
286 __ add(eax, Immediate(kPointerSize));
287 __ bind(&entry);
288 __ cmp(eax, ecx);
289 __ j(below, &loop);
290 }
291
292 // Store the initialized FixedArray into the properties field of
293 // the JSObject
294 // ebx: JSObject
295 // edi: FixedArray
296 __ or_(edi, Immediate(kHeapObjectTag)); // add the heap tag
297 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
298
299
300 // Continue with JSObject being successfully allocated
301 // ebx: JSObject
302 __ jmp(&allocated);
303
304 // Undo the setting of the new top so that the heap is verifiable. For
305 // example, the map's unused properties potentially do not match the
306 // allocated objects unused properties.
307 // ebx: JSObject (previous new top)
308 __ bind(&undo_allocation);
309 __ UndoAllocationInNewSpace(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000310 }
311
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000312 // Allocate the new receiver object using the runtime call.
313 __ bind(&rt_call);
314 // Must restore edi (constructor) before calling runtime.
315 __ mov(edi, Operand(esp, 0));
316 // edi: function (constructor)
317 __ push(edi);
318 __ CallRuntime(Runtime::kNewObject, 1);
319 __ mov(ebx, eax); // store result in ebx
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000321 // New object allocated.
322 // ebx: newly allocated object
323 __ bind(&allocated);
324 // Retrieve the function from the stack.
325 __ pop(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000327 // Retrieve smi-tagged arguments count from the stack.
328 __ mov(eax, Operand(esp, 0));
329 __ SmiUntag(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000331 // Push the allocated receiver to the stack. We need two copies
332 // because we may have to return the original one and the calling
333 // conventions dictate that the called function pops the receiver.
334 __ push(ebx);
335 __ push(ebx);
336
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000337 // Set up pointer to last argument.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000338 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
339
340 // Copy arguments and receiver to the expression stack.
341 Label loop, entry;
342 __ mov(ecx, eax);
343 __ jmp(&entry);
344 __ bind(&loop);
345 __ push(Operand(ebx, ecx, times_4, 0));
346 __ bind(&entry);
347 __ dec(ecx);
348 __ j(greater_equal, &loop);
349
350 // Call the function.
351 if (is_api_function) {
352 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
353 Handle<Code> code =
354 masm->isolate()->builtins()->HandleApiCallConstruct();
355 ParameterCount expected(0);
356 __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
357 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
358 } else {
359 ParameterCount actual(eax);
360 __ InvokeFunction(edi, actual, CALL_FUNCTION,
361 NullCallWrapper(), CALL_AS_METHOD);
362 }
363
ulan@chromium.org967e2702012-02-28 09:49:15 +0000364 // Store offset of return address for deoptimizer.
365 if (!is_api_function && !count_constructions) {
366 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
367 }
368
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000369 // Restore context from the frame.
370 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
371
372 // If the result is an object (in the ECMA sense), we should get rid
373 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
374 // on page 74.
375 Label use_receiver, exit;
376
377 // If the result is a smi, it is *not* an object in the ECMA sense.
378 __ JumpIfSmi(eax, &use_receiver);
379
380 // If the type of the result (stored in its map) is less than
381 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
382 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
383 __ j(above_equal, &exit);
384
385 // Throw away the result of the constructor invocation and use the
386 // on-stack receiver as the result.
387 __ bind(&use_receiver);
388 __ mov(eax, Operand(esp, 0));
389
390 // Restore the arguments count and leave the construct frame.
391 __ bind(&exit);
392 __ mov(ebx, Operand(esp, kPointerSize)); // Get arguments count.
393
394 // Leave construct frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 }
396
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000397 // Remove caller arguments from the stack and return.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000398 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 __ pop(ecx);
400 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
401 __ push(ecx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000402 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000403 __ ret(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404}
405
406
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000407void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
408 Generate_JSConstructStubHelper(masm, false, true);
409}
410
411
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000412void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000413 Generate_JSConstructStubHelper(masm, false, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000414}
415
416
417void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000418 Generate_JSConstructStubHelper(masm, true, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000419}
420
421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000422static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
423 bool is_construct) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000424 // Clear the context before we push it when entering the internal frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000425 __ Set(esi, Immediate(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000426
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000427 {
428 FrameScope scope(masm, StackFrame::INTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000430 // Load the previous frame pointer (ebx) to access C arguments
431 __ mov(ebx, Operand(ebp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000433 // Get the function from the frame and setup the context.
434 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
435 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000437 // Push the function and the receiver onto the stack.
438 __ push(ecx);
439 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000441 // Load the number of arguments and setup pointer to the arguments.
442 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
443 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000445 // Copy arguments to the stack in a loop.
446 Label loop, entry;
447 __ Set(ecx, Immediate(0));
448 __ jmp(&entry);
449 __ bind(&loop);
450 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
451 __ push(Operand(edx, 0)); // dereference handle
452 __ inc(ecx);
453 __ bind(&entry);
454 __ cmp(ecx, eax);
455 __ j(not_equal, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000457 // Get the function from the stack and call it.
458 // kPointerSize for the receiver.
459 __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000460
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000461 // Invoke the code.
462 if (is_construct) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000463 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
464 __ CallStub(&stub);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000465 } else {
466 ParameterCount actual(eax);
467 __ InvokeFunction(edi, actual, CALL_FUNCTION,
468 NullCallWrapper(), CALL_AS_METHOD);
469 }
470
471 // Exit the internal frame. Notice that this also removes the empty.
472 // context and the function left on the stack by the code
473 // invocation.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000475 __ ret(kPointerSize); // Remove receiver.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000476}
477
478
479void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
480 Generate_JSEntryTrampolineHelper(masm, false);
481}
482
483
484void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
485 Generate_JSEntryTrampolineHelper(masm, true);
486}
487
488
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000489void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000490 {
491 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000492
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000493 // Push a copy of the function.
494 __ push(edi);
495 // Push call kind information.
496 __ push(ecx);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000497
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000498 __ push(edi); // Function is also the parameter to the runtime call.
499 __ CallRuntime(Runtime::kLazyCompile, 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000500
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000501 // Restore call kind information.
502 __ pop(ecx);
503 // Restore receiver.
504 __ pop(edi);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000505
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000506 // Tear down internal frame.
507 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000508
509 // Do a tail-call of the compiled function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000510 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000511 __ jmp(eax);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000512}
513
514
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000515void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000516 {
517 FrameScope scope(masm, StackFrame::INTERNAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000518
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000519 // Push a copy of the function onto the stack.
520 __ push(edi);
521 // Push call kind information.
522 __ push(ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000523
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000524 __ push(edi); // Function is also the parameter to the runtime call.
525 __ CallRuntime(Runtime::kLazyRecompile, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000526
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000527 // Restore call kind information.
528 __ pop(ecx);
529 // Restore receiver.
530 __ pop(edi);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000531
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000532 // Tear down internal frame.
533 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000534
535 // Do a tail-call of the compiled function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000536 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000537 __ jmp(eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000538}
539
540
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000541static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
542 // For now, we are relying on the fact that make_code_young doesn't do any
543 // garbage collection which allows us to save/restore the registers without
544 // worrying about which of them contain pointers. We also don't build an
545 // internal frame to make the code faster, since we shouldn't have to do stack
546 // crawls in MakeCodeYoung. This seems a bit fragile.
547
548 // Re-execute the code that was patched back to the young age when
549 // the stub returns.
550 __ sub(Operand(esp, 0), Immediate(5));
551 __ pushad();
552 __ mov(eax, Operand(esp, 8 * kPointerSize));
553 {
554 FrameScope scope(masm, StackFrame::MANUAL);
555 __ PrepareCallCFunction(1, ebx);
556 __ mov(Operand(esp, 0), eax);
557 __ CallCFunction(
558 ExternalReference::get_make_code_young_function(masm->isolate()), 1);
559 }
560 __ popad();
561 __ ret(0);
562}
563
564#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
565void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
566 MacroAssembler* masm) { \
567 GenerateMakeCodeYoungAgainCommon(masm); \
568} \
569void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
570 MacroAssembler* masm) { \
571 GenerateMakeCodeYoungAgainCommon(masm); \
572}
573CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
574#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
575
576
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000577static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
578 Deoptimizer::BailoutType type) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000579 {
580 FrameScope scope(masm, StackFrame::INTERNAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000581
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000582 // Pass deoptimization type to the runtime system.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000583 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
584 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000585
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000586 // Tear down internal frame.
587 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000588
589 // Get the full codegen state from the stack and untag it.
590 __ mov(ecx, Operand(esp, 1 * kPointerSize));
591 __ SmiUntag(ecx);
592
593 // Switch on the state.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000594 Label not_no_registers, not_tos_eax;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000595 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000596 __ j(not_equal, &not_no_registers, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000597 __ ret(1 * kPointerSize); // Remove state.
598
599 __ bind(&not_no_registers);
600 __ mov(eax, Operand(esp, 2 * kPointerSize));
601 __ cmp(ecx, FullCodeGenerator::TOS_REG);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000602 __ j(not_equal, &not_tos_eax, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000603 __ ret(2 * kPointerSize); // Remove state, eax.
604
605 __ bind(&not_tos_eax);
606 __ Abort("no cases left");
607}
608
609
610void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
611 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
612}
613
614
615void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
616 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
617}
618
619
620void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
621 // TODO(kasperl): Do we need to save/restore the XMM registers too?
622
623 // For now, we are relying on the fact that Runtime::NotifyOSR
624 // doesn't do any garbage collection which allows us to save/restore
625 // the registers without worrying about which of them contain
626 // pointers. This seems a bit fragile.
627 __ pushad();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000628 {
629 FrameScope scope(masm, StackFrame::INTERNAL);
630 __ CallRuntime(Runtime::kNotifyOSR, 0);
631 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000632 __ popad();
633 __ ret(0);
634}
635
636
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000637void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000638 Factory* factory = masm->isolate()->factory();
639
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000640 // 1. Make sure we have at least one argument.
641 { Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000642 __ test(eax, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000643 __ j(not_zero, &done);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000644 __ pop(ebx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000645 __ push(Immediate(factory->undefined_value()));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000646 __ push(ebx);
647 __ inc(eax);
648 __ bind(&done);
649 }
650
ager@chromium.org5c838252010-02-19 08:53:10 +0000651 // 2. Get the function to call (passed as receiver) from the stack, check
652 // if it is a function.
lrn@chromium.org34e60782011-09-15 07:25:40 +0000653 Label slow, non_function;
ager@chromium.org5c838252010-02-19 08:53:10 +0000654 // 1 ~ return address.
655 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000656 __ JumpIfSmi(edi, &non_function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000657 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000658 __ j(not_equal, &slow);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000659
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000660
ager@chromium.org5c838252010-02-19 08:53:10 +0000661 // 3a. Patch the first argument if necessary when calling a function.
662 Label shift_arguments;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000663 __ Set(edx, Immediate(0)); // indicate regular JS_FUNCTION
ager@chromium.org5c838252010-02-19 08:53:10 +0000664 { Label convert_to_object, use_global_receiver, patch_receiver;
665 // Change context eagerly in case we need the global receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000666 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
667
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000668 // Do not transform the receiver for strict mode functions.
669 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
670 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
671 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
672 __ j(not_equal, &shift_arguments);
673
lrn@chromium.org1c092762011-05-09 09:42:16 +0000674 // Do not transform the receiver for natives (shared already in ebx).
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000675 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
676 1 << SharedFunctionInfo::kNativeBitWithinByte);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +0000677 __ j(not_equal, &shift_arguments);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000678
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000679 // Compute the receiver in non-strict mode.
ager@chromium.org5c838252010-02-19 08:53:10 +0000680 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000681
682 // Call ToObject on the receiver if it is not an object, or use the
683 // global object if it is null or undefined.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000684 __ JumpIfSmi(ebx, &convert_to_object);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000685 __ cmp(ebx, factory->null_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000686 __ j(equal, &use_global_receiver);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000687 __ cmp(ebx, factory->undefined_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000688 __ j(equal, &use_global_receiver);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000689 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
690 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000691 __ j(above_equal, &shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000692
ager@chromium.org5c838252010-02-19 08:53:10 +0000693 __ bind(&convert_to_object);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000694
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000695 { // In order to preserve argument count.
696 FrameScope scope(masm, StackFrame::INTERNAL);
697 __ SmiTag(eax);
698 __ push(eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000699
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000700 __ push(ebx);
701 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
702 __ mov(ebx, eax);
703 __ Set(edx, Immediate(0)); // restore
704
705 __ pop(eax);
706 __ SmiUntag(eax);
707 }
708
ager@chromium.org5c838252010-02-19 08:53:10 +0000709 // Restore the function to edi.
710 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000711 __ jmp(&patch_receiver);
712
ager@chromium.org5c838252010-02-19 08:53:10 +0000713 // Use the global receiver object from the called function as the
714 // receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000715 __ bind(&use_global_receiver);
716 const int kGlobalIndex =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000717 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000718 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000719 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
ager@chromium.org3811b432009-10-28 14:53:37 +0000720 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000721 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000722
723 __ bind(&patch_receiver);
724 __ mov(Operand(esp, eax, times_4, 0), ebx);
725
ager@chromium.org5c838252010-02-19 08:53:10 +0000726 __ jmp(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000727 }
728
lrn@chromium.org34e60782011-09-15 07:25:40 +0000729 // 3b. Check for function proxy.
730 __ bind(&slow);
731 __ Set(edx, Immediate(1)); // indicate function proxy
732 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
733 __ j(equal, &shift_arguments);
734 __ bind(&non_function);
735 __ Set(edx, Immediate(2)); // indicate non-function
736
737 // 3c. Patch the first argument when calling a non-function. The
ager@chromium.org5c838252010-02-19 08:53:10 +0000738 // CALL_NON_FUNCTION builtin expects the non-function callee as
739 // receiver, so overwrite the first argument which will ultimately
740 // become the receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +0000741 __ mov(Operand(esp, eax, times_4, 0), edi);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000742
ager@chromium.org5c838252010-02-19 08:53:10 +0000743 // 4. Shift arguments and return address one slot down on the stack
744 // (overwriting the original receiver). Adjust argument count to make
745 // the original first argument the new receiver.
746 __ bind(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000747 { Label loop;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000748 __ mov(ecx, eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000749 __ bind(&loop);
750 __ mov(ebx, Operand(esp, ecx, times_4, 0));
751 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
752 __ dec(ecx);
ager@chromium.org5c838252010-02-19 08:53:10 +0000753 __ j(not_sign, &loop); // While non-negative (to copy return address).
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000754 __ pop(ebx); // Discard copy of return address.
755 __ dec(eax); // One fewer argument (first argument is new receiver).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000756 }
757
lrn@chromium.org34e60782011-09-15 07:25:40 +0000758 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
759 // or a function proxy via CALL_FUNCTION_PROXY.
760 { Label function, non_proxy;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000761 __ test(edx, edx);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000762 __ j(zero, &function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000763 __ Set(ebx, Immediate(0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000764 __ cmp(edx, Immediate(1));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000765 __ j(not_equal, &non_proxy);
766
767 __ pop(edx); // return address
768 __ push(edi); // re-add proxy object as additional argument
769 __ push(edx);
770 __ inc(eax);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000771 __ SetCallKind(ecx, CALL_AS_FUNCTION);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000772 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
773 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
774 RelocInfo::CODE_TARGET);
775
776 __ bind(&non_proxy);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000777 __ SetCallKind(ecx, CALL_AS_METHOD);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000778 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000779 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
780 RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000781 __ bind(&function);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000782 }
783
ager@chromium.org5c838252010-02-19 08:53:10 +0000784 // 5b. Get the code to call from the function and check that the number of
785 // expected arguments matches what we're providing. If so, jump
786 // (tail-call) to the code in register edx without checking arguments.
787 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
788 __ mov(ebx,
789 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000790 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000791 __ SmiUntag(ebx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000792 __ SetCallKind(ecx, CALL_AS_METHOD);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000793 __ cmp(eax, ebx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000794 __ j(not_equal,
795 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
ager@chromium.org5c838252010-02-19 08:53:10 +0000796
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000797 ParameterCount expected(0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000798 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper(),
799 CALL_AS_METHOD);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000800}
801
802
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
lrn@chromium.org34e60782011-09-15 07:25:40 +0000804 static const int kArgumentsOffset = 2 * kPointerSize;
805 static const int kReceiverOffset = 3 * kPointerSize;
806 static const int kFunctionOffset = 4 * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000807 {
808 FrameScope frame_scope(masm, StackFrame::INTERNAL);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000809
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000810 __ push(Operand(ebp, kFunctionOffset)); // push this
811 __ push(Operand(ebp, kArgumentsOffset)); // push arguments
812 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000814 // Check the stack for overflow. We are not trying to catch
815 // interruptions (e.g. debug break and preemption) here, so the "real stack
816 // limit" is checked.
817 Label okay;
818 ExternalReference real_stack_limit =
819 ExternalReference::address_of_real_stack_limit(masm->isolate());
820 __ mov(edi, Operand::StaticVariable(real_stack_limit));
821 // Make ecx the space we have left. The stack might already be overflowed
822 // here which will cause ecx to become negative.
823 __ mov(ecx, esp);
824 __ sub(ecx, edi);
825 // Make edx the space we need for the array when it is unrolled onto the
826 // stack.
827 __ mov(edx, eax);
828 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
829 // Check if the arguments will overflow the stack.
830 __ cmp(ecx, edx);
831 __ j(greater, &okay); // Signed comparison.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 // Out of stack space.
834 __ push(Operand(ebp, 4 * kPointerSize)); // push this
835 __ push(eax);
836 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
837 __ bind(&okay);
838 // End of stack check.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000839
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000840 // Push current index and limit.
841 const int kLimitOffset =
842 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
843 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
844 __ push(eax); // limit
845 __ push(Immediate(0)); // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000846
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000847 // Get the receiver.
848 __ mov(ebx, Operand(ebp, kReceiverOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000850 // Check that the function is a JS function (otherwise it must be a proxy).
851 Label push_receiver;
852 __ mov(edi, Operand(ebp, kFunctionOffset));
853 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
854 __ j(not_equal, &push_receiver);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000855
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000856 // Change context eagerly to get the right global object if necessary.
857 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000858
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000859 // Compute the receiver.
860 // Do not transform the receiver for strict mode functions.
861 Label call_to_object, use_global_receiver;
862 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
863 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
864 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
865 __ j(not_equal, &push_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000867 Factory* factory = masm->isolate()->factory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000868
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000869 // Do not transform the receiver for natives (shared already in ecx).
870 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
871 1 << SharedFunctionInfo::kNativeBitWithinByte);
872 __ j(not_equal, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000873
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000874 // Compute the receiver in non-strict mode.
875 // Call ToObject on the receiver if it is not an object, or use the
876 // global object if it is null or undefined.
877 __ JumpIfSmi(ebx, &call_to_object);
878 __ cmp(ebx, factory->null_value());
879 __ j(equal, &use_global_receiver);
880 __ cmp(ebx, factory->undefined_value());
881 __ j(equal, &use_global_receiver);
882 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
883 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
884 __ j(above_equal, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000885
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000886 __ bind(&call_to_object);
887 __ push(ebx);
888 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
889 __ mov(ebx, eax);
890 __ jmp(&push_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000892 // Use the current global receiver object as the receiver.
893 __ bind(&use_global_receiver);
894 const int kGlobalOffset =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000895 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000896 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000897 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000898 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
899 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000901 // Push the receiver.
902 __ bind(&push_receiver);
903 __ push(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000905 // Copy all arguments from the array to the stack.
906 Label entry, loop;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000907 __ mov(ecx, Operand(ebp, kIndexOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000908 __ jmp(&entry);
909 __ bind(&loop);
910 __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000912 // Use inline caching to speed up access to arguments.
913 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
914 __ call(ic, RelocInfo::CODE_TARGET);
915 // It is important that we do not have a test instruction after the
916 // call. A test instruction after the call is used to indicate that
917 // we have generated an inline version of the keyed load. In this
918 // case, we know that we are not generating a test instruction next.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000920 // Push the nth argument.
921 __ push(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000922
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000923 // Update the index on the stack and in register eax.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000924 __ mov(ecx, Operand(ebp, kIndexOffset));
925 __ add(ecx, Immediate(1 << kSmiTagSize));
926 __ mov(Operand(ebp, kIndexOffset), ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000928 __ bind(&entry);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000929 __ cmp(ecx, Operand(ebp, kLimitOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000930 __ j(not_equal, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000932 // Invoke the function.
933 Label call_proxy;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000934 __ mov(eax, ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000935 ParameterCount actual(eax);
936 __ SmiUntag(eax);
937 __ mov(edi, Operand(ebp, kFunctionOffset));
938 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
939 __ j(not_equal, &call_proxy);
940 __ InvokeFunction(edi, actual, CALL_FUNCTION,
941 NullCallWrapper(), CALL_AS_METHOD);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000943 frame_scope.GenerateLeaveFrame();
944 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000945
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000946 // Invoke the function proxy.
947 __ bind(&call_proxy);
948 __ push(edi); // add function proxy as last argument
949 __ inc(eax);
950 __ Set(ebx, Immediate(0));
951 __ SetCallKind(ecx, CALL_AS_METHOD);
952 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
953 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
954 RelocInfo::CODE_TARGET);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000955
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000956 // Leave internal frame.
957 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000958 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959}
960
961
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000962// Allocate an empty JSArray. The allocated array is put into the result
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000963// register. If the parameter initial_capacity is larger than zero an elements
964// backing store is allocated with this size and filled with the hole values.
965// Otherwise the elements backing store is set to the empty FixedArray.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000966static void AllocateEmptyJSArray(MacroAssembler* masm,
967 Register array_function,
968 Register result,
969 Register scratch1,
970 Register scratch2,
971 Register scratch3,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000972 Label* gc_required) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000973 const int initial_capacity = JSArray::kPreallocatedArrayElements;
974 STATIC_ASSERT(initial_capacity >= 0);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000975
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000976 __ LoadInitialArrayMap(array_function, scratch2, scratch1, false);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000977
978 // Allocate the JSArray object together with space for a fixed array with the
979 // requested elements.
980 int size = JSArray::kSize;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000981 if (initial_capacity > 0) {
982 size += FixedArray::SizeFor(initial_capacity);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000983 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000984 __ AllocateInNewSpace(size,
985 result,
986 scratch2,
987 scratch3,
988 gc_required,
989 TAG_OBJECT);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000990
991 // Allocated the JSArray. Now initialize the fields except for the elements
992 // array.
993 // result: JSObject
994 // scratch1: initial map
995 // scratch2: start of next object
996 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000997 Factory* factory = masm->isolate()->factory();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000998 __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000999 factory->empty_fixed_array());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001000 // Field JSArray::kElementsOffset is initialized later.
1001 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
1002
1003 // If no storage is requested for the elements array just set the empty
1004 // fixed array.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001005 if (initial_capacity == 0) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001006 __ mov(FieldOperand(result, JSArray::kElementsOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001007 factory->empty_fixed_array());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001008 return;
1009 }
1010
1011 // Calculate the location of the elements array and set elements array member
1012 // of the JSArray.
1013 // result: JSObject
1014 // scratch2: start of next object
1015 __ lea(scratch1, Operand(result, JSArray::kSize));
1016 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
1017
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001018 // Initialize the FixedArray and fill it with holes. FixedArray length is
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001019 // stored as a smi.
1020 // result: JSObject
1021 // scratch1: elements array
1022 // scratch2: start of next object
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001023 __ mov(FieldOperand(scratch1, FixedArray::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001024 factory->fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001025 __ mov(FieldOperand(scratch1, FixedArray::kLengthOffset),
1026 Immediate(Smi::FromInt(initial_capacity)));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001027
1028 // Fill the FixedArray with the hole value. Inline the code if short.
1029 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
1030 static const int kLoopUnfoldLimit = 4;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001031 if (initial_capacity <= kLoopUnfoldLimit) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001032 // Use a scratch register here to have only one reloc info when unfolding
1033 // the loop.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001034 __ mov(scratch3, factory->the_hole_value());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001035 for (int i = 0; i < initial_capacity; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001036 __ mov(FieldOperand(scratch1,
1037 FixedArray::kHeaderSize + i * kPointerSize),
1038 scratch3);
1039 }
1040 } else {
1041 Label loop, entry;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001042 __ mov(scratch2, Immediate(initial_capacity));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001043 __ jmp(&entry);
1044 __ bind(&loop);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001045 __ mov(FieldOperand(scratch1,
1046 scratch2,
1047 times_pointer_size,
1048 FixedArray::kHeaderSize),
1049 factory->the_hole_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001050 __ bind(&entry);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00001051 __ dec(scratch2);
1052 __ j(not_sign, &loop);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001053 }
1054}
1055
1056
1057// Allocate a JSArray with the number of elements stored in a register. The
1058// register array_function holds the built-in Array function and the register
1059// array_size holds the size of the array as a smi. The allocated array is put
1060// into the result register and beginning and end of the FixedArray elements
1061// storage is put into registers elements_array and elements_array_end (see
1062// below for when that is not the case). If the parameter fill_with_holes is
1063// true the allocated elements backing store is filled with the hole values
1064// otherwise it is left uninitialized. When the backing store is filled the
1065// register elements_array is scratched.
1066static void AllocateJSArray(MacroAssembler* masm,
1067 Register array_function, // Array function.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001068 Register array_size, // As a smi, cannot be 0.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001069 Register result,
1070 Register elements_array,
1071 Register elements_array_end,
1072 Register scratch,
1073 bool fill_with_hole,
1074 Label* gc_required) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001075 ASSERT(scratch.is(edi)); // rep stos destination
1076 ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001077 ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001078
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001079 __ LoadInitialArrayMap(array_function, scratch,
1080 elements_array, fill_with_hole);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001081
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001082 // Allocate the JSArray object together with space for a FixedArray with the
1083 // requested elements.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001084 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001085 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
1086 times_half_pointer_size, // array_size is a smi.
1087 array_size,
1088 result,
1089 elements_array_end,
1090 scratch,
1091 gc_required,
1092 TAG_OBJECT);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001093
1094 // Allocated the JSArray. Now initialize the fields except for the elements
1095 // array.
1096 // result: JSObject
1097 // elements_array: initial map
1098 // elements_array_end: start of next object
1099 // array_size: size of array (smi)
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001100 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001101 Factory* factory = masm->isolate()->factory();
1102 __ mov(elements_array, factory->empty_fixed_array());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001103 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
1104 // Field JSArray::kElementsOffset is initialized later.
1105 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
1106
1107 // Calculate the location of the elements array and set elements array member
1108 // of the JSArray.
1109 // result: JSObject
1110 // elements_array_end: start of next object
1111 // array_size: size of array (smi)
1112 __ lea(elements_array, Operand(result, JSArray::kSize));
1113 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
1114
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001115 // Initialize the fixed array. FixedArray length is stored as a smi.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001116 // result: JSObject
1117 // elements_array: elements array
1118 // elements_array_end: start of next object
1119 // array_size: size of array (smi)
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001120 __ mov(FieldOperand(elements_array, FixedArray::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001121 factory->fixed_array_map());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001122 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
1123 // same.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001124 __ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001125
1126 // Fill the allocated FixedArray with the hole value if requested.
1127 // result: JSObject
1128 // elements_array: elements array
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001129 if (fill_with_hole) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001130 __ SmiUntag(array_size);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001131 __ lea(edi, Operand(elements_array,
1132 FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001133 __ mov(eax, factory->the_hole_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001134 __ cld();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001135 // Do not use rep stos when filling less than kRepStosThreshold
1136 // words.
1137 const int kRepStosThreshold = 16;
1138 Label loop, entry, done;
1139 __ cmp(ecx, kRepStosThreshold);
1140 __ j(below, &loop); // Note: ecx > 0.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001141 __ rep_stos();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001142 __ jmp(&done);
1143 __ bind(&loop);
1144 __ stos();
1145 __ bind(&entry);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001146 __ cmp(edi, elements_array_end);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001147 __ j(below, &loop);
1148 __ bind(&done);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001149 }
1150}
1151
1152
1153// Create a new array for the built-in Array function. This function allocates
1154// the JSArray object and the FixedArray elements array and initializes these.
1155// If the Array cannot be constructed in native code the runtime is called. This
1156// function assumes the following state:
1157// edi: constructor (built-in Array function)
1158// eax: argc
1159// esp[0]: return address
1160// esp[4]: last argument
1161// This function is used for both construct and normal calls of Array. Whether
1162// it is a construct call or not is indicated by the construct_call parameter.
1163// The only difference between handling a construct call and a normal call is
1164// that for a construct call the constructor function in edi needs to be
1165// preserved for entering the generic code. In both cases argc in eax needs to
1166// be preserved.
1167static void ArrayNativeCode(MacroAssembler* masm,
1168 bool construct_call,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001169 Label* call_generic_code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001170 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001171 empty_array, not_empty_array, finish, cant_transition_map, not_double;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001172
1173 // Push the constructor and argc. No need to tag argc as a smi, as there will
1174 // be no garbage collection with this on the stack.
1175 int push_count = 0;
1176 if (construct_call) {
1177 push_count++;
1178 __ push(edi);
1179 }
1180 push_count++;
1181 __ push(eax);
1182
1183 // Check for array construction with zero arguments.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001184 __ test(eax, eax);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001185 __ j(not_zero, &argc_one_or_more);
1186
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001187 __ bind(&empty_array);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001188 // Handle construction of an empty array.
1189 AllocateEmptyJSArray(masm,
1190 edi,
1191 eax,
1192 ebx,
1193 ecx,
1194 edi,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001195 &prepare_generic_code_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001196 __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001197 __ pop(ebx);
1198 if (construct_call) {
1199 __ pop(edi);
1200 }
1201 __ ret(kPointerSize);
1202
1203 // Check for one argument. Bail out if argument is not smi or if it is
1204 // negative.
1205 __ bind(&argc_one_or_more);
1206 __ cmp(eax, 1);
1207 __ j(not_equal, &argc_two_or_more);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001208 STATIC_ASSERT(kSmiTag == 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001209 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001210 __ test(ecx, ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001211 __ j(not_zero, &not_empty_array);
1212
1213 // The single argument passed is zero, so we jump to the code above used to
1214 // handle the case of no arguments passed. To adapt the stack for that we move
1215 // the return address and the pushed constructor (if pushed) one stack slot up
1216 // thereby removing the passed argument. Argc is also on the stack - at the
1217 // bottom - and it needs to be changed from 1 to 0 to have the call into the
1218 // runtime system work in case a GC is required.
1219 for (int i = push_count; i > 0; i--) {
1220 __ mov(eax, Operand(esp, i * kPointerSize));
1221 __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
1222 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001223 __ Drop(2); // Drop two stack slots.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001224 __ push(Immediate(0)); // Treat this as a call with argc of zero.
1225 __ jmp(&empty_array);
1226
1227 __ bind(&not_empty_array);
1228 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001229 __ j(not_zero, &prepare_generic_code_call);
1230
1231 // Handle construction of an empty array of a certain size. Get the size from
1232 // the stack and bail out if size is to large to actually allocate an elements
1233 // array.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001234 __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001235 __ j(greater_equal, &prepare_generic_code_call);
1236
1237 // edx: array_size (smi)
1238 // edi: constructor
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001239 // esp[0]: argc (cannot be 0 here)
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001240 // esp[4]: constructor (only if construct_call)
1241 // esp[8]: return address
1242 // esp[C]: argument
1243 AllocateJSArray(masm,
1244 edi,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001245 ecx,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001246 ebx,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001247 eax,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001248 edx,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001249 edi,
1250 true,
1251 &prepare_generic_code_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001252 Counters* counters = masm->isolate()->counters();
1253 __ IncrementCounter(counters->array_function_native(), 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001254 __ mov(eax, ebx);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001255 __ pop(ebx);
1256 if (construct_call) {
1257 __ pop(edi);
1258 }
1259 __ ret(2 * kPointerSize);
1260
1261 // Handle construction of an array from a list of arguments.
1262 __ bind(&argc_two_or_more);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001263 STATIC_ASSERT(kSmiTag == 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001264 __ SmiTag(eax); // Convet argc to a smi.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001265 // eax: array_size (smi)
1266 // edi: constructor
1267 // esp[0] : argc
1268 // esp[4]: constructor (only if construct_call)
1269 // esp[8] : return address
1270 // esp[C] : last argument
1271 AllocateJSArray(masm,
1272 edi,
1273 eax,
1274 ebx,
1275 ecx,
1276 edx,
1277 edi,
1278 false,
1279 &prepare_generic_code_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001280 __ IncrementCounter(counters->array_function_native(), 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001281 __ push(ebx);
1282 __ mov(ebx, Operand(esp, kPointerSize));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001283 // ebx: argc
1284 // edx: elements_array_end (untagged)
1285 // esp[0]: JSArray
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001286 // esp[4]: argc
1287 // esp[8]: constructor (only if construct_call)
1288 // esp[12]: return address
1289 // esp[16]: last argument
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001290
1291 // Location of the last argument
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001292 int last_arg_offset = (construct_call ? 4 : 3) * kPointerSize;
1293 __ lea(edi, Operand(esp, last_arg_offset));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001294
1295 // Location of the first array element (Parameter fill_with_holes to
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001296 // AllocateJSArray is false, so the FixedArray is returned in ecx).
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001297 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
1298
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001299 Label has_non_smi_element;
1300
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001301 // ebx: argc
1302 // edx: location of the first array element
1303 // edi: location of the last argument
1304 // esp[0]: JSArray
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001305 // esp[4]: argc
1306 // esp[8]: constructor (only if construct_call)
1307 // esp[12]: return address
1308 // esp[16]: last argument
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001309 Label loop, entry;
1310 __ mov(ecx, ebx);
1311 __ jmp(&entry);
1312 __ bind(&loop);
1313 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001314 if (FLAG_smi_only_arrays) {
1315 __ JumpIfNotSmi(eax, &has_non_smi_element);
1316 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001317 __ mov(Operand(edx, 0), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001318 __ add(edx, Immediate(kPointerSize));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001319 __ bind(&entry);
1320 __ dec(ecx);
1321 __ j(greater_equal, &loop);
1322
1323 // Remove caller arguments from the stack and return.
1324 // ebx: argc
1325 // esp[0]: JSArray
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001326 // esp[4]: argc
1327 // esp[8]: constructor (only if construct_call)
1328 // esp[12]: return address
1329 // esp[16]: last argument
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001330 __ bind(&finish);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001331 __ mov(ecx, Operand(esp, last_arg_offset - kPointerSize));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001332 __ pop(eax);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001333 __ pop(ebx);
1334 __ lea(esp, Operand(esp, ebx, times_pointer_size,
1335 last_arg_offset - kPointerSize));
1336 __ jmp(ecx);
1337
1338 __ bind(&has_non_smi_element);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001339 // Double values are handled by the runtime.
1340 __ CheckMap(eax,
1341 masm->isolate()->factory()->heap_number_map(),
1342 &not_double,
1343 DONT_DO_SMI_CHECK);
1344 __ bind(&cant_transition_map);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001345 // Throw away the array that's only been partially constructed.
1346 __ pop(eax);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001347 __ UndoAllocationInNewSpace(eax);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001348 __ jmp(&prepare_generic_code_call);
1349
1350 __ bind(&not_double);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001351 // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001352 __ mov(ebx, Operand(esp, 0));
1353 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
1354 __ LoadTransitionedArrayMapConditional(
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001355 FAST_SMI_ELEMENTS,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001356 FAST_ELEMENTS,
1357 edi,
1358 eax,
1359 &cant_transition_map);
1360 __ mov(FieldOperand(ebx, HeapObject::kMapOffset), edi);
1361 __ RecordWriteField(ebx, HeapObject::kMapOffset, edi, eax,
1362 kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
1363
1364 // Prepare to re-enter the loop
1365 __ lea(edi, Operand(esp, last_arg_offset));
1366
1367 // Finish the array initialization loop.
1368 Label loop2;
1369 __ bind(&loop2);
1370 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1371 __ mov(Operand(edx, 0), eax);
1372 __ add(edx, Immediate(kPointerSize));
1373 __ dec(ecx);
1374 __ j(greater_equal, &loop2);
1375 __ jmp(&finish);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001376
1377 // Restore argc and constructor before running the generic code.
1378 __ bind(&prepare_generic_code_call);
1379 __ pop(eax);
1380 if (construct_call) {
1381 __ pop(edi);
1382 }
1383 __ jmp(call_generic_code);
1384}
1385
1386
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001387void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1388 // ----------- S t a t e -------------
1389 // -- eax : argc
1390 // -- esp[0] : return address
1391 // -- esp[4] : last argument
1392 // -----------------------------------
1393 Label generic_array_code;
1394
1395 // Get the InternalArray function.
1396 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1397
1398 if (FLAG_debug_code) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001399 // Initial map for the builtin InternalArray function should be a map.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001400 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1401 // Will both indicate a NULL and a Smi.
1402 __ test(ebx, Immediate(kSmiTagMask));
1403 __ Assert(not_zero, "Unexpected initial map for InternalArray function");
1404 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1405 __ Assert(equal, "Unexpected initial map for InternalArray function");
1406 }
1407
1408 // Run the native code for the InternalArray function called as a normal
1409 // function.
1410 ArrayNativeCode(masm, false, &generic_array_code);
1411
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001412 // Jump to the generic internal array code in case the specialized code cannot
1413 // handle the construction.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001414 __ bind(&generic_array_code);
1415 Handle<Code> array_code =
1416 masm->isolate()->builtins()->InternalArrayCodeGeneric();
1417 __ jmp(array_code, RelocInfo::CODE_TARGET);
1418}
1419
1420
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001421void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1422 // ----------- S t a t e -------------
1423 // -- eax : argc
1424 // -- esp[0] : return address
1425 // -- esp[4] : last argument
1426 // -----------------------------------
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001427 Label generic_array_code;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001428
1429 // Get the Array function.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001430 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001431
1432 if (FLAG_debug_code) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001433 // Initial map for the builtin Array function should be a map.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001434 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1435 // Will both indicate a NULL and a Smi.
1436 __ test(ebx, Immediate(kSmiTagMask));
1437 __ Assert(not_zero, "Unexpected initial map for Array function");
1438 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1439 __ Assert(equal, "Unexpected initial map for Array function");
1440 }
1441
1442 // Run the native code for the Array function called as a normal function.
1443 ArrayNativeCode(masm, false, &generic_array_code);
1444
1445 // Jump to the generic array code in case the specialized code cannot handle
1446 // the construction.
1447 __ bind(&generic_array_code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001448 Handle<Code> array_code =
1449 masm->isolate()->builtins()->ArrayCodeGeneric();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001450 __ jmp(array_code, RelocInfo::CODE_TARGET);
1451}
1452
1453
1454void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
1455 // ----------- S t a t e -------------
1456 // -- eax : argc
1457 // -- edi : constructor
1458 // -- esp[0] : return address
1459 // -- esp[4] : last argument
1460 // -----------------------------------
1461 Label generic_constructor;
1462
1463 if (FLAG_debug_code) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001464 // The array construct code is only set for the global and natives
1465 // builtin Array functions which always have maps.
1466
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001467 // Initial map for the builtin Array function should be a map.
1468 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1469 // Will both indicate a NULL and a Smi.
1470 __ test(ebx, Immediate(kSmiTagMask));
1471 __ Assert(not_zero, "Unexpected initial map for Array function");
1472 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1473 __ Assert(equal, "Unexpected initial map for Array function");
1474 }
1475
1476 // Run the native code for the Array function called as constructor.
1477 ArrayNativeCode(masm, true, &generic_constructor);
1478
1479 // Jump to the generic construct code in case the specialized code cannot
1480 // handle the construction.
1481 __ bind(&generic_constructor);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001482 Handle<Code> generic_construct_stub =
1483 masm->isolate()->builtins()->JSConstructStubGeneric();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001484 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1485}
1486
1487
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001488void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1489 // ----------- S t a t e -------------
1490 // -- eax : number of arguments
1491 // -- edi : constructor function
1492 // -- esp[0] : return address
1493 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1494 // -- esp[(argc + 1) * 4] : receiver
1495 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001496 Counters* counters = masm->isolate()->counters();
1497 __ IncrementCounter(counters->string_ctor_calls(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001498
1499 if (FLAG_debug_code) {
1500 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 __ cmp(edi, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001502 __ Assert(equal, "Unexpected String function");
1503 }
1504
1505 // Load the first argument into eax and get rid of the rest
1506 // (including the receiver).
1507 Label no_arguments;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 __ test(eax, eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001509 __ j(zero, &no_arguments);
1510 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1511 __ pop(ecx);
1512 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1513 __ push(ecx);
1514 __ mov(eax, ebx);
1515
1516 // Lookup the argument in the number to string cache.
1517 Label not_cached, argument_is_string;
1518 NumberToStringStub::GenerateLookupNumberStringCache(
1519 masm,
1520 eax, // Input.
1521 ebx, // Result.
1522 ecx, // Scratch 1.
1523 edx, // Scratch 2.
1524 false, // Input is known to be smi?
1525 &not_cached);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001526 __ IncrementCounter(counters->string_ctor_cached_number(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001527 __ bind(&argument_is_string);
1528 // ----------- S t a t e -------------
1529 // -- ebx : argument converted to string
1530 // -- edi : constructor function
1531 // -- esp[0] : return address
1532 // -----------------------------------
1533
1534 // Allocate a JSValue and put the tagged pointer into eax.
1535 Label gc_required;
1536 __ AllocateInNewSpace(JSValue::kSize,
1537 eax, // Result.
1538 ecx, // New allocation top (we ignore it).
1539 no_reg,
1540 &gc_required,
1541 TAG_OBJECT);
1542
1543 // Set the map.
1544 __ LoadGlobalFunctionInitialMap(edi, ecx);
1545 if (FLAG_debug_code) {
1546 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1547 JSValue::kSize >> kPointerSizeLog2);
1548 __ Assert(equal, "Unexpected string wrapper instance size");
1549 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1550 __ Assert(equal, "Unexpected unused properties of string wrapper");
1551 }
1552 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1553
1554 // Set properties and elements.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001555 Factory* factory = masm->isolate()->factory();
1556 __ Set(ecx, Immediate(factory->empty_fixed_array()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001557 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1558 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1559
1560 // Set the value.
1561 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1562
1563 // Ensure the object is fully initialized.
1564 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1565
1566 // We're done. Return.
1567 __ ret(0);
1568
1569 // The argument was not found in the number to string cache. Check
1570 // if it's a string already before calling the conversion builtin.
1571 Label convert_argument;
1572 __ bind(&not_cached);
1573 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001574 __ JumpIfSmi(eax, &convert_argument);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001575 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1576 __ j(NegateCondition(is_string), &convert_argument);
1577 __ mov(ebx, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001578 __ IncrementCounter(counters->string_ctor_string_value(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001579 __ jmp(&argument_is_string);
1580
1581 // Invoke the conversion builtin and put the result into ebx.
1582 __ bind(&convert_argument);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001583 __ IncrementCounter(counters->string_ctor_conversions(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001584 {
1585 FrameScope scope(masm, StackFrame::INTERNAL);
1586 __ push(edi); // Preserve the function.
1587 __ push(eax);
1588 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1589 __ pop(edi);
1590 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001591 __ mov(ebx, eax);
1592 __ jmp(&argument_is_string);
1593
1594 // Load the empty string into ebx, remove the receiver from the
1595 // stack, and jump back to the case where the argument is a string.
1596 __ bind(&no_arguments);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001597 __ Set(ebx, Immediate(factory->empty_string()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001598 __ pop(ecx);
1599 __ lea(esp, Operand(esp, kPointerSize));
1600 __ push(ecx);
1601 __ jmp(&argument_is_string);
1602
1603 // At this point the argument is already a string. Call runtime to
1604 // create a string wrapper.
1605 __ bind(&gc_required);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001606 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001607 {
1608 FrameScope scope(masm, StackFrame::INTERNAL);
1609 __ push(ebx);
1610 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1611 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001612 __ ret(0);
1613}
1614
1615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001616static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1617 __ push(ebp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001618 __ mov(ebp, esp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619
1620 // Store the arguments adaptor context sentinel.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001621 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001622
1623 // Push the function on the stack.
1624 __ push(edi);
1625
danno@chromium.org40cb8782011-05-25 07:58:50 +00001626 // Preserve the number of arguments on the stack. Must preserve eax,
1627 // ebx and ecx because these registers are used when copying the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628 // arguments and the receiver.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001629 STATIC_ASSERT(kSmiTagSize == 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001630 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1631 __ push(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632}
1633
1634
ager@chromium.org7c537e22008-10-16 08:43:32 +00001635static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 // Retrieve the number of arguments from the stack.
1637 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1638
1639 // Leave the frame.
1640 __ leave();
1641
1642 // Remove caller arguments from the stack.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001643 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644 __ pop(ecx);
1645 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1646 __ push(ecx);
1647}
1648
1649
1650void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1651 // ----------- S t a t e -------------
1652 // -- eax : actual number of arguments
1653 // -- ebx : expected number of arguments
danno@chromium.org40cb8782011-05-25 07:58:50 +00001654 // -- ecx : call kind information
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655 // -- edx : code entry to call
1656 // -----------------------------------
1657
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001658 Label invoke, dont_adapt_arguments;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001659 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001660
1661 Label enough, too_few;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001662 __ cmp(eax, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001663 __ j(less, &too_few);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001664 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1665 __ j(equal, &dont_adapt_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666
1667 { // Enough parameters: Actual >= expected.
1668 __ bind(&enough);
1669 EnterArgumentsAdaptorFrame(masm);
1670
1671 // Copy receiver and all expected arguments.
1672 const int offset = StandardFrameConstants::kCallerSPOffset;
1673 __ lea(eax, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001674 __ mov(edi, -1); // account for receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675
1676 Label copy;
1677 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001678 __ inc(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679 __ push(Operand(eax, 0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001680 __ sub(eax, Immediate(kPointerSize));
1681 __ cmp(edi, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 __ j(less, &copy);
1683 __ jmp(&invoke);
1684 }
1685
1686 { // Too few parameters: Actual < expected.
1687 __ bind(&too_few);
1688 EnterArgumentsAdaptorFrame(masm);
1689
1690 // Copy receiver and all actual arguments.
1691 const int offset = StandardFrameConstants::kCallerSPOffset;
1692 __ lea(edi, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001693 // ebx = expected - actual.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001694 __ sub(ebx, eax);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001695 // eax = -actual - 1
1696 __ neg(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001697 __ sub(eax, Immediate(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698
1699 Label copy;
1700 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001701 __ inc(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 __ push(Operand(edi, 0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001703 __ sub(edi, Immediate(kPointerSize));
1704 __ test(eax, eax);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001705 __ j(not_zero, &copy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706
1707 // Fill remaining expected arguments with undefined values.
1708 Label fill;
1709 __ bind(&fill);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001710 __ inc(eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001711 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001712 __ cmp(eax, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001713 __ j(less, &fill);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001714 }
1715
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001716 // Call the entry point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001717 __ bind(&invoke);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001718 // Restore function pointer.
1719 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001720 __ call(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001721
ulan@chromium.org967e2702012-02-28 09:49:15 +00001722 // Store offset of return address for deoptimizer.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001723 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
ulan@chromium.org967e2702012-02-28 09:49:15 +00001724
ager@chromium.org7c537e22008-10-16 08:43:32 +00001725 // Leave frame and return.
1726 LeaveArgumentsAdaptorFrame(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 __ ret(0);
1728
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001729 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001730 // Dont adapt arguments.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001731 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001732 __ bind(&dont_adapt_arguments);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001733 __ jmp(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001734}
1735
1736
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001737void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001738 CpuFeatures::TryForceFeatureScope scope(SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001739 if (!CpuFeatures::IsSupported(SSE2) && FLAG_debug_code) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001740 __ Abort("Unreachable code: Cannot optimize without SSE2 support.");
1741 return;
1742 }
1743
1744 // Get the loop depth of the stack guard check. This is recorded in
1745 // a test(eax, depth) instruction right after the call.
1746 Label stack_check;
1747 __ mov(ebx, Operand(esp, 0)); // return address
1748 if (FLAG_debug_code) {
1749 __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte);
1750 __ Assert(equal, "test eax instruction not found after loop stack check");
1751 }
1752 __ movzx_b(ebx, Operand(ebx, 1)); // depth
1753
1754 // Get the loop nesting level at which we allow OSR from the
1755 // unoptimized code and check if we want to do OSR yet. If not we
1756 // should perform a stack guard check so we can get interrupts while
1757 // waiting for on-stack replacement.
1758 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1759 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
1760 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
1761 __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset));
1762 __ j(greater, &stack_check);
1763
1764 // Pass the function to optimize as the argument to the on-stack
1765 // replacement runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001766 {
1767 FrameScope scope(masm, StackFrame::INTERNAL);
1768 __ push(eax);
1769 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1770 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001771
1772 // If the result was -1 it means that we couldn't optimize the
1773 // function. Just return and continue in the unoptimized version.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001774 Label skip;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001775 __ cmp(eax, Immediate(Smi::FromInt(-1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001776 __ j(not_equal, &skip, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001777 __ ret(0);
1778
yangguo@chromium.org56454712012-02-16 15:33:53 +00001779 // Insert a stack guard check so that if we decide not to perform
1780 // on-stack replacement right away, the function calling this stub can
1781 // still be interrupted.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001782 __ bind(&stack_check);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001783 Label ok;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001784 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001785 ExternalReference::address_of_stack_limit(masm->isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001786 __ cmp(esp, Operand::StaticVariable(stack_limit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001787 __ j(above_equal, &ok, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001788 StackCheckStub stub;
1789 __ TailCallStub(&stub);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001790 if (FLAG_debug_code) {
1791 __ Abort("Unreachable code: returned from tail call.");
1792 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001793 __ bind(&ok);
1794 __ ret(0);
1795
1796 __ bind(&skip);
1797 // Untag the AST id and push it on the stack.
1798 __ SmiUntag(eax);
1799 __ push(eax);
1800
1801 // Generate the code for doing the frame-to-frame translation using
1802 // the deoptimizer infrastructure.
1803 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1804 generator.Generate();
1805}
1806
1807
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808#undef __
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001809}
1810} // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001811
1812#endif // V8_TARGET_ARCH_IA32