blob: 918f346d89cbcbf31ea1adce228128123a7567a8 [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 Block6ded16b2010-05-10 14:33:55 +010073 __ JumpToExternalReference(ExternalReference(id));
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);
103 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
104 RelocInfo::CODE_TARGET);
105}
106
107
Leon Clarkee46be812010-01-19 14:06:41 +0000108static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100109 bool is_api_function,
110 bool count_constructions) {
111 // Should never count constructions for api objects.
112 ASSERT(!is_api_function || !count_constructions);
113
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 // Enter a construct frame.
115 __ EnterConstructFrame();
116
117 // Store a smi-tagged arguments count on the stack.
Leon Clarkee46be812010-01-19 14:06:41 +0000118 __ SmiTag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000119 __ push(eax);
120
121 // Push the function to invoke on the stack.
122 __ push(edi);
123
124 // Try to allocate the object without transitioning into C code. If any of the
125 // preconditions is not met, the code bails out to the runtime call.
126 Label rt_call, allocated;
127 if (FLAG_inline_new) {
128 Label undo_allocation;
129#ifdef ENABLE_DEBUGGER_SUPPORT
130 ExternalReference debug_step_in_fp =
131 ExternalReference::debug_step_in_fp_address();
132 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
133 __ j(not_equal, &rt_call);
134#endif
135
136 // Verified that the constructor is a JSFunction.
137 // Load the initial map and verify that it is in fact a map.
138 // edi: constructor
139 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
140 // Will both indicate a NULL and a Smi
141 __ test(eax, Immediate(kSmiTagMask));
142 __ j(zero, &rt_call);
143 // 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);
187 __ mov(ecx, Factory::empty_fixed_array());
188 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
189 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
190 // Set extra fields in the newly allocated object.
191 // eax: initial map
192 // ebx: JSObject
193 // edi: start of next object
194 { Label loop, entry;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100195 // To allow for truncation.
196 if (count_constructions) {
197 __ mov(edx, Factory::one_pointer_filler_map());
198 } else {
199 __ mov(edx, Factory::undefined_value());
200 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
202 __ jmp(&entry);
203 __ bind(&loop);
204 __ mov(Operand(ecx, 0), edx);
205 __ add(Operand(ecx), Immediate(kPointerSize));
206 __ bind(&entry);
207 __ cmp(ecx, Operand(edi));
208 __ j(less, &loop);
209 }
210
211 // Add the object tag to make the JSObject real, so that we can continue and
212 // jump into the continuation code at any time from now on. Any failures
213 // need to undo the allocation, so that the heap is in a consistent state
214 // and verifiable.
215 // eax: initial map
216 // ebx: JSObject
217 // edi: start of next object
218 __ or_(Operand(ebx), Immediate(kHeapObjectTag));
219
220 // Check if a non-empty properties array is needed.
221 // Allocate and initialize a FixedArray if it is.
222 // eax: initial map
223 // ebx: JSObject
224 // edi: start of next object
225 // Calculate the total number of properties described by the map.
226 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
227 __ movzx_b(ecx, FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
228 __ add(edx, Operand(ecx));
229 // Calculate unused properties past the end of the in-object properties.
230 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
231 __ sub(edx, Operand(ecx));
232 // Done if no extra properties are to be allocated.
233 __ j(zero, &allocated);
234 __ Assert(positive, "Property allocation count failed.");
235
236 // Scale the number of elements by pointer size and add the header for
237 // FixedArrays to the start of the next object calculation from above.
238 // ebx: JSObject
239 // edi: start of next object (will be start of FixedArray)
240 // edx: number of elements in properties array
241 __ AllocateInNewSpace(FixedArray::kHeaderSize,
242 times_pointer_size,
243 edx,
244 edi,
245 ecx,
246 no_reg,
247 &undo_allocation,
248 RESULT_CONTAINS_TOP);
249
250 // Initialize the FixedArray.
251 // ebx: JSObject
252 // edi: FixedArray
253 // edx: number of elements
254 // ecx: start of next object
255 __ mov(eax, Factory::fixed_array_map());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100256 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
257 __ SmiTag(edx);
258 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
Steve Blocka7e24c12009-10-30 11:49:00 +0000259
260 // Initialize the fields to undefined.
261 // ebx: JSObject
262 // edi: FixedArray
263 // ecx: start of next object
264 { Label loop, entry;
265 __ mov(edx, Factory::undefined_value());
266 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
267 __ jmp(&entry);
268 __ bind(&loop);
269 __ mov(Operand(eax, 0), edx);
270 __ add(Operand(eax), Immediate(kPointerSize));
271 __ bind(&entry);
272 __ cmp(eax, Operand(ecx));
273 __ j(below, &loop);
274 }
275
276 // Store the initialized FixedArray into the properties field of
277 // the JSObject
278 // ebx: JSObject
279 // edi: FixedArray
280 __ or_(Operand(edi), Immediate(kHeapObjectTag)); // add the heap tag
281 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
282
283
284 // Continue with JSObject being successfully allocated
285 // ebx: JSObject
286 __ jmp(&allocated);
287
288 // Undo the setting of the new top so that the heap is verifiable. For
289 // example, the map's unused properties potentially do not match the
290 // allocated objects unused properties.
291 // ebx: JSObject (previous new top)
292 __ bind(&undo_allocation);
293 __ UndoAllocationInNewSpace(ebx);
294 }
295
296 // Allocate the new receiver object using the runtime call.
297 __ bind(&rt_call);
298 // Must restore edi (constructor) before calling runtime.
299 __ mov(edi, Operand(esp, 0));
300 // edi: function (constructor)
301 __ push(edi);
302 __ CallRuntime(Runtime::kNewObject, 1);
303 __ mov(ebx, Operand(eax)); // store result in ebx
304
305 // New object allocated.
306 // ebx: newly allocated object
307 __ bind(&allocated);
308 // Retrieve the function from the stack.
309 __ pop(edi);
310
311 // Retrieve smi-tagged arguments count from the stack.
312 __ mov(eax, Operand(esp, 0));
Leon Clarkee46be812010-01-19 14:06:41 +0000313 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000314
315 // Push the allocated receiver to the stack. We need two copies
316 // because we may have to return the original one and the calling
317 // conventions dictate that the called function pops the receiver.
318 __ push(ebx);
319 __ push(ebx);
320
321 // Setup pointer to last argument.
322 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
323
324 // Copy arguments and receiver to the expression stack.
325 Label loop, entry;
326 __ mov(ecx, Operand(eax));
327 __ jmp(&entry);
328 __ bind(&loop);
329 __ push(Operand(ebx, ecx, times_4, 0));
330 __ bind(&entry);
331 __ dec(ecx);
332 __ j(greater_equal, &loop);
333
334 // Call the function.
Leon Clarkee46be812010-01-19 14:06:41 +0000335 if (is_api_function) {
336 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
337 Handle<Code> code = Handle<Code>(
338 Builtins::builtin(Builtins::HandleApiCallConstruct));
339 ParameterCount expected(0);
340 __ InvokeCode(code, expected, expected,
341 RelocInfo::CODE_TARGET, CALL_FUNCTION);
342 } else {
343 ParameterCount actual(eax);
344 __ InvokeFunction(edi, actual, CALL_FUNCTION);
345 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000346
347 // Restore context from the frame.
348 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
349
350 // If the result is an object (in the ECMA sense), we should get rid
351 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
352 // on page 74.
353 Label use_receiver, exit;
354
355 // If the result is a smi, it is *not* an object in the ECMA sense.
356 __ test(eax, Immediate(kSmiTagMask));
357 __ j(zero, &use_receiver, not_taken);
358
359 // If the type of the result (stored in its map) is less than
360 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100361 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
362 __ j(above_equal, &exit, not_taken);
Steve Blocka7e24c12009-10-30 11:49:00 +0000363
364 // Throw away the result of the constructor invocation and use the
365 // on-stack receiver as the result.
366 __ bind(&use_receiver);
367 __ mov(eax, Operand(esp, 0));
368
369 // Restore the arguments count and leave the construct frame.
370 __ bind(&exit);
371 __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
372 __ LeaveConstructFrame();
373
374 // Remove caller arguments from the stack and return.
375 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
376 __ pop(ecx);
377 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
378 __ push(ecx);
379 __ IncrementCounter(&Counters::constructed_objects, 1);
380 __ ret(0);
381}
382
383
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100384void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
385 Generate_JSConstructStubHelper(masm, false, true);
386}
387
388
Leon Clarkee46be812010-01-19 14:06:41 +0000389void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100390 Generate_JSConstructStubHelper(masm, false, false);
Leon Clarkee46be812010-01-19 14:06:41 +0000391}
392
393
394void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100395 Generate_JSConstructStubHelper(masm, true, false);
Leon Clarkee46be812010-01-19 14:06:41 +0000396}
397
398
Steve Blocka7e24c12009-10-30 11:49:00 +0000399static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
400 bool is_construct) {
401 // Clear the context before we push it when entering the JS frame.
402 __ xor_(esi, Operand(esi)); // clear esi
403
404 // Enter an internal frame.
405 __ EnterInternalFrame();
406
407 // Load the previous frame pointer (ebx) to access C arguments
408 __ mov(ebx, Operand(ebp, 0));
409
410 // Get the function from the frame and setup the context.
411 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
412 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
413
414 // Push the function and the receiver onto the stack.
415 __ push(ecx);
416 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
417
418 // Load the number of arguments and setup pointer to the arguments.
419 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
420 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
421
422 // Copy arguments to the stack in a loop.
423 Label loop, entry;
424 __ xor_(ecx, Operand(ecx)); // clear ecx
425 __ jmp(&entry);
426 __ bind(&loop);
427 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
428 __ push(Operand(edx, 0)); // dereference handle
429 __ inc(Operand(ecx));
430 __ bind(&entry);
431 __ cmp(ecx, Operand(eax));
432 __ j(not_equal, &loop);
433
434 // Get the function from the stack and call it.
435 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); // +1 ~ receiver
436
437 // Invoke the code.
438 if (is_construct) {
439 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
440 RelocInfo::CODE_TARGET);
441 } else {
442 ParameterCount actual(eax);
443 __ InvokeFunction(edi, actual, CALL_FUNCTION);
444 }
445
446 // Exit the JS frame. Notice that this also removes the empty
447 // context and the function left on the stack by the code
448 // invocation.
449 __ LeaveInternalFrame();
450 __ ret(1 * kPointerSize); // remove receiver
451}
452
453
454void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
455 Generate_JSEntryTrampolineHelper(masm, false);
456}
457
458
459void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
460 Generate_JSEntryTrampolineHelper(masm, true);
461}
462
463
Iain Merrick75681382010-08-19 15:07:18 +0100464void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
465 // Enter an internal frame.
466 __ EnterInternalFrame();
467
468 // Push a copy of the function onto the stack.
469 __ push(edi);
470
471 __ push(edi); // Function is also the parameter to the runtime call.
472 __ CallRuntime(Runtime::kLazyCompile, 1);
473 __ pop(edi);
474
475 // Tear down temporary frame.
476 __ LeaveInternalFrame();
477
478 // Do a tail-call of the compiled function.
479 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
480 __ jmp(Operand(ecx));
481}
482
483
Ben Murdochb0fe1622011-05-05 13:52:32 +0100484void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
485 // Enter an internal frame.
486 __ EnterInternalFrame();
487
488 // Push a copy of the function onto the stack.
489 __ push(edi);
490
491 __ push(edi); // Function is also the parameter to the runtime call.
492 __ CallRuntime(Runtime::kLazyRecompile, 1);
493
494 // Restore function and tear down temporary frame.
495 __ pop(edi);
496 __ LeaveInternalFrame();
497
498 // Do a tail-call of the compiled function.
499 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
500 __ jmp(Operand(ecx));
501}
502
503
504static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
505 Deoptimizer::BailoutType type) {
506 // Enter an internal frame.
507 __ EnterInternalFrame();
508
509 // Pass the function and deoptimization type to the runtime system.
510 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
511 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
512
513 // Tear down temporary frame.
514 __ LeaveInternalFrame();
515
516 // Get the full codegen state from the stack and untag it.
517 __ mov(ecx, Operand(esp, 1 * kPointerSize));
518 __ SmiUntag(ecx);
519
520 // Switch on the state.
521 NearLabel not_no_registers, not_tos_eax;
522 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
523 __ j(not_equal, &not_no_registers);
524 __ ret(1 * kPointerSize); // Remove state.
525
526 __ bind(&not_no_registers);
527 __ mov(eax, Operand(esp, 2 * kPointerSize));
528 __ cmp(ecx, FullCodeGenerator::TOS_REG);
529 __ j(not_equal, &not_tos_eax);
530 __ ret(2 * kPointerSize); // Remove state, eax.
531
532 __ bind(&not_tos_eax);
533 __ Abort("no cases left");
534}
535
536
537void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
538 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
539}
540
541
542void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
543 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
544}
545
546
547void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
548 // TODO(kasperl): Do we need to save/restore the XMM registers too?
549
550 // For now, we are relying on the fact that Runtime::NotifyOSR
551 // doesn't do any garbage collection which allows us to save/restore
552 // the registers without worrying about which of them contain
553 // pointers. This seems a bit fragile.
554 __ pushad();
555 __ EnterInternalFrame();
556 __ CallRuntime(Runtime::kNotifyOSR, 0);
557 __ LeaveInternalFrame();
558 __ popad();
559 __ ret(0);
560}
561
562
Steve Blocka7e24c12009-10-30 11:49:00 +0000563void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
564 // 1. Make sure we have at least one argument.
565 { Label done;
566 __ test(eax, Operand(eax));
567 __ j(not_zero, &done, taken);
568 __ pop(ebx);
569 __ push(Immediate(Factory::undefined_value()));
570 __ push(ebx);
571 __ inc(eax);
572 __ bind(&done);
573 }
574
Andrei Popescu402d9372010-02-26 13:31:12 +0000575 // 2. Get the function to call (passed as receiver) from the stack, check
576 // if it is a function.
577 Label non_function;
578 // 1 ~ return address.
579 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
580 __ test(edi, Immediate(kSmiTagMask));
581 __ j(zero, &non_function, not_taken);
582 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
583 __ j(not_equal, &non_function, not_taken);
Steve Blocka7e24c12009-10-30 11:49:00 +0000584
Steve Blocka7e24c12009-10-30 11:49:00 +0000585
Andrei Popescu402d9372010-02-26 13:31:12 +0000586 // 3a. Patch the first argument if necessary when calling a function.
587 Label shift_arguments;
588 { Label convert_to_object, use_global_receiver, patch_receiver;
589 // Change context eagerly in case we need the global receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000590 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
591
Andrei Popescu402d9372010-02-26 13:31:12 +0000592 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
Steve Blocka7e24c12009-10-30 11:49:00 +0000593 __ test(ebx, Immediate(kSmiTagMask));
Andrei Popescu402d9372010-02-26 13:31:12 +0000594 __ j(zero, &convert_to_object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000595
596 __ cmp(ebx, Factory::null_value());
597 __ j(equal, &use_global_receiver);
598 __ cmp(ebx, Factory::undefined_value());
599 __ j(equal, &use_global_receiver);
600
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100601 // We don't use IsObjectJSObjectType here because we jump on success.
Steve Blocka7e24c12009-10-30 11:49:00 +0000602 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
603 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100604 __ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
605 __ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000606 __ j(below_equal, &shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000607
Andrei Popescu402d9372010-02-26 13:31:12 +0000608 __ bind(&convert_to_object);
609 __ EnterInternalFrame(); // In order to preserve argument count.
Leon Clarkee46be812010-01-19 14:06:41 +0000610 __ SmiTag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000611 __ push(eax);
612
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 __ push(ebx);
614 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
615 __ mov(ebx, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000616
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 __ pop(eax);
Leon Clarkee46be812010-01-19 14:06:41 +0000618 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000619 __ LeaveInternalFrame();
Andrei Popescu402d9372010-02-26 13:31:12 +0000620 // Restore the function to edi.
621 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +0000622 __ jmp(&patch_receiver);
623
Andrei Popescu402d9372010-02-26 13:31:12 +0000624 // Use the global receiver object from the called function as the
625 // receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000626 __ bind(&use_global_receiver);
627 const int kGlobalIndex =
628 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
629 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
Steve Blockd0582a62009-12-15 09:54:21 +0000630 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
631 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +0000632 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
633
634 __ bind(&patch_receiver);
635 __ mov(Operand(esp, eax, times_4, 0), ebx);
636
Andrei Popescu402d9372010-02-26 13:31:12 +0000637 __ jmp(&shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000638 }
639
Andrei Popescu402d9372010-02-26 13:31:12 +0000640 // 3b. Patch the first argument when calling a non-function. The
641 // CALL_NON_FUNCTION builtin expects the non-function callee as
642 // receiver, so overwrite the first argument which will ultimately
643 // become the receiver.
644 __ bind(&non_function);
645 __ mov(Operand(esp, eax, times_4, 0), edi);
646 // Clear edi to indicate a non-function being called.
647 __ xor_(edi, Operand(edi));
Leon Clarkee46be812010-01-19 14:06:41 +0000648
Andrei Popescu402d9372010-02-26 13:31:12 +0000649 // 4. Shift arguments and return address one slot down on the stack
650 // (overwriting the original receiver). Adjust argument count to make
651 // the original first argument the new receiver.
652 __ bind(&shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000653 { Label loop;
Leon Clarkee46be812010-01-19 14:06:41 +0000654 __ mov(ecx, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000655 __ bind(&loop);
656 __ mov(ebx, Operand(esp, ecx, times_4, 0));
657 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
658 __ dec(ecx);
Andrei Popescu402d9372010-02-26 13:31:12 +0000659 __ j(not_sign, &loop); // While non-negative (to copy return address).
Leon Clarkee46be812010-01-19 14:06:41 +0000660 __ pop(ebx); // Discard copy of return address.
661 __ dec(eax); // One fewer argument (first argument is new receiver).
Steve Blocka7e24c12009-10-30 11:49:00 +0000662 }
663
Andrei Popescu402d9372010-02-26 13:31:12 +0000664 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
665 { Label function;
666 __ test(edi, Operand(edi));
667 __ j(not_zero, &function, taken);
668 __ xor_(ebx, Operand(ebx));
669 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
670 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
671 RelocInfo::CODE_TARGET);
672 __ bind(&function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000673 }
674
Andrei Popescu402d9372010-02-26 13:31:12 +0000675 // 5b. Get the code to call from the function and check that the number of
676 // expected arguments matches what we're providing. If so, jump
677 // (tail-call) to the code in register edx without checking arguments.
678 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
679 __ mov(ebx,
680 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
Steve Block791712a2010-08-27 10:21:07 +0100681 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100682 __ SmiUntag(ebx);
Andrei Popescu402d9372010-02-26 13:31:12 +0000683 __ cmp(eax, Operand(ebx));
684 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline)));
685
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 ParameterCount expected(0);
687 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
688}
689
690
691void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
692 __ EnterInternalFrame();
693
694 __ push(Operand(ebp, 4 * kPointerSize)); // push this
695 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments
696 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
697
Steve Blockd0582a62009-12-15 09:54:21 +0000698 // Check the stack for overflow. We are not trying need to catch
699 // interruptions (e.g. debug break and preemption) here, so the "real stack
700 // limit" is checked.
701 Label okay;
702 ExternalReference real_stack_limit =
703 ExternalReference::address_of_real_stack_limit();
704 __ mov(edi, Operand::StaticVariable(real_stack_limit));
705 // Make ecx the space we have left. The stack might already be overflowed
706 // here which will cause ecx to become negative.
707 __ mov(ecx, Operand(esp));
708 __ sub(ecx, Operand(edi));
709 // Make edx the space we need for the array when it is unrolled onto the
710 // stack.
711 __ mov(edx, Operand(eax));
712 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
713 // Check if the arguments will overflow the stack.
714 __ cmp(ecx, Operand(edx));
715 __ j(greater, &okay, taken); // Signed comparison.
Steve Blocka7e24c12009-10-30 11:49:00 +0000716
Steve Blockd0582a62009-12-15 09:54:21 +0000717 // Out of stack space.
718 __ push(Operand(ebp, 4 * kPointerSize)); // push this
719 __ push(eax);
720 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
721 __ bind(&okay);
722 // End of stack check.
Steve Blocka7e24c12009-10-30 11:49:00 +0000723
724 // Push current index and limit.
725 const int kLimitOffset =
726 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
727 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
728 __ push(eax); // limit
729 __ push(Immediate(0)); // index
730
731 // Change context eagerly to get the right global object if
732 // necessary.
733 __ mov(edi, Operand(ebp, 4 * kPointerSize));
734 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
735
736 // Compute the receiver.
737 Label call_to_object, use_global_receiver, push_receiver;
738 __ mov(ebx, Operand(ebp, 3 * kPointerSize));
739 __ test(ebx, Immediate(kSmiTagMask));
740 __ j(zero, &call_to_object);
741 __ cmp(ebx, Factory::null_value());
742 __ j(equal, &use_global_receiver);
743 __ cmp(ebx, Factory::undefined_value());
744 __ j(equal, &use_global_receiver);
745
746 // If given receiver is already a JavaScript object then there's no
747 // reason for converting it.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100748 // We don't use IsObjectJSObjectType here because we jump on success.
Steve Blocka7e24c12009-10-30 11:49:00 +0000749 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
750 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100751 __ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
752 __ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
753 __ j(below_equal, &push_receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000754
755 // Convert the receiver to an object.
756 __ bind(&call_to_object);
757 __ push(ebx);
758 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
759 __ mov(ebx, Operand(eax));
760 __ jmp(&push_receiver);
761
762 // Use the current global receiver object as the receiver.
763 __ bind(&use_global_receiver);
764 const int kGlobalOffset =
765 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
766 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
Steve Blockd0582a62009-12-15 09:54:21 +0000767 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
768 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
770
771 // Push the receiver.
772 __ bind(&push_receiver);
773 __ push(ebx);
774
775 // Copy all arguments from the array to the stack.
776 Label entry, loop;
777 __ mov(eax, Operand(ebp, kIndexOffset));
778 __ jmp(&entry);
779 __ bind(&loop);
Andrei Popescu402d9372010-02-26 13:31:12 +0000780 __ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments
Steve Blocka7e24c12009-10-30 11:49:00 +0000781
782 // Use inline caching to speed up access to arguments.
783 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
784 __ call(ic, RelocInfo::CODE_TARGET);
785 // It is important that we do not have a test instruction after the
786 // call. A test instruction after the call is used to indicate that
787 // we have generated an inline version of the keyed load. In this
788 // case, we know that we are not generating a test instruction next.
789
Andrei Popescu402d9372010-02-26 13:31:12 +0000790 // Push the nth argument.
Steve Blocka7e24c12009-10-30 11:49:00 +0000791 __ push(eax);
792
793 // Update the index on the stack and in register eax.
794 __ mov(eax, Operand(ebp, kIndexOffset));
795 __ add(Operand(eax), Immediate(1 << kSmiTagSize));
796 __ mov(Operand(ebp, kIndexOffset), eax);
797
798 __ bind(&entry);
799 __ cmp(eax, Operand(ebp, kLimitOffset));
800 __ j(not_equal, &loop);
801
802 // Invoke the function.
803 ParameterCount actual(eax);
Leon Clarkee46be812010-01-19 14:06:41 +0000804 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000805 __ mov(edi, Operand(ebp, 4 * kPointerSize));
806 __ InvokeFunction(edi, actual, CALL_FUNCTION);
807
808 __ LeaveInternalFrame();
809 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
810}
811
812
Steve Blocka7e24c12009-10-30 11:49:00 +0000813// Number of empty elements to allocate for an empty array.
814static const int kPreallocatedArrayElements = 4;
815
816
817// Allocate an empty JSArray. The allocated array is put into the result
818// register. If the parameter initial_capacity is larger than zero an elements
819// backing store is allocated with this size and filled with the hole values.
820// Otherwise the elements backing store is set to the empty FixedArray.
821static void AllocateEmptyJSArray(MacroAssembler* masm,
822 Register array_function,
823 Register result,
824 Register scratch1,
825 Register scratch2,
826 Register scratch3,
827 int initial_capacity,
828 Label* gc_required) {
829 ASSERT(initial_capacity >= 0);
830
831 // Load the initial map from the array function.
832 __ mov(scratch1, FieldOperand(array_function,
833 JSFunction::kPrototypeOrInitialMapOffset));
834
835 // Allocate the JSArray object together with space for a fixed array with the
836 // requested elements.
837 int size = JSArray::kSize;
838 if (initial_capacity > 0) {
839 size += FixedArray::SizeFor(initial_capacity);
840 }
841 __ AllocateInNewSpace(size,
842 result,
843 scratch2,
844 scratch3,
845 gc_required,
846 TAG_OBJECT);
847
848 // Allocated the JSArray. Now initialize the fields except for the elements
849 // array.
850 // result: JSObject
851 // scratch1: initial map
852 // scratch2: start of next object
853 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
854 __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
855 Factory::empty_fixed_array());
856 // Field JSArray::kElementsOffset is initialized later.
857 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
858
859 // If no storage is requested for the elements array just set the empty
860 // fixed array.
861 if (initial_capacity == 0) {
862 __ mov(FieldOperand(result, JSArray::kElementsOffset),
863 Factory::empty_fixed_array());
864 return;
865 }
866
867 // Calculate the location of the elements array and set elements array member
868 // of the JSArray.
869 // result: JSObject
870 // scratch2: start of next object
871 __ lea(scratch1, Operand(result, JSArray::kSize));
872 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
873
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100874 // Initialize the FixedArray and fill it with holes. FixedArray length is
Steve Blocka7e24c12009-10-30 11:49:00 +0000875 // stored as a smi.
876 // result: JSObject
877 // scratch1: elements array
878 // scratch2: start of next object
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100879 __ mov(FieldOperand(scratch1, FixedArray::kMapOffset),
Steve Blocka7e24c12009-10-30 11:49:00 +0000880 Factory::fixed_array_map());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100881 __ mov(FieldOperand(scratch1, FixedArray::kLengthOffset),
882 Immediate(Smi::FromInt(initial_capacity)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000883
884 // Fill the FixedArray with the hole value. Inline the code if short.
885 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
886 static const int kLoopUnfoldLimit = 4;
887 ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
888 if (initial_capacity <= kLoopUnfoldLimit) {
889 // Use a scratch register here to have only one reloc info when unfolding
890 // the loop.
891 __ mov(scratch3, Factory::the_hole_value());
892 for (int i = 0; i < initial_capacity; i++) {
893 __ mov(FieldOperand(scratch1,
894 FixedArray::kHeaderSize + i * kPointerSize),
895 scratch3);
896 }
897 } else {
898 Label loop, entry;
899 __ jmp(&entry);
900 __ bind(&loop);
901 __ mov(Operand(scratch1, 0), Factory::the_hole_value());
902 __ add(Operand(scratch1), Immediate(kPointerSize));
903 __ bind(&entry);
904 __ cmp(scratch1, Operand(scratch2));
905 __ j(below, &loop);
906 }
907}
908
909
910// Allocate a JSArray with the number of elements stored in a register. The
911// register array_function holds the built-in Array function and the register
912// array_size holds the size of the array as a smi. The allocated array is put
913// into the result register and beginning and end of the FixedArray elements
914// storage is put into registers elements_array and elements_array_end (see
915// below for when that is not the case). If the parameter fill_with_holes is
916// true the allocated elements backing store is filled with the hole values
917// otherwise it is left uninitialized. When the backing store is filled the
918// register elements_array is scratched.
919static void AllocateJSArray(MacroAssembler* masm,
920 Register array_function, // Array function.
Steve Block6ded16b2010-05-10 14:33:55 +0100921 Register array_size, // As a smi, cannot be 0.
Steve Blocka7e24c12009-10-30 11:49:00 +0000922 Register result,
923 Register elements_array,
924 Register elements_array_end,
925 Register scratch,
926 bool fill_with_hole,
927 Label* gc_required) {
Steve Block6ded16b2010-05-10 14:33:55 +0100928 ASSERT(scratch.is(edi)); // rep stos destination
929 ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
Leon Clarkef7060e22010-06-03 12:02:55 +0100930 ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax
Steve Blocka7e24c12009-10-30 11:49:00 +0000931
932 // Load the initial map from the array function.
933 __ mov(elements_array,
934 FieldOperand(array_function,
935 JSFunction::kPrototypeOrInitialMapOffset));
936
Steve Blocka7e24c12009-10-30 11:49:00 +0000937 // Allocate the JSArray object together with space for a FixedArray with the
938 // requested elements.
Steve Blocka7e24c12009-10-30 11:49:00 +0000939 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
940 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
941 times_half_pointer_size, // array_size is a smi.
942 array_size,
943 result,
944 elements_array_end,
945 scratch,
946 gc_required,
947 TAG_OBJECT);
948
949 // Allocated the JSArray. Now initialize the fields except for the elements
950 // array.
951 // result: JSObject
952 // elements_array: initial map
953 // elements_array_end: start of next object
954 // array_size: size of array (smi)
Steve Blocka7e24c12009-10-30 11:49:00 +0000955 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
956 __ mov(elements_array, Factory::empty_fixed_array());
957 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
958 // Field JSArray::kElementsOffset is initialized later.
959 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
960
961 // Calculate the location of the elements array and set elements array member
962 // of the JSArray.
963 // result: JSObject
964 // elements_array_end: start of next object
965 // array_size: size of array (smi)
966 __ lea(elements_array, Operand(result, JSArray::kSize));
967 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
968
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100969 // Initialize the fixed array. FixedArray length is stored as a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +0000970 // result: JSObject
971 // elements_array: elements array
972 // elements_array_end: start of next object
973 // array_size: size of array (smi)
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100974 __ mov(FieldOperand(elements_array, FixedArray::kMapOffset),
Steve Blocka7e24c12009-10-30 11:49:00 +0000975 Factory::fixed_array_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000976 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
977 // same.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100978 __ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000979
980 // Fill the allocated FixedArray with the hole value if requested.
981 // result: JSObject
982 // elements_array: elements array
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 if (fill_with_hole) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100984 __ SmiUntag(array_size);
Steve Block6ded16b2010-05-10 14:33:55 +0100985 __ lea(edi, Operand(elements_array,
986 FixedArray::kHeaderSize - kHeapObjectTag));
Steve Block6ded16b2010-05-10 14:33:55 +0100987 __ mov(eax, Factory::the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +0100988 __ cld();
Leon Clarkef7060e22010-06-03 12:02:55 +0100989 // Do not use rep stos when filling less than kRepStosThreshold
990 // words.
991 const int kRepStosThreshold = 16;
992 Label loop, entry, done;
993 __ cmp(ecx, kRepStosThreshold);
994 __ j(below, &loop); // Note: ecx > 0.
Steve Block6ded16b2010-05-10 14:33:55 +0100995 __ rep_stos();
Leon Clarkef7060e22010-06-03 12:02:55 +0100996 __ jmp(&done);
997 __ bind(&loop);
998 __ stos();
999 __ bind(&entry);
1000 __ cmp(edi, Operand(elements_array_end));
1001 __ j(below, &loop);
1002 __ bind(&done);
Steve Blocka7e24c12009-10-30 11:49:00 +00001003 }
1004}
1005
1006
1007// Create a new array for the built-in Array function. This function allocates
1008// the JSArray object and the FixedArray elements array and initializes these.
1009// If the Array cannot be constructed in native code the runtime is called. This
1010// function assumes the following state:
1011// edi: constructor (built-in Array function)
1012// eax: argc
1013// esp[0]: return address
1014// esp[4]: last argument
1015// This function is used for both construct and normal calls of Array. Whether
1016// it is a construct call or not is indicated by the construct_call parameter.
1017// The only difference between handling a construct call and a normal call is
1018// that for a construct call the constructor function in edi needs to be
1019// preserved for entering the generic code. In both cases argc in eax needs to
1020// be preserved.
1021static void ArrayNativeCode(MacroAssembler* masm,
1022 bool construct_call,
Steve Blockd0582a62009-12-15 09:54:21 +00001023 Label* call_generic_code) {
Steve Block6ded16b2010-05-10 14:33:55 +01001024 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
1025 empty_array, not_empty_array;
Steve Blocka7e24c12009-10-30 11:49:00 +00001026
1027 // Push the constructor and argc. No need to tag argc as a smi, as there will
1028 // be no garbage collection with this on the stack.
1029 int push_count = 0;
1030 if (construct_call) {
1031 push_count++;
1032 __ push(edi);
1033 }
1034 push_count++;
1035 __ push(eax);
1036
1037 // Check for array construction with zero arguments.
1038 __ test(eax, Operand(eax));
1039 __ j(not_zero, &argc_one_or_more);
1040
Steve Block6ded16b2010-05-10 14:33:55 +01001041 __ bind(&empty_array);
Steve Blocka7e24c12009-10-30 11:49:00 +00001042 // Handle construction of an empty array.
1043 AllocateEmptyJSArray(masm,
1044 edi,
1045 eax,
1046 ebx,
1047 ecx,
1048 edi,
1049 kPreallocatedArrayElements,
1050 &prepare_generic_code_call);
1051 __ IncrementCounter(&Counters::array_function_native, 1);
1052 __ pop(ebx);
1053 if (construct_call) {
1054 __ pop(edi);
1055 }
1056 __ ret(kPointerSize);
1057
1058 // Check for one argument. Bail out if argument is not smi or if it is
1059 // negative.
1060 __ bind(&argc_one_or_more);
1061 __ cmp(eax, 1);
1062 __ j(not_equal, &argc_two_or_more);
1063 ASSERT(kSmiTag == 0);
Steve Block6ded16b2010-05-10 14:33:55 +01001064 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
1065 __ test(ecx, Operand(ecx));
1066 __ j(not_zero, &not_empty_array);
1067
1068 // The single argument passed is zero, so we jump to the code above used to
1069 // handle the case of no arguments passed. To adapt the stack for that we move
1070 // the return address and the pushed constructor (if pushed) one stack slot up
1071 // thereby removing the passed argument. Argc is also on the stack - at the
1072 // bottom - and it needs to be changed from 1 to 0 to have the call into the
1073 // runtime system work in case a GC is required.
1074 for (int i = push_count; i > 0; i--) {
1075 __ mov(eax, Operand(esp, i * kPointerSize));
1076 __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
1077 }
1078 __ add(Operand(esp), Immediate(2 * kPointerSize)); // Drop two stack slots.
1079 __ push(Immediate(0)); // Treat this as a call with argc of zero.
1080 __ jmp(&empty_array);
1081
1082 __ bind(&not_empty_array);
1083 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001084 __ j(not_zero, &prepare_generic_code_call);
1085
1086 // Handle construction of an empty array of a certain size. Get the size from
1087 // the stack and bail out if size is to large to actually allocate an elements
1088 // array.
Steve Block6ded16b2010-05-10 14:33:55 +01001089 __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00001090 __ j(greater_equal, &prepare_generic_code_call);
1091
1092 // edx: array_size (smi)
1093 // edi: constructor
Steve Block6ded16b2010-05-10 14:33:55 +01001094 // esp[0]: argc (cannot be 0 here)
Steve Blocka7e24c12009-10-30 11:49:00 +00001095 // esp[4]: constructor (only if construct_call)
1096 // esp[8]: return address
1097 // esp[C]: argument
1098 AllocateJSArray(masm,
1099 edi,
Steve Block6ded16b2010-05-10 14:33:55 +01001100 ecx,
Steve Blocka7e24c12009-10-30 11:49:00 +00001101 ebx,
Leon Clarkef7060e22010-06-03 12:02:55 +01001102 eax,
Steve Block6ded16b2010-05-10 14:33:55 +01001103 edx,
Steve Blocka7e24c12009-10-30 11:49:00 +00001104 edi,
1105 true,
1106 &prepare_generic_code_call);
1107 __ IncrementCounter(&Counters::array_function_native, 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01001108 __ mov(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001109 __ pop(ebx);
1110 if (construct_call) {
1111 __ pop(edi);
1112 }
1113 __ ret(2 * kPointerSize);
1114
1115 // Handle construction of an array from a list of arguments.
1116 __ bind(&argc_two_or_more);
1117 ASSERT(kSmiTag == 0);
Leon Clarkee46be812010-01-19 14:06:41 +00001118 __ SmiTag(eax); // Convet argc to a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +00001119 // eax: array_size (smi)
1120 // edi: constructor
1121 // esp[0] : argc
1122 // esp[4]: constructor (only if construct_call)
1123 // esp[8] : return address
1124 // esp[C] : last argument
1125 AllocateJSArray(masm,
1126 edi,
1127 eax,
1128 ebx,
1129 ecx,
1130 edx,
1131 edi,
1132 false,
1133 &prepare_generic_code_call);
1134 __ IncrementCounter(&Counters::array_function_native, 1);
1135 __ mov(eax, ebx);
1136 __ pop(ebx);
1137 if (construct_call) {
1138 __ pop(edi);
1139 }
1140 __ push(eax);
1141 // eax: JSArray
1142 // ebx: argc
1143 // edx: elements_array_end (untagged)
1144 // esp[0]: JSArray
1145 // esp[4]: return address
1146 // esp[8]: last argument
1147
1148 // Location of the last argument
1149 __ lea(edi, Operand(esp, 2 * kPointerSize));
1150
1151 // Location of the first array element (Parameter fill_with_holes to
1152 // AllocateJSArrayis false, so the FixedArray is returned in ecx).
1153 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
1154
1155 // ebx: argc
1156 // edx: location of the first array element
1157 // edi: location of the last argument
1158 // esp[0]: JSArray
1159 // esp[4]: return address
1160 // esp[8]: last argument
1161 Label loop, entry;
1162 __ mov(ecx, ebx);
1163 __ jmp(&entry);
1164 __ bind(&loop);
1165 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1166 __ mov(Operand(edx, 0), eax);
1167 __ add(Operand(edx), Immediate(kPointerSize));
1168 __ bind(&entry);
1169 __ dec(ecx);
1170 __ j(greater_equal, &loop);
1171
1172 // Remove caller arguments from the stack and return.
1173 // ebx: argc
1174 // esp[0]: JSArray
1175 // esp[4]: return address
1176 // esp[8]: last argument
1177 __ pop(eax);
1178 __ pop(ecx);
1179 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1180 __ push(ecx);
1181 __ ret(0);
1182
1183 // Restore argc and constructor before running the generic code.
1184 __ bind(&prepare_generic_code_call);
1185 __ pop(eax);
1186 if (construct_call) {
1187 __ pop(edi);
1188 }
1189 __ jmp(call_generic_code);
1190}
1191
1192
1193void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1194 // ----------- S t a t e -------------
1195 // -- eax : argc
1196 // -- esp[0] : return address
1197 // -- esp[4] : last argument
1198 // -----------------------------------
Kristian Monsen25f61362010-05-21 11:50:48 +01001199 Label generic_array_code;
Steve Blocka7e24c12009-10-30 11:49:00 +00001200
1201 // Get the Array function.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001202 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001203
1204 if (FLAG_debug_code) {
1205 // Initial map for the builtin Array function shoud be a map.
1206 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1207 // Will both indicate a NULL and a Smi.
1208 __ test(ebx, Immediate(kSmiTagMask));
1209 __ Assert(not_zero, "Unexpected initial map for Array function");
1210 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1211 __ Assert(equal, "Unexpected initial map for Array function");
1212 }
1213
1214 // Run the native code for the Array function called as a normal function.
1215 ArrayNativeCode(masm, false, &generic_array_code);
1216
1217 // Jump to the generic array code in case the specialized code cannot handle
1218 // the construction.
1219 __ bind(&generic_array_code);
1220 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
1221 Handle<Code> array_code(code);
1222 __ jmp(array_code, RelocInfo::CODE_TARGET);
1223}
1224
1225
1226void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
1227 // ----------- S t a t e -------------
1228 // -- eax : argc
1229 // -- edi : constructor
1230 // -- esp[0] : return address
1231 // -- esp[4] : last argument
1232 // -----------------------------------
1233 Label generic_constructor;
1234
1235 if (FLAG_debug_code) {
1236 // The array construct code is only set for the builtin Array function which
1237 // does always have a map.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001238 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001239 __ cmp(edi, Operand(ebx));
1240 __ Assert(equal, "Unexpected Array function");
1241 // Initial map for the builtin Array function should be a map.
1242 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1243 // Will both indicate a NULL and a Smi.
1244 __ test(ebx, Immediate(kSmiTagMask));
1245 __ Assert(not_zero, "Unexpected initial map for Array function");
1246 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1247 __ Assert(equal, "Unexpected initial map for Array function");
1248 }
1249
1250 // Run the native code for the Array function called as constructor.
1251 ArrayNativeCode(masm, true, &generic_constructor);
1252
1253 // Jump to the generic construct code in case the specialized code cannot
1254 // handle the construction.
1255 __ bind(&generic_constructor);
1256 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1257 Handle<Code> generic_construct_stub(code);
1258 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1259}
1260
1261
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001262void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1263 // ----------- S t a t e -------------
1264 // -- eax : number of arguments
1265 // -- edi : constructor function
1266 // -- esp[0] : return address
1267 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1268 // -- esp[(argc + 1) * 4] : receiver
1269 // -----------------------------------
1270 __ IncrementCounter(&Counters::string_ctor_calls, 1);
1271
1272 if (FLAG_debug_code) {
1273 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1274 __ cmp(edi, Operand(ecx));
1275 __ Assert(equal, "Unexpected String function");
1276 }
1277
1278 // Load the first argument into eax and get rid of the rest
1279 // (including the receiver).
1280 Label no_arguments;
1281 __ test(eax, Operand(eax));
1282 __ j(zero, &no_arguments);
1283 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1284 __ pop(ecx);
1285 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1286 __ push(ecx);
1287 __ mov(eax, ebx);
1288
1289 // Lookup the argument in the number to string cache.
1290 Label not_cached, argument_is_string;
1291 NumberToStringStub::GenerateLookupNumberStringCache(
1292 masm,
1293 eax, // Input.
1294 ebx, // Result.
1295 ecx, // Scratch 1.
1296 edx, // Scratch 2.
1297 false, // Input is known to be smi?
1298 &not_cached);
1299 __ IncrementCounter(&Counters::string_ctor_cached_number, 1);
1300 __ bind(&argument_is_string);
1301 // ----------- S t a t e -------------
1302 // -- ebx : argument converted to string
1303 // -- edi : constructor function
1304 // -- esp[0] : return address
1305 // -----------------------------------
1306
1307 // Allocate a JSValue and put the tagged pointer into eax.
1308 Label gc_required;
1309 __ AllocateInNewSpace(JSValue::kSize,
1310 eax, // Result.
1311 ecx, // New allocation top (we ignore it).
1312 no_reg,
1313 &gc_required,
1314 TAG_OBJECT);
1315
1316 // Set the map.
1317 __ LoadGlobalFunctionInitialMap(edi, ecx);
1318 if (FLAG_debug_code) {
1319 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1320 JSValue::kSize >> kPointerSizeLog2);
1321 __ Assert(equal, "Unexpected string wrapper instance size");
1322 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1323 __ Assert(equal, "Unexpected unused properties of string wrapper");
1324 }
1325 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1326
1327 // Set properties and elements.
1328 __ Set(ecx, Immediate(Factory::empty_fixed_array()));
1329 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1330 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1331
1332 // Set the value.
1333 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1334
1335 // Ensure the object is fully initialized.
1336 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1337
1338 // We're done. Return.
1339 __ ret(0);
1340
1341 // The argument was not found in the number to string cache. Check
1342 // if it's a string already before calling the conversion builtin.
1343 Label convert_argument;
1344 __ bind(&not_cached);
1345 STATIC_ASSERT(kSmiTag == 0);
1346 __ test(eax, Immediate(kSmiTagMask));
1347 __ j(zero, &convert_argument);
1348 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1349 __ j(NegateCondition(is_string), &convert_argument);
1350 __ mov(ebx, eax);
1351 __ IncrementCounter(&Counters::string_ctor_string_value, 1);
1352 __ jmp(&argument_is_string);
1353
1354 // Invoke the conversion builtin and put the result into ebx.
1355 __ bind(&convert_argument);
1356 __ IncrementCounter(&Counters::string_ctor_conversions, 1);
1357 __ EnterInternalFrame();
1358 __ push(edi); // Preserve the function.
1359 __ push(eax);
1360 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1361 __ pop(edi);
1362 __ LeaveInternalFrame();
1363 __ mov(ebx, eax);
1364 __ jmp(&argument_is_string);
1365
1366 // Load the empty string into ebx, remove the receiver from the
1367 // stack, and jump back to the case where the argument is a string.
1368 __ bind(&no_arguments);
1369 __ Set(ebx, Immediate(Factory::empty_string()));
1370 __ pop(ecx);
1371 __ lea(esp, Operand(esp, kPointerSize));
1372 __ push(ecx);
1373 __ jmp(&argument_is_string);
1374
1375 // At this point the argument is already a string. Call runtime to
1376 // create a string wrapper.
1377 __ bind(&gc_required);
1378 __ IncrementCounter(&Counters::string_ctor_gc_required, 1);
1379 __ EnterInternalFrame();
1380 __ push(ebx);
1381 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1382 __ LeaveInternalFrame();
1383 __ ret(0);
1384}
1385
1386
Steve Blocka7e24c12009-10-30 11:49:00 +00001387static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1388 __ push(ebp);
1389 __ mov(ebp, Operand(esp));
1390
1391 // Store the arguments adaptor context sentinel.
1392 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1393
1394 // Push the function on the stack.
1395 __ push(edi);
1396
1397 // Preserve the number of arguments on the stack. Must preserve both
1398 // eax and ebx because these registers are used when copying the
1399 // arguments and the receiver.
1400 ASSERT(kSmiTagSize == 1);
1401 __ lea(ecx, Operand(eax, eax, times_1, kSmiTag));
1402 __ push(ecx);
1403}
1404
1405
1406static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1407 // Retrieve the number of arguments from the stack.
1408 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1409
1410 // Leave the frame.
1411 __ leave();
1412
1413 // Remove caller arguments from the stack.
1414 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1415 __ pop(ecx);
1416 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1417 __ push(ecx);
1418}
1419
1420
1421void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1422 // ----------- S t a t e -------------
1423 // -- eax : actual number of arguments
1424 // -- ebx : expected number of arguments
1425 // -- edx : code entry to call
1426 // -----------------------------------
1427
1428 Label invoke, dont_adapt_arguments;
1429 __ IncrementCounter(&Counters::arguments_adaptors, 1);
1430
1431 Label enough, too_few;
1432 __ cmp(eax, Operand(ebx));
1433 __ j(less, &too_few);
1434 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1435 __ j(equal, &dont_adapt_arguments);
1436
1437 { // Enough parameters: Actual >= expected.
1438 __ bind(&enough);
1439 EnterArgumentsAdaptorFrame(masm);
1440
1441 // Copy receiver and all expected arguments.
1442 const int offset = StandardFrameConstants::kCallerSPOffset;
1443 __ lea(eax, Operand(ebp, eax, times_4, offset));
1444 __ mov(ecx, -1); // account for receiver
1445
1446 Label copy;
1447 __ bind(&copy);
1448 __ inc(ecx);
1449 __ push(Operand(eax, 0));
1450 __ sub(Operand(eax), Immediate(kPointerSize));
1451 __ cmp(ecx, Operand(ebx));
1452 __ j(less, &copy);
1453 __ jmp(&invoke);
1454 }
1455
1456 { // Too few parameters: Actual < expected.
1457 __ bind(&too_few);
1458 EnterArgumentsAdaptorFrame(masm);
1459
1460 // Copy receiver and all actual arguments.
1461 const int offset = StandardFrameConstants::kCallerSPOffset;
1462 __ lea(edi, Operand(ebp, eax, times_4, offset));
1463 __ mov(ecx, -1); // account for receiver
1464
1465 Label copy;
1466 __ bind(&copy);
1467 __ inc(ecx);
1468 __ push(Operand(edi, 0));
1469 __ sub(Operand(edi), Immediate(kPointerSize));
1470 __ cmp(ecx, Operand(eax));
1471 __ j(less, &copy);
1472
1473 // Fill remaining expected arguments with undefined values.
1474 Label fill;
1475 __ bind(&fill);
1476 __ inc(ecx);
1477 __ push(Immediate(Factory::undefined_value()));
1478 __ cmp(ecx, Operand(ebx));
1479 __ j(less, &fill);
1480
1481 // Restore function pointer.
1482 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1483 }
1484
1485 // Call the entry point.
1486 __ bind(&invoke);
1487 __ call(Operand(edx));
1488
1489 // Leave frame and return.
1490 LeaveArgumentsAdaptorFrame(masm);
1491 __ ret(0);
1492
1493 // -------------------------------------------
1494 // Dont adapt arguments.
1495 // -------------------------------------------
1496 __ bind(&dont_adapt_arguments);
1497 __ jmp(Operand(edx));
1498}
1499
1500
Ben Murdochb0fe1622011-05-05 13:52:32 +01001501void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1502 // We shouldn't be performing on-stack replacement in the first
1503 // place if the CPU features we need for the optimized Crankshaft
1504 // code aren't supported.
1505 CpuFeatures::Probe(false);
1506 if (!CpuFeatures::IsSupported(SSE2)) {
1507 __ Abort("Unreachable code: Cannot optimize without SSE2 support.");
1508 return;
1509 }
1510
1511 // Get the loop depth of the stack guard check. This is recorded in
1512 // a test(eax, depth) instruction right after the call.
1513 Label stack_check;
1514 __ mov(ebx, Operand(esp, 0)); // return address
1515 if (FLAG_debug_code) {
1516 __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte);
1517 __ Assert(equal, "test eax instruction not found after loop stack check");
1518 }
1519 __ movzx_b(ebx, Operand(ebx, 1)); // depth
1520
1521 // Get the loop nesting level at which we allow OSR from the
1522 // unoptimized code and check if we want to do OSR yet. If not we
1523 // should perform a stack guard check so we can get interrupts while
1524 // waiting for on-stack replacement.
1525 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1526 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
1527 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
1528 __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset));
1529 __ j(greater, &stack_check);
1530
1531 // Pass the function to optimize as the argument to the on-stack
1532 // replacement runtime function.
1533 __ EnterInternalFrame();
1534 __ push(eax);
1535 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1536 __ LeaveInternalFrame();
1537
1538 // If the result was -1 it means that we couldn't optimize the
1539 // function. Just return and continue in the unoptimized version.
1540 NearLabel skip;
1541 __ cmp(Operand(eax), Immediate(Smi::FromInt(-1)));
1542 __ j(not_equal, &skip);
1543 __ ret(0);
1544
1545 // If we decide not to perform on-stack replacement we perform a
1546 // stack guard check to enable interrupts.
1547 __ bind(&stack_check);
1548 NearLabel ok;
1549 ExternalReference stack_limit =
1550 ExternalReference::address_of_stack_limit();
1551 __ cmp(esp, Operand::StaticVariable(stack_limit));
1552 __ j(above_equal, &ok, taken);
1553 StackCheckStub stub;
1554 __ TailCallStub(&stub);
1555 __ Abort("Unreachable code: returned from tail call.");
1556 __ bind(&ok);
1557 __ ret(0);
1558
1559 __ bind(&skip);
1560 // Untag the AST id and push it on the stack.
1561 __ SmiUntag(eax);
1562 __ push(eax);
1563
1564 // Generate the code for doing the frame-to-frame translation using
1565 // the deoptimizer infrastructure.
1566 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1567 generator.Generate();
1568}
1569
1570
Steve Blocka7e24c12009-10-30 11:49:00 +00001571#undef __
1572
1573} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01001574
1575#endif // V8_TARGET_ARCH_IA32