blob: 7f9b7d858a5370e1c91157f7f7e6b03e387e2d86 [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_IA32)
31
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000032#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000033#include "deoptimizer.h"
34#include "full-codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036namespace v8 {
37namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
39
ager@chromium.org65dad4b2009-04-23 08:48:43 +000040#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
42
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000043void Builtins::Generate_Adaptor(MacroAssembler* masm,
44 CFunctionId id,
45 BuiltinExtraArguments extra_args) {
46 // ----------- S t a t e -------------
47 // -- eax : number of arguments excluding receiver
48 // -- edi : called function (only guaranteed when
49 // extra_args requires it)
50 // -- esi : context
51 // -- esp[0] : return address
52 // -- esp[4] : last argument
53 // -- ...
54 // -- esp[4 * argc] : first argument (argc == eax)
55 // -- esp[4 * (argc +1)] : receiver
56 // -----------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000057
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000058 // Insert extra arguments.
59 int num_extra_args = 0;
60 if (extra_args == NEEDS_CALLED_FUNCTION) {
61 num_extra_args = 1;
62 Register scratch = ebx;
63 __ pop(scratch); // Save return address.
64 __ push(edi);
65 __ push(scratch); // Restore return address.
66 } else {
67 ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
68 }
69
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000070 // JumpToExternalReference expects eax to contain the number of arguments
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000071 // including the receiver and the extra arguments.
72 __ add(Operand(eax), Immediate(num_extra_args + 1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000073 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074}
75
76
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000078 // ----------- S t a t e -------------
79 // -- eax: number of arguments
80 // -- edi: constructor function
81 // -----------------------------------
82
ager@chromium.org5ec48922009-05-05 07:25:34 +000083 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
ager@chromium.org5aa501c2009-06-23 07:57:28 +000091 // 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);
ager@chromium.org5aa501c2009-06-23 07:57:28 +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);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000103 Handle<Code> arguments_adaptor =
104 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000105 __ SetCallKind(ecx, CALL_AS_METHOD);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000106 __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000107}
108
109
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000110static void Generate_JSConstructStubHelper(MacroAssembler* masm,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000111 bool is_api_function,
112 bool count_constructions) {
113 // Should never count constructions for api objects.
114 ASSERT(!is_api_function || !count_constructions);
115
ager@chromium.org7c537e22008-10-16 08:43:32 +0000116 // Enter a construct frame.
117 __ EnterConstructFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118
119 // Store a smi-tagged arguments count on the stack.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000120 __ SmiTag(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121 __ push(eax);
122
123 // Push the function to invoke on the stack.
124 __ push(edi);
125
126 // Try to allocate the object without transitioning into C code. If any of the
127 // preconditions is not met, the code bails out to the runtime call.
128 Label rt_call, allocated;
129 if (FLAG_inline_new) {
130 Label undo_allocation;
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000131#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132 ExternalReference debug_step_in_fp =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000133 ExternalReference::debug_step_in_fp_address(masm->isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
135 __ j(not_equal, &rt_call);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000136#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000137
138 // Verified that the constructor is a JSFunction.
139 // Load the initial map and verify that it is in fact a map.
140 // edi: constructor
141 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
142 // Will both indicate a NULL and a Smi
143 __ test(eax, Immediate(kSmiTagMask));
144 __ j(zero, &rt_call);
145 // edi: constructor
146 // eax: initial map (if proven valid below)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000147 __ CmpObjectType(eax, MAP_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148 __ j(not_equal, &rt_call);
149
150 // Check that the constructor is not constructing a JSFunction (see comments
151 // in Runtime_NewObject in runtime.cc). In which case the initial map's
152 // instance type would be JS_FUNCTION_TYPE.
153 // edi: constructor
154 // eax: initial map
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000155 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000156 __ j(equal, &rt_call);
157
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000158 if (count_constructions) {
159 Label allocate;
160 // Decrease generous allocation count.
161 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
162 __ dec_b(FieldOperand(ecx, SharedFunctionInfo::kConstructionCountOffset));
163 __ j(not_zero, &allocate);
164
165 __ push(eax);
166 __ push(edi);
167
168 __ push(edi); // constructor
169 // The call will replace the stub, so the countdown is only done once.
170 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
171
172 __ pop(edi);
173 __ pop(eax);
174
175 __ bind(&allocate);
176 }
177
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178 // Now allocate the JSObject on the heap.
179 // edi: constructor
180 // eax: initial map
181 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000182 __ shl(edi, kPointerSizeLog2);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000183 __ AllocateInNewSpace(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000184 // Allocated the JSObject, now initialize the fields.
185 // eax: initial map
186 // ebx: JSObject
187 // edi: start of next object
188 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000189 Factory* factory = masm->isolate()->factory();
190 __ mov(ecx, factory->empty_fixed_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
192 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
193 // Set extra fields in the newly allocated object.
194 // eax: initial map
195 // ebx: JSObject
196 // edi: start of next object
197 { Label loop, entry;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000198 // To allow for truncation.
199 if (count_constructions) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000200 __ mov(edx, factory->one_pointer_filler_map());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000201 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000202 __ mov(edx, factory->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000203 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
205 __ jmp(&entry);
206 __ bind(&loop);
207 __ mov(Operand(ecx, 0), edx);
208 __ add(Operand(ecx), Immediate(kPointerSize));
209 __ bind(&entry);
210 __ cmp(ecx, Operand(edi));
211 __ j(less, &loop);
212 }
213
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000214 // Add the object tag to make the JSObject real, so that we can continue and
215 // jump into the continuation code at any time from now on. Any failures
216 // need to undo the allocation, so that the heap is in a consistent state
217 // and verifiable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218 // eax: initial map
219 // ebx: JSObject
220 // edi: start of next object
221 __ or_(Operand(ebx), Immediate(kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000223 // Check if a non-empty properties array is needed.
224 // Allocate and initialize a FixedArray if it is.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225 // eax: initial map
226 // ebx: JSObject
227 // edi: start of next object
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000228 // Calculate the total number of properties described by the map.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000229 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000230 __ movzx_b(ecx, FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
231 __ add(edx, Operand(ecx));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000232 // Calculate unused properties past the end of the in-object properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000233 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000234 __ sub(edx, Operand(ecx));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000235 // Done if no extra properties are to be allocated.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 __ j(zero, &allocated);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000237 __ Assert(positive, "Property allocation count failed.");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238
239 // Scale the number of elements by pointer size and add the header for
240 // FixedArrays to the start of the next object calculation from above.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241 // ebx: JSObject
242 // edi: start of next object (will be start of FixedArray)
243 // edx: number of elements in properties array
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000244 __ AllocateInNewSpace(FixedArray::kHeaderSize,
245 times_pointer_size,
246 edx,
247 edi,
248 ecx,
249 no_reg,
250 &undo_allocation,
251 RESULT_CONTAINS_TOP);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252
253 // Initialize the FixedArray.
254 // ebx: JSObject
255 // edi: FixedArray
256 // edx: number of elements
257 // ecx: start of next object
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000258 __ mov(eax, factory->fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000259 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
260 __ SmiTag(edx);
261 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000262
263 // Initialize the fields to undefined.
264 // ebx: JSObject
265 // edi: FixedArray
266 // ecx: start of next object
267 { Label loop, entry;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000268 __ mov(edx, factory->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000269 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
270 __ jmp(&entry);
271 __ bind(&loop);
272 __ mov(Operand(eax, 0), edx);
273 __ add(Operand(eax), Immediate(kPointerSize));
274 __ bind(&entry);
275 __ cmp(eax, Operand(ecx));
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000276 __ j(below, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277 }
278
279 // Store the initialized FixedArray into the properties field of
280 // the JSObject
281 // ebx: JSObject
282 // edi: FixedArray
283 __ or_(Operand(edi), Immediate(kHeapObjectTag)); // add the heap tag
284 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
285
286
287 // Continue with JSObject being successfully allocated
288 // ebx: JSObject
289 __ jmp(&allocated);
290
291 // Undo the setting of the new top so that the heap is verifiable. For
292 // example, the map's unused properties potentially do not match the
293 // allocated objects unused properties.
294 // ebx: JSObject (previous new top)
295 __ bind(&undo_allocation);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000296 __ UndoAllocationInNewSpace(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297 }
298
299 // Allocate the new receiver object using the runtime call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300 __ bind(&rt_call);
301 // Must restore edi (constructor) before calling runtime.
302 __ mov(edi, Operand(esp, 0));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000303 // edi: function (constructor)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304 __ push(edi);
305 __ CallRuntime(Runtime::kNewObject, 1);
306 __ mov(ebx, Operand(eax)); // store result in ebx
307
308 // New object allocated.
309 // ebx: newly allocated object
310 __ bind(&allocated);
311 // Retrieve the function from the stack.
312 __ pop(edi);
313
314 // Retrieve smi-tagged arguments count from the stack.
315 __ mov(eax, Operand(esp, 0));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000316 __ SmiUntag(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317
318 // Push the allocated receiver to the stack. We need two copies
319 // because we may have to return the original one and the calling
320 // conventions dictate that the called function pops the receiver.
321 __ push(ebx);
322 __ push(ebx);
323
324 // Setup pointer to last argument.
325 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
326
327 // Copy arguments and receiver to the expression stack.
328 Label loop, entry;
329 __ mov(ecx, Operand(eax));
330 __ jmp(&entry);
331 __ bind(&loop);
332 __ push(Operand(ebx, ecx, times_4, 0));
333 __ bind(&entry);
334 __ dec(ecx);
335 __ j(greater_equal, &loop);
336
337 // Call the function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000338 if (is_api_function) {
339 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000340 Handle<Code> code =
341 masm->isolate()->builtins()->HandleApiCallConstruct();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000342 ParameterCount expected(0);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000343 __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
344 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000345 } else {
346 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000347 __ InvokeFunction(edi, actual, CALL_FUNCTION,
348 NullCallWrapper(), CALL_AS_METHOD);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350
351 // Restore context from the frame.
352 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
353
354 // If the result is an object (in the ECMA sense), we should get rid
355 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
356 // on page 74.
357 Label use_receiver, exit;
358
359 // If the result is a smi, it is *not* an object in the ECMA sense.
360 __ test(eax, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000361 __ j(zero, &use_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362
363 // If the type of the result (stored in its map) is less than
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000364 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
365 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000366 __ j(above_equal, &exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367
368 // Throw away the result of the constructor invocation and use the
369 // on-stack receiver as the result.
370 __ bind(&use_receiver);
371 __ mov(eax, Operand(esp, 0));
372
ager@chromium.org7c537e22008-10-16 08:43:32 +0000373 // Restore the arguments count and leave the construct frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374 __ bind(&exit);
375 __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
ager@chromium.org7c537e22008-10-16 08:43:32 +0000376 __ LeaveConstructFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377
378 // Remove caller arguments from the stack and return.
379 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
380 __ pop(ecx);
381 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
382 __ push(ecx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000383 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 __ ret(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385}
386
387
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000388void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
389 Generate_JSConstructStubHelper(masm, false, true);
390}
391
392
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000393void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000394 Generate_JSConstructStubHelper(masm, false, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000395}
396
397
398void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000399 Generate_JSConstructStubHelper(masm, true, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000400}
401
402
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000403static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
404 bool is_construct) {
405 // Clear the context before we push it when entering the JS frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000406 __ Set(esi, Immediate(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407
408 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000409 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410
411 // Load the previous frame pointer (ebx) to access C arguments
412 __ mov(ebx, Operand(ebp, 0));
413
414 // Get the function from the frame and setup the context.
415 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
416 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
417
418 // Push the function and the receiver onto the stack.
419 __ push(ecx);
420 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
421
422 // Load the number of arguments and setup pointer to the arguments.
423 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
424 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
425
426 // Copy arguments to the stack in a loop.
427 Label loop, entry;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000428 __ Set(ecx, Immediate(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 __ jmp(&entry);
430 __ bind(&loop);
431 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
432 __ push(Operand(edx, 0)); // dereference handle
433 __ inc(Operand(ecx));
434 __ bind(&entry);
435 __ cmp(ecx, Operand(eax));
436 __ j(not_equal, &loop);
437
438 // Get the function from the stack and call it.
439 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); // +1 ~ receiver
440
441 // Invoke the code.
442 if (is_construct) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000443 __ call(masm->isolate()->builtins()->JSConstructCall(),
444 RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445 } else {
446 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000447 __ InvokeFunction(edi, actual, CALL_FUNCTION,
448 NullCallWrapper(), CALL_AS_METHOD);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449 }
450
451 // Exit the JS frame. Notice that this also removes the empty
452 // context and the function left on the stack by the code
453 // invocation.
ager@chromium.org236ad962008-09-25 09:45:57 +0000454 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455 __ ret(1 * kPointerSize); // remove receiver
456}
457
458
459void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
460 Generate_JSEntryTrampolineHelper(masm, false);
461}
462
463
464void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
465 Generate_JSEntryTrampolineHelper(masm, true);
466}
467
468
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000469void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
470 // Enter an internal frame.
471 __ EnterInternalFrame();
472
danno@chromium.org40cb8782011-05-25 07:58:50 +0000473 // Push a copy of the function.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000474 __ push(edi);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000475 // Push call kind information.
476 __ push(ecx);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000477
478 __ push(edi); // Function is also the parameter to the runtime call.
479 __ CallRuntime(Runtime::kLazyCompile, 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000480
481 // Restore call kind information.
482 __ pop(ecx);
483 // Restore receiver.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000484 __ pop(edi);
485
486 // Tear down temporary frame.
487 __ LeaveInternalFrame();
488
489 // Do a tail-call of the compiled function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000490 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
491 __ jmp(Operand(eax));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000492}
493
494
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000495void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
496 // Enter an internal frame.
497 __ EnterInternalFrame();
498
499 // Push a copy of the function onto the stack.
500 __ push(edi);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000501 // Push call kind information.
502 __ push(ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000503
504 __ push(edi); // Function is also the parameter to the runtime call.
505 __ CallRuntime(Runtime::kLazyRecompile, 1);
506
danno@chromium.org40cb8782011-05-25 07:58:50 +0000507 // Restore call kind information.
508 __ pop(ecx);
509 // Restore receiver.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000510 __ pop(edi);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000511
512 // Tear down temporary frame.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000513 __ LeaveInternalFrame();
514
515 // Do a tail-call of the compiled function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000516 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
517 __ jmp(Operand(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000518}
519
520
521static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
522 Deoptimizer::BailoutType type) {
523 // Enter an internal frame.
524 __ EnterInternalFrame();
525
526 // Pass the function and deoptimization type to the runtime system.
527 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
528 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
529
530 // Tear down temporary frame.
531 __ LeaveInternalFrame();
532
533 // Get the full codegen state from the stack and untag it.
534 __ mov(ecx, Operand(esp, 1 * kPointerSize));
535 __ SmiUntag(ecx);
536
537 // Switch on the state.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000538 Label not_no_registers, not_tos_eax;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000539 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000540 __ j(not_equal, &not_no_registers, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000541 __ ret(1 * kPointerSize); // Remove state.
542
543 __ bind(&not_no_registers);
544 __ mov(eax, Operand(esp, 2 * kPointerSize));
545 __ cmp(ecx, FullCodeGenerator::TOS_REG);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000546 __ j(not_equal, &not_tos_eax, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000547 __ ret(2 * kPointerSize); // Remove state, eax.
548
549 __ bind(&not_tos_eax);
550 __ Abort("no cases left");
551}
552
553
554void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
555 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
556}
557
558
559void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
560 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
561}
562
563
564void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
565 // TODO(kasperl): Do we need to save/restore the XMM registers too?
566
567 // For now, we are relying on the fact that Runtime::NotifyOSR
568 // doesn't do any garbage collection which allows us to save/restore
569 // the registers without worrying about which of them contain
570 // pointers. This seems a bit fragile.
571 __ pushad();
572 __ EnterInternalFrame();
573 __ CallRuntime(Runtime::kNotifyOSR, 0);
574 __ LeaveInternalFrame();
575 __ popad();
576 __ ret(0);
577}
578
579
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000580void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000581 Factory* factory = masm->isolate()->factory();
582
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000583 // 1. Make sure we have at least one argument.
584 { Label done;
585 __ test(eax, Operand(eax));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000586 __ j(not_zero, &done);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000587 __ pop(ebx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000588 __ push(Immediate(factory->undefined_value()));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000589 __ push(ebx);
590 __ inc(eax);
591 __ bind(&done);
592 }
593
ager@chromium.org5c838252010-02-19 08:53:10 +0000594 // 2. Get the function to call (passed as receiver) from the stack, check
595 // if it is a function.
596 Label non_function;
597 // 1 ~ return address.
598 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
599 __ test(edi, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000600 __ j(zero, &non_function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000601 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000602 __ j(not_equal, &non_function);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000603
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000604
ager@chromium.org5c838252010-02-19 08:53:10 +0000605 // 3a. Patch the first argument if necessary when calling a function.
606 Label shift_arguments;
607 { Label convert_to_object, use_global_receiver, patch_receiver;
608 // Change context eagerly in case we need the global receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000609 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
610
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000611 // Do not transform the receiver for strict mode functions.
612 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
613 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
614 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
615 __ j(not_equal, &shift_arguments);
616
lrn@chromium.org1c092762011-05-09 09:42:16 +0000617 // Do not transform the receiver for natives (shared already in ebx).
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000618 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
619 1 << SharedFunctionInfo::kNativeBitWithinByte);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +0000620 __ j(not_equal, &shift_arguments);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000621
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000622 // Compute the receiver in non-strict mode.
ager@chromium.org5c838252010-02-19 08:53:10 +0000623 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000624
625 // Call ToObject on the receiver if it is not an object, or use the
626 // global object if it is null or undefined.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000627 __ test(ebx, Immediate(kSmiTagMask));
ager@chromium.org5c838252010-02-19 08:53:10 +0000628 __ j(zero, &convert_to_object);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000629 __ cmp(ebx, factory->null_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000630 __ j(equal, &use_global_receiver);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000631 __ cmp(ebx, factory->undefined_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000632 __ j(equal, &use_global_receiver);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000633 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
634 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000635 __ j(above_equal, &shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000636
ager@chromium.org5c838252010-02-19 08:53:10 +0000637 __ bind(&convert_to_object);
638 __ EnterInternalFrame(); // In order to preserve argument count.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000639 __ SmiTag(eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000640 __ push(eax);
641
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000642 __ push(ebx);
643 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000644 __ mov(ebx, eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000645
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000646 __ pop(eax);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000647 __ SmiUntag(eax);
ager@chromium.org236ad962008-09-25 09:45:57 +0000648 __ LeaveInternalFrame();
ager@chromium.org5c838252010-02-19 08:53:10 +0000649 // Restore the function to edi.
650 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000651 __ jmp(&patch_receiver);
652
ager@chromium.org5c838252010-02-19 08:53:10 +0000653 // Use the global receiver object from the called function as the
654 // receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000655 __ bind(&use_global_receiver);
656 const int kGlobalIndex =
657 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
658 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
ager@chromium.org3811b432009-10-28 14:53:37 +0000659 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
660 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000661 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000662
663 __ bind(&patch_receiver);
664 __ mov(Operand(esp, eax, times_4, 0), ebx);
665
ager@chromium.org5c838252010-02-19 08:53:10 +0000666 __ jmp(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000667 }
668
ager@chromium.org5c838252010-02-19 08:53:10 +0000669 // 3b. Patch the first argument when calling a non-function. The
670 // CALL_NON_FUNCTION builtin expects the non-function callee as
671 // receiver, so overwrite the first argument which will ultimately
672 // become the receiver.
673 __ bind(&non_function);
674 __ mov(Operand(esp, eax, times_4, 0), edi);
675 // Clear edi to indicate a non-function being called.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000676 __ Set(edi, Immediate(0));
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000677
ager@chromium.org5c838252010-02-19 08:53:10 +0000678 // 4. Shift arguments and return address one slot down on the stack
679 // (overwriting the original receiver). Adjust argument count to make
680 // the original first argument the new receiver.
681 __ bind(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000682 { Label loop;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000683 __ mov(ecx, eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000684 __ bind(&loop);
685 __ mov(ebx, Operand(esp, ecx, times_4, 0));
686 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
687 __ dec(ecx);
ager@chromium.org5c838252010-02-19 08:53:10 +0000688 __ j(not_sign, &loop); // While non-negative (to copy return address).
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000689 __ pop(ebx); // Discard copy of return address.
690 __ dec(eax); // One fewer argument (first argument is new receiver).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000691 }
692
ager@chromium.org5c838252010-02-19 08:53:10 +0000693 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
694 { Label function;
695 __ test(edi, Operand(edi));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000696 __ j(not_zero, &function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000697 __ Set(ebx, Immediate(0));
ager@chromium.org5c838252010-02-19 08:53:10 +0000698 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000699 __ SetCallKind(ecx, CALL_AS_METHOD);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000700 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
701 RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000702 __ bind(&function);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000703 }
704
ager@chromium.org5c838252010-02-19 08:53:10 +0000705 // 5b. Get the code to call from the function and check that the number of
706 // expected arguments matches what we're providing. If so, jump
707 // (tail-call) to the code in register edx without checking arguments.
708 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
709 __ mov(ebx,
710 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000711 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000712 __ SmiUntag(ebx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000713 __ SetCallKind(ecx, CALL_AS_METHOD);
ager@chromium.org5c838252010-02-19 08:53:10 +0000714 __ cmp(eax, Operand(ebx));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000715 __ j(not_equal,
716 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
ager@chromium.org5c838252010-02-19 08:53:10 +0000717
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000718 ParameterCount expected(0);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000719 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION,
720 NullCallWrapper(), CALL_AS_METHOD);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000721}
722
723
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000724void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000725 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000726
727 __ push(Operand(ebp, 4 * kPointerSize)); // push this
728 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments
729 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
730
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000731 // Check the stack for overflow. We are not trying need to catch
732 // interruptions (e.g. debug break and preemption) here, so the "real stack
733 // limit" is checked.
ager@chromium.org3811b432009-10-28 14:53:37 +0000734 Label okay;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000735 ExternalReference real_stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000736 ExternalReference::address_of_real_stack_limit(masm->isolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000737 __ mov(edi, Operand::StaticVariable(real_stack_limit));
738 // Make ecx the space we have left. The stack might already be overflowed
739 // here which will cause ecx to become negative.
ager@chromium.org3811b432009-10-28 14:53:37 +0000740 __ mov(ecx, Operand(esp));
741 __ sub(ecx, Operand(edi));
742 // Make edx the space we need for the array when it is unrolled onto the
743 // stack.
744 __ mov(edx, Operand(eax));
745 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000746 // Check if the arguments will overflow the stack.
ager@chromium.org3811b432009-10-28 14:53:37 +0000747 __ cmp(ecx, Operand(edx));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000748 __ j(greater, &okay); // Signed comparison.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000749
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000750 // Out of stack space.
ager@chromium.org3811b432009-10-28 14:53:37 +0000751 __ push(Operand(ebp, 4 * kPointerSize)); // push this
752 __ push(eax);
753 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
754 __ bind(&okay);
755 // End of stack check.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756
757 // Push current index and limit.
758 const int kLimitOffset =
759 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
760 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
761 __ push(eax); // limit
762 __ push(Immediate(0)); // index
763
764 // Change context eagerly to get the right global object if
765 // necessary.
766 __ mov(edi, Operand(ebp, 4 * kPointerSize));
767 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
768
769 // Compute the receiver.
770 Label call_to_object, use_global_receiver, push_receiver;
771 __ mov(ebx, Operand(ebp, 3 * kPointerSize));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000772
773 // Do not transform the receiver for strict mode functions.
774 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
775 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
776 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
777 __ j(not_equal, &push_receiver);
778
lrn@chromium.org1c092762011-05-09 09:42:16 +0000779 Factory* factory = masm->isolate()->factory();
780
781 // Do not transform the receiver for natives (shared already in ecx).
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000782 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
783 1 << SharedFunctionInfo::kNativeBitWithinByte);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +0000784 __ j(not_equal, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000785
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000786 // Compute the receiver in non-strict mode.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000787 // Call ToObject on the receiver if it is not an object, or use the
788 // global object if it is null or undefined.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789 __ test(ebx, Immediate(kSmiTagMask));
790 __ j(zero, &call_to_object);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000791 __ cmp(ebx, factory->null_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000792 __ j(equal, &use_global_receiver);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000793 __ cmp(ebx, factory->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000794 __ j(equal, &use_global_receiver);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000795 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
796 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000797 __ j(above_equal, &push_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000799 __ bind(&call_to_object);
800 __ push(ebx);
801 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
802 __ mov(ebx, Operand(eax));
803 __ jmp(&push_receiver);
804
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000805 // Use the current global receiver object as the receiver.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806 __ bind(&use_global_receiver);
807 const int kGlobalOffset =
808 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
809 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
ager@chromium.org3811b432009-10-28 14:53:37 +0000810 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
811 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000812 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813
814 // Push the receiver.
815 __ bind(&push_receiver);
816 __ push(ebx);
817
818 // Copy all arguments from the array to the stack.
819 Label entry, loop;
820 __ mov(eax, Operand(ebp, kIndexOffset));
821 __ jmp(&entry);
822 __ bind(&loop);
ager@chromium.org5c838252010-02-19 08:53:10 +0000823 __ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824
825 // Use inline caching to speed up access to arguments.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000826 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
ager@chromium.org236ad962008-09-25 09:45:57 +0000827 __ call(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000828 // It is important that we do not have a test instruction after the
829 // call. A test instruction after the call is used to indicate that
830 // we have generated an inline version of the keyed load. In this
831 // case, we know that we are not generating a test instruction next.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832
ager@chromium.org5c838252010-02-19 08:53:10 +0000833 // Push the nth argument.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000834 __ push(eax);
835
836 // Update the index on the stack and in register eax.
837 __ mov(eax, Operand(ebp, kIndexOffset));
838 __ add(Operand(eax), Immediate(1 << kSmiTagSize));
839 __ mov(Operand(ebp, kIndexOffset), eax);
840
841 __ bind(&entry);
842 __ cmp(eax, Operand(ebp, kLimitOffset));
843 __ j(not_equal, &loop);
844
845 // Invoke the function.
846 ParameterCount actual(eax);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000847 __ SmiUntag(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000848 __ mov(edi, Operand(ebp, 4 * kPointerSize));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000849 __ InvokeFunction(edi, actual, CALL_FUNCTION,
850 NullCallWrapper(), CALL_AS_METHOD);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851
ager@chromium.org236ad962008-09-25 09:45:57 +0000852 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
854}
855
856
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000857// Number of empty elements to allocate for an empty array.
858static const int kPreallocatedArrayElements = 4;
859
860
861// Allocate an empty JSArray. The allocated array is put into the result
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000862// register. If the parameter initial_capacity is larger than zero an elements
863// backing store is allocated with this size and filled with the hole values.
864// Otherwise the elements backing store is set to the empty FixedArray.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000865static void AllocateEmptyJSArray(MacroAssembler* masm,
866 Register array_function,
867 Register result,
868 Register scratch1,
869 Register scratch2,
870 Register scratch3,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000871 int initial_capacity,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000872 Label* gc_required) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000873 ASSERT(initial_capacity >= 0);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000874
875 // Load the initial map from the array function.
876 __ mov(scratch1, FieldOperand(array_function,
877 JSFunction::kPrototypeOrInitialMapOffset));
878
879 // Allocate the JSArray object together with space for a fixed array with the
880 // requested elements.
881 int size = JSArray::kSize;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000882 if (initial_capacity > 0) {
883 size += FixedArray::SizeFor(initial_capacity);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000884 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000885 __ AllocateInNewSpace(size,
886 result,
887 scratch2,
888 scratch3,
889 gc_required,
890 TAG_OBJECT);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000891
892 // Allocated the JSArray. Now initialize the fields except for the elements
893 // array.
894 // result: JSObject
895 // scratch1: initial map
896 // scratch2: start of next object
897 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000898 Factory* factory = masm->isolate()->factory();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000899 __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000900 factory->empty_fixed_array());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000901 // Field JSArray::kElementsOffset is initialized later.
902 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
903
904 // If no storage is requested for the elements array just set the empty
905 // fixed array.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000906 if (initial_capacity == 0) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000907 __ mov(FieldOperand(result, JSArray::kElementsOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000908 factory->empty_fixed_array());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000909 return;
910 }
911
912 // Calculate the location of the elements array and set elements array member
913 // of the JSArray.
914 // result: JSObject
915 // scratch2: start of next object
916 __ lea(scratch1, Operand(result, JSArray::kSize));
917 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
918
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000919 // Initialize the FixedArray and fill it with holes. FixedArray length is
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000920 // stored as a smi.
921 // result: JSObject
922 // scratch1: elements array
923 // scratch2: start of next object
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000924 __ mov(FieldOperand(scratch1, FixedArray::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000925 factory->fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000926 __ mov(FieldOperand(scratch1, FixedArray::kLengthOffset),
927 Immediate(Smi::FromInt(initial_capacity)));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000928
929 // Fill the FixedArray with the hole value. Inline the code if short.
930 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
931 static const int kLoopUnfoldLimit = 4;
932 ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000933 if (initial_capacity <= kLoopUnfoldLimit) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000934 // Use a scratch register here to have only one reloc info when unfolding
935 // the loop.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000936 __ mov(scratch3, factory->the_hole_value());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000937 for (int i = 0; i < initial_capacity; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000938 __ mov(FieldOperand(scratch1,
939 FixedArray::kHeaderSize + i * kPointerSize),
940 scratch3);
941 }
942 } else {
943 Label loop, entry;
944 __ jmp(&entry);
945 __ bind(&loop);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000946 __ mov(Operand(scratch1, 0), factory->the_hole_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000947 __ add(Operand(scratch1), Immediate(kPointerSize));
948 __ bind(&entry);
949 __ cmp(scratch1, Operand(scratch2));
950 __ j(below, &loop);
951 }
952}
953
954
955// Allocate a JSArray with the number of elements stored in a register. The
956// register array_function holds the built-in Array function and the register
957// array_size holds the size of the array as a smi. The allocated array is put
958// into the result register and beginning and end of the FixedArray elements
959// storage is put into registers elements_array and elements_array_end (see
960// below for when that is not the case). If the parameter fill_with_holes is
961// true the allocated elements backing store is filled with the hole values
962// otherwise it is left uninitialized. When the backing store is filled the
963// register elements_array is scratched.
964static void AllocateJSArray(MacroAssembler* masm,
965 Register array_function, // Array function.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000966 Register array_size, // As a smi, cannot be 0.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000967 Register result,
968 Register elements_array,
969 Register elements_array_end,
970 Register scratch,
971 bool fill_with_hole,
972 Label* gc_required) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000973 ASSERT(scratch.is(edi)); // rep stos destination
974 ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000975 ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000976
977 // Load the initial map from the array function.
978 __ mov(elements_array,
979 FieldOperand(array_function,
980 JSFunction::kPrototypeOrInitialMapOffset));
981
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000982 // Allocate the JSArray object together with space for a FixedArray with the
983 // requested elements.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000984 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000985 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
986 times_half_pointer_size, // array_size is a smi.
987 array_size,
988 result,
989 elements_array_end,
990 scratch,
991 gc_required,
992 TAG_OBJECT);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000993
994 // Allocated the JSArray. Now initialize the fields except for the elements
995 // array.
996 // result: JSObject
997 // elements_array: initial map
998 // elements_array_end: start of next object
999 // array_size: size of array (smi)
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001000 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001001 Factory* factory = masm->isolate()->factory();
1002 __ mov(elements_array, factory->empty_fixed_array());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001003 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
1004 // Field JSArray::kElementsOffset is initialized later.
1005 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
1006
1007 // Calculate the location of the elements array and set elements array member
1008 // of the JSArray.
1009 // result: JSObject
1010 // elements_array_end: start of next object
1011 // array_size: size of array (smi)
1012 __ lea(elements_array, Operand(result, JSArray::kSize));
1013 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
1014
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001015 // Initialize the fixed array. FixedArray length is stored as a smi.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001016 // result: JSObject
1017 // elements_array: elements array
1018 // elements_array_end: start of next object
1019 // array_size: size of array (smi)
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001020 __ mov(FieldOperand(elements_array, FixedArray::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001021 factory->fixed_array_map());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001022 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
1023 // same.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001024 __ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001025
1026 // Fill the allocated FixedArray with the hole value if requested.
1027 // result: JSObject
1028 // elements_array: elements array
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001029 if (fill_with_hole) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001030 __ SmiUntag(array_size);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001031 __ lea(edi, Operand(elements_array,
1032 FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001033 __ mov(eax, factory->the_hole_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001034 __ cld();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001035 // Do not use rep stos when filling less than kRepStosThreshold
1036 // words.
1037 const int kRepStosThreshold = 16;
1038 Label loop, entry, done;
1039 __ cmp(ecx, kRepStosThreshold);
1040 __ j(below, &loop); // Note: ecx > 0.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001041 __ rep_stos();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001042 __ jmp(&done);
1043 __ bind(&loop);
1044 __ stos();
1045 __ bind(&entry);
1046 __ cmp(edi, Operand(elements_array_end));
1047 __ j(below, &loop);
1048 __ bind(&done);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001049 }
1050}
1051
1052
1053// Create a new array for the built-in Array function. This function allocates
1054// the JSArray object and the FixedArray elements array and initializes these.
1055// If the Array cannot be constructed in native code the runtime is called. This
1056// function assumes the following state:
1057// edi: constructor (built-in Array function)
1058// eax: argc
1059// esp[0]: return address
1060// esp[4]: last argument
1061// This function is used for both construct and normal calls of Array. Whether
1062// it is a construct call or not is indicated by the construct_call parameter.
1063// The only difference between handling a construct call and a normal call is
1064// that for a construct call the constructor function in edi needs to be
1065// preserved for entering the generic code. In both cases argc in eax needs to
1066// be preserved.
1067static void ArrayNativeCode(MacroAssembler* masm,
1068 bool construct_call,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001069 Label* call_generic_code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001070 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
1071 empty_array, not_empty_array;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001072
1073 // Push the constructor and argc. No need to tag argc as a smi, as there will
1074 // be no garbage collection with this on the stack.
1075 int push_count = 0;
1076 if (construct_call) {
1077 push_count++;
1078 __ push(edi);
1079 }
1080 push_count++;
1081 __ push(eax);
1082
1083 // Check for array construction with zero arguments.
1084 __ test(eax, Operand(eax));
1085 __ j(not_zero, &argc_one_or_more);
1086
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001087 __ bind(&empty_array);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001088 // Handle construction of an empty array.
1089 AllocateEmptyJSArray(masm,
1090 edi,
1091 eax,
1092 ebx,
1093 ecx,
1094 edi,
1095 kPreallocatedArrayElements,
1096 &prepare_generic_code_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001097 __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001098 __ pop(ebx);
1099 if (construct_call) {
1100 __ pop(edi);
1101 }
1102 __ ret(kPointerSize);
1103
1104 // Check for one argument. Bail out if argument is not smi or if it is
1105 // negative.
1106 __ bind(&argc_one_or_more);
1107 __ cmp(eax, 1);
1108 __ j(not_equal, &argc_two_or_more);
1109 ASSERT(kSmiTag == 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001110 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
1111 __ test(ecx, Operand(ecx));
1112 __ j(not_zero, &not_empty_array);
1113
1114 // The single argument passed is zero, so we jump to the code above used to
1115 // handle the case of no arguments passed. To adapt the stack for that we move
1116 // the return address and the pushed constructor (if pushed) one stack slot up
1117 // thereby removing the passed argument. Argc is also on the stack - at the
1118 // bottom - and it needs to be changed from 1 to 0 to have the call into the
1119 // runtime system work in case a GC is required.
1120 for (int i = push_count; i > 0; i--) {
1121 __ mov(eax, Operand(esp, i * kPointerSize));
1122 __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
1123 }
1124 __ add(Operand(esp), Immediate(2 * kPointerSize)); // Drop two stack slots.
1125 __ push(Immediate(0)); // Treat this as a call with argc of zero.
1126 __ jmp(&empty_array);
1127
1128 __ bind(&not_empty_array);
1129 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001130 __ j(not_zero, &prepare_generic_code_call);
1131
1132 // Handle construction of an empty array of a certain size. Get the size from
1133 // the stack and bail out if size is to large to actually allocate an elements
1134 // array.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001135 __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001136 __ j(greater_equal, &prepare_generic_code_call);
1137
1138 // edx: array_size (smi)
1139 // edi: constructor
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001140 // esp[0]: argc (cannot be 0 here)
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001141 // esp[4]: constructor (only if construct_call)
1142 // esp[8]: return address
1143 // esp[C]: argument
1144 AllocateJSArray(masm,
1145 edi,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001146 ecx,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001147 ebx,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001148 eax,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001149 edx,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001150 edi,
1151 true,
1152 &prepare_generic_code_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001153 Counters* counters = masm->isolate()->counters();
1154 __ IncrementCounter(counters->array_function_native(), 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001155 __ mov(eax, ebx);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001156 __ pop(ebx);
1157 if (construct_call) {
1158 __ pop(edi);
1159 }
1160 __ ret(2 * kPointerSize);
1161
1162 // Handle construction of an array from a list of arguments.
1163 __ bind(&argc_two_or_more);
1164 ASSERT(kSmiTag == 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001165 __ SmiTag(eax); // Convet argc to a smi.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001166 // eax: array_size (smi)
1167 // edi: constructor
1168 // esp[0] : argc
1169 // esp[4]: constructor (only if construct_call)
1170 // esp[8] : return address
1171 // esp[C] : last argument
1172 AllocateJSArray(masm,
1173 edi,
1174 eax,
1175 ebx,
1176 ecx,
1177 edx,
1178 edi,
1179 false,
1180 &prepare_generic_code_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001181 __ IncrementCounter(counters->array_function_native(), 1);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001182 __ mov(eax, ebx);
1183 __ pop(ebx);
1184 if (construct_call) {
1185 __ pop(edi);
1186 }
1187 __ push(eax);
1188 // eax: JSArray
1189 // ebx: argc
1190 // edx: elements_array_end (untagged)
1191 // esp[0]: JSArray
1192 // esp[4]: return address
1193 // esp[8]: last argument
1194
1195 // Location of the last argument
1196 __ lea(edi, Operand(esp, 2 * kPointerSize));
1197
1198 // Location of the first array element (Parameter fill_with_holes to
1199 // AllocateJSArrayis false, so the FixedArray is returned in ecx).
1200 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
1201
1202 // ebx: argc
1203 // edx: location of the first array element
1204 // edi: location of the last argument
1205 // esp[0]: JSArray
1206 // esp[4]: return address
1207 // esp[8]: last argument
1208 Label loop, entry;
1209 __ mov(ecx, ebx);
1210 __ jmp(&entry);
1211 __ bind(&loop);
1212 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1213 __ mov(Operand(edx, 0), eax);
1214 __ add(Operand(edx), Immediate(kPointerSize));
1215 __ bind(&entry);
1216 __ dec(ecx);
1217 __ j(greater_equal, &loop);
1218
1219 // Remove caller arguments from the stack and return.
1220 // ebx: argc
1221 // esp[0]: JSArray
1222 // esp[4]: return address
1223 // esp[8]: last argument
1224 __ pop(eax);
1225 __ pop(ecx);
1226 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1227 __ push(ecx);
1228 __ ret(0);
1229
1230 // Restore argc and constructor before running the generic code.
1231 __ bind(&prepare_generic_code_call);
1232 __ pop(eax);
1233 if (construct_call) {
1234 __ pop(edi);
1235 }
1236 __ jmp(call_generic_code);
1237}
1238
1239
1240void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1241 // ----------- S t a t e -------------
1242 // -- eax : argc
1243 // -- esp[0] : return address
1244 // -- esp[4] : last argument
1245 // -----------------------------------
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001246 Label generic_array_code;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001247
1248 // Get the Array function.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001249 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001250
1251 if (FLAG_debug_code) {
1252 // Initial map for the builtin Array function shoud be a map.
1253 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1254 // Will both indicate a NULL and a Smi.
1255 __ test(ebx, Immediate(kSmiTagMask));
1256 __ Assert(not_zero, "Unexpected initial map for Array function");
1257 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1258 __ Assert(equal, "Unexpected initial map for Array function");
1259 }
1260
1261 // Run the native code for the Array function called as a normal function.
1262 ArrayNativeCode(masm, false, &generic_array_code);
1263
1264 // Jump to the generic array code in case the specialized code cannot handle
1265 // the construction.
1266 __ bind(&generic_array_code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001267 Handle<Code> array_code =
1268 masm->isolate()->builtins()->ArrayCodeGeneric();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001269 __ jmp(array_code, RelocInfo::CODE_TARGET);
1270}
1271
1272
1273void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
1274 // ----------- S t a t e -------------
1275 // -- eax : argc
1276 // -- edi : constructor
1277 // -- esp[0] : return address
1278 // -- esp[4] : last argument
1279 // -----------------------------------
1280 Label generic_constructor;
1281
1282 if (FLAG_debug_code) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001283 // The array construct code is only set for the global and natives
1284 // builtin Array functions which always have maps.
1285
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001286 // Initial map for the builtin Array function should be a map.
1287 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1288 // Will both indicate a NULL and a Smi.
1289 __ test(ebx, Immediate(kSmiTagMask));
1290 __ Assert(not_zero, "Unexpected initial map for Array function");
1291 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1292 __ Assert(equal, "Unexpected initial map for Array function");
1293 }
1294
1295 // Run the native code for the Array function called as constructor.
1296 ArrayNativeCode(masm, true, &generic_constructor);
1297
1298 // Jump to the generic construct code in case the specialized code cannot
1299 // handle the construction.
1300 __ bind(&generic_constructor);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001301 Handle<Code> generic_construct_stub =
1302 masm->isolate()->builtins()->JSConstructStubGeneric();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001303 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1304}
1305
1306
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001307void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1308 // ----------- S t a t e -------------
1309 // -- eax : number of arguments
1310 // -- edi : constructor function
1311 // -- esp[0] : return address
1312 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1313 // -- esp[(argc + 1) * 4] : receiver
1314 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001315 Counters* counters = masm->isolate()->counters();
1316 __ IncrementCounter(counters->string_ctor_calls(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001317
1318 if (FLAG_debug_code) {
1319 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1320 __ cmp(edi, Operand(ecx));
1321 __ Assert(equal, "Unexpected String function");
1322 }
1323
1324 // Load the first argument into eax and get rid of the rest
1325 // (including the receiver).
1326 Label no_arguments;
1327 __ test(eax, Operand(eax));
1328 __ j(zero, &no_arguments);
1329 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1330 __ pop(ecx);
1331 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1332 __ push(ecx);
1333 __ mov(eax, ebx);
1334
1335 // Lookup the argument in the number to string cache.
1336 Label not_cached, argument_is_string;
1337 NumberToStringStub::GenerateLookupNumberStringCache(
1338 masm,
1339 eax, // Input.
1340 ebx, // Result.
1341 ecx, // Scratch 1.
1342 edx, // Scratch 2.
1343 false, // Input is known to be smi?
1344 &not_cached);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001345 __ IncrementCounter(counters->string_ctor_cached_number(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001346 __ bind(&argument_is_string);
1347 // ----------- S t a t e -------------
1348 // -- ebx : argument converted to string
1349 // -- edi : constructor function
1350 // -- esp[0] : return address
1351 // -----------------------------------
1352
1353 // Allocate a JSValue and put the tagged pointer into eax.
1354 Label gc_required;
1355 __ AllocateInNewSpace(JSValue::kSize,
1356 eax, // Result.
1357 ecx, // New allocation top (we ignore it).
1358 no_reg,
1359 &gc_required,
1360 TAG_OBJECT);
1361
1362 // Set the map.
1363 __ LoadGlobalFunctionInitialMap(edi, ecx);
1364 if (FLAG_debug_code) {
1365 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1366 JSValue::kSize >> kPointerSizeLog2);
1367 __ Assert(equal, "Unexpected string wrapper instance size");
1368 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1369 __ Assert(equal, "Unexpected unused properties of string wrapper");
1370 }
1371 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1372
1373 // Set properties and elements.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001374 Factory* factory = masm->isolate()->factory();
1375 __ Set(ecx, Immediate(factory->empty_fixed_array()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001376 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1377 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1378
1379 // Set the value.
1380 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1381
1382 // Ensure the object is fully initialized.
1383 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1384
1385 // We're done. Return.
1386 __ ret(0);
1387
1388 // The argument was not found in the number to string cache. Check
1389 // if it's a string already before calling the conversion builtin.
1390 Label convert_argument;
1391 __ bind(&not_cached);
1392 STATIC_ASSERT(kSmiTag == 0);
1393 __ test(eax, Immediate(kSmiTagMask));
1394 __ j(zero, &convert_argument);
1395 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1396 __ j(NegateCondition(is_string), &convert_argument);
1397 __ mov(ebx, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001398 __ IncrementCounter(counters->string_ctor_string_value(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001399 __ jmp(&argument_is_string);
1400
1401 // Invoke the conversion builtin and put the result into ebx.
1402 __ bind(&convert_argument);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001403 __ IncrementCounter(counters->string_ctor_conversions(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001404 __ EnterInternalFrame();
1405 __ push(edi); // Preserve the function.
1406 __ push(eax);
1407 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1408 __ pop(edi);
1409 __ LeaveInternalFrame();
1410 __ mov(ebx, eax);
1411 __ jmp(&argument_is_string);
1412
1413 // Load the empty string into ebx, remove the receiver from the
1414 // stack, and jump back to the case where the argument is a string.
1415 __ bind(&no_arguments);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001416 __ Set(ebx, Immediate(factory->empty_string()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001417 __ pop(ecx);
1418 __ lea(esp, Operand(esp, kPointerSize));
1419 __ push(ecx);
1420 __ jmp(&argument_is_string);
1421
1422 // At this point the argument is already a string. Call runtime to
1423 // create a string wrapper.
1424 __ bind(&gc_required);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001425 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001426 __ EnterInternalFrame();
1427 __ push(ebx);
1428 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1429 __ LeaveInternalFrame();
1430 __ ret(0);
1431}
1432
1433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1435 __ push(ebp);
1436 __ mov(ebp, Operand(esp));
1437
1438 // Store the arguments adaptor context sentinel.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001439 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440
1441 // Push the function on the stack.
1442 __ push(edi);
1443
danno@chromium.org40cb8782011-05-25 07:58:50 +00001444 // Preserve the number of arguments on the stack. Must preserve eax,
1445 // ebx and ecx because these registers are used when copying the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446 // arguments and the receiver.
1447 ASSERT(kSmiTagSize == 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001448 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1449 __ push(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450}
1451
1452
ager@chromium.org7c537e22008-10-16 08:43:32 +00001453static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454 // Retrieve the number of arguments from the stack.
1455 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1456
1457 // Leave the frame.
1458 __ leave();
1459
1460 // Remove caller arguments from the stack.
1461 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1462 __ pop(ecx);
1463 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1464 __ push(ecx);
1465}
1466
1467
1468void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1469 // ----------- S t a t e -------------
1470 // -- eax : actual number of arguments
1471 // -- ebx : expected number of arguments
danno@chromium.org40cb8782011-05-25 07:58:50 +00001472 // -- ecx : call kind information
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473 // -- edx : code entry to call
1474 // -----------------------------------
1475
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001476 Label invoke, dont_adapt_arguments;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001477 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478
1479 Label enough, too_few;
1480 __ cmp(eax, Operand(ebx));
1481 __ j(less, &too_few);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001482 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1483 __ j(equal, &dont_adapt_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484
1485 { // Enough parameters: Actual >= expected.
1486 __ bind(&enough);
1487 EnterArgumentsAdaptorFrame(masm);
1488
1489 // Copy receiver and all expected arguments.
1490 const int offset = StandardFrameConstants::kCallerSPOffset;
1491 __ lea(eax, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001492 __ mov(edi, -1); // account for receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493
1494 Label copy;
1495 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001496 __ inc(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 __ push(Operand(eax, 0));
1498 __ sub(Operand(eax), Immediate(kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001499 __ cmp(edi, Operand(ebx));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 __ j(less, &copy);
1501 __ jmp(&invoke);
1502 }
1503
1504 { // Too few parameters: Actual < expected.
1505 __ bind(&too_few);
1506 EnterArgumentsAdaptorFrame(masm);
1507
1508 // Copy receiver and all actual arguments.
1509 const int offset = StandardFrameConstants::kCallerSPOffset;
1510 __ lea(edi, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001511 // ebx = expected - actual.
1512 __ sub(ebx, Operand(eax));
1513 // eax = -actual - 1
1514 __ neg(eax);
1515 __ sub(Operand(eax), Immediate(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516
1517 Label copy;
1518 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001519 __ inc(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520 __ push(Operand(edi, 0));
1521 __ sub(Operand(edi), Immediate(kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001522 __ test(eax, Operand(eax));
1523 __ j(not_zero, &copy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524
1525 // Fill remaining expected arguments with undefined values.
1526 Label fill;
1527 __ bind(&fill);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001528 __ inc(eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001529 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001530 __ cmp(eax, Operand(ebx));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 __ j(less, &fill);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532 }
1533
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001534 // Call the entry point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 __ bind(&invoke);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001536 // Restore function pointer.
1537 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001538 __ call(Operand(edx));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539
ager@chromium.org7c537e22008-10-16 08:43:32 +00001540 // Leave frame and return.
1541 LeaveArgumentsAdaptorFrame(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 __ ret(0);
1543
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001545 // Dont adapt arguments.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001547 __ bind(&dont_adapt_arguments);
1548 __ jmp(Operand(edx));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549}
1550
1551
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001552void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001553 CpuFeatures::TryForceFeatureScope scope(SSE2);
1554 if (!CpuFeatures::IsSupported(SSE2)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001555 __ Abort("Unreachable code: Cannot optimize without SSE2 support.");
1556 return;
1557 }
1558
1559 // Get the loop depth of the stack guard check. This is recorded in
1560 // a test(eax, depth) instruction right after the call.
1561 Label stack_check;
1562 __ mov(ebx, Operand(esp, 0)); // return address
1563 if (FLAG_debug_code) {
1564 __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte);
1565 __ Assert(equal, "test eax instruction not found after loop stack check");
1566 }
1567 __ movzx_b(ebx, Operand(ebx, 1)); // depth
1568
1569 // Get the loop nesting level at which we allow OSR from the
1570 // unoptimized code and check if we want to do OSR yet. If not we
1571 // should perform a stack guard check so we can get interrupts while
1572 // waiting for on-stack replacement.
1573 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1574 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
1575 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
1576 __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset));
1577 __ j(greater, &stack_check);
1578
1579 // Pass the function to optimize as the argument to the on-stack
1580 // replacement runtime function.
1581 __ EnterInternalFrame();
1582 __ push(eax);
1583 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1584 __ LeaveInternalFrame();
1585
1586 // If the result was -1 it means that we couldn't optimize the
1587 // function. Just return and continue in the unoptimized version.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001588 Label skip;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001589 __ cmp(Operand(eax), Immediate(Smi::FromInt(-1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001590 __ j(not_equal, &skip, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001591 __ ret(0);
1592
1593 // If we decide not to perform on-stack replacement we perform a
1594 // stack guard check to enable interrupts.
1595 __ bind(&stack_check);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001596 Label ok;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001597 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 ExternalReference::address_of_stack_limit(masm->isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001599 __ cmp(esp, Operand::StaticVariable(stack_limit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001600 __ j(above_equal, &ok, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001601 StackCheckStub stub;
1602 __ TailCallStub(&stub);
1603 __ Abort("Unreachable code: returned from tail call.");
1604 __ bind(&ok);
1605 __ ret(0);
1606
1607 __ bind(&skip);
1608 // Untag the AST id and push it on the stack.
1609 __ SmiUntag(eax);
1610 __ push(eax);
1611
1612 // Generate the code for doing the frame-to-frame translation using
1613 // the deoptimizer infrastructure.
1614 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1615 generator.Generate();
1616}
1617
1618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619#undef __
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001620}
1621} // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001622
1623#endif // V8_TARGET_ARCH_IA32