blob: 2970a0e08074288540adc78b44d0e7026b24645d [file] [log] [blame]
Ben Murdochb0fe1622011-05-05 13:52:32 +01001// Copyright 2010 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
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "codegen-inl.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.
85 __ test(edi, Immediate(kSmiTagMask));
86 __ j(zero, &non_function_call);
87 // Check that function is a JSFunction.
88 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
89 __ j(not_equal, &non_function_call);
90
91 // Jump to the function-specific construct stub.
92 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
93 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
94 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
95 __ jmp(Operand(ebx));
96
97 // edi: called object
98 // eax: number of arguments
99 __ bind(&non_function_call);
Steve Blocka7e24c12009-10-30 11:49:00 +0000100 // Set expected number of arguments to zero (not changing eax).
101 __ Set(ebx, Immediate(0));
102 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
Steve Block44f0eee2011-05-26 01:26:41 +0100103 Handle<Code> arguments_adaptor =
104 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
105 __ 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
142 __ test(eax, Immediate(kSmiTagMask));
143 __ j(zero, &rt_call);
144 // edi: constructor
145 // eax: initial map (if proven valid below)
146 __ CmpObjectType(eax, MAP_TYPE, ebx);
147 __ j(not_equal, &rt_call);
148
149 // Check that the constructor is not constructing a JSFunction (see comments
150 // in Runtime_NewObject in runtime.cc). In which case the initial map's
151 // instance type would be JS_FUNCTION_TYPE.
152 // edi: constructor
153 // eax: initial map
154 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
155 __ j(equal, &rt_call);
156
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100157 if (count_constructions) {
158 Label allocate;
159 // Decrease generous allocation count.
160 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
161 __ dec_b(FieldOperand(ecx, SharedFunctionInfo::kConstructionCountOffset));
162 __ j(not_zero, &allocate);
163
164 __ push(eax);
165 __ push(edi);
166
167 __ push(edi); // constructor
168 // The call will replace the stub, so the countdown is only done once.
169 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
170
171 __ pop(edi);
172 __ pop(eax);
173
174 __ bind(&allocate);
175 }
176
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 // Now allocate the JSObject on the heap.
178 // edi: constructor
179 // eax: initial map
180 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
181 __ shl(edi, kPointerSizeLog2);
182 __ AllocateInNewSpace(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
183 // Allocated the JSObject, now initialize the fields.
184 // eax: initial map
185 // ebx: JSObject
186 // edi: start of next object
187 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
Steve Block44f0eee2011-05-26 01:26:41 +0100188 Factory* factory = masm->isolate()->factory();
189 __ mov(ecx, factory->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +0000190 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
191 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
192 // Set extra fields in the newly allocated object.
193 // eax: initial map
194 // ebx: JSObject
195 // edi: start of next object
196 { Label loop, entry;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100197 // To allow for truncation.
198 if (count_constructions) {
Steve Block44f0eee2011-05-26 01:26:41 +0100199 __ mov(edx, factory->one_pointer_filler_map());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100200 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100201 __ mov(edx, factory->undefined_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100202 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000203 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
204 __ jmp(&entry);
205 __ bind(&loop);
206 __ mov(Operand(ecx, 0), edx);
207 __ add(Operand(ecx), Immediate(kPointerSize));
208 __ bind(&entry);
209 __ cmp(ecx, Operand(edi));
210 __ j(less, &loop);
211 }
212
213 // Add the object tag to make the JSObject real, so that we can continue and
214 // jump into the continuation code at any time from now on. Any failures
215 // need to undo the allocation, so that the heap is in a consistent state
216 // and verifiable.
217 // eax: initial map
218 // ebx: JSObject
219 // edi: start of next object
220 __ or_(Operand(ebx), Immediate(kHeapObjectTag));
221
222 // Check if a non-empty properties array is needed.
223 // Allocate and initialize a FixedArray if it is.
224 // eax: initial map
225 // ebx: JSObject
226 // edi: start of next object
227 // Calculate the total number of properties described by the map.
228 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
229 __ movzx_b(ecx, FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
230 __ add(edx, Operand(ecx));
231 // Calculate unused properties past the end of the in-object properties.
232 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
233 __ sub(edx, Operand(ecx));
234 // Done if no extra properties are to be allocated.
235 __ j(zero, &allocated);
236 __ Assert(positive, "Property allocation count failed.");
237
238 // Scale the number of elements by pointer size and add the header for
239 // FixedArrays to the start of the next object calculation from above.
240 // ebx: JSObject
241 // edi: start of next object (will be start of FixedArray)
242 // edx: number of elements in properties array
243 __ AllocateInNewSpace(FixedArray::kHeaderSize,
244 times_pointer_size,
245 edx,
246 edi,
247 ecx,
248 no_reg,
249 &undo_allocation,
250 RESULT_CONTAINS_TOP);
251
252 // Initialize the FixedArray.
253 // ebx: JSObject
254 // edi: FixedArray
255 // edx: number of elements
256 // ecx: start of next object
Steve Block44f0eee2011-05-26 01:26:41 +0100257 __ mov(eax, factory->fixed_array_map());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100258 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
259 __ SmiTag(edx);
260 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
Steve Blocka7e24c12009-10-30 11:49:00 +0000261
262 // Initialize the fields to undefined.
263 // ebx: JSObject
264 // edi: FixedArray
265 // ecx: start of next object
266 { Label loop, entry;
Steve Block44f0eee2011-05-26 01:26:41 +0100267 __ mov(edx, factory->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000268 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
269 __ jmp(&entry);
270 __ bind(&loop);
271 __ mov(Operand(eax, 0), edx);
272 __ add(Operand(eax), Immediate(kPointerSize));
273 __ bind(&entry);
274 __ cmp(eax, Operand(ecx));
275 __ j(below, &loop);
276 }
277
278 // Store the initialized FixedArray into the properties field of
279 // the JSObject
280 // ebx: JSObject
281 // edi: FixedArray
282 __ or_(Operand(edi), Immediate(kHeapObjectTag)); // add the heap tag
283 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
284
285
286 // Continue with JSObject being successfully allocated
287 // ebx: JSObject
288 __ jmp(&allocated);
289
290 // Undo the setting of the new top so that the heap is verifiable. For
291 // example, the map's unused properties potentially do not match the
292 // allocated objects unused properties.
293 // ebx: JSObject (previous new top)
294 __ bind(&undo_allocation);
295 __ UndoAllocationInNewSpace(ebx);
296 }
297
298 // Allocate the new receiver object using the runtime call.
299 __ bind(&rt_call);
300 // Must restore edi (constructor) before calling runtime.
301 __ mov(edi, Operand(esp, 0));
302 // edi: function (constructor)
303 __ push(edi);
304 __ CallRuntime(Runtime::kNewObject, 1);
305 __ mov(ebx, Operand(eax)); // store result in ebx
306
307 // New object allocated.
308 // ebx: newly allocated object
309 __ bind(&allocated);
310 // Retrieve the function from the stack.
311 __ pop(edi);
312
313 // Retrieve smi-tagged arguments count from the stack.
314 __ mov(eax, Operand(esp, 0));
Leon Clarkee46be812010-01-19 14:06:41 +0000315 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000316
317 // Push the allocated receiver to the stack. We need two copies
318 // because we may have to return the original one and the calling
319 // conventions dictate that the called function pops the receiver.
320 __ push(ebx);
321 __ push(ebx);
322
323 // Setup pointer to last argument.
324 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
325
326 // Copy arguments and receiver to the expression stack.
327 Label loop, entry;
328 __ mov(ecx, Operand(eax));
329 __ jmp(&entry);
330 __ bind(&loop);
331 __ push(Operand(ebx, ecx, times_4, 0));
332 __ bind(&entry);
333 __ dec(ecx);
334 __ j(greater_equal, &loop);
335
336 // Call the function.
Leon Clarkee46be812010-01-19 14:06:41 +0000337 if (is_api_function) {
338 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Steve Block44f0eee2011-05-26 01:26:41 +0100339 Handle<Code> code =
340 masm->isolate()->builtins()->HandleApiCallConstruct();
Leon Clarkee46be812010-01-19 14:06:41 +0000341 ParameterCount expected(0);
342 __ InvokeCode(code, expected, expected,
343 RelocInfo::CODE_TARGET, CALL_FUNCTION);
344 } else {
345 ParameterCount actual(eax);
346 __ InvokeFunction(edi, actual, CALL_FUNCTION);
347 }
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.
358 __ test(eax, Immediate(kSmiTagMask));
359 __ j(zero, &use_receiver, not_taken);
360
361 // If the type of the result (stored in its map) is less than
362 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100363 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
364 __ j(above_equal, &exit, not_taken);
Steve Blocka7e24c12009-10-30 11:49:00 +0000365
366 // Throw away the result of the constructor invocation and use the
367 // on-stack receiver as the result.
368 __ bind(&use_receiver);
369 __ mov(eax, Operand(esp, 0));
370
371 // Restore the arguments count and leave the construct frame.
372 __ bind(&exit);
373 __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
374 __ LeaveConstructFrame();
375
376 // Remove caller arguments from the stack and return.
377 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
378 __ pop(ecx);
379 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
380 __ push(ecx);
Steve Block44f0eee2011-05-26 01:26:41 +0100381 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000382 __ ret(0);
383}
384
385
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100386void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
387 Generate_JSConstructStubHelper(masm, false, true);
388}
389
390
Leon Clarkee46be812010-01-19 14:06:41 +0000391void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100392 Generate_JSConstructStubHelper(masm, false, false);
Leon Clarkee46be812010-01-19 14:06:41 +0000393}
394
395
396void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100397 Generate_JSConstructStubHelper(masm, true, false);
Leon Clarkee46be812010-01-19 14:06:41 +0000398}
399
400
Steve Blocka7e24c12009-10-30 11:49:00 +0000401static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
402 bool is_construct) {
403 // Clear the context before we push it when entering the JS frame.
Steve Block9fac8402011-05-12 15:51:54 +0100404 __ Set(esi, Immediate(0));
Steve Blocka7e24c12009-10-30 11:49:00 +0000405
406 // Enter an internal frame.
407 __ EnterInternalFrame();
408
409 // Load the previous frame pointer (ebx) to access C arguments
410 __ mov(ebx, Operand(ebp, 0));
411
412 // Get the function from the frame and setup the context.
413 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
414 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
415
416 // Push the function and the receiver onto the stack.
417 __ push(ecx);
418 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
419
420 // Load the number of arguments and setup pointer to the arguments.
421 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
422 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
423
424 // Copy arguments to the stack in a loop.
425 Label loop, entry;
Steve Block9fac8402011-05-12 15:51:54 +0100426 __ Set(ecx, Immediate(0));
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 __ jmp(&entry);
428 __ bind(&loop);
429 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
430 __ push(Operand(edx, 0)); // dereference handle
431 __ inc(Operand(ecx));
432 __ bind(&entry);
433 __ cmp(ecx, Operand(eax));
434 __ j(not_equal, &loop);
435
436 // Get the function from the stack and call it.
437 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); // +1 ~ receiver
438
439 // Invoke the code.
440 if (is_construct) {
Steve Block44f0eee2011-05-26 01:26:41 +0100441 __ call(masm->isolate()->builtins()->JSConstructCall(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000442 RelocInfo::CODE_TARGET);
443 } else {
444 ParameterCount actual(eax);
445 __ InvokeFunction(edi, actual, CALL_FUNCTION);
446 }
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
470 // Push a copy of the function onto the stack.
471 __ push(edi);
472
473 __ push(edi); // Function is also the parameter to the runtime call.
474 __ CallRuntime(Runtime::kLazyCompile, 1);
475 __ pop(edi);
476
477 // Tear down temporary frame.
478 __ LeaveInternalFrame();
479
480 // Do a tail-call of the compiled function.
481 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
482 __ jmp(Operand(ecx));
483}
484
485
Ben Murdochb0fe1622011-05-05 13:52:32 +0100486void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
487 // Enter an internal frame.
488 __ EnterInternalFrame();
489
490 // Push a copy of the function onto the stack.
491 __ push(edi);
492
493 __ push(edi); // Function is also the parameter to the runtime call.
494 __ CallRuntime(Runtime::kLazyRecompile, 1);
495
496 // Restore function and tear down temporary frame.
497 __ pop(edi);
498 __ LeaveInternalFrame();
499
500 // Do a tail-call of the compiled function.
501 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
502 __ jmp(Operand(ecx));
503}
504
505
506static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
507 Deoptimizer::BailoutType type) {
508 // Enter an internal frame.
509 __ EnterInternalFrame();
510
511 // Pass the function and deoptimization type to the runtime system.
512 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
513 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
514
515 // Tear down temporary frame.
516 __ LeaveInternalFrame();
517
518 // Get the full codegen state from the stack and untag it.
519 __ mov(ecx, Operand(esp, 1 * kPointerSize));
520 __ SmiUntag(ecx);
521
522 // Switch on the state.
523 NearLabel not_no_registers, not_tos_eax;
524 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
525 __ j(not_equal, &not_no_registers);
526 __ ret(1 * kPointerSize); // Remove state.
527
528 __ bind(&not_no_registers);
529 __ mov(eax, Operand(esp, 2 * kPointerSize));
530 __ cmp(ecx, FullCodeGenerator::TOS_REG);
531 __ j(not_equal, &not_tos_eax);
532 __ ret(2 * kPointerSize); // Remove state, eax.
533
534 __ bind(&not_tos_eax);
535 __ Abort("no cases left");
536}
537
538
539void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
540 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
541}
542
543
544void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
545 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
546}
547
548
549void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
550 // TODO(kasperl): Do we need to save/restore the XMM registers too?
551
552 // For now, we are relying on the fact that Runtime::NotifyOSR
553 // doesn't do any garbage collection which allows us to save/restore
554 // the registers without worrying about which of them contain
555 // pointers. This seems a bit fragile.
556 __ pushad();
557 __ EnterInternalFrame();
558 __ CallRuntime(Runtime::kNotifyOSR, 0);
559 __ LeaveInternalFrame();
560 __ popad();
561 __ ret(0);
562}
563
564
Steve Blocka7e24c12009-10-30 11:49:00 +0000565void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
Steve Block44f0eee2011-05-26 01:26:41 +0100566 Factory* factory = masm->isolate()->factory();
567
Steve Blocka7e24c12009-10-30 11:49:00 +0000568 // 1. Make sure we have at least one argument.
569 { Label done;
570 __ test(eax, Operand(eax));
571 __ j(not_zero, &done, taken);
572 __ pop(ebx);
Steve Block44f0eee2011-05-26 01:26:41 +0100573 __ push(Immediate(factory->undefined_value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000574 __ push(ebx);
575 __ inc(eax);
576 __ bind(&done);
577 }
578
Andrei Popescu402d9372010-02-26 13:31:12 +0000579 // 2. Get the function to call (passed as receiver) from the stack, check
580 // if it is a function.
581 Label non_function;
582 // 1 ~ return address.
583 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
584 __ test(edi, Immediate(kSmiTagMask));
585 __ j(zero, &non_function, not_taken);
586 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
587 __ j(not_equal, &non_function, not_taken);
Steve Blocka7e24c12009-10-30 11:49:00 +0000588
Steve Blocka7e24c12009-10-30 11:49:00 +0000589
Andrei Popescu402d9372010-02-26 13:31:12 +0000590 // 3a. Patch the first argument if necessary when calling a function.
591 Label shift_arguments;
592 { Label convert_to_object, use_global_receiver, patch_receiver;
593 // Change context eagerly in case we need the global receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000594 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
595
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100596 // Do not transform the receiver for strict mode functions.
597 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
598 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
599 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
600 __ j(not_equal, &shift_arguments);
601
602 // Compute the receiver in non-strict mode.
Andrei Popescu402d9372010-02-26 13:31:12 +0000603 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
Steve Blocka7e24c12009-10-30 11:49:00 +0000604 __ test(ebx, Immediate(kSmiTagMask));
Andrei Popescu402d9372010-02-26 13:31:12 +0000605 __ j(zero, &convert_to_object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000606
Steve Block44f0eee2011-05-26 01:26:41 +0100607 __ cmp(ebx, factory->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000608 __ j(equal, &use_global_receiver);
Steve Block44f0eee2011-05-26 01:26:41 +0100609 __ cmp(ebx, factory->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000610 __ j(equal, &use_global_receiver);
611
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100612 // We don't use IsObjectJSObjectType here because we jump on success.
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
614 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100615 __ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
616 __ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000617 __ j(below_equal, &shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000618
Andrei Popescu402d9372010-02-26 13:31:12 +0000619 __ bind(&convert_to_object);
620 __ EnterInternalFrame(); // In order to preserve argument count.
Leon Clarkee46be812010-01-19 14:06:41 +0000621 __ SmiTag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000622 __ push(eax);
623
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 __ push(ebx);
625 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
626 __ mov(ebx, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000627
Steve Blocka7e24c12009-10-30 11:49:00 +0000628 __ pop(eax);
Leon Clarkee46be812010-01-19 14:06:41 +0000629 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000630 __ LeaveInternalFrame();
Andrei Popescu402d9372010-02-26 13:31:12 +0000631 // Restore the function to edi.
632 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +0000633 __ jmp(&patch_receiver);
634
Andrei Popescu402d9372010-02-26 13:31:12 +0000635 // Use the global receiver object from the called function as the
636 // receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000637 __ bind(&use_global_receiver);
638 const int kGlobalIndex =
639 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
640 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
Steve Blockd0582a62009-12-15 09:54:21 +0000641 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
642 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +0000643 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
644
645 __ bind(&patch_receiver);
646 __ mov(Operand(esp, eax, times_4, 0), ebx);
647
Andrei Popescu402d9372010-02-26 13:31:12 +0000648 __ jmp(&shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000649 }
650
Andrei Popescu402d9372010-02-26 13:31:12 +0000651 // 3b. Patch the first argument when calling a non-function. The
652 // CALL_NON_FUNCTION builtin expects the non-function callee as
653 // receiver, so overwrite the first argument which will ultimately
654 // become the receiver.
655 __ bind(&non_function);
656 __ mov(Operand(esp, eax, times_4, 0), edi);
657 // Clear edi to indicate a non-function being called.
Steve Block9fac8402011-05-12 15:51:54 +0100658 __ Set(edi, Immediate(0));
Leon Clarkee46be812010-01-19 14:06:41 +0000659
Andrei Popescu402d9372010-02-26 13:31:12 +0000660 // 4. Shift arguments and return address one slot down on the stack
661 // (overwriting the original receiver). Adjust argument count to make
662 // the original first argument the new receiver.
663 __ bind(&shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000664 { Label loop;
Leon Clarkee46be812010-01-19 14:06:41 +0000665 __ mov(ecx, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000666 __ bind(&loop);
667 __ mov(ebx, Operand(esp, ecx, times_4, 0));
668 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
669 __ dec(ecx);
Andrei Popescu402d9372010-02-26 13:31:12 +0000670 __ j(not_sign, &loop); // While non-negative (to copy return address).
Leon Clarkee46be812010-01-19 14:06:41 +0000671 __ pop(ebx); // Discard copy of return address.
672 __ dec(eax); // One fewer argument (first argument is new receiver).
Steve Blocka7e24c12009-10-30 11:49:00 +0000673 }
674
Andrei Popescu402d9372010-02-26 13:31:12 +0000675 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
676 { Label function;
677 __ test(edi, Operand(edi));
678 __ j(not_zero, &function, taken);
Steve Block9fac8402011-05-12 15:51:54 +0100679 __ Set(ebx, Immediate(0));
Andrei Popescu402d9372010-02-26 13:31:12 +0000680 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
Steve Block44f0eee2011-05-26 01:26:41 +0100681 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
Andrei Popescu402d9372010-02-26 13:31:12 +0000682 RelocInfo::CODE_TARGET);
683 __ bind(&function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000684 }
685
Andrei Popescu402d9372010-02-26 13:31:12 +0000686 // 5b. Get the code to call from the function and check that the number of
687 // expected arguments matches what we're providing. If so, jump
688 // (tail-call) to the code in register edx without checking arguments.
689 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
690 __ mov(ebx,
691 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
Steve Block791712a2010-08-27 10:21:07 +0100692 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100693 __ SmiUntag(ebx);
Andrei Popescu402d9372010-02-26 13:31:12 +0000694 __ cmp(eax, Operand(ebx));
Steve Block44f0eee2011-05-26 01:26:41 +0100695 __ j(not_equal,
696 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
Andrei Popescu402d9372010-02-26 13:31:12 +0000697
Steve Blocka7e24c12009-10-30 11:49:00 +0000698 ParameterCount expected(0);
699 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
700}
701
702
703void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
704 __ EnterInternalFrame();
705
706 __ push(Operand(ebp, 4 * kPointerSize)); // push this
707 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments
708 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
709
Steve Blockd0582a62009-12-15 09:54:21 +0000710 // Check the stack for overflow. We are not trying need to catch
711 // interruptions (e.g. debug break and preemption) here, so the "real stack
712 // limit" is checked.
713 Label okay;
714 ExternalReference real_stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +0100715 ExternalReference::address_of_real_stack_limit(masm->isolate());
Steve Blockd0582a62009-12-15 09:54:21 +0000716 __ mov(edi, Operand::StaticVariable(real_stack_limit));
717 // Make ecx the space we have left. The stack might already be overflowed
718 // here which will cause ecx to become negative.
719 __ mov(ecx, Operand(esp));
720 __ sub(ecx, Operand(edi));
721 // Make edx the space we need for the array when it is unrolled onto the
722 // stack.
723 __ mov(edx, Operand(eax));
724 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
725 // Check if the arguments will overflow the stack.
726 __ cmp(ecx, Operand(edx));
727 __ j(greater, &okay, taken); // Signed comparison.
Steve Blocka7e24c12009-10-30 11:49:00 +0000728
Steve Blockd0582a62009-12-15 09:54:21 +0000729 // Out of stack space.
730 __ push(Operand(ebp, 4 * kPointerSize)); // push this
731 __ push(eax);
732 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
733 __ bind(&okay);
734 // End of stack check.
Steve Blocka7e24c12009-10-30 11:49:00 +0000735
736 // Push current index and limit.
737 const int kLimitOffset =
738 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
739 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
740 __ push(eax); // limit
741 __ push(Immediate(0)); // index
742
743 // Change context eagerly to get the right global object if
744 // necessary.
745 __ mov(edi, Operand(ebp, 4 * kPointerSize));
746 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
747
748 // Compute the receiver.
749 Label call_to_object, use_global_receiver, push_receiver;
750 __ mov(ebx, Operand(ebp, 3 * kPointerSize));
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100751
752 // Do not transform the receiver for strict mode functions.
753 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
754 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
755 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
756 __ j(not_equal, &push_receiver);
757
758 // Compute the receiver in non-strict mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000759 __ test(ebx, Immediate(kSmiTagMask));
760 __ j(zero, &call_to_object);
Steve Block44f0eee2011-05-26 01:26:41 +0100761 Factory* factory = masm->isolate()->factory();
762 __ cmp(ebx, factory->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000763 __ j(equal, &use_global_receiver);
Steve Block44f0eee2011-05-26 01:26:41 +0100764 __ cmp(ebx, factory->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000765 __ j(equal, &use_global_receiver);
766
767 // If given receiver is already a JavaScript object then there's no
768 // reason for converting it.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100769 // We don't use IsObjectJSObjectType here because we jump on success.
Steve Blocka7e24c12009-10-30 11:49:00 +0000770 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
771 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100772 __ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
773 __ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
774 __ j(below_equal, &push_receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000775
776 // Convert the receiver to an object.
777 __ bind(&call_to_object);
778 __ push(ebx);
779 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
780 __ mov(ebx, Operand(eax));
781 __ jmp(&push_receiver);
782
783 // Use the current global receiver object as the receiver.
784 __ bind(&use_global_receiver);
785 const int kGlobalOffset =
786 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
787 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
Steve Blockd0582a62009-12-15 09:54:21 +0000788 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
789 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000790 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
791
792 // Push the receiver.
793 __ bind(&push_receiver);
794 __ push(ebx);
795
796 // Copy all arguments from the array to the stack.
797 Label entry, loop;
798 __ mov(eax, Operand(ebp, kIndexOffset));
799 __ jmp(&entry);
800 __ bind(&loop);
Andrei Popescu402d9372010-02-26 13:31:12 +0000801 __ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments
Steve Blocka7e24c12009-10-30 11:49:00 +0000802
803 // Use inline caching to speed up access to arguments.
Steve Block44f0eee2011-05-26 01:26:41 +0100804 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +0000805 __ call(ic, RelocInfo::CODE_TARGET);
806 // It is important that we do not have a test instruction after the
807 // call. A test instruction after the call is used to indicate that
808 // we have generated an inline version of the keyed load. In this
809 // case, we know that we are not generating a test instruction next.
810
Andrei Popescu402d9372010-02-26 13:31:12 +0000811 // Push the nth argument.
Steve Blocka7e24c12009-10-30 11:49:00 +0000812 __ push(eax);
813
814 // Update the index on the stack and in register eax.
815 __ mov(eax, Operand(ebp, kIndexOffset));
816 __ add(Operand(eax), Immediate(1 << kSmiTagSize));
817 __ mov(Operand(ebp, kIndexOffset), eax);
818
819 __ bind(&entry);
820 __ cmp(eax, Operand(ebp, kLimitOffset));
821 __ j(not_equal, &loop);
822
823 // Invoke the function.
824 ParameterCount actual(eax);
Leon Clarkee46be812010-01-19 14:06:41 +0000825 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000826 __ mov(edi, Operand(ebp, 4 * kPointerSize));
827 __ InvokeFunction(edi, actual, CALL_FUNCTION);
828
829 __ LeaveInternalFrame();
830 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
831}
832
833
Steve Blocka7e24c12009-10-30 11:49:00 +0000834// Number of empty elements to allocate for an empty array.
835static const int kPreallocatedArrayElements = 4;
836
837
838// Allocate an empty JSArray. The allocated array is put into the result
839// register. If the parameter initial_capacity is larger than zero an elements
840// backing store is allocated with this size and filled with the hole values.
841// Otherwise the elements backing store is set to the empty FixedArray.
842static void AllocateEmptyJSArray(MacroAssembler* masm,
843 Register array_function,
844 Register result,
845 Register scratch1,
846 Register scratch2,
847 Register scratch3,
848 int initial_capacity,
849 Label* gc_required) {
850 ASSERT(initial_capacity >= 0);
851
852 // Load the initial map from the array function.
853 __ mov(scratch1, FieldOperand(array_function,
854 JSFunction::kPrototypeOrInitialMapOffset));
855
856 // Allocate the JSArray object together with space for a fixed array with the
857 // requested elements.
858 int size = JSArray::kSize;
859 if (initial_capacity > 0) {
860 size += FixedArray::SizeFor(initial_capacity);
861 }
862 __ AllocateInNewSpace(size,
863 result,
864 scratch2,
865 scratch3,
866 gc_required,
867 TAG_OBJECT);
868
869 // Allocated the JSArray. Now initialize the fields except for the elements
870 // array.
871 // result: JSObject
872 // scratch1: initial map
873 // scratch2: start of next object
874 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
Steve Block44f0eee2011-05-26 01:26:41 +0100875 Factory* factory = masm->isolate()->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +0000876 __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
Steve Block44f0eee2011-05-26 01:26:41 +0100877 factory->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +0000878 // Field JSArray::kElementsOffset is initialized later.
879 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
880
881 // If no storage is requested for the elements array just set the empty
882 // fixed array.
883 if (initial_capacity == 0) {
884 __ mov(FieldOperand(result, JSArray::kElementsOffset),
Steve Block44f0eee2011-05-26 01:26:41 +0100885 factory->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +0000886 return;
887 }
888
889 // Calculate the location of the elements array and set elements array member
890 // of the JSArray.
891 // result: JSObject
892 // scratch2: start of next object
893 __ lea(scratch1, Operand(result, JSArray::kSize));
894 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
895
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100896 // Initialize the FixedArray and fill it with holes. FixedArray length is
Steve Blocka7e24c12009-10-30 11:49:00 +0000897 // stored as a smi.
898 // result: JSObject
899 // scratch1: elements array
900 // scratch2: start of next object
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100901 __ mov(FieldOperand(scratch1, FixedArray::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +0100902 factory->fixed_array_map());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100903 __ mov(FieldOperand(scratch1, FixedArray::kLengthOffset),
904 Immediate(Smi::FromInt(initial_capacity)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000905
906 // Fill the FixedArray with the hole value. Inline the code if short.
907 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
908 static const int kLoopUnfoldLimit = 4;
909 ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
910 if (initial_capacity <= kLoopUnfoldLimit) {
911 // Use a scratch register here to have only one reloc info when unfolding
912 // the loop.
Steve Block44f0eee2011-05-26 01:26:41 +0100913 __ mov(scratch3, factory->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000914 for (int i = 0; i < initial_capacity; i++) {
915 __ mov(FieldOperand(scratch1,
916 FixedArray::kHeaderSize + i * kPointerSize),
917 scratch3);
918 }
919 } else {
920 Label loop, entry;
921 __ jmp(&entry);
922 __ bind(&loop);
Steve Block44f0eee2011-05-26 01:26:41 +0100923 __ mov(Operand(scratch1, 0), factory->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000924 __ add(Operand(scratch1), Immediate(kPointerSize));
925 __ bind(&entry);
926 __ cmp(scratch1, Operand(scratch2));
927 __ j(below, &loop);
928 }
929}
930
931
932// Allocate a JSArray with the number of elements stored in a register. The
933// register array_function holds the built-in Array function and the register
934// array_size holds the size of the array as a smi. The allocated array is put
935// into the result register and beginning and end of the FixedArray elements
936// storage is put into registers elements_array and elements_array_end (see
937// below for when that is not the case). If the parameter fill_with_holes is
938// true the allocated elements backing store is filled with the hole values
939// otherwise it is left uninitialized. When the backing store is filled the
940// register elements_array is scratched.
941static void AllocateJSArray(MacroAssembler* masm,
942 Register array_function, // Array function.
Steve Block6ded16b2010-05-10 14:33:55 +0100943 Register array_size, // As a smi, cannot be 0.
Steve Blocka7e24c12009-10-30 11:49:00 +0000944 Register result,
945 Register elements_array,
946 Register elements_array_end,
947 Register scratch,
948 bool fill_with_hole,
949 Label* gc_required) {
Steve Block6ded16b2010-05-10 14:33:55 +0100950 ASSERT(scratch.is(edi)); // rep stos destination
951 ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
Leon Clarkef7060e22010-06-03 12:02:55 +0100952 ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax
Steve Blocka7e24c12009-10-30 11:49:00 +0000953
954 // Load the initial map from the array function.
955 __ mov(elements_array,
956 FieldOperand(array_function,
957 JSFunction::kPrototypeOrInitialMapOffset));
958
Steve Blocka7e24c12009-10-30 11:49:00 +0000959 // Allocate the JSArray object together with space for a FixedArray with the
960 // requested elements.
Steve Blocka7e24c12009-10-30 11:49:00 +0000961 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
962 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
963 times_half_pointer_size, // array_size is a smi.
964 array_size,
965 result,
966 elements_array_end,
967 scratch,
968 gc_required,
969 TAG_OBJECT);
970
971 // Allocated the JSArray. Now initialize the fields except for the elements
972 // array.
973 // result: JSObject
974 // elements_array: initial map
975 // elements_array_end: start of next object
976 // array_size: size of array (smi)
Steve Blocka7e24c12009-10-30 11:49:00 +0000977 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
Steve Block44f0eee2011-05-26 01:26:41 +0100978 Factory* factory = masm->isolate()->factory();
979 __ mov(elements_array, factory->empty_fixed_array());
Steve Blocka7e24c12009-10-30 11:49:00 +0000980 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
981 // Field JSArray::kElementsOffset is initialized later.
982 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
983
984 // Calculate the location of the elements array and set elements array member
985 // of the JSArray.
986 // result: JSObject
987 // elements_array_end: start of next object
988 // array_size: size of array (smi)
989 __ lea(elements_array, Operand(result, JSArray::kSize));
990 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
991
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100992 // Initialize the fixed array. FixedArray length is stored as a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +0000993 // result: JSObject
994 // elements_array: elements array
995 // elements_array_end: start of next object
996 // array_size: size of array (smi)
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100997 __ mov(FieldOperand(elements_array, FixedArray::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +0100998 factory->fixed_array_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000999 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
1000 // same.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001001 __ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001002
1003 // Fill the allocated FixedArray with the hole value if requested.
1004 // result: JSObject
1005 // elements_array: elements array
Steve Blocka7e24c12009-10-30 11:49:00 +00001006 if (fill_with_hole) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001007 __ SmiUntag(array_size);
Steve Block6ded16b2010-05-10 14:33:55 +01001008 __ lea(edi, Operand(elements_array,
1009 FixedArray::kHeaderSize - kHeapObjectTag));
Steve Block44f0eee2011-05-26 01:26:41 +01001010 __ mov(eax, factory->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01001011 __ cld();
Leon Clarkef7060e22010-06-03 12:02:55 +01001012 // Do not use rep stos when filling less than kRepStosThreshold
1013 // words.
1014 const int kRepStosThreshold = 16;
1015 Label loop, entry, done;
1016 __ cmp(ecx, kRepStosThreshold);
1017 __ j(below, &loop); // Note: ecx > 0.
Steve Block6ded16b2010-05-10 14:33:55 +01001018 __ rep_stos();
Leon Clarkef7060e22010-06-03 12:02:55 +01001019 __ jmp(&done);
1020 __ bind(&loop);
1021 __ stos();
1022 __ bind(&entry);
1023 __ cmp(edi, Operand(elements_array_end));
1024 __ j(below, &loop);
1025 __ bind(&done);
Steve Blocka7e24c12009-10-30 11:49:00 +00001026 }
1027}
1028
1029
1030// Create a new array for the built-in Array function. This function allocates
1031// the JSArray object and the FixedArray elements array and initializes these.
1032// If the Array cannot be constructed in native code the runtime is called. This
1033// function assumes the following state:
1034// edi: constructor (built-in Array function)
1035// eax: argc
1036// esp[0]: return address
1037// esp[4]: last argument
1038// This function is used for both construct and normal calls of Array. Whether
1039// it is a construct call or not is indicated by the construct_call parameter.
1040// The only difference between handling a construct call and a normal call is
1041// that for a construct call the constructor function in edi needs to be
1042// preserved for entering the generic code. In both cases argc in eax needs to
1043// be preserved.
1044static void ArrayNativeCode(MacroAssembler* masm,
1045 bool construct_call,
Steve Blockd0582a62009-12-15 09:54:21 +00001046 Label* call_generic_code) {
Steve Block6ded16b2010-05-10 14:33:55 +01001047 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
1048 empty_array, not_empty_array;
Steve Blocka7e24c12009-10-30 11:49:00 +00001049
1050 // Push the constructor and argc. No need to tag argc as a smi, as there will
1051 // be no garbage collection with this on the stack.
1052 int push_count = 0;
1053 if (construct_call) {
1054 push_count++;
1055 __ push(edi);
1056 }
1057 push_count++;
1058 __ push(eax);
1059
1060 // Check for array construction with zero arguments.
1061 __ test(eax, Operand(eax));
1062 __ j(not_zero, &argc_one_or_more);
1063
Steve Block6ded16b2010-05-10 14:33:55 +01001064 __ bind(&empty_array);
Steve Blocka7e24c12009-10-30 11:49:00 +00001065 // Handle construction of an empty array.
1066 AllocateEmptyJSArray(masm,
1067 edi,
1068 eax,
1069 ebx,
1070 ecx,
1071 edi,
1072 kPreallocatedArrayElements,
1073 &prepare_generic_code_call);
Steve Block44f0eee2011-05-26 01:26:41 +01001074 __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001075 __ pop(ebx);
1076 if (construct_call) {
1077 __ pop(edi);
1078 }
1079 __ ret(kPointerSize);
1080
1081 // Check for one argument. Bail out if argument is not smi or if it is
1082 // negative.
1083 __ bind(&argc_one_or_more);
1084 __ cmp(eax, 1);
1085 __ j(not_equal, &argc_two_or_more);
1086 ASSERT(kSmiTag == 0);
Steve Block6ded16b2010-05-10 14:33:55 +01001087 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
1088 __ test(ecx, Operand(ecx));
1089 __ j(not_zero, &not_empty_array);
1090
1091 // The single argument passed is zero, so we jump to the code above used to
1092 // handle the case of no arguments passed. To adapt the stack for that we move
1093 // the return address and the pushed constructor (if pushed) one stack slot up
1094 // thereby removing the passed argument. Argc is also on the stack - at the
1095 // bottom - and it needs to be changed from 1 to 0 to have the call into the
1096 // runtime system work in case a GC is required.
1097 for (int i = push_count; i > 0; i--) {
1098 __ mov(eax, Operand(esp, i * kPointerSize));
1099 __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
1100 }
1101 __ add(Operand(esp), Immediate(2 * kPointerSize)); // Drop two stack slots.
1102 __ push(Immediate(0)); // Treat this as a call with argc of zero.
1103 __ jmp(&empty_array);
1104
1105 __ bind(&not_empty_array);
1106 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001107 __ j(not_zero, &prepare_generic_code_call);
1108
1109 // Handle construction of an empty array of a certain size. Get the size from
1110 // the stack and bail out if size is to large to actually allocate an elements
1111 // array.
Steve Block6ded16b2010-05-10 14:33:55 +01001112 __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00001113 __ j(greater_equal, &prepare_generic_code_call);
1114
1115 // edx: array_size (smi)
1116 // edi: constructor
Steve Block6ded16b2010-05-10 14:33:55 +01001117 // esp[0]: argc (cannot be 0 here)
Steve Blocka7e24c12009-10-30 11:49:00 +00001118 // esp[4]: constructor (only if construct_call)
1119 // esp[8]: return address
1120 // esp[C]: argument
1121 AllocateJSArray(masm,
1122 edi,
Steve Block6ded16b2010-05-10 14:33:55 +01001123 ecx,
Steve Blocka7e24c12009-10-30 11:49:00 +00001124 ebx,
Leon Clarkef7060e22010-06-03 12:02:55 +01001125 eax,
Steve Block6ded16b2010-05-10 14:33:55 +01001126 edx,
Steve Blocka7e24c12009-10-30 11:49:00 +00001127 edi,
1128 true,
1129 &prepare_generic_code_call);
Steve Block44f0eee2011-05-26 01:26:41 +01001130 Counters* counters = masm->isolate()->counters();
1131 __ IncrementCounter(counters->array_function_native(), 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01001132 __ mov(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001133 __ pop(ebx);
1134 if (construct_call) {
1135 __ pop(edi);
1136 }
1137 __ ret(2 * kPointerSize);
1138
1139 // Handle construction of an array from a list of arguments.
1140 __ bind(&argc_two_or_more);
1141 ASSERT(kSmiTag == 0);
Leon Clarkee46be812010-01-19 14:06:41 +00001142 __ SmiTag(eax); // Convet argc to a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +00001143 // eax: array_size (smi)
1144 // edi: constructor
1145 // esp[0] : argc
1146 // esp[4]: constructor (only if construct_call)
1147 // esp[8] : return address
1148 // esp[C] : last argument
1149 AllocateJSArray(masm,
1150 edi,
1151 eax,
1152 ebx,
1153 ecx,
1154 edx,
1155 edi,
1156 false,
1157 &prepare_generic_code_call);
Steve Block44f0eee2011-05-26 01:26:41 +01001158 __ IncrementCounter(counters->array_function_native(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001159 __ mov(eax, ebx);
1160 __ pop(ebx);
1161 if (construct_call) {
1162 __ pop(edi);
1163 }
1164 __ push(eax);
1165 // eax: JSArray
1166 // ebx: argc
1167 // edx: elements_array_end (untagged)
1168 // esp[0]: JSArray
1169 // esp[4]: return address
1170 // esp[8]: last argument
1171
1172 // Location of the last argument
1173 __ lea(edi, Operand(esp, 2 * kPointerSize));
1174
1175 // Location of the first array element (Parameter fill_with_holes to
1176 // AllocateJSArrayis false, so the FixedArray is returned in ecx).
1177 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
1178
1179 // ebx: argc
1180 // edx: location of the first array element
1181 // edi: location of the last argument
1182 // esp[0]: JSArray
1183 // esp[4]: return address
1184 // esp[8]: last argument
1185 Label loop, entry;
1186 __ mov(ecx, ebx);
1187 __ jmp(&entry);
1188 __ bind(&loop);
1189 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1190 __ mov(Operand(edx, 0), eax);
1191 __ add(Operand(edx), Immediate(kPointerSize));
1192 __ bind(&entry);
1193 __ dec(ecx);
1194 __ j(greater_equal, &loop);
1195
1196 // Remove caller arguments from the stack and return.
1197 // ebx: argc
1198 // esp[0]: JSArray
1199 // esp[4]: return address
1200 // esp[8]: last argument
1201 __ pop(eax);
1202 __ pop(ecx);
1203 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1204 __ push(ecx);
1205 __ ret(0);
1206
1207 // Restore argc and constructor before running the generic code.
1208 __ bind(&prepare_generic_code_call);
1209 __ pop(eax);
1210 if (construct_call) {
1211 __ pop(edi);
1212 }
1213 __ jmp(call_generic_code);
1214}
1215
1216
1217void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1218 // ----------- S t a t e -------------
1219 // -- eax : argc
1220 // -- esp[0] : return address
1221 // -- esp[4] : last argument
1222 // -----------------------------------
Kristian Monsen25f61362010-05-21 11:50:48 +01001223 Label generic_array_code;
Steve Blocka7e24c12009-10-30 11:49:00 +00001224
1225 // Get the Array function.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001226 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001227
1228 if (FLAG_debug_code) {
1229 // Initial map for the builtin Array function shoud be a map.
1230 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1231 // Will both indicate a NULL and a Smi.
1232 __ test(ebx, Immediate(kSmiTagMask));
1233 __ Assert(not_zero, "Unexpected initial map for Array function");
1234 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1235 __ Assert(equal, "Unexpected initial map for Array function");
1236 }
1237
1238 // Run the native code for the Array function called as a normal function.
1239 ArrayNativeCode(masm, false, &generic_array_code);
1240
1241 // Jump to the generic array code in case the specialized code cannot handle
1242 // the construction.
1243 __ bind(&generic_array_code);
Steve Block44f0eee2011-05-26 01:26:41 +01001244 Handle<Code> array_code =
1245 masm->isolate()->builtins()->ArrayCodeGeneric();
Steve Blocka7e24c12009-10-30 11:49:00 +00001246 __ jmp(array_code, RelocInfo::CODE_TARGET);
1247}
1248
1249
1250void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
1251 // ----------- S t a t e -------------
1252 // -- eax : argc
1253 // -- edi : constructor
1254 // -- esp[0] : return address
1255 // -- esp[4] : last argument
1256 // -----------------------------------
1257 Label generic_constructor;
1258
1259 if (FLAG_debug_code) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001260 // The array construct code is only set for the global and natives
1261 // builtin Array functions which always have maps.
1262
Steve Blocka7e24c12009-10-30 11:49:00 +00001263 // Initial map for the builtin Array function should be a map.
1264 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1265 // Will both indicate a NULL and a Smi.
1266 __ test(ebx, Immediate(kSmiTagMask));
1267 __ Assert(not_zero, "Unexpected initial map for Array function");
1268 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1269 __ Assert(equal, "Unexpected initial map for Array function");
1270 }
1271
1272 // Run the native code for the Array function called as constructor.
1273 ArrayNativeCode(masm, true, &generic_constructor);
1274
1275 // Jump to the generic construct code in case the specialized code cannot
1276 // handle the construction.
1277 __ bind(&generic_constructor);
Steve Block44f0eee2011-05-26 01:26:41 +01001278 Handle<Code> generic_construct_stub =
1279 masm->isolate()->builtins()->JSConstructStubGeneric();
Steve Blocka7e24c12009-10-30 11:49:00 +00001280 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1281}
1282
1283
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001284void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1285 // ----------- S t a t e -------------
1286 // -- eax : number of arguments
1287 // -- edi : constructor function
1288 // -- esp[0] : return address
1289 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1290 // -- esp[(argc + 1) * 4] : receiver
1291 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +01001292 Counters* counters = masm->isolate()->counters();
1293 __ IncrementCounter(counters->string_ctor_calls(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001294
1295 if (FLAG_debug_code) {
1296 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1297 __ cmp(edi, Operand(ecx));
1298 __ Assert(equal, "Unexpected String function");
1299 }
1300
1301 // Load the first argument into eax and get rid of the rest
1302 // (including the receiver).
1303 Label no_arguments;
1304 __ test(eax, Operand(eax));
1305 __ j(zero, &no_arguments);
1306 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1307 __ pop(ecx);
1308 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1309 __ push(ecx);
1310 __ mov(eax, ebx);
1311
1312 // Lookup the argument in the number to string cache.
1313 Label not_cached, argument_is_string;
1314 NumberToStringStub::GenerateLookupNumberStringCache(
1315 masm,
1316 eax, // Input.
1317 ebx, // Result.
1318 ecx, // Scratch 1.
1319 edx, // Scratch 2.
1320 false, // Input is known to be smi?
1321 &not_cached);
Steve Block44f0eee2011-05-26 01:26:41 +01001322 __ IncrementCounter(counters->string_ctor_cached_number(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001323 __ bind(&argument_is_string);
1324 // ----------- S t a t e -------------
1325 // -- ebx : argument converted to string
1326 // -- edi : constructor function
1327 // -- esp[0] : return address
1328 // -----------------------------------
1329
1330 // Allocate a JSValue and put the tagged pointer into eax.
1331 Label gc_required;
1332 __ AllocateInNewSpace(JSValue::kSize,
1333 eax, // Result.
1334 ecx, // New allocation top (we ignore it).
1335 no_reg,
1336 &gc_required,
1337 TAG_OBJECT);
1338
1339 // Set the map.
1340 __ LoadGlobalFunctionInitialMap(edi, ecx);
1341 if (FLAG_debug_code) {
1342 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1343 JSValue::kSize >> kPointerSizeLog2);
1344 __ Assert(equal, "Unexpected string wrapper instance size");
1345 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1346 __ Assert(equal, "Unexpected unused properties of string wrapper");
1347 }
1348 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1349
1350 // Set properties and elements.
Steve Block44f0eee2011-05-26 01:26:41 +01001351 Factory* factory = masm->isolate()->factory();
1352 __ Set(ecx, Immediate(factory->empty_fixed_array()));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001353 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1354 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1355
1356 // Set the value.
1357 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1358
1359 // Ensure the object is fully initialized.
1360 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1361
1362 // We're done. Return.
1363 __ ret(0);
1364
1365 // The argument was not found in the number to string cache. Check
1366 // if it's a string already before calling the conversion builtin.
1367 Label convert_argument;
1368 __ bind(&not_cached);
1369 STATIC_ASSERT(kSmiTag == 0);
1370 __ test(eax, Immediate(kSmiTagMask));
1371 __ j(zero, &convert_argument);
1372 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1373 __ j(NegateCondition(is_string), &convert_argument);
1374 __ mov(ebx, eax);
Steve Block44f0eee2011-05-26 01:26:41 +01001375 __ IncrementCounter(counters->string_ctor_string_value(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001376 __ jmp(&argument_is_string);
1377
1378 // Invoke the conversion builtin and put the result into ebx.
1379 __ bind(&convert_argument);
Steve Block44f0eee2011-05-26 01:26:41 +01001380 __ IncrementCounter(counters->string_ctor_conversions(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001381 __ EnterInternalFrame();
1382 __ push(edi); // Preserve the function.
1383 __ push(eax);
1384 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1385 __ pop(edi);
1386 __ LeaveInternalFrame();
1387 __ mov(ebx, eax);
1388 __ jmp(&argument_is_string);
1389
1390 // Load the empty string into ebx, remove the receiver from the
1391 // stack, and jump back to the case where the argument is a string.
1392 __ bind(&no_arguments);
Steve Block44f0eee2011-05-26 01:26:41 +01001393 __ Set(ebx, Immediate(factory->empty_string()));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001394 __ pop(ecx);
1395 __ lea(esp, Operand(esp, kPointerSize));
1396 __ push(ecx);
1397 __ jmp(&argument_is_string);
1398
1399 // At this point the argument is already a string. Call runtime to
1400 // create a string wrapper.
1401 __ bind(&gc_required);
Steve Block44f0eee2011-05-26 01:26:41 +01001402 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001403 __ EnterInternalFrame();
1404 __ push(ebx);
1405 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1406 __ LeaveInternalFrame();
1407 __ ret(0);
1408}
1409
1410
Steve Blocka7e24c12009-10-30 11:49:00 +00001411static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1412 __ push(ebp);
1413 __ mov(ebp, Operand(esp));
1414
1415 // Store the arguments adaptor context sentinel.
1416 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1417
1418 // Push the function on the stack.
1419 __ push(edi);
1420
1421 // Preserve the number of arguments on the stack. Must preserve both
1422 // eax and ebx because these registers are used when copying the
1423 // arguments and the receiver.
1424 ASSERT(kSmiTagSize == 1);
1425 __ lea(ecx, Operand(eax, eax, times_1, kSmiTag));
1426 __ push(ecx);
1427}
1428
1429
1430static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1431 // Retrieve the number of arguments from the stack.
1432 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1433
1434 // Leave the frame.
1435 __ leave();
1436
1437 // Remove caller arguments from the stack.
1438 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1439 __ pop(ecx);
1440 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1441 __ push(ecx);
1442}
1443
1444
1445void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1446 // ----------- S t a t e -------------
1447 // -- eax : actual number of arguments
1448 // -- ebx : expected number of arguments
1449 // -- edx : code entry to call
1450 // -----------------------------------
1451
1452 Label invoke, dont_adapt_arguments;
Steve Block44f0eee2011-05-26 01:26:41 +01001453 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001454
1455 Label enough, too_few;
1456 __ cmp(eax, Operand(ebx));
1457 __ j(less, &too_few);
1458 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1459 __ j(equal, &dont_adapt_arguments);
1460
1461 { // Enough parameters: Actual >= expected.
1462 __ bind(&enough);
1463 EnterArgumentsAdaptorFrame(masm);
1464
1465 // Copy receiver and all expected arguments.
1466 const int offset = StandardFrameConstants::kCallerSPOffset;
1467 __ lea(eax, Operand(ebp, eax, times_4, offset));
1468 __ mov(ecx, -1); // account for receiver
1469
1470 Label copy;
1471 __ bind(&copy);
1472 __ inc(ecx);
1473 __ push(Operand(eax, 0));
1474 __ sub(Operand(eax), Immediate(kPointerSize));
1475 __ cmp(ecx, Operand(ebx));
1476 __ j(less, &copy);
1477 __ jmp(&invoke);
1478 }
1479
1480 { // Too few parameters: Actual < expected.
1481 __ bind(&too_few);
1482 EnterArgumentsAdaptorFrame(masm);
1483
1484 // Copy receiver and all actual arguments.
1485 const int offset = StandardFrameConstants::kCallerSPOffset;
1486 __ lea(edi, Operand(ebp, eax, times_4, offset));
1487 __ mov(ecx, -1); // account for receiver
1488
1489 Label copy;
1490 __ bind(&copy);
1491 __ inc(ecx);
1492 __ push(Operand(edi, 0));
1493 __ sub(Operand(edi), Immediate(kPointerSize));
1494 __ cmp(ecx, Operand(eax));
1495 __ j(less, &copy);
1496
1497 // Fill remaining expected arguments with undefined values.
1498 Label fill;
1499 __ bind(&fill);
1500 __ inc(ecx);
Steve Block44f0eee2011-05-26 01:26:41 +01001501 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001502 __ cmp(ecx, Operand(ebx));
1503 __ j(less, &fill);
1504
1505 // Restore function pointer.
1506 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1507 }
1508
1509 // Call the entry point.
1510 __ bind(&invoke);
1511 __ call(Operand(edx));
1512
1513 // Leave frame and return.
1514 LeaveArgumentsAdaptorFrame(masm);
1515 __ ret(0);
1516
1517 // -------------------------------------------
1518 // Dont adapt arguments.
1519 // -------------------------------------------
1520 __ bind(&dont_adapt_arguments);
1521 __ jmp(Operand(edx));
1522}
1523
1524
Ben Murdochb0fe1622011-05-05 13:52:32 +01001525void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1526 // We shouldn't be performing on-stack replacement in the first
1527 // place if the CPU features we need for the optimized Crankshaft
1528 // code aren't supported.
Steve Block44f0eee2011-05-26 01:26:41 +01001529 CpuFeatures* cpu_features = masm->isolate()->cpu_features();
1530 cpu_features->Probe(false);
1531 if (!cpu_features->IsSupported(SSE2)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001532 __ Abort("Unreachable code: Cannot optimize without SSE2 support.");
1533 return;
1534 }
1535
1536 // Get the loop depth of the stack guard check. This is recorded in
1537 // a test(eax, depth) instruction right after the call.
1538 Label stack_check;
1539 __ mov(ebx, Operand(esp, 0)); // return address
1540 if (FLAG_debug_code) {
1541 __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte);
1542 __ Assert(equal, "test eax instruction not found after loop stack check");
1543 }
1544 __ movzx_b(ebx, Operand(ebx, 1)); // depth
1545
1546 // Get the loop nesting level at which we allow OSR from the
1547 // unoptimized code and check if we want to do OSR yet. If not we
1548 // should perform a stack guard check so we can get interrupts while
1549 // waiting for on-stack replacement.
1550 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1551 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
1552 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
1553 __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset));
1554 __ j(greater, &stack_check);
1555
1556 // Pass the function to optimize as the argument to the on-stack
1557 // replacement runtime function.
1558 __ EnterInternalFrame();
1559 __ push(eax);
1560 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1561 __ LeaveInternalFrame();
1562
1563 // If the result was -1 it means that we couldn't optimize the
1564 // function. Just return and continue in the unoptimized version.
1565 NearLabel skip;
1566 __ cmp(Operand(eax), Immediate(Smi::FromInt(-1)));
1567 __ j(not_equal, &skip);
1568 __ ret(0);
1569
1570 // If we decide not to perform on-stack replacement we perform a
1571 // stack guard check to enable interrupts.
1572 __ bind(&stack_check);
1573 NearLabel ok;
1574 ExternalReference stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +01001575 ExternalReference::address_of_stack_limit(masm->isolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001576 __ cmp(esp, Operand::StaticVariable(stack_limit));
1577 __ j(above_equal, &ok, taken);
1578 StackCheckStub stub;
1579 __ TailCallStub(&stub);
1580 __ Abort("Unreachable code: returned from tail call.");
1581 __ bind(&ok);
1582 __ ret(0);
1583
1584 __ bind(&skip);
1585 // Untag the AST id and push it on the stack.
1586 __ SmiUntag(eax);
1587 __ push(eax);
1588
1589 // Generate the code for doing the frame-to-frame translation using
1590 // the deoptimizer infrastructure.
1591 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1592 generator.Generate();
1593}
1594
1595
Steve Blocka7e24c12009-10-30 11:49:00 +00001596#undef __
Steve Block44f0eee2011-05-26 01:26:41 +01001597}
1598} // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01001599
1600#endif // V8_TARGET_ARCH_IA32