[go: nahoru, domu]

blob: 310ea3d1234826012e0a324214db648ab0d758f7 [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_IA32)
31
Ben Murdoch8b112d22011-06-08 16:22:53 +010032#include "codegen.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "deoptimizer.h"
34#include "full-codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035
36namespace v8 {
37namespace internal {
38
39
40#define __ ACCESS_MASM(masm)
41
42
Leon Clarkee46be812010-01-19 14:06:41 +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 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +000057
Leon Clarkee46be812010-01-19 14:06:41 +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
Steve Block6ded16b2010-05-10 14:33:55 +010070 // JumpToExternalReference expects eax to contain the number of arguments
Leon Clarkee46be812010-01-19 14:06:41 +000071 // including the receiver and the extra arguments.
72 __ add(Operand(eax), Immediate(num_extra_args + 1));
Steve Block44f0eee2011-05-26 01:26:41 +010073 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000074}
75
76
77void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
78 // ----------- S t a t e -------------
79 // -- eax: number of arguments
80 // -- edi: constructor function
81 // -----------------------------------
82
83 Label non_function_call;
84 // Check that function is not a smi.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000085 __ JumpIfSmi(edi, &non_function_call);
Steve Blocka7e24c12009-10-30 11:49:00 +000086 // Check that function is a JSFunction.
87 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
88 __ j(not_equal, &non_function_call);
89
90 // Jump to the function-specific construct stub.
91 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
92 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
93 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
94 __ jmp(Operand(ebx));
95
96 // edi: called object
97 // eax: number of arguments
98 __ bind(&non_function_call);
Steve Blocka7e24c12009-10-30 11:49:00 +000099 // Set expected number of arguments to zero (not changing eax).
100 __ Set(ebx, Immediate(0));
101 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
Steve Block44f0eee2011-05-26 01:26:41 +0100102 Handle<Code> arguments_adaptor =
103 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
Ben Murdoch257744e2011-11-30 15:57:28 +0000104 __ SetCallKind(ecx, CALL_AS_METHOD);
Steve Block44f0eee2011-05-26 01:26:41 +0100105 __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
Steve Blocka7e24c12009-10-30 11:49:00 +0000106}
107
108
Leon Clarkee46be812010-01-19 14:06:41 +0000109static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100110 bool is_api_function,
111 bool count_constructions) {
112 // Should never count constructions for api objects.
113 ASSERT(!is_api_function || !count_constructions);
114
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 // Enter a construct frame.
116 __ EnterConstructFrame();
117
118 // Store a smi-tagged arguments count on the stack.
Leon Clarkee46be812010-01-19 14:06:41 +0000119 __ SmiTag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000120 __ push(eax);
121
122 // Push the function to invoke on the stack.
123 __ push(edi);
124
125 // Try to allocate the object without transitioning into C code. If any of the
126 // preconditions is not met, the code bails out to the runtime call.
127 Label rt_call, allocated;
128 if (FLAG_inline_new) {
129 Label undo_allocation;
130#ifdef ENABLE_DEBUGGER_SUPPORT
131 ExternalReference debug_step_in_fp =
Steve Block44f0eee2011-05-26 01:26:41 +0100132 ExternalReference::debug_step_in_fp_address(masm->isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
134 __ j(not_equal, &rt_call);
135#endif
136
137 // Verified that the constructor is a JSFunction.
138 // Load the initial map and verify that it is in fact a map.
139 // edi: constructor
140 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
141 // Will both indicate a NULL and a Smi
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000142 __ JumpIfSmi(eax, &rt_call);
Steve Blocka7e24c12009-10-30 11:49:00 +0000143 // edi: constructor
144 // eax: initial map (if proven valid below)
145 __ CmpObjectType(eax, MAP_TYPE, ebx);
146 __ j(not_equal, &rt_call);
147
148 // Check that the constructor is not constructing a JSFunction (see comments
149 // in Runtime_NewObject in runtime.cc). In which case the initial map's
150 // instance type would be JS_FUNCTION_TYPE.
151 // edi: constructor
152 // eax: initial map
153 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
154 __ j(equal, &rt_call);
155
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100156 if (count_constructions) {
157 Label allocate;
158 // Decrease generous allocation count.
159 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
160 __ dec_b(FieldOperand(ecx, SharedFunctionInfo::kConstructionCountOffset));
161 __ j(not_zero, &allocate);
162
163 __ push(eax);
164 __ push(edi);
165
166 __ push(edi); // constructor
167 // The call will replace the stub, so the countdown is only done once.
168 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
169
170 __ pop(edi);
171 __ pop(eax);
172
173 __ bind(&allocate);
174 }
175
Steve Blocka7e24c12009-10-30 11:49:00 +0000176 // Now allocate the JSObject on the heap.
177 // edi: constructor
178 // eax: initial map
179 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
180 __ shl(edi, kPointerSizeLog2);
181 __ AllocateInNewSpace(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
182 // Allocated the JSObject, now initialize the fields.
183 // eax: initial map
184 // ebx: JSObject
185 // edi: start of next object
186 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
Steve Block44f0eee2011-05-26 01:26:41 +0100187 Factory* factory = masm->isolate()->factory();
188 __ mov(ecx, factory->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +0000189 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
190 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
191 // Set extra fields in the newly allocated object.
192 // eax: initial map
193 // ebx: JSObject
194 // edi: start of next object
195 { Label loop, entry;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100196 // To allow for truncation.
197 if (count_constructions) {
Steve Block44f0eee2011-05-26 01:26:41 +0100198 __ mov(edx, factory->one_pointer_filler_map());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100199 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100200 __ mov(edx, factory->undefined_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100201 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000202 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
203 __ jmp(&entry);
204 __ bind(&loop);
205 __ mov(Operand(ecx, 0), edx);
206 __ add(Operand(ecx), Immediate(kPointerSize));
207 __ bind(&entry);
208 __ cmp(ecx, Operand(edi));
209 __ j(less, &loop);
210 }
211
212 // Add the object tag to make the JSObject real, so that we can continue and
213 // jump into the continuation code at any time from now on. Any failures
214 // need to undo the allocation, so that the heap is in a consistent state
215 // and verifiable.
216 // eax: initial map
217 // ebx: JSObject
218 // edi: start of next object
219 __ or_(Operand(ebx), Immediate(kHeapObjectTag));
220
221 // Check if a non-empty properties array is needed.
222 // Allocate and initialize a FixedArray if it is.
223 // eax: initial map
224 // ebx: JSObject
225 // edi: start of next object
226 // Calculate the total number of properties described by the map.
227 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
228 __ movzx_b(ecx, FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
229 __ add(edx, Operand(ecx));
230 // Calculate unused properties past the end of the in-object properties.
231 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
232 __ sub(edx, Operand(ecx));
233 // Done if no extra properties are to be allocated.
234 __ j(zero, &allocated);
235 __ Assert(positive, "Property allocation count failed.");
236
237 // Scale the number of elements by pointer size and add the header for
238 // FixedArrays to the start of the next object calculation from above.
239 // ebx: JSObject
240 // edi: start of next object (will be start of FixedArray)
241 // edx: number of elements in properties array
242 __ AllocateInNewSpace(FixedArray::kHeaderSize,
243 times_pointer_size,
244 edx,
245 edi,
246 ecx,
247 no_reg,
248 &undo_allocation,
249 RESULT_CONTAINS_TOP);
250
251 // Initialize the FixedArray.
252 // ebx: JSObject
253 // edi: FixedArray
254 // edx: number of elements
255 // ecx: start of next object
Steve Block44f0eee2011-05-26 01:26:41 +0100256 __ mov(eax, factory->fixed_array_map());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100257 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
258 __ SmiTag(edx);
259 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
Steve Blocka7e24c12009-10-30 11:49:00 +0000260
261 // Initialize the fields to undefined.
262 // ebx: JSObject
263 // edi: FixedArray
264 // ecx: start of next object
265 { Label loop, entry;
Steve Block44f0eee2011-05-26 01:26:41 +0100266 __ mov(edx, factory->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
268 __ jmp(&entry);
269 __ bind(&loop);
270 __ mov(Operand(eax, 0), edx);
271 __ add(Operand(eax), Immediate(kPointerSize));
272 __ bind(&entry);
273 __ cmp(eax, Operand(ecx));
274 __ j(below, &loop);
275 }
276
277 // Store the initialized FixedArray into the properties field of
278 // the JSObject
279 // ebx: JSObject
280 // edi: FixedArray
281 __ or_(Operand(edi), Immediate(kHeapObjectTag)); // add the heap tag
282 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
283
284
285 // Continue with JSObject being successfully allocated
286 // ebx: JSObject
287 __ jmp(&allocated);
288
289 // Undo the setting of the new top so that the heap is verifiable. For
290 // example, the map's unused properties potentially do not match the
291 // allocated objects unused properties.
292 // ebx: JSObject (previous new top)
293 __ bind(&undo_allocation);
294 __ UndoAllocationInNewSpace(ebx);
295 }
296
297 // Allocate the new receiver object using the runtime call.
298 __ bind(&rt_call);
299 // Must restore edi (constructor) before calling runtime.
300 __ mov(edi, Operand(esp, 0));
301 // edi: function (constructor)
302 __ push(edi);
303 __ CallRuntime(Runtime::kNewObject, 1);
304 __ mov(ebx, Operand(eax)); // store result in ebx
305
306 // New object allocated.
307 // ebx: newly allocated object
308 __ bind(&allocated);
309 // Retrieve the function from the stack.
310 __ pop(edi);
311
312 // Retrieve smi-tagged arguments count from the stack.
313 __ mov(eax, Operand(esp, 0));
Leon Clarkee46be812010-01-19 14:06:41 +0000314 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000315
316 // Push the allocated receiver to the stack. We need two copies
317 // because we may have to return the original one and the calling
318 // conventions dictate that the called function pops the receiver.
319 __ push(ebx);
320 __ push(ebx);
321
322 // Setup pointer to last argument.
323 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
324
325 // Copy arguments and receiver to the expression stack.
326 Label loop, entry;
327 __ mov(ecx, Operand(eax));
328 __ jmp(&entry);
329 __ bind(&loop);
330 __ push(Operand(ebx, ecx, times_4, 0));
331 __ bind(&entry);
332 __ dec(ecx);
333 __ j(greater_equal, &loop);
334
335 // Call the function.
Leon Clarkee46be812010-01-19 14:06:41 +0000336 if (is_api_function) {
337 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Steve Block44f0eee2011-05-26 01:26:41 +0100338 Handle<Code> code =
339 masm->isolate()->builtins()->HandleApiCallConstruct();
Leon Clarkee46be812010-01-19 14:06:41 +0000340 ParameterCount expected(0);
Ben Murdoch257744e2011-11-30 15:57:28 +0000341 __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
342 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
Leon Clarkee46be812010-01-19 14:06:41 +0000343 } else {
344 ParameterCount actual(eax);
Ben Murdoch257744e2011-11-30 15:57:28 +0000345 __ InvokeFunction(edi, actual, CALL_FUNCTION,
346 NullCallWrapper(), CALL_AS_METHOD);
Leon Clarkee46be812010-01-19 14:06:41 +0000347 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000348
349 // Restore context from the frame.
350 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
351
352 // If the result is an object (in the ECMA sense), we should get rid
353 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
354 // on page 74.
355 Label use_receiver, exit;
356
357 // If the result is a smi, it is *not* an object in the ECMA sense.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000358 __ JumpIfSmi(eax, &use_receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000359
360 // If the type of the result (stored in its map) is less than
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000361 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
362 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +0000363 __ j(above_equal, &exit);
Steve Blocka7e24c12009-10-30 11:49:00 +0000364
365 // Throw away the result of the constructor invocation and use the
366 // on-stack receiver as the result.
367 __ bind(&use_receiver);
368 __ mov(eax, Operand(esp, 0));
369
370 // Restore the arguments count and leave the construct frame.
371 __ bind(&exit);
372 __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
373 __ LeaveConstructFrame();
374
375 // Remove caller arguments from the stack and return.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000376 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000377 __ pop(ecx);
378 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
379 __ push(ecx);
Steve Block44f0eee2011-05-26 01:26:41 +0100380 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 __ ret(0);
382}
383
384
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100385void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
386 Generate_JSConstructStubHelper(masm, false, true);
387}
388
389
Leon Clarkee46be812010-01-19 14:06:41 +0000390void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100391 Generate_JSConstructStubHelper(masm, false, false);
Leon Clarkee46be812010-01-19 14:06:41 +0000392}
393
394
395void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100396 Generate_JSConstructStubHelper(masm, true, false);
Leon Clarkee46be812010-01-19 14:06:41 +0000397}
398
399
Steve Blocka7e24c12009-10-30 11:49:00 +0000400static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
401 bool is_construct) {
402 // Clear the context before we push it when entering the JS frame.
Steve Block9fac8402011-05-12 15:51:54 +0100403 __ Set(esi, Immediate(0));
Steve Blocka7e24c12009-10-30 11:49:00 +0000404
405 // Enter an internal frame.
406 __ EnterInternalFrame();
407
408 // Load the previous frame pointer (ebx) to access C arguments
409 __ mov(ebx, Operand(ebp, 0));
410
411 // Get the function from the frame and setup the context.
412 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
413 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
414
415 // Push the function and the receiver onto the stack.
416 __ push(ecx);
417 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
418
419 // Load the number of arguments and setup pointer to the arguments.
420 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
421 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
422
423 // Copy arguments to the stack in a loop.
424 Label loop, entry;
Steve Block9fac8402011-05-12 15:51:54 +0100425 __ Set(ecx, Immediate(0));
Steve Blocka7e24c12009-10-30 11:49:00 +0000426 __ jmp(&entry);
427 __ bind(&loop);
428 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
429 __ push(Operand(edx, 0)); // dereference handle
430 __ inc(Operand(ecx));
431 __ bind(&entry);
432 __ cmp(ecx, Operand(eax));
433 __ j(not_equal, &loop);
434
435 // Get the function from the stack and call it.
436 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); // +1 ~ receiver
437
438 // Invoke the code.
439 if (is_construct) {
Steve Block44f0eee2011-05-26 01:26:41 +0100440 __ call(masm->isolate()->builtins()->JSConstructCall(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000441 RelocInfo::CODE_TARGET);
442 } else {
443 ParameterCount actual(eax);
Ben Murdoch257744e2011-11-30 15:57:28 +0000444 __ InvokeFunction(edi, actual, CALL_FUNCTION,
445 NullCallWrapper(), CALL_AS_METHOD);
Steve Blocka7e24c12009-10-30 11:49:00 +0000446 }
447
448 // Exit the JS frame. Notice that this also removes the empty
449 // context and the function left on the stack by the code
450 // invocation.
451 __ LeaveInternalFrame();
452 __ ret(1 * kPointerSize); // remove receiver
453}
454
455
456void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
457 Generate_JSEntryTrampolineHelper(masm, false);
458}
459
460
461void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
462 Generate_JSEntryTrampolineHelper(masm, true);
463}
464
465
Iain Merrick75681382010-08-19 15:07:18 +0100466void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
467 // Enter an internal frame.
468 __ EnterInternalFrame();
469
Ben Murdoch257744e2011-11-30 15:57:28 +0000470 // Push a copy of the function.
Iain Merrick75681382010-08-19 15:07:18 +0100471 __ push(edi);
Ben Murdoch257744e2011-11-30 15:57:28 +0000472 // Push call kind information.
473 __ push(ecx);
Iain Merrick75681382010-08-19 15:07:18 +0100474
475 __ push(edi); // Function is also the parameter to the runtime call.
476 __ CallRuntime(Runtime::kLazyCompile, 1);
Ben Murdoch257744e2011-11-30 15:57:28 +0000477
478 // Restore call kind information.
479 __ pop(ecx);
480 // Restore receiver.
Iain Merrick75681382010-08-19 15:07:18 +0100481 __ pop(edi);
482
483 // Tear down temporary frame.
484 __ LeaveInternalFrame();
485
486 // Do a tail-call of the compiled function.
Ben Murdoch257744e2011-11-30 15:57:28 +0000487 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
488 __ jmp(Operand(eax));
Iain Merrick75681382010-08-19 15:07:18 +0100489}
490
491
Ben Murdochb0fe1622011-05-05 13:52:32 +0100492void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
493 // Enter an internal frame.
494 __ EnterInternalFrame();
495
496 // Push a copy of the function onto the stack.
497 __ push(edi);
Ben Murdoch257744e2011-11-30 15:57:28 +0000498 // Push call kind information.
499 __ push(ecx);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100500
501 __ push(edi); // Function is also the parameter to the runtime call.
502 __ CallRuntime(Runtime::kLazyRecompile, 1);
503
Ben Murdoch257744e2011-11-30 15:57:28 +0000504 // Restore call kind information.
505 __ pop(ecx);
506 // Restore receiver.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100507 __ pop(edi);
Ben Murdoch257744e2011-11-30 15:57:28 +0000508
509 // Tear down temporary frame.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100510 __ LeaveInternalFrame();
511
512 // Do a tail-call of the compiled function.
Ben Murdoch257744e2011-11-30 15:57:28 +0000513 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
514 __ jmp(Operand(eax));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100515}
516
517
518static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
519 Deoptimizer::BailoutType type) {
520 // Enter an internal frame.
521 __ EnterInternalFrame();
522
523 // Pass the function and deoptimization type to the runtime system.
524 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
525 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
526
527 // Tear down temporary frame.
528 __ LeaveInternalFrame();
529
530 // Get the full codegen state from the stack and untag it.
531 __ mov(ecx, Operand(esp, 1 * kPointerSize));
532 __ SmiUntag(ecx);
533
534 // Switch on the state.
Ben Murdoch257744e2011-11-30 15:57:28 +0000535 Label not_no_registers, not_tos_eax;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100536 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
Ben Murdoch257744e2011-11-30 15:57:28 +0000537 __ j(not_equal, &not_no_registers, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100538 __ ret(1 * kPointerSize); // Remove state.
539
540 __ bind(&not_no_registers);
541 __ mov(eax, Operand(esp, 2 * kPointerSize));
542 __ cmp(ecx, FullCodeGenerator::TOS_REG);
Ben Murdoch257744e2011-11-30 15:57:28 +0000543 __ j(not_equal, &not_tos_eax, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100544 __ ret(2 * kPointerSize); // Remove state, eax.
545
546 __ bind(&not_tos_eax);
547 __ Abort("no cases left");
548}
549
550
551void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
552 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
553}
554
555
556void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
557 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
558}
559
560
561void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
562 // TODO(kasperl): Do we need to save/restore the XMM registers too?
563
564 // For now, we are relying on the fact that Runtime::NotifyOSR
565 // doesn't do any garbage collection which allows us to save/restore
566 // the registers without worrying about which of them contain
567 // pointers. This seems a bit fragile.
568 __ pushad();
569 __ EnterInternalFrame();
570 __ CallRuntime(Runtime::kNotifyOSR, 0);
571 __ LeaveInternalFrame();
572 __ popad();
573 __ ret(0);
574}
575
576
Steve Blocka7e24c12009-10-30 11:49:00 +0000577void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
Steve Block44f0eee2011-05-26 01:26:41 +0100578 Factory* factory = masm->isolate()->factory();
579
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 // 1. Make sure we have at least one argument.
581 { Label done;
582 __ test(eax, Operand(eax));
Ben Murdoch257744e2011-11-30 15:57:28 +0000583 __ j(not_zero, &done);
Steve Blocka7e24c12009-10-30 11:49:00 +0000584 __ pop(ebx);
Steve Block44f0eee2011-05-26 01:26:41 +0100585 __ push(Immediate(factory->undefined_value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000586 __ push(ebx);
587 __ inc(eax);
588 __ bind(&done);
589 }
590
Andrei Popescu402d9372010-02-26 13:31:12 +0000591 // 2. Get the function to call (passed as receiver) from the stack, check
592 // if it is a function.
Ben Murdoch589d6972011-11-30 16:04:58 +0000593 Label slow, non_function;
Andrei Popescu402d9372010-02-26 13:31:12 +0000594 // 1 ~ return address.
595 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000596 __ JumpIfSmi(edi, &non_function);
Andrei Popescu402d9372010-02-26 13:31:12 +0000597 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
Ben Murdoch589d6972011-11-30 16:04:58 +0000598 __ j(not_equal, &slow);
Steve Blocka7e24c12009-10-30 11:49:00 +0000599
Steve Blocka7e24c12009-10-30 11:49:00 +0000600
Andrei Popescu402d9372010-02-26 13:31:12 +0000601 // 3a. Patch the first argument if necessary when calling a function.
602 Label shift_arguments;
Ben Murdoch589d6972011-11-30 16:04:58 +0000603 __ Set(edx, Immediate(0)); // indicate regular JS_FUNCTION
Andrei Popescu402d9372010-02-26 13:31:12 +0000604 { Label convert_to_object, use_global_receiver, patch_receiver;
605 // Change context eagerly in case we need the global receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000606 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
607
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100608 // Do not transform the receiver for strict mode functions.
609 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
610 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
611 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
612 __ j(not_equal, &shift_arguments);
613
Ben Murdoch257744e2011-11-30 15:57:28 +0000614 // Do not transform the receiver for natives (shared already in ebx).
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000615 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
616 1 << SharedFunctionInfo::kNativeBitWithinByte);
Ben Murdoch257744e2011-11-30 15:57:28 +0000617 __ j(not_equal, &shift_arguments);
618
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100619 // Compute the receiver in non-strict mode.
Andrei Popescu402d9372010-02-26 13:31:12 +0000620 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
Ben Murdoch257744e2011-11-30 15:57:28 +0000621
622 // Call ToObject on the receiver if it is not an object, or use the
623 // global object if it is null or undefined.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000624 __ JumpIfSmi(ebx, &convert_to_object);
Steve Block44f0eee2011-05-26 01:26:41 +0100625 __ cmp(ebx, factory->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000626 __ j(equal, &use_global_receiver);
Steve Block44f0eee2011-05-26 01:26:41 +0100627 __ cmp(ebx, factory->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000628 __ j(equal, &use_global_receiver);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000629 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
630 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +0000631 __ j(above_equal, &shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000632
Andrei Popescu402d9372010-02-26 13:31:12 +0000633 __ bind(&convert_to_object);
634 __ EnterInternalFrame(); // In order to preserve argument count.
Leon Clarkee46be812010-01-19 14:06:41 +0000635 __ SmiTag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000636 __ push(eax);
637
Steve Blocka7e24c12009-10-30 11:49:00 +0000638 __ push(ebx);
639 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
640 __ mov(ebx, eax);
Ben Murdoch589d6972011-11-30 16:04:58 +0000641 __ Set(edx, Immediate(0)); // restore
Steve Blocka7e24c12009-10-30 11:49:00 +0000642
Steve Blocka7e24c12009-10-30 11:49:00 +0000643 __ pop(eax);
Leon Clarkee46be812010-01-19 14:06:41 +0000644 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000645 __ LeaveInternalFrame();
Andrei Popescu402d9372010-02-26 13:31:12 +0000646 // Restore the function to edi.
647 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +0000648 __ jmp(&patch_receiver);
649
Andrei Popescu402d9372010-02-26 13:31:12 +0000650 // Use the global receiver object from the called function as the
651 // receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000652 __ bind(&use_global_receiver);
653 const int kGlobalIndex =
654 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
655 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
Steve Blockd0582a62009-12-15 09:54:21 +0000656 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
657 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +0000658 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
659
660 __ bind(&patch_receiver);
661 __ mov(Operand(esp, eax, times_4, 0), ebx);
662
Andrei Popescu402d9372010-02-26 13:31:12 +0000663 __ jmp(&shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000664 }
665
Ben Murdoch589d6972011-11-30 16:04:58 +0000666 // 3b. Check for function proxy.
667 __ bind(&slow);
668 __ Set(edx, Immediate(1)); // indicate function proxy
669 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
670 __ j(equal, &shift_arguments);
671 __ bind(&non_function);
672 __ Set(edx, Immediate(2)); // indicate non-function
673
674 // 3c. Patch the first argument when calling a non-function. The
Andrei Popescu402d9372010-02-26 13:31:12 +0000675 // CALL_NON_FUNCTION builtin expects the non-function callee as
676 // receiver, so overwrite the first argument which will ultimately
677 // become the receiver.
Andrei Popescu402d9372010-02-26 13:31:12 +0000678 __ mov(Operand(esp, eax, times_4, 0), edi);
Leon Clarkee46be812010-01-19 14:06:41 +0000679
Andrei Popescu402d9372010-02-26 13:31:12 +0000680 // 4. Shift arguments and return address one slot down on the stack
681 // (overwriting the original receiver). Adjust argument count to make
682 // the original first argument the new receiver.
683 __ bind(&shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000684 { Label loop;
Leon Clarkee46be812010-01-19 14:06:41 +0000685 __ mov(ecx, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 __ bind(&loop);
687 __ mov(ebx, Operand(esp, ecx, times_4, 0));
688 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
689 __ dec(ecx);
Andrei Popescu402d9372010-02-26 13:31:12 +0000690 __ j(not_sign, &loop); // While non-negative (to copy return address).
Leon Clarkee46be812010-01-19 14:06:41 +0000691 __ pop(ebx); // Discard copy of return address.
692 __ dec(eax); // One fewer argument (first argument is new receiver).
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 }
694
Ben Murdoch589d6972011-11-30 16:04:58 +0000695 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
696 // or a function proxy via CALL_FUNCTION_PROXY.
697 { Label function, non_proxy;
698 __ test(edx, Operand(edx));
699 __ j(zero, &function);
Steve Block9fac8402011-05-12 15:51:54 +0100700 __ Set(ebx, Immediate(0));
Ben Murdoch257744e2011-11-30 15:57:28 +0000701 __ SetCallKind(ecx, CALL_AS_METHOD);
Ben Murdoch589d6972011-11-30 16:04:58 +0000702 __ cmp(Operand(edx), Immediate(1));
703 __ j(not_equal, &non_proxy);
704
705 __ pop(edx); // return address
706 __ push(edi); // re-add proxy object as additional argument
707 __ push(edx);
708 __ inc(eax);
709 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
710 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
711 RelocInfo::CODE_TARGET);
712
713 __ bind(&non_proxy);
714 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
Steve Block44f0eee2011-05-26 01:26:41 +0100715 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
Andrei Popescu402d9372010-02-26 13:31:12 +0000716 RelocInfo::CODE_TARGET);
717 __ bind(&function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000718 }
719
Andrei Popescu402d9372010-02-26 13:31:12 +0000720 // 5b. Get the code to call from the function and check that the number of
721 // expected arguments matches what we're providing. If so, jump
722 // (tail-call) to the code in register edx without checking arguments.
723 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
724 __ mov(ebx,
725 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
Steve Block791712a2010-08-27 10:21:07 +0100726 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100727 __ SmiUntag(ebx);
Ben Murdoch257744e2011-11-30 15:57:28 +0000728 __ SetCallKind(ecx, CALL_AS_METHOD);
Andrei Popescu402d9372010-02-26 13:31:12 +0000729 __ cmp(eax, Operand(ebx));
Steve Block44f0eee2011-05-26 01:26:41 +0100730 __ j(not_equal,
731 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
Andrei Popescu402d9372010-02-26 13:31:12 +0000732
Steve Blocka7e24c12009-10-30 11:49:00 +0000733 ParameterCount expected(0);
Ben Murdoch257744e2011-11-30 15:57:28 +0000734 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION,
735 NullCallWrapper(), CALL_AS_METHOD);
Steve Blocka7e24c12009-10-30 11:49:00 +0000736}
737
738
739void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000740 static const int kArgumentsOffset = 2 * kPointerSize;
741 static const int kReceiverOffset = 3 * kPointerSize;
742 static const int kFunctionOffset = 4 * kPointerSize;
743
Steve Blocka7e24c12009-10-30 11:49:00 +0000744 __ EnterInternalFrame();
745
Ben Murdoch589d6972011-11-30 16:04:58 +0000746 __ push(Operand(ebp, kFunctionOffset)); // push this
747 __ push(Operand(ebp, kArgumentsOffset)); // push arguments
Steve Blocka7e24c12009-10-30 11:49:00 +0000748 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
749
Ben Murdoch589d6972011-11-30 16:04:58 +0000750 // Check the stack for overflow. We are not trying to catch
Steve Blockd0582a62009-12-15 09:54:21 +0000751 // interruptions (e.g. debug break and preemption) here, so the "real stack
752 // limit" is checked.
753 Label okay;
754 ExternalReference real_stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +0100755 ExternalReference::address_of_real_stack_limit(masm->isolate());
Steve Blockd0582a62009-12-15 09:54:21 +0000756 __ mov(edi, Operand::StaticVariable(real_stack_limit));
757 // Make ecx the space we have left. The stack might already be overflowed
758 // here which will cause ecx to become negative.
759 __ mov(ecx, Operand(esp));
760 __ sub(ecx, Operand(edi));
761 // Make edx the space we need for the array when it is unrolled onto the
762 // stack.
763 __ mov(edx, Operand(eax));
764 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
765 // Check if the arguments will overflow the stack.
766 __ cmp(ecx, Operand(edx));
Ben Murdoch257744e2011-11-30 15:57:28 +0000767 __ j(greater, &okay); // Signed comparison.
Steve Blocka7e24c12009-10-30 11:49:00 +0000768
Steve Blockd0582a62009-12-15 09:54:21 +0000769 // Out of stack space.
770 __ push(Operand(ebp, 4 * kPointerSize)); // push this
771 __ push(eax);
772 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
773 __ bind(&okay);
774 // End of stack check.
Steve Blocka7e24c12009-10-30 11:49:00 +0000775
776 // Push current index and limit.
777 const int kLimitOffset =
778 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
779 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
780 __ push(eax); // limit
781 __ push(Immediate(0)); // index
782
Ben Murdoch589d6972011-11-30 16:04:58 +0000783 // Get the receiver.
784 __ mov(ebx, Operand(ebp, kReceiverOffset));
785
786 // Check that the function is a JS function (otherwise it must be a proxy).
787 Label push_receiver;
788 __ mov(edi, Operand(ebp, kFunctionOffset));
789 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
790 __ j(not_equal, &push_receiver);
791
792 // Change context eagerly to get the right global object if necessary.
Steve Blocka7e24c12009-10-30 11:49:00 +0000793 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
794
795 // Compute the receiver.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100796 // Do not transform the receiver for strict mode functions.
Ben Murdoch589d6972011-11-30 16:04:58 +0000797 Label call_to_object, use_global_receiver;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100798 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
799 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
800 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
801 __ j(not_equal, &push_receiver);
802
Ben Murdoch257744e2011-11-30 15:57:28 +0000803 Factory* factory = masm->isolate()->factory();
804
805 // Do not transform the receiver for natives (shared already in ecx).
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000806 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
807 1 << SharedFunctionInfo::kNativeBitWithinByte);
Ben Murdoch257744e2011-11-30 15:57:28 +0000808 __ j(not_equal, &push_receiver);
809
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100810 // Compute the receiver in non-strict mode.
Ben Murdoch257744e2011-11-30 15:57:28 +0000811 // Call ToObject on the receiver if it is not an object, or use the
812 // global object if it is null or undefined.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000813 __ JumpIfSmi(ebx, &call_to_object);
Steve Block44f0eee2011-05-26 01:26:41 +0100814 __ cmp(ebx, factory->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000815 __ j(equal, &use_global_receiver);
Steve Block44f0eee2011-05-26 01:26:41 +0100816 __ cmp(ebx, factory->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000817 __ j(equal, &use_global_receiver);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000818 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
819 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +0000820 __ j(above_equal, &push_receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000821
Steve Blocka7e24c12009-10-30 11:49:00 +0000822 __ bind(&call_to_object);
823 __ push(ebx);
824 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
825 __ mov(ebx, Operand(eax));
826 __ jmp(&push_receiver);
827
828 // Use the current global receiver object as the receiver.
829 __ bind(&use_global_receiver);
830 const int kGlobalOffset =
831 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
832 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
Steve Blockd0582a62009-12-15 09:54:21 +0000833 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
834 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000835 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
836
837 // Push the receiver.
838 __ bind(&push_receiver);
839 __ push(ebx);
840
841 // Copy all arguments from the array to the stack.
842 Label entry, loop;
843 __ mov(eax, Operand(ebp, kIndexOffset));
844 __ jmp(&entry);
845 __ bind(&loop);
Ben Murdoch589d6972011-11-30 16:04:58 +0000846 __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
Steve Blocka7e24c12009-10-30 11:49:00 +0000847
848 // Use inline caching to speed up access to arguments.
Steve Block44f0eee2011-05-26 01:26:41 +0100849 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 __ call(ic, RelocInfo::CODE_TARGET);
851 // It is important that we do not have a test instruction after the
852 // call. A test instruction after the call is used to indicate that
853 // we have generated an inline version of the keyed load. In this
854 // case, we know that we are not generating a test instruction next.
855
Andrei Popescu402d9372010-02-26 13:31:12 +0000856 // Push the nth argument.
Steve Blocka7e24c12009-10-30 11:49:00 +0000857 __ push(eax);
858
859 // Update the index on the stack and in register eax.
860 __ mov(eax, Operand(ebp, kIndexOffset));
861 __ add(Operand(eax), Immediate(1 << kSmiTagSize));
862 __ mov(Operand(ebp, kIndexOffset), eax);
863
864 __ bind(&entry);
865 __ cmp(eax, Operand(ebp, kLimitOffset));
866 __ j(not_equal, &loop);
867
868 // Invoke the function.
Ben Murdoch589d6972011-11-30 16:04:58 +0000869 Label call_proxy;
Steve Blocka7e24c12009-10-30 11:49:00 +0000870 ParameterCount actual(eax);
Leon Clarkee46be812010-01-19 14:06:41 +0000871 __ SmiUntag(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +0000872 __ mov(edi, Operand(ebp, kFunctionOffset));
873 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
874 __ j(not_equal, &call_proxy);
Ben Murdoch257744e2011-11-30 15:57:28 +0000875 __ InvokeFunction(edi, actual, CALL_FUNCTION,
876 NullCallWrapper(), CALL_AS_METHOD);
Steve Blocka7e24c12009-10-30 11:49:00 +0000877
878 __ LeaveInternalFrame();
879 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
Ben Murdoch589d6972011-11-30 16:04:58 +0000880
881 // Invoke the function proxy.
882 __ bind(&call_proxy);
883 __ push(edi); // add function proxy as last argument
884 __ inc(eax);
885 __ Set(ebx, Immediate(0));
886 __ SetCallKind(ecx, CALL_AS_METHOD);
887 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
888 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
889 RelocInfo::CODE_TARGET);
890
891 __ LeaveInternalFrame();
892 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
Steve Blocka7e24c12009-10-30 11:49:00 +0000893}
894
895
Steve Blocka7e24c12009-10-30 11:49:00 +0000896// Number of empty elements to allocate for an empty array.
897static const int kPreallocatedArrayElements = 4;
898
899
900// Allocate an empty JSArray. The allocated array is put into the result
901// register. If the parameter initial_capacity is larger than zero an elements
902// backing store is allocated with this size and filled with the hole values.
903// Otherwise the elements backing store is set to the empty FixedArray.
904static void AllocateEmptyJSArray(MacroAssembler* masm,
905 Register array_function,
906 Register result,
907 Register scratch1,
908 Register scratch2,
909 Register scratch3,
910 int initial_capacity,
911 Label* gc_required) {
912 ASSERT(initial_capacity >= 0);
913
914 // Load the initial map from the array function.
915 __ mov(scratch1, FieldOperand(array_function,
916 JSFunction::kPrototypeOrInitialMapOffset));
917
918 // Allocate the JSArray object together with space for a fixed array with the
919 // requested elements.
920 int size = JSArray::kSize;
921 if (initial_capacity > 0) {
922 size += FixedArray::SizeFor(initial_capacity);
923 }
924 __ AllocateInNewSpace(size,
925 result,
926 scratch2,
927 scratch3,
928 gc_required,
929 TAG_OBJECT);
930
931 // Allocated the JSArray. Now initialize the fields except for the elements
932 // array.
933 // result: JSObject
934 // scratch1: initial map
935 // scratch2: start of next object
936 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
Steve Block44f0eee2011-05-26 01:26:41 +0100937 Factory* factory = masm->isolate()->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +0000938 __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
Steve Block44f0eee2011-05-26 01:26:41 +0100939 factory->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +0000940 // Field JSArray::kElementsOffset is initialized later.
941 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
942
943 // If no storage is requested for the elements array just set the empty
944 // fixed array.
945 if (initial_capacity == 0) {
946 __ mov(FieldOperand(result, JSArray::kElementsOffset),
Steve Block44f0eee2011-05-26 01:26:41 +0100947 factory->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +0000948 return;
949 }
950
951 // Calculate the location of the elements array and set elements array member
952 // of the JSArray.
953 // result: JSObject
954 // scratch2: start of next object
955 __ lea(scratch1, Operand(result, JSArray::kSize));
956 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
957
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100958 // Initialize the FixedArray and fill it with holes. FixedArray length is
Steve Blocka7e24c12009-10-30 11:49:00 +0000959 // stored as a smi.
960 // result: JSObject
961 // scratch1: elements array
962 // scratch2: start of next object
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100963 __ mov(FieldOperand(scratch1, FixedArray::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +0100964 factory->fixed_array_map());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100965 __ mov(FieldOperand(scratch1, FixedArray::kLengthOffset),
966 Immediate(Smi::FromInt(initial_capacity)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000967
968 // Fill the FixedArray with the hole value. Inline the code if short.
969 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
970 static const int kLoopUnfoldLimit = 4;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000971 STATIC_ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
Steve Blocka7e24c12009-10-30 11:49:00 +0000972 if (initial_capacity <= kLoopUnfoldLimit) {
973 // Use a scratch register here to have only one reloc info when unfolding
974 // the loop.
Steve Block44f0eee2011-05-26 01:26:41 +0100975 __ mov(scratch3, factory->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000976 for (int i = 0; i < initial_capacity; i++) {
977 __ mov(FieldOperand(scratch1,
978 FixedArray::kHeaderSize + i * kPointerSize),
979 scratch3);
980 }
981 } else {
982 Label loop, entry;
983 __ jmp(&entry);
984 __ bind(&loop);
Steve Block44f0eee2011-05-26 01:26:41 +0100985 __ mov(Operand(scratch1, 0), factory->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000986 __ add(Operand(scratch1), Immediate(kPointerSize));
987 __ bind(&entry);
988 __ cmp(scratch1, Operand(scratch2));
989 __ j(below, &loop);
990 }
991}
992
993
994// Allocate a JSArray with the number of elements stored in a register. The
995// register array_function holds the built-in Array function and the register
996// array_size holds the size of the array as a smi. The allocated array is put
997// into the result register and beginning and end of the FixedArray elements
998// storage is put into registers elements_array and elements_array_end (see
999// below for when that is not the case). If the parameter fill_with_holes is
1000// true the allocated elements backing store is filled with the hole values
1001// otherwise it is left uninitialized. When the backing store is filled the
1002// register elements_array is scratched.
1003static void AllocateJSArray(MacroAssembler* masm,
1004 Register array_function, // Array function.
Steve Block6ded16b2010-05-10 14:33:55 +01001005 Register array_size, // As a smi, cannot be 0.
Steve Blocka7e24c12009-10-30 11:49:00 +00001006 Register result,
1007 Register elements_array,
1008 Register elements_array_end,
1009 Register scratch,
1010 bool fill_with_hole,
1011 Label* gc_required) {
Steve Block6ded16b2010-05-10 14:33:55 +01001012 ASSERT(scratch.is(edi)); // rep stos destination
1013 ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
Leon Clarkef7060e22010-06-03 12:02:55 +01001014 ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax
Steve Blocka7e24c12009-10-30 11:49:00 +00001015
1016 // Load the initial map from the array function.
1017 __ mov(elements_array,
1018 FieldOperand(array_function,
1019 JSFunction::kPrototypeOrInitialMapOffset));
1020
Steve Blocka7e24c12009-10-30 11:49:00 +00001021 // Allocate the JSArray object together with space for a FixedArray with the
1022 // requested elements.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001023 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001024 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
1025 times_half_pointer_size, // array_size is a smi.
1026 array_size,
1027 result,
1028 elements_array_end,
1029 scratch,
1030 gc_required,
1031 TAG_OBJECT);
1032
1033 // Allocated the JSArray. Now initialize the fields except for the elements
1034 // array.
1035 // result: JSObject
1036 // elements_array: initial map
1037 // elements_array_end: start of next object
1038 // array_size: size of array (smi)
Steve Blocka7e24c12009-10-30 11:49:00 +00001039 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
Steve Block44f0eee2011-05-26 01:26:41 +01001040 Factory* factory = masm->isolate()->factory();
1041 __ mov(elements_array, factory->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +00001042 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
1043 // Field JSArray::kElementsOffset is initialized later.
1044 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
1045
1046 // Calculate the location of the elements array and set elements array member
1047 // of the JSArray.
1048 // result: JSObject
1049 // elements_array_end: start of next object
1050 // array_size: size of array (smi)
1051 __ lea(elements_array, Operand(result, JSArray::kSize));
1052 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
1053
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001054 // Initialize the fixed array. FixedArray length is stored as a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +00001055 // result: JSObject
1056 // elements_array: elements array
1057 // elements_array_end: start of next object
1058 // array_size: size of array (smi)
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001059 __ mov(FieldOperand(elements_array, FixedArray::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +01001060 factory->fixed_array_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001061 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
1062 // same.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001063 __ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001064
1065 // Fill the allocated FixedArray with the hole value if requested.
1066 // result: JSObject
1067 // elements_array: elements array
Steve Blocka7e24c12009-10-30 11:49:00 +00001068 if (fill_with_hole) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001069 __ SmiUntag(array_size);
Steve Block6ded16b2010-05-10 14:33:55 +01001070 __ lea(edi, Operand(elements_array,
1071 FixedArray::kHeaderSize - kHeapObjectTag));
Steve Block44f0eee2011-05-26 01:26:41 +01001072 __ mov(eax, factory->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01001073 __ cld();
Leon Clarkef7060e22010-06-03 12:02:55 +01001074 // Do not use rep stos when filling less than kRepStosThreshold
1075 // words.
1076 const int kRepStosThreshold = 16;
1077 Label loop, entry, done;
1078 __ cmp(ecx, kRepStosThreshold);
1079 __ j(below, &loop); // Note: ecx > 0.
Steve Block6ded16b2010-05-10 14:33:55 +01001080 __ rep_stos();
Leon Clarkef7060e22010-06-03 12:02:55 +01001081 __ jmp(&done);
1082 __ bind(&loop);
1083 __ stos();
1084 __ bind(&entry);
1085 __ cmp(edi, Operand(elements_array_end));
1086 __ j(below, &loop);
1087 __ bind(&done);
Steve Blocka7e24c12009-10-30 11:49:00 +00001088 }
1089}
1090
1091
1092// Create a new array for the built-in Array function. This function allocates
1093// the JSArray object and the FixedArray elements array and initializes these.
1094// If the Array cannot be constructed in native code the runtime is called. This
1095// function assumes the following state:
1096// edi: constructor (built-in Array function)
1097// eax: argc
1098// esp[0]: return address
1099// esp[4]: last argument
1100// This function is used for both construct and normal calls of Array. Whether
1101// it is a construct call or not is indicated by the construct_call parameter.
1102// The only difference between handling a construct call and a normal call is
1103// that for a construct call the constructor function in edi needs to be
1104// preserved for entering the generic code. In both cases argc in eax needs to
1105// be preserved.
1106static void ArrayNativeCode(MacroAssembler* masm,
1107 bool construct_call,
Steve Blockd0582a62009-12-15 09:54:21 +00001108 Label* call_generic_code) {
Steve Block6ded16b2010-05-10 14:33:55 +01001109 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
1110 empty_array, not_empty_array;
Steve Blocka7e24c12009-10-30 11:49:00 +00001111
1112 // Push the constructor and argc. No need to tag argc as a smi, as there will
1113 // be no garbage collection with this on the stack.
1114 int push_count = 0;
1115 if (construct_call) {
1116 push_count++;
1117 __ push(edi);
1118 }
1119 push_count++;
1120 __ push(eax);
1121
1122 // Check for array construction with zero arguments.
1123 __ test(eax, Operand(eax));
1124 __ j(not_zero, &argc_one_or_more);
1125
Steve Block6ded16b2010-05-10 14:33:55 +01001126 __ bind(&empty_array);
Steve Blocka7e24c12009-10-30 11:49:00 +00001127 // Handle construction of an empty array.
1128 AllocateEmptyJSArray(masm,
1129 edi,
1130 eax,
1131 ebx,
1132 ecx,
1133 edi,
1134 kPreallocatedArrayElements,
1135 &prepare_generic_code_call);
Steve Block44f0eee2011-05-26 01:26:41 +01001136 __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001137 __ pop(ebx);
1138 if (construct_call) {
1139 __ pop(edi);
1140 }
1141 __ ret(kPointerSize);
1142
1143 // Check for one argument. Bail out if argument is not smi or if it is
1144 // negative.
1145 __ bind(&argc_one_or_more);
1146 __ cmp(eax, 1);
1147 __ j(not_equal, &argc_two_or_more);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001148 STATIC_ASSERT(kSmiTag == 0);
Steve Block6ded16b2010-05-10 14:33:55 +01001149 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
1150 __ test(ecx, Operand(ecx));
1151 __ j(not_zero, &not_empty_array);
1152
1153 // The single argument passed is zero, so we jump to the code above used to
1154 // handle the case of no arguments passed. To adapt the stack for that we move
1155 // the return address and the pushed constructor (if pushed) one stack slot up
1156 // thereby removing the passed argument. Argc is also on the stack - at the
1157 // bottom - and it needs to be changed from 1 to 0 to have the call into the
1158 // runtime system work in case a GC is required.
1159 for (int i = push_count; i > 0; i--) {
1160 __ mov(eax, Operand(esp, i * kPointerSize));
1161 __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
1162 }
1163 __ add(Operand(esp), Immediate(2 * kPointerSize)); // Drop two stack slots.
1164 __ push(Immediate(0)); // Treat this as a call with argc of zero.
1165 __ jmp(&empty_array);
1166
1167 __ bind(&not_empty_array);
1168 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001169 __ j(not_zero, &prepare_generic_code_call);
1170
1171 // Handle construction of an empty array of a certain size. Get the size from
1172 // the stack and bail out if size is to large to actually allocate an elements
1173 // array.
Steve Block6ded16b2010-05-10 14:33:55 +01001174 __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00001175 __ j(greater_equal, &prepare_generic_code_call);
1176
1177 // edx: array_size (smi)
1178 // edi: constructor
Steve Block6ded16b2010-05-10 14:33:55 +01001179 // esp[0]: argc (cannot be 0 here)
Steve Blocka7e24c12009-10-30 11:49:00 +00001180 // esp[4]: constructor (only if construct_call)
1181 // esp[8]: return address
1182 // esp[C]: argument
1183 AllocateJSArray(masm,
1184 edi,
Steve Block6ded16b2010-05-10 14:33:55 +01001185 ecx,
Steve Blocka7e24c12009-10-30 11:49:00 +00001186 ebx,
Leon Clarkef7060e22010-06-03 12:02:55 +01001187 eax,
Steve Block6ded16b2010-05-10 14:33:55 +01001188 edx,
Steve Blocka7e24c12009-10-30 11:49:00 +00001189 edi,
1190 true,
1191 &prepare_generic_code_call);
Steve Block44f0eee2011-05-26 01:26:41 +01001192 Counters* counters = masm->isolate()->counters();
1193 __ IncrementCounter(counters->array_function_native(), 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01001194 __ mov(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001195 __ pop(ebx);
1196 if (construct_call) {
1197 __ pop(edi);
1198 }
1199 __ ret(2 * kPointerSize);
1200
1201 // Handle construction of an array from a list of arguments.
1202 __ bind(&argc_two_or_more);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001203 STATIC_ASSERT(kSmiTag == 0);
Leon Clarkee46be812010-01-19 14:06:41 +00001204 __ SmiTag(eax); // Convet argc to a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +00001205 // eax: array_size (smi)
1206 // edi: constructor
1207 // esp[0] : argc
1208 // esp[4]: constructor (only if construct_call)
1209 // esp[8] : return address
1210 // esp[C] : last argument
1211 AllocateJSArray(masm,
1212 edi,
1213 eax,
1214 ebx,
1215 ecx,
1216 edx,
1217 edi,
1218 false,
1219 &prepare_generic_code_call);
Steve Block44f0eee2011-05-26 01:26:41 +01001220 __ IncrementCounter(counters->array_function_native(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001221 __ mov(eax, ebx);
1222 __ pop(ebx);
1223 if (construct_call) {
1224 __ pop(edi);
1225 }
1226 __ push(eax);
1227 // eax: JSArray
1228 // ebx: argc
1229 // edx: elements_array_end (untagged)
1230 // esp[0]: JSArray
1231 // esp[4]: return address
1232 // esp[8]: last argument
1233
1234 // Location of the last argument
1235 __ lea(edi, Operand(esp, 2 * kPointerSize));
1236
1237 // Location of the first array element (Parameter fill_with_holes to
1238 // AllocateJSArrayis false, so the FixedArray is returned in ecx).
1239 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
1240
1241 // ebx: argc
1242 // edx: location of the first array element
1243 // edi: location of the last argument
1244 // esp[0]: JSArray
1245 // esp[4]: return address
1246 // esp[8]: last argument
1247 Label loop, entry;
1248 __ mov(ecx, ebx);
1249 __ jmp(&entry);
1250 __ bind(&loop);
1251 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1252 __ mov(Operand(edx, 0), eax);
1253 __ add(Operand(edx), Immediate(kPointerSize));
1254 __ bind(&entry);
1255 __ dec(ecx);
1256 __ j(greater_equal, &loop);
1257
1258 // Remove caller arguments from the stack and return.
1259 // ebx: argc
1260 // esp[0]: JSArray
1261 // esp[4]: return address
1262 // esp[8]: last argument
1263 __ pop(eax);
1264 __ pop(ecx);
1265 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1266 __ push(ecx);
1267 __ ret(0);
1268
1269 // Restore argc and constructor before running the generic code.
1270 __ bind(&prepare_generic_code_call);
1271 __ pop(eax);
1272 if (construct_call) {
1273 __ pop(edi);
1274 }
1275 __ jmp(call_generic_code);
1276}
1277
1278
1279void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1280 // ----------- S t a t e -------------
1281 // -- eax : argc
1282 // -- esp[0] : return address
1283 // -- esp[4] : last argument
1284 // -----------------------------------
Kristian Monsen25f61362010-05-21 11:50:48 +01001285 Label generic_array_code;
Steve Blocka7e24c12009-10-30 11:49:00 +00001286
1287 // Get the Array function.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001288 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001289
1290 if (FLAG_debug_code) {
1291 // Initial map for the builtin Array function shoud be a map.
1292 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1293 // Will both indicate a NULL and a Smi.
1294 __ test(ebx, Immediate(kSmiTagMask));
1295 __ Assert(not_zero, "Unexpected initial map for Array function");
1296 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1297 __ Assert(equal, "Unexpected initial map for Array function");
1298 }
1299
1300 // Run the native code for the Array function called as a normal function.
1301 ArrayNativeCode(masm, false, &generic_array_code);
1302
1303 // Jump to the generic array code in case the specialized code cannot handle
1304 // the construction.
1305 __ bind(&generic_array_code);
Steve Block44f0eee2011-05-26 01:26:41 +01001306 Handle<Code> array_code =
1307 masm->isolate()->builtins()->ArrayCodeGeneric();
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 __ jmp(array_code, RelocInfo::CODE_TARGET);
1309}
1310
1311
1312void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
1313 // ----------- S t a t e -------------
1314 // -- eax : argc
1315 // -- edi : constructor
1316 // -- esp[0] : return address
1317 // -- esp[4] : last argument
1318 // -----------------------------------
1319 Label generic_constructor;
1320
1321 if (FLAG_debug_code) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001322 // The array construct code is only set for the global and natives
1323 // builtin Array functions which always have maps.
1324
Steve Blocka7e24c12009-10-30 11:49:00 +00001325 // Initial map for the builtin Array function should be a map.
1326 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1327 // Will both indicate a NULL and a Smi.
1328 __ test(ebx, Immediate(kSmiTagMask));
1329 __ Assert(not_zero, "Unexpected initial map for Array function");
1330 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1331 __ Assert(equal, "Unexpected initial map for Array function");
1332 }
1333
1334 // Run the native code for the Array function called as constructor.
1335 ArrayNativeCode(masm, true, &generic_constructor);
1336
1337 // Jump to the generic construct code in case the specialized code cannot
1338 // handle the construction.
1339 __ bind(&generic_constructor);
Steve Block44f0eee2011-05-26 01:26:41 +01001340 Handle<Code> generic_construct_stub =
1341 masm->isolate()->builtins()->JSConstructStubGeneric();
Steve Blocka7e24c12009-10-30 11:49:00 +00001342 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1343}
1344
1345
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001346void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1347 // ----------- S t a t e -------------
1348 // -- eax : number of arguments
1349 // -- edi : constructor function
1350 // -- esp[0] : return address
1351 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1352 // -- esp[(argc + 1) * 4] : receiver
1353 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +01001354 Counters* counters = masm->isolate()->counters();
1355 __ IncrementCounter(counters->string_ctor_calls(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001356
1357 if (FLAG_debug_code) {
1358 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1359 __ cmp(edi, Operand(ecx));
1360 __ Assert(equal, "Unexpected String function");
1361 }
1362
1363 // Load the first argument into eax and get rid of the rest
1364 // (including the receiver).
1365 Label no_arguments;
1366 __ test(eax, Operand(eax));
1367 __ j(zero, &no_arguments);
1368 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1369 __ pop(ecx);
1370 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1371 __ push(ecx);
1372 __ mov(eax, ebx);
1373
1374 // Lookup the argument in the number to string cache.
1375 Label not_cached, argument_is_string;
1376 NumberToStringStub::GenerateLookupNumberStringCache(
1377 masm,
1378 eax, // Input.
1379 ebx, // Result.
1380 ecx, // Scratch 1.
1381 edx, // Scratch 2.
1382 false, // Input is known to be smi?
1383 &not_cached);
Steve Block44f0eee2011-05-26 01:26:41 +01001384 __ IncrementCounter(counters->string_ctor_cached_number(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001385 __ bind(&argument_is_string);
1386 // ----------- S t a t e -------------
1387 // -- ebx : argument converted to string
1388 // -- edi : constructor function
1389 // -- esp[0] : return address
1390 // -----------------------------------
1391
1392 // Allocate a JSValue and put the tagged pointer into eax.
1393 Label gc_required;
1394 __ AllocateInNewSpace(JSValue::kSize,
1395 eax, // Result.
1396 ecx, // New allocation top (we ignore it).
1397 no_reg,
1398 &gc_required,
1399 TAG_OBJECT);
1400
1401 // Set the map.
1402 __ LoadGlobalFunctionInitialMap(edi, ecx);
1403 if (FLAG_debug_code) {
1404 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1405 JSValue::kSize >> kPointerSizeLog2);
1406 __ Assert(equal, "Unexpected string wrapper instance size");
1407 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1408 __ Assert(equal, "Unexpected unused properties of string wrapper");
1409 }
1410 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1411
1412 // Set properties and elements.
Steve Block44f0eee2011-05-26 01:26:41 +01001413 Factory* factory = masm->isolate()->factory();
1414 __ Set(ecx, Immediate(factory->empty_fixed_array()));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001415 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1416 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1417
1418 // Set the value.
1419 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1420
1421 // Ensure the object is fully initialized.
1422 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1423
1424 // We're done. Return.
1425 __ ret(0);
1426
1427 // The argument was not found in the number to string cache. Check
1428 // if it's a string already before calling the conversion builtin.
1429 Label convert_argument;
1430 __ bind(&not_cached);
1431 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001432 __ JumpIfSmi(eax, &convert_argument);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001433 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1434 __ j(NegateCondition(is_string), &convert_argument);
1435 __ mov(ebx, eax);
Steve Block44f0eee2011-05-26 01:26:41 +01001436 __ IncrementCounter(counters->string_ctor_string_value(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001437 __ jmp(&argument_is_string);
1438
1439 // Invoke the conversion builtin and put the result into ebx.
1440 __ bind(&convert_argument);
Steve Block44f0eee2011-05-26 01:26:41 +01001441 __ IncrementCounter(counters->string_ctor_conversions(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001442 __ EnterInternalFrame();
1443 __ push(edi); // Preserve the function.
1444 __ push(eax);
1445 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1446 __ pop(edi);
1447 __ LeaveInternalFrame();
1448 __ mov(ebx, eax);
1449 __ jmp(&argument_is_string);
1450
1451 // Load the empty string into ebx, remove the receiver from the
1452 // stack, and jump back to the case where the argument is a string.
1453 __ bind(&no_arguments);
Steve Block44f0eee2011-05-26 01:26:41 +01001454 __ Set(ebx, Immediate(factory->empty_string()));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001455 __ pop(ecx);
1456 __ lea(esp, Operand(esp, kPointerSize));
1457 __ push(ecx);
1458 __ jmp(&argument_is_string);
1459
1460 // At this point the argument is already a string. Call runtime to
1461 // create a string wrapper.
1462 __ bind(&gc_required);
Steve Block44f0eee2011-05-26 01:26:41 +01001463 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001464 __ EnterInternalFrame();
1465 __ push(ebx);
1466 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1467 __ LeaveInternalFrame();
1468 __ ret(0);
1469}
1470
1471
Steve Blocka7e24c12009-10-30 11:49:00 +00001472static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1473 __ push(ebp);
1474 __ mov(ebp, Operand(esp));
1475
1476 // Store the arguments adaptor context sentinel.
1477 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1478
1479 // Push the function on the stack.
1480 __ push(edi);
1481
Ben Murdoch257744e2011-11-30 15:57:28 +00001482 // Preserve the number of arguments on the stack. Must preserve eax,
1483 // ebx and ecx because these registers are used when copying the
Steve Blocka7e24c12009-10-30 11:49:00 +00001484 // arguments and the receiver.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001485 STATIC_ASSERT(kSmiTagSize == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +00001486 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1487 __ push(edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001488}
1489
1490
1491static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1492 // Retrieve the number of arguments from the stack.
1493 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1494
1495 // Leave the frame.
1496 __ leave();
1497
1498 // Remove caller arguments from the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001499 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001500 __ pop(ecx);
1501 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1502 __ push(ecx);
1503}
1504
1505
1506void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1507 // ----------- S t a t e -------------
1508 // -- eax : actual number of arguments
1509 // -- ebx : expected number of arguments
Ben Murdoch257744e2011-11-30 15:57:28 +00001510 // -- ecx : call kind information
Steve Blocka7e24c12009-10-30 11:49:00 +00001511 // -- edx : code entry to call
1512 // -----------------------------------
1513
1514 Label invoke, dont_adapt_arguments;
Steve Block44f0eee2011-05-26 01:26:41 +01001515 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001516
1517 Label enough, too_few;
1518 __ cmp(eax, Operand(ebx));
1519 __ j(less, &too_few);
1520 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1521 __ j(equal, &dont_adapt_arguments);
1522
1523 { // Enough parameters: Actual >= expected.
1524 __ bind(&enough);
1525 EnterArgumentsAdaptorFrame(masm);
1526
1527 // Copy receiver and all expected arguments.
1528 const int offset = StandardFrameConstants::kCallerSPOffset;
1529 __ lea(eax, Operand(ebp, eax, times_4, offset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001530 __ mov(edi, -1); // account for receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001531
1532 Label copy;
1533 __ bind(&copy);
Ben Murdoch257744e2011-11-30 15:57:28 +00001534 __ inc(edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001535 __ push(Operand(eax, 0));
1536 __ sub(Operand(eax), Immediate(kPointerSize));
Ben Murdoch257744e2011-11-30 15:57:28 +00001537 __ cmp(edi, Operand(ebx));
Steve Blocka7e24c12009-10-30 11:49:00 +00001538 __ j(less, &copy);
1539 __ jmp(&invoke);
1540 }
1541
1542 { // Too few parameters: Actual < expected.
1543 __ bind(&too_few);
1544 EnterArgumentsAdaptorFrame(masm);
1545
1546 // Copy receiver and all actual arguments.
1547 const int offset = StandardFrameConstants::kCallerSPOffset;
1548 __ lea(edi, Operand(ebp, eax, times_4, offset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001549 // ebx = expected - actual.
1550 __ sub(ebx, Operand(eax));
1551 // eax = -actual - 1
1552 __ neg(eax);
1553 __ sub(Operand(eax), Immediate(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001554
1555 Label copy;
1556 __ bind(&copy);
Ben Murdoch257744e2011-11-30 15:57:28 +00001557 __ inc(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +00001558 __ push(Operand(edi, 0));
1559 __ sub(Operand(edi), Immediate(kPointerSize));
Ben Murdoch257744e2011-11-30 15:57:28 +00001560 __ test(eax, Operand(eax));
1561 __ j(not_zero, &copy);
Steve Blocka7e24c12009-10-30 11:49:00 +00001562
1563 // Fill remaining expected arguments with undefined values.
1564 Label fill;
1565 __ bind(&fill);
Ben Murdoch257744e2011-11-30 15:57:28 +00001566 __ inc(eax);
Steve Block44f0eee2011-05-26 01:26:41 +01001567 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
Ben Murdoch257744e2011-11-30 15:57:28 +00001568 __ cmp(eax, Operand(ebx));
Steve Blocka7e24c12009-10-30 11:49:00 +00001569 __ j(less, &fill);
Steve Blocka7e24c12009-10-30 11:49:00 +00001570 }
1571
1572 // Call the entry point.
1573 __ bind(&invoke);
Ben Murdoch257744e2011-11-30 15:57:28 +00001574 // Restore function pointer.
1575 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001576 __ call(Operand(edx));
1577
1578 // Leave frame and return.
1579 LeaveArgumentsAdaptorFrame(masm);
1580 __ ret(0);
1581
1582 // -------------------------------------------
1583 // Dont adapt arguments.
1584 // -------------------------------------------
1585 __ bind(&dont_adapt_arguments);
1586 __ jmp(Operand(edx));
1587}
1588
1589
Ben Murdochb0fe1622011-05-05 13:52:32 +01001590void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001591 CpuFeatures::TryForceFeatureScope scope(SSE2);
1592 if (!CpuFeatures::IsSupported(SSE2)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001593 __ Abort("Unreachable code: Cannot optimize without SSE2 support.");
1594 return;
1595 }
1596
1597 // Get the loop depth of the stack guard check. This is recorded in
1598 // a test(eax, depth) instruction right after the call.
1599 Label stack_check;
1600 __ mov(ebx, Operand(esp, 0)); // return address
1601 if (FLAG_debug_code) {
1602 __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte);
1603 __ Assert(equal, "test eax instruction not found after loop stack check");
1604 }
1605 __ movzx_b(ebx, Operand(ebx, 1)); // depth
1606
1607 // Get the loop nesting level at which we allow OSR from the
1608 // unoptimized code and check if we want to do OSR yet. If not we
1609 // should perform a stack guard check so we can get interrupts while
1610 // waiting for on-stack replacement.
1611 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1612 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
1613 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
1614 __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset));
1615 __ j(greater, &stack_check);
1616
1617 // Pass the function to optimize as the argument to the on-stack
1618 // replacement runtime function.
1619 __ EnterInternalFrame();
1620 __ push(eax);
1621 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1622 __ LeaveInternalFrame();
1623
1624 // If the result was -1 it means that we couldn't optimize the
1625 // function. Just return and continue in the unoptimized version.
Ben Murdoch257744e2011-11-30 15:57:28 +00001626 Label skip;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001627 __ cmp(Operand(eax), Immediate(Smi::FromInt(-1)));
Ben Murdoch257744e2011-11-30 15:57:28 +00001628 __ j(not_equal, &skip, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001629 __ ret(0);
1630
1631 // If we decide not to perform on-stack replacement we perform a
1632 // stack guard check to enable interrupts.
1633 __ bind(&stack_check);
Ben Murdoch257744e2011-11-30 15:57:28 +00001634 Label ok;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001635 ExternalReference stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +01001636 ExternalReference::address_of_stack_limit(masm->isolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001637 __ cmp(esp, Operand::StaticVariable(stack_limit));
Ben Murdoch257744e2011-11-30 15:57:28 +00001638 __ j(above_equal, &ok, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001639 StackCheckStub stub;
1640 __ TailCallStub(&stub);
1641 __ Abort("Unreachable code: returned from tail call.");
1642 __ bind(&ok);
1643 __ ret(0);
1644
1645 __ bind(&skip);
1646 // Untag the AST id and push it on the stack.
1647 __ SmiUntag(eax);
1648 __ push(eax);
1649
1650 // Generate the code for doing the frame-to-frame translation using
1651 // the deoptimizer infrastructure.
1652 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1653 generator.Generate();
1654}
1655
1656
Steve Blocka7e24c12009-10-30 11:49:00 +00001657#undef __
Steve Block44f0eee2011-05-26 01:26:41 +01001658}
1659} // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01001660
1661#endif // V8_TARGET_ARCH_IA32