blob: c7e552705d4eac5760cbceff73f669a2516b2919 [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.
Steve Block9fac8402011-05-12 15:51:54 +0100402 __ Set(esi, Immediate(0));
Steve Blocka7e24c12009-10-30 11:49:00 +0000403
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;
Steve Block9fac8402011-05-12 15:51:54 +0100424 __ Set(ecx, Immediate(0));
Steve Blocka7e24c12009-10-30 11:49:00 +0000425 __ 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
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100592 // Do not transform the receiver for strict mode functions.
593 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
594 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
595 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
596 __ j(not_equal, &shift_arguments);
597
598 // Compute the receiver in non-strict mode.
Andrei Popescu402d9372010-02-26 13:31:12 +0000599 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
Steve Blocka7e24c12009-10-30 11:49:00 +0000600 __ test(ebx, Immediate(kSmiTagMask));
Andrei Popescu402d9372010-02-26 13:31:12 +0000601 __ j(zero, &convert_to_object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000602
603 __ cmp(ebx, Factory::null_value());
604 __ j(equal, &use_global_receiver);
605 __ cmp(ebx, Factory::undefined_value());
606 __ j(equal, &use_global_receiver);
607
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100608 // We don't use IsObjectJSObjectType here because we jump on success.
Steve Blocka7e24c12009-10-30 11:49:00 +0000609 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
610 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100611 __ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
612 __ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000613 __ j(below_equal, &shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000614
Andrei Popescu402d9372010-02-26 13:31:12 +0000615 __ bind(&convert_to_object);
616 __ EnterInternalFrame(); // In order to preserve argument count.
Leon Clarkee46be812010-01-19 14:06:41 +0000617 __ SmiTag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000618 __ push(eax);
619
Steve Blocka7e24c12009-10-30 11:49:00 +0000620 __ push(ebx);
621 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
622 __ mov(ebx, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000623
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 __ pop(eax);
Leon Clarkee46be812010-01-19 14:06:41 +0000625 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000626 __ LeaveInternalFrame();
Andrei Popescu402d9372010-02-26 13:31:12 +0000627 // Restore the function to edi.
628 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +0000629 __ jmp(&patch_receiver);
630
Andrei Popescu402d9372010-02-26 13:31:12 +0000631 // Use the global receiver object from the called function as the
632 // receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000633 __ bind(&use_global_receiver);
634 const int kGlobalIndex =
635 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
636 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
Steve Blockd0582a62009-12-15 09:54:21 +0000637 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
638 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +0000639 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
640
641 __ bind(&patch_receiver);
642 __ mov(Operand(esp, eax, times_4, 0), ebx);
643
Andrei Popescu402d9372010-02-26 13:31:12 +0000644 __ jmp(&shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000645 }
646
Andrei Popescu402d9372010-02-26 13:31:12 +0000647 // 3b. Patch the first argument when calling a non-function. The
648 // CALL_NON_FUNCTION builtin expects the non-function callee as
649 // receiver, so overwrite the first argument which will ultimately
650 // become the receiver.
651 __ bind(&non_function);
652 __ mov(Operand(esp, eax, times_4, 0), edi);
653 // Clear edi to indicate a non-function being called.
Steve Block9fac8402011-05-12 15:51:54 +0100654 __ Set(edi, Immediate(0));
Leon Clarkee46be812010-01-19 14:06:41 +0000655
Andrei Popescu402d9372010-02-26 13:31:12 +0000656 // 4. Shift arguments and return address one slot down on the stack
657 // (overwriting the original receiver). Adjust argument count to make
658 // the original first argument the new receiver.
659 __ bind(&shift_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000660 { Label loop;
Leon Clarkee46be812010-01-19 14:06:41 +0000661 __ mov(ecx, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000662 __ bind(&loop);
663 __ mov(ebx, Operand(esp, ecx, times_4, 0));
664 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
665 __ dec(ecx);
Andrei Popescu402d9372010-02-26 13:31:12 +0000666 __ j(not_sign, &loop); // While non-negative (to copy return address).
Leon Clarkee46be812010-01-19 14:06:41 +0000667 __ pop(ebx); // Discard copy of return address.
668 __ dec(eax); // One fewer argument (first argument is new receiver).
Steve Blocka7e24c12009-10-30 11:49:00 +0000669 }
670
Andrei Popescu402d9372010-02-26 13:31:12 +0000671 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
672 { Label function;
673 __ test(edi, Operand(edi));
674 __ j(not_zero, &function, taken);
Steve Block9fac8402011-05-12 15:51:54 +0100675 __ Set(ebx, Immediate(0));
Andrei Popescu402d9372010-02-26 13:31:12 +0000676 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
677 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
678 RelocInfo::CODE_TARGET);
679 __ bind(&function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000680 }
681
Andrei Popescu402d9372010-02-26 13:31:12 +0000682 // 5b. Get the code to call from the function and check that the number of
683 // expected arguments matches what we're providing. If so, jump
684 // (tail-call) to the code in register edx without checking arguments.
685 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
686 __ mov(ebx,
687 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
Steve Block791712a2010-08-27 10:21:07 +0100688 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100689 __ SmiUntag(ebx);
Andrei Popescu402d9372010-02-26 13:31:12 +0000690 __ cmp(eax, Operand(ebx));
691 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline)));
692
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 ParameterCount expected(0);
694 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
695}
696
697
698void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
699 __ EnterInternalFrame();
700
701 __ push(Operand(ebp, 4 * kPointerSize)); // push this
702 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments
703 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
704
Steve Blockd0582a62009-12-15 09:54:21 +0000705 // Check the stack for overflow. We are not trying need to catch
706 // interruptions (e.g. debug break and preemption) here, so the "real stack
707 // limit" is checked.
708 Label okay;
709 ExternalReference real_stack_limit =
710 ExternalReference::address_of_real_stack_limit();
711 __ mov(edi, Operand::StaticVariable(real_stack_limit));
712 // Make ecx the space we have left. The stack might already be overflowed
713 // here which will cause ecx to become negative.
714 __ mov(ecx, Operand(esp));
715 __ sub(ecx, Operand(edi));
716 // Make edx the space we need for the array when it is unrolled onto the
717 // stack.
718 __ mov(edx, Operand(eax));
719 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
720 // Check if the arguments will overflow the stack.
721 __ cmp(ecx, Operand(edx));
722 __ j(greater, &okay, taken); // Signed comparison.
Steve Blocka7e24c12009-10-30 11:49:00 +0000723
Steve Blockd0582a62009-12-15 09:54:21 +0000724 // Out of stack space.
725 __ push(Operand(ebp, 4 * kPointerSize)); // push this
726 __ push(eax);
727 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
728 __ bind(&okay);
729 // End of stack check.
Steve Blocka7e24c12009-10-30 11:49:00 +0000730
731 // Push current index and limit.
732 const int kLimitOffset =
733 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
734 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
735 __ push(eax); // limit
736 __ push(Immediate(0)); // index
737
738 // Change context eagerly to get the right global object if
739 // necessary.
740 __ mov(edi, Operand(ebp, 4 * kPointerSize));
741 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
742
743 // Compute the receiver.
744 Label call_to_object, use_global_receiver, push_receiver;
745 __ mov(ebx, Operand(ebp, 3 * kPointerSize));
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100746
747 // Do not transform the receiver for strict mode functions.
748 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
749 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
750 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
751 __ j(not_equal, &push_receiver);
752
753 // Compute the receiver in non-strict mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000754 __ test(ebx, Immediate(kSmiTagMask));
755 __ j(zero, &call_to_object);
756 __ cmp(ebx, Factory::null_value());
757 __ j(equal, &use_global_receiver);
758 __ cmp(ebx, Factory::undefined_value());
759 __ j(equal, &use_global_receiver);
760
761 // If given receiver is already a JavaScript object then there's no
762 // reason for converting it.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100763 // We don't use IsObjectJSObjectType here because we jump on success.
Steve Blocka7e24c12009-10-30 11:49:00 +0000764 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
765 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100766 __ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
767 __ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
768 __ j(below_equal, &push_receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000769
770 // Convert the receiver to an object.
771 __ bind(&call_to_object);
772 __ push(ebx);
773 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
774 __ mov(ebx, Operand(eax));
775 __ jmp(&push_receiver);
776
777 // Use the current global receiver object as the receiver.
778 __ bind(&use_global_receiver);
779 const int kGlobalOffset =
780 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
781 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
Steve Blockd0582a62009-12-15 09:54:21 +0000782 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
783 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000784 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
785
786 // Push the receiver.
787 __ bind(&push_receiver);
788 __ push(ebx);
789
790 // Copy all arguments from the array to the stack.
791 Label entry, loop;
792 __ mov(eax, Operand(ebp, kIndexOffset));
793 __ jmp(&entry);
794 __ bind(&loop);
Andrei Popescu402d9372010-02-26 13:31:12 +0000795 __ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments
Steve Blocka7e24c12009-10-30 11:49:00 +0000796
797 // Use inline caching to speed up access to arguments.
798 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
799 __ call(ic, RelocInfo::CODE_TARGET);
800 // It is important that we do not have a test instruction after the
801 // call. A test instruction after the call is used to indicate that
802 // we have generated an inline version of the keyed load. In this
803 // case, we know that we are not generating a test instruction next.
804
Andrei Popescu402d9372010-02-26 13:31:12 +0000805 // Push the nth argument.
Steve Blocka7e24c12009-10-30 11:49:00 +0000806 __ push(eax);
807
808 // Update the index on the stack and in register eax.
809 __ mov(eax, Operand(ebp, kIndexOffset));
810 __ add(Operand(eax), Immediate(1 << kSmiTagSize));
811 __ mov(Operand(ebp, kIndexOffset), eax);
812
813 __ bind(&entry);
814 __ cmp(eax, Operand(ebp, kLimitOffset));
815 __ j(not_equal, &loop);
816
817 // Invoke the function.
818 ParameterCount actual(eax);
Leon Clarkee46be812010-01-19 14:06:41 +0000819 __ SmiUntag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000820 __ mov(edi, Operand(ebp, 4 * kPointerSize));
821 __ InvokeFunction(edi, actual, CALL_FUNCTION);
822
823 __ LeaveInternalFrame();
824 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
825}
826
827
Steve Blocka7e24c12009-10-30 11:49:00 +0000828// Number of empty elements to allocate for an empty array.
829static const int kPreallocatedArrayElements = 4;
830
831
832// Allocate an empty JSArray. The allocated array is put into the result
833// register. If the parameter initial_capacity is larger than zero an elements
834// backing store is allocated with this size and filled with the hole values.
835// Otherwise the elements backing store is set to the empty FixedArray.
836static void AllocateEmptyJSArray(MacroAssembler* masm,
837 Register array_function,
838 Register result,
839 Register scratch1,
840 Register scratch2,
841 Register scratch3,
842 int initial_capacity,
843 Label* gc_required) {
844 ASSERT(initial_capacity >= 0);
845
846 // Load the initial map from the array function.
847 __ mov(scratch1, FieldOperand(array_function,
848 JSFunction::kPrototypeOrInitialMapOffset));
849
850 // Allocate the JSArray object together with space for a fixed array with the
851 // requested elements.
852 int size = JSArray::kSize;
853 if (initial_capacity > 0) {
854 size += FixedArray::SizeFor(initial_capacity);
855 }
856 __ AllocateInNewSpace(size,
857 result,
858 scratch2,
859 scratch3,
860 gc_required,
861 TAG_OBJECT);
862
863 // Allocated the JSArray. Now initialize the fields except for the elements
864 // array.
865 // result: JSObject
866 // scratch1: initial map
867 // scratch2: start of next object
868 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
869 __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
870 Factory::empty_fixed_array());
871 // Field JSArray::kElementsOffset is initialized later.
872 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
873
874 // If no storage is requested for the elements array just set the empty
875 // fixed array.
876 if (initial_capacity == 0) {
877 __ mov(FieldOperand(result, JSArray::kElementsOffset),
878 Factory::empty_fixed_array());
879 return;
880 }
881
882 // Calculate the location of the elements array and set elements array member
883 // of the JSArray.
884 // result: JSObject
885 // scratch2: start of next object
886 __ lea(scratch1, Operand(result, JSArray::kSize));
887 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
888
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100889 // Initialize the FixedArray and fill it with holes. FixedArray length is
Steve Blocka7e24c12009-10-30 11:49:00 +0000890 // stored as a smi.
891 // result: JSObject
892 // scratch1: elements array
893 // scratch2: start of next object
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100894 __ mov(FieldOperand(scratch1, FixedArray::kMapOffset),
Steve Blocka7e24c12009-10-30 11:49:00 +0000895 Factory::fixed_array_map());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100896 __ mov(FieldOperand(scratch1, FixedArray::kLengthOffset),
897 Immediate(Smi::FromInt(initial_capacity)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000898
899 // Fill the FixedArray with the hole value. Inline the code if short.
900 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
901 static const int kLoopUnfoldLimit = 4;
902 ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
903 if (initial_capacity <= kLoopUnfoldLimit) {
904 // Use a scratch register here to have only one reloc info when unfolding
905 // the loop.
906 __ mov(scratch3, Factory::the_hole_value());
907 for (int i = 0; i < initial_capacity; i++) {
908 __ mov(FieldOperand(scratch1,
909 FixedArray::kHeaderSize + i * kPointerSize),
910 scratch3);
911 }
912 } else {
913 Label loop, entry;
914 __ jmp(&entry);
915 __ bind(&loop);
916 __ mov(Operand(scratch1, 0), Factory::the_hole_value());
917 __ add(Operand(scratch1), Immediate(kPointerSize));
918 __ bind(&entry);
919 __ cmp(scratch1, Operand(scratch2));
920 __ j(below, &loop);
921 }
922}
923
924
925// Allocate a JSArray with the number of elements stored in a register. The
926// register array_function holds the built-in Array function and the register
927// array_size holds the size of the array as a smi. The allocated array is put
928// into the result register and beginning and end of the FixedArray elements
929// storage is put into registers elements_array and elements_array_end (see
930// below for when that is not the case). If the parameter fill_with_holes is
931// true the allocated elements backing store is filled with the hole values
932// otherwise it is left uninitialized. When the backing store is filled the
933// register elements_array is scratched.
934static void AllocateJSArray(MacroAssembler* masm,
935 Register array_function, // Array function.
Steve Block6ded16b2010-05-10 14:33:55 +0100936 Register array_size, // As a smi, cannot be 0.
Steve Blocka7e24c12009-10-30 11:49:00 +0000937 Register result,
938 Register elements_array,
939 Register elements_array_end,
940 Register scratch,
941 bool fill_with_hole,
942 Label* gc_required) {
Steve Block6ded16b2010-05-10 14:33:55 +0100943 ASSERT(scratch.is(edi)); // rep stos destination
944 ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
Leon Clarkef7060e22010-06-03 12:02:55 +0100945 ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax
Steve Blocka7e24c12009-10-30 11:49:00 +0000946
947 // Load the initial map from the array function.
948 __ mov(elements_array,
949 FieldOperand(array_function,
950 JSFunction::kPrototypeOrInitialMapOffset));
951
Steve Blocka7e24c12009-10-30 11:49:00 +0000952 // Allocate the JSArray object together with space for a FixedArray with the
953 // requested elements.
Steve Blocka7e24c12009-10-30 11:49:00 +0000954 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
955 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
956 times_half_pointer_size, // array_size is a smi.
957 array_size,
958 result,
959 elements_array_end,
960 scratch,
961 gc_required,
962 TAG_OBJECT);
963
964 // Allocated the JSArray. Now initialize the fields except for the elements
965 // array.
966 // result: JSObject
967 // elements_array: initial map
968 // elements_array_end: start of next object
969 // array_size: size of array (smi)
Steve Blocka7e24c12009-10-30 11:49:00 +0000970 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
971 __ mov(elements_array, Factory::empty_fixed_array());
972 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
973 // Field JSArray::kElementsOffset is initialized later.
974 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
975
976 // Calculate the location of the elements array and set elements array member
977 // of the JSArray.
978 // result: JSObject
979 // elements_array_end: start of next object
980 // array_size: size of array (smi)
981 __ lea(elements_array, Operand(result, JSArray::kSize));
982 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
983
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100984 // Initialize the fixed array. FixedArray length is stored as a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +0000985 // result: JSObject
986 // elements_array: elements array
987 // elements_array_end: start of next object
988 // array_size: size of array (smi)
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100989 __ mov(FieldOperand(elements_array, FixedArray::kMapOffset),
Steve Blocka7e24c12009-10-30 11:49:00 +0000990 Factory::fixed_array_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000991 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
992 // same.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100993 __ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000994
995 // Fill the allocated FixedArray with the hole value if requested.
996 // result: JSObject
997 // elements_array: elements array
Steve Blocka7e24c12009-10-30 11:49:00 +0000998 if (fill_with_hole) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100999 __ SmiUntag(array_size);
Steve Block6ded16b2010-05-10 14:33:55 +01001000 __ lea(edi, Operand(elements_array,
1001 FixedArray::kHeaderSize - kHeapObjectTag));
Steve Block6ded16b2010-05-10 14:33:55 +01001002 __ mov(eax, Factory::the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01001003 __ cld();
Leon Clarkef7060e22010-06-03 12:02:55 +01001004 // Do not use rep stos when filling less than kRepStosThreshold
1005 // words.
1006 const int kRepStosThreshold = 16;
1007 Label loop, entry, done;
1008 __ cmp(ecx, kRepStosThreshold);
1009 __ j(below, &loop); // Note: ecx > 0.
Steve Block6ded16b2010-05-10 14:33:55 +01001010 __ rep_stos();
Leon Clarkef7060e22010-06-03 12:02:55 +01001011 __ jmp(&done);
1012 __ bind(&loop);
1013 __ stos();
1014 __ bind(&entry);
1015 __ cmp(edi, Operand(elements_array_end));
1016 __ j(below, &loop);
1017 __ bind(&done);
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 }
1019}
1020
1021
1022// Create a new array for the built-in Array function. This function allocates
1023// the JSArray object and the FixedArray elements array and initializes these.
1024// If the Array cannot be constructed in native code the runtime is called. This
1025// function assumes the following state:
1026// edi: constructor (built-in Array function)
1027// eax: argc
1028// esp[0]: return address
1029// esp[4]: last argument
1030// This function is used for both construct and normal calls of Array. Whether
1031// it is a construct call or not is indicated by the construct_call parameter.
1032// The only difference between handling a construct call and a normal call is
1033// that for a construct call the constructor function in edi needs to be
1034// preserved for entering the generic code. In both cases argc in eax needs to
1035// be preserved.
1036static void ArrayNativeCode(MacroAssembler* masm,
1037 bool construct_call,
Steve Blockd0582a62009-12-15 09:54:21 +00001038 Label* call_generic_code) {
Steve Block6ded16b2010-05-10 14:33:55 +01001039 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
1040 empty_array, not_empty_array;
Steve Blocka7e24c12009-10-30 11:49:00 +00001041
1042 // Push the constructor and argc. No need to tag argc as a smi, as there will
1043 // be no garbage collection with this on the stack.
1044 int push_count = 0;
1045 if (construct_call) {
1046 push_count++;
1047 __ push(edi);
1048 }
1049 push_count++;
1050 __ push(eax);
1051
1052 // Check for array construction with zero arguments.
1053 __ test(eax, Operand(eax));
1054 __ j(not_zero, &argc_one_or_more);
1055
Steve Block6ded16b2010-05-10 14:33:55 +01001056 __ bind(&empty_array);
Steve Blocka7e24c12009-10-30 11:49:00 +00001057 // Handle construction of an empty array.
1058 AllocateEmptyJSArray(masm,
1059 edi,
1060 eax,
1061 ebx,
1062 ecx,
1063 edi,
1064 kPreallocatedArrayElements,
1065 &prepare_generic_code_call);
1066 __ IncrementCounter(&Counters::array_function_native, 1);
1067 __ pop(ebx);
1068 if (construct_call) {
1069 __ pop(edi);
1070 }
1071 __ ret(kPointerSize);
1072
1073 // Check for one argument. Bail out if argument is not smi or if it is
1074 // negative.
1075 __ bind(&argc_one_or_more);
1076 __ cmp(eax, 1);
1077 __ j(not_equal, &argc_two_or_more);
1078 ASSERT(kSmiTag == 0);
Steve Block6ded16b2010-05-10 14:33:55 +01001079 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
1080 __ test(ecx, Operand(ecx));
1081 __ j(not_zero, &not_empty_array);
1082
1083 // The single argument passed is zero, so we jump to the code above used to
1084 // handle the case of no arguments passed. To adapt the stack for that we move
1085 // the return address and the pushed constructor (if pushed) one stack slot up
1086 // thereby removing the passed argument. Argc is also on the stack - at the
1087 // bottom - and it needs to be changed from 1 to 0 to have the call into the
1088 // runtime system work in case a GC is required.
1089 for (int i = push_count; i > 0; i--) {
1090 __ mov(eax, Operand(esp, i * kPointerSize));
1091 __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
1092 }
1093 __ add(Operand(esp), Immediate(2 * kPointerSize)); // Drop two stack slots.
1094 __ push(Immediate(0)); // Treat this as a call with argc of zero.
1095 __ jmp(&empty_array);
1096
1097 __ bind(&not_empty_array);
1098 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001099 __ j(not_zero, &prepare_generic_code_call);
1100
1101 // Handle construction of an empty array of a certain size. Get the size from
1102 // the stack and bail out if size is to large to actually allocate an elements
1103 // array.
Steve Block6ded16b2010-05-10 14:33:55 +01001104 __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00001105 __ j(greater_equal, &prepare_generic_code_call);
1106
1107 // edx: array_size (smi)
1108 // edi: constructor
Steve Block6ded16b2010-05-10 14:33:55 +01001109 // esp[0]: argc (cannot be 0 here)
Steve Blocka7e24c12009-10-30 11:49:00 +00001110 // esp[4]: constructor (only if construct_call)
1111 // esp[8]: return address
1112 // esp[C]: argument
1113 AllocateJSArray(masm,
1114 edi,
Steve Block6ded16b2010-05-10 14:33:55 +01001115 ecx,
Steve Blocka7e24c12009-10-30 11:49:00 +00001116 ebx,
Leon Clarkef7060e22010-06-03 12:02:55 +01001117 eax,
Steve Block6ded16b2010-05-10 14:33:55 +01001118 edx,
Steve Blocka7e24c12009-10-30 11:49:00 +00001119 edi,
1120 true,
1121 &prepare_generic_code_call);
1122 __ IncrementCounter(&Counters::array_function_native, 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01001123 __ mov(eax, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001124 __ pop(ebx);
1125 if (construct_call) {
1126 __ pop(edi);
1127 }
1128 __ ret(2 * kPointerSize);
1129
1130 // Handle construction of an array from a list of arguments.
1131 __ bind(&argc_two_or_more);
1132 ASSERT(kSmiTag == 0);
Leon Clarkee46be812010-01-19 14:06:41 +00001133 __ SmiTag(eax); // Convet argc to a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +00001134 // eax: array_size (smi)
1135 // edi: constructor
1136 // esp[0] : argc
1137 // esp[4]: constructor (only if construct_call)
1138 // esp[8] : return address
1139 // esp[C] : last argument
1140 AllocateJSArray(masm,
1141 edi,
1142 eax,
1143 ebx,
1144 ecx,
1145 edx,
1146 edi,
1147 false,
1148 &prepare_generic_code_call);
1149 __ IncrementCounter(&Counters::array_function_native, 1);
1150 __ mov(eax, ebx);
1151 __ pop(ebx);
1152 if (construct_call) {
1153 __ pop(edi);
1154 }
1155 __ push(eax);
1156 // eax: JSArray
1157 // ebx: argc
1158 // edx: elements_array_end (untagged)
1159 // esp[0]: JSArray
1160 // esp[4]: return address
1161 // esp[8]: last argument
1162
1163 // Location of the last argument
1164 __ lea(edi, Operand(esp, 2 * kPointerSize));
1165
1166 // Location of the first array element (Parameter fill_with_holes to
1167 // AllocateJSArrayis false, so the FixedArray is returned in ecx).
1168 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
1169
1170 // ebx: argc
1171 // edx: location of the first array element
1172 // edi: location of the last argument
1173 // esp[0]: JSArray
1174 // esp[4]: return address
1175 // esp[8]: last argument
1176 Label loop, entry;
1177 __ mov(ecx, ebx);
1178 __ jmp(&entry);
1179 __ bind(&loop);
1180 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1181 __ mov(Operand(edx, 0), eax);
1182 __ add(Operand(edx), Immediate(kPointerSize));
1183 __ bind(&entry);
1184 __ dec(ecx);
1185 __ j(greater_equal, &loop);
1186
1187 // Remove caller arguments from the stack and return.
1188 // ebx: argc
1189 // esp[0]: JSArray
1190 // esp[4]: return address
1191 // esp[8]: last argument
1192 __ pop(eax);
1193 __ pop(ecx);
1194 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1195 __ push(ecx);
1196 __ ret(0);
1197
1198 // Restore argc and constructor before running the generic code.
1199 __ bind(&prepare_generic_code_call);
1200 __ pop(eax);
1201 if (construct_call) {
1202 __ pop(edi);
1203 }
1204 __ jmp(call_generic_code);
1205}
1206
1207
1208void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1209 // ----------- S t a t e -------------
1210 // -- eax : argc
1211 // -- esp[0] : return address
1212 // -- esp[4] : last argument
1213 // -----------------------------------
Kristian Monsen25f61362010-05-21 11:50:48 +01001214 Label generic_array_code;
Steve Blocka7e24c12009-10-30 11:49:00 +00001215
1216 // Get the Array function.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001217 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001218
1219 if (FLAG_debug_code) {
1220 // Initial map for the builtin Array function shoud be a map.
1221 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1222 // Will both indicate a NULL and a Smi.
1223 __ test(ebx, Immediate(kSmiTagMask));
1224 __ Assert(not_zero, "Unexpected initial map for Array function");
1225 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1226 __ Assert(equal, "Unexpected initial map for Array function");
1227 }
1228
1229 // Run the native code for the Array function called as a normal function.
1230 ArrayNativeCode(masm, false, &generic_array_code);
1231
1232 // Jump to the generic array code in case the specialized code cannot handle
1233 // the construction.
1234 __ bind(&generic_array_code);
1235 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
1236 Handle<Code> array_code(code);
1237 __ jmp(array_code, RelocInfo::CODE_TARGET);
1238}
1239
1240
1241void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
1242 // ----------- S t a t e -------------
1243 // -- eax : argc
1244 // -- edi : constructor
1245 // -- esp[0] : return address
1246 // -- esp[4] : last argument
1247 // -----------------------------------
1248 Label generic_constructor;
1249
1250 if (FLAG_debug_code) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001251 // The array construct code is only set for the global and natives
1252 // builtin Array functions which always have maps.
1253
Steve Blocka7e24c12009-10-30 11:49:00 +00001254 // Initial map for the builtin Array function should be a map.
1255 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1256 // Will both indicate a NULL and a Smi.
1257 __ test(ebx, Immediate(kSmiTagMask));
1258 __ Assert(not_zero, "Unexpected initial map for Array function");
1259 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1260 __ Assert(equal, "Unexpected initial map for Array function");
1261 }
1262
1263 // Run the native code for the Array function called as constructor.
1264 ArrayNativeCode(masm, true, &generic_constructor);
1265
1266 // Jump to the generic construct code in case the specialized code cannot
1267 // handle the construction.
1268 __ bind(&generic_constructor);
1269 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1270 Handle<Code> generic_construct_stub(code);
1271 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1272}
1273
1274
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001275void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1276 // ----------- S t a t e -------------
1277 // -- eax : number of arguments
1278 // -- edi : constructor function
1279 // -- esp[0] : return address
1280 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1281 // -- esp[(argc + 1) * 4] : receiver
1282 // -----------------------------------
1283 __ IncrementCounter(&Counters::string_ctor_calls, 1);
1284
1285 if (FLAG_debug_code) {
1286 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1287 __ cmp(edi, Operand(ecx));
1288 __ Assert(equal, "Unexpected String function");
1289 }
1290
1291 // Load the first argument into eax and get rid of the rest
1292 // (including the receiver).
1293 Label no_arguments;
1294 __ test(eax, Operand(eax));
1295 __ j(zero, &no_arguments);
1296 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1297 __ pop(ecx);
1298 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1299 __ push(ecx);
1300 __ mov(eax, ebx);
1301
1302 // Lookup the argument in the number to string cache.
1303 Label not_cached, argument_is_string;
1304 NumberToStringStub::GenerateLookupNumberStringCache(
1305 masm,
1306 eax, // Input.
1307 ebx, // Result.
1308 ecx, // Scratch 1.
1309 edx, // Scratch 2.
1310 false, // Input is known to be smi?
1311 &not_cached);
1312 __ IncrementCounter(&Counters::string_ctor_cached_number, 1);
1313 __ bind(&argument_is_string);
1314 // ----------- S t a t e -------------
1315 // -- ebx : argument converted to string
1316 // -- edi : constructor function
1317 // -- esp[0] : return address
1318 // -----------------------------------
1319
1320 // Allocate a JSValue and put the tagged pointer into eax.
1321 Label gc_required;
1322 __ AllocateInNewSpace(JSValue::kSize,
1323 eax, // Result.
1324 ecx, // New allocation top (we ignore it).
1325 no_reg,
1326 &gc_required,
1327 TAG_OBJECT);
1328
1329 // Set the map.
1330 __ LoadGlobalFunctionInitialMap(edi, ecx);
1331 if (FLAG_debug_code) {
1332 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1333 JSValue::kSize >> kPointerSizeLog2);
1334 __ Assert(equal, "Unexpected string wrapper instance size");
1335 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1336 __ Assert(equal, "Unexpected unused properties of string wrapper");
1337 }
1338 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1339
1340 // Set properties and elements.
1341 __ Set(ecx, Immediate(Factory::empty_fixed_array()));
1342 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1343 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1344
1345 // Set the value.
1346 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1347
1348 // Ensure the object is fully initialized.
1349 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1350
1351 // We're done. Return.
1352 __ ret(0);
1353
1354 // The argument was not found in the number to string cache. Check
1355 // if it's a string already before calling the conversion builtin.
1356 Label convert_argument;
1357 __ bind(&not_cached);
1358 STATIC_ASSERT(kSmiTag == 0);
1359 __ test(eax, Immediate(kSmiTagMask));
1360 __ j(zero, &convert_argument);
1361 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1362 __ j(NegateCondition(is_string), &convert_argument);
1363 __ mov(ebx, eax);
1364 __ IncrementCounter(&Counters::string_ctor_string_value, 1);
1365 __ jmp(&argument_is_string);
1366
1367 // Invoke the conversion builtin and put the result into ebx.
1368 __ bind(&convert_argument);
1369 __ IncrementCounter(&Counters::string_ctor_conversions, 1);
1370 __ EnterInternalFrame();
1371 __ push(edi); // Preserve the function.
1372 __ push(eax);
1373 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1374 __ pop(edi);
1375 __ LeaveInternalFrame();
1376 __ mov(ebx, eax);
1377 __ jmp(&argument_is_string);
1378
1379 // Load the empty string into ebx, remove the receiver from the
1380 // stack, and jump back to the case where the argument is a string.
1381 __ bind(&no_arguments);
1382 __ Set(ebx, Immediate(Factory::empty_string()));
1383 __ pop(ecx);
1384 __ lea(esp, Operand(esp, kPointerSize));
1385 __ push(ecx);
1386 __ jmp(&argument_is_string);
1387
1388 // At this point the argument is already a string. Call runtime to
1389 // create a string wrapper.
1390 __ bind(&gc_required);
1391 __ IncrementCounter(&Counters::string_ctor_gc_required, 1);
1392 __ EnterInternalFrame();
1393 __ push(ebx);
1394 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1395 __ LeaveInternalFrame();
1396 __ ret(0);
1397}
1398
1399
Steve Blocka7e24c12009-10-30 11:49:00 +00001400static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1401 __ push(ebp);
1402 __ mov(ebp, Operand(esp));
1403
1404 // Store the arguments adaptor context sentinel.
1405 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1406
1407 // Push the function on the stack.
1408 __ push(edi);
1409
1410 // Preserve the number of arguments on the stack. Must preserve both
1411 // eax and ebx because these registers are used when copying the
1412 // arguments and the receiver.
1413 ASSERT(kSmiTagSize == 1);
1414 __ lea(ecx, Operand(eax, eax, times_1, kSmiTag));
1415 __ push(ecx);
1416}
1417
1418
1419static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1420 // Retrieve the number of arguments from the stack.
1421 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1422
1423 // Leave the frame.
1424 __ leave();
1425
1426 // Remove caller arguments from the stack.
1427 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1428 __ pop(ecx);
1429 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1430 __ push(ecx);
1431}
1432
1433
1434void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1435 // ----------- S t a t e -------------
1436 // -- eax : actual number of arguments
1437 // -- ebx : expected number of arguments
1438 // -- edx : code entry to call
1439 // -----------------------------------
1440
1441 Label invoke, dont_adapt_arguments;
1442 __ IncrementCounter(&Counters::arguments_adaptors, 1);
1443
1444 Label enough, too_few;
1445 __ cmp(eax, Operand(ebx));
1446 __ j(less, &too_few);
1447 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1448 __ j(equal, &dont_adapt_arguments);
1449
1450 { // Enough parameters: Actual >= expected.
1451 __ bind(&enough);
1452 EnterArgumentsAdaptorFrame(masm);
1453
1454 // Copy receiver and all expected arguments.
1455 const int offset = StandardFrameConstants::kCallerSPOffset;
1456 __ lea(eax, Operand(ebp, eax, times_4, offset));
1457 __ mov(ecx, -1); // account for receiver
1458
1459 Label copy;
1460 __ bind(&copy);
1461 __ inc(ecx);
1462 __ push(Operand(eax, 0));
1463 __ sub(Operand(eax), Immediate(kPointerSize));
1464 __ cmp(ecx, Operand(ebx));
1465 __ j(less, &copy);
1466 __ jmp(&invoke);
1467 }
1468
1469 { // Too few parameters: Actual < expected.
1470 __ bind(&too_few);
1471 EnterArgumentsAdaptorFrame(masm);
1472
1473 // Copy receiver and all actual arguments.
1474 const int offset = StandardFrameConstants::kCallerSPOffset;
1475 __ lea(edi, Operand(ebp, eax, times_4, offset));
1476 __ mov(ecx, -1); // account for receiver
1477
1478 Label copy;
1479 __ bind(&copy);
1480 __ inc(ecx);
1481 __ push(Operand(edi, 0));
1482 __ sub(Operand(edi), Immediate(kPointerSize));
1483 __ cmp(ecx, Operand(eax));
1484 __ j(less, &copy);
1485
1486 // Fill remaining expected arguments with undefined values.
1487 Label fill;
1488 __ bind(&fill);
1489 __ inc(ecx);
1490 __ push(Immediate(Factory::undefined_value()));
1491 __ cmp(ecx, Operand(ebx));
1492 __ j(less, &fill);
1493
1494 // Restore function pointer.
1495 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1496 }
1497
1498 // Call the entry point.
1499 __ bind(&invoke);
1500 __ call(Operand(edx));
1501
1502 // Leave frame and return.
1503 LeaveArgumentsAdaptorFrame(masm);
1504 __ ret(0);
1505
1506 // -------------------------------------------
1507 // Dont adapt arguments.
1508 // -------------------------------------------
1509 __ bind(&dont_adapt_arguments);
1510 __ jmp(Operand(edx));
1511}
1512
1513
Ben Murdochb0fe1622011-05-05 13:52:32 +01001514void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1515 // We shouldn't be performing on-stack replacement in the first
1516 // place if the CPU features we need for the optimized Crankshaft
1517 // code aren't supported.
1518 CpuFeatures::Probe(false);
1519 if (!CpuFeatures::IsSupported(SSE2)) {
1520 __ Abort("Unreachable code: Cannot optimize without SSE2 support.");
1521 return;
1522 }
1523
1524 // Get the loop depth of the stack guard check. This is recorded in
1525 // a test(eax, depth) instruction right after the call.
1526 Label stack_check;
1527 __ mov(ebx, Operand(esp, 0)); // return address
1528 if (FLAG_debug_code) {
1529 __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte);
1530 __ Assert(equal, "test eax instruction not found after loop stack check");
1531 }
1532 __ movzx_b(ebx, Operand(ebx, 1)); // depth
1533
1534 // Get the loop nesting level at which we allow OSR from the
1535 // unoptimized code and check if we want to do OSR yet. If not we
1536 // should perform a stack guard check so we can get interrupts while
1537 // waiting for on-stack replacement.
1538 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1539 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
1540 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
1541 __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset));
1542 __ j(greater, &stack_check);
1543
1544 // Pass the function to optimize as the argument to the on-stack
1545 // replacement runtime function.
1546 __ EnterInternalFrame();
1547 __ push(eax);
1548 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1549 __ LeaveInternalFrame();
1550
1551 // If the result was -1 it means that we couldn't optimize the
1552 // function. Just return and continue in the unoptimized version.
1553 NearLabel skip;
1554 __ cmp(Operand(eax), Immediate(Smi::FromInt(-1)));
1555 __ j(not_equal, &skip);
1556 __ ret(0);
1557
1558 // If we decide not to perform on-stack replacement we perform a
1559 // stack guard check to enable interrupts.
1560 __ bind(&stack_check);
1561 NearLabel ok;
1562 ExternalReference stack_limit =
1563 ExternalReference::address_of_stack_limit();
1564 __ cmp(esp, Operand::StaticVariable(stack_limit));
1565 __ j(above_equal, &ok, taken);
1566 StackCheckStub stub;
1567 __ TailCallStub(&stub);
1568 __ Abort("Unreachable code: returned from tail call.");
1569 __ bind(&ok);
1570 __ ret(0);
1571
1572 __ bind(&skip);
1573 // Untag the AST id and push it on the stack.
1574 __ SmiUntag(eax);
1575 __ push(eax);
1576
1577 // Generate the code for doing the frame-to-frame translation using
1578 // the deoptimizer infrastructure.
1579 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1580 generator.Generate();
1581}
1582
1583
Steve Blocka7e24c12009-10-30 11:49:00 +00001584#undef __
1585
1586} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01001587
1588#endif // V8_TARGET_ARCH_IA32