blob: 24a2e6e35300da01b8c1df8a763fcd973dbe4b79 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 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
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_IA32
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
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.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000072 __ add(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
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000077static void CallRuntimePassFunction(MacroAssembler* masm,
78 Runtime::FunctionId function_id) {
79 FrameScope scope(masm, StackFrame::INTERNAL);
80 // Push a copy of the function.
81 __ push(edi);
82 // Push call kind information.
83 __ push(ecx);
84 // Function is also the parameter to the runtime call.
85 __ push(edi);
86
87 __ CallRuntime(function_id, 1);
88 // Restore call kind information.
89 __ pop(ecx);
90 // Restore receiver.
91 __ pop(edi);
92}
93
94
yangguo@chromium.org304cc332012-07-24 07:59:48 +000095static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
96 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
97 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kCodeOffset));
98 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
99 __ jmp(eax);
100}
101
102
103void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000104 // Checking whether the queued function is ready for install is optional,
105 // since we come across interrupts and stack checks elsewhere. However,
106 // not checking may delay installing ready functions, and always checking
107 // would be quite expensive. A good compromise is to first check against
108 // stack limit as a cue for an interrupt signal.
109 Label ok;
110 ExternalReference stack_limit =
111 ExternalReference::address_of_stack_limit(masm->isolate());
112 __ cmp(esp, Operand::StaticVariable(stack_limit));
113 __ j(above_equal, &ok, Label::kNear);
114
115 CallRuntimePassFunction(masm, Runtime::kTryInstallRecompiledCode);
116 // Tail call to returned code.
117 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
118 __ jmp(eax);
119
120 __ bind(&ok);
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000121 GenerateTailCallToSharedCode(masm);
122}
123
124
rossberg@chromium.org92597162013-08-23 13:28:00 +0000125void Builtins::Generate_ConcurrentRecompile(MacroAssembler* masm) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000126 CallRuntimePassFunction(masm, Runtime::kConcurrentRecompile);
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000127 GenerateTailCallToSharedCode(masm);
128}
129
130
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000131static void Generate_JSConstructStubHelper(MacroAssembler* masm,
132 bool is_api_function,
133 bool count_constructions) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000134 // ----------- S t a t e -------------
135 // -- eax: number of arguments
136 // -- edi: constructor function
137 // -----------------------------------
138
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000139 // Should never count constructions for api objects.
140 ASSERT(!is_api_function || !count_constructions);
141
ager@chromium.org7c537e22008-10-16 08:43:32 +0000142 // Enter a construct frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000143 {
144 FrameScope scope(masm, StackFrame::CONSTRUCT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000146 // Store a smi-tagged arguments count on the stack.
147 __ SmiTag(eax);
148 __ push(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000150 // Push the function to invoke on the stack.
151 __ push(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000152
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000153 // Try to allocate the object without transitioning into C code. If any of
154 // the preconditions is not met, the code bails out to the runtime call.
155 Label rt_call, allocated;
156 if (FLAG_inline_new) {
157 Label undo_allocation;
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000158#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000159 ExternalReference debug_step_in_fp =
160 ExternalReference::debug_step_in_fp_address(masm->isolate());
161 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
162 __ j(not_equal, &rt_call);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000163#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000164
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000165 // Verified that the constructor is a JSFunction.
166 // Load the initial map and verify that it is in fact a map.
167 // edi: constructor
168 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
169 // Will both indicate a NULL and a Smi
170 __ JumpIfSmi(eax, &rt_call);
171 // edi: constructor
172 // eax: initial map (if proven valid below)
173 __ CmpObjectType(eax, MAP_TYPE, ebx);
174 __ j(not_equal, &rt_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000176 // Check that the constructor is not constructing a JSFunction (see
177 // comments in Runtime_NewObject in runtime.cc). In which case the
178 // initial map's instance type would be JS_FUNCTION_TYPE.
179 // edi: constructor
180 // eax: initial map
181 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
182 __ j(equal, &rt_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000184 if (count_constructions) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000185 Label allocate;
186 // Decrease generous allocation count.
187 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
188 __ dec_b(FieldOperand(ecx,
189 SharedFunctionInfo::kConstructionCountOffset));
190 __ j(not_zero, &allocate);
191
192 __ push(eax);
193 __ push(edi);
194
195 __ push(edi); // constructor
196 // The call will replace the stub, so the countdown is only done once.
197 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
198
199 __ pop(edi);
200 __ pop(eax);
201
202 __ bind(&allocate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000203 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000204
205 // Now allocate the JSObject on the heap.
206 // edi: constructor
207 // eax: initial map
208 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
209 __ shl(edi, kPointerSizeLog2);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000210 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000211 // Allocated the JSObject, now initialize the fields.
212 // eax: initial map
213 // ebx: JSObject
214 // edi: start of next object
215 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
216 Factory* factory = masm->isolate()->factory();
217 __ mov(ecx, factory->empty_fixed_array());
218 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
219 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
220 // Set extra fields in the newly allocated object.
221 // eax: initial map
222 // ebx: JSObject
223 // edi: start of next object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000225 __ mov(edx, factory->undefined_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000226 if (count_constructions) {
227 __ movzx_b(esi,
228 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
229 __ lea(esi,
230 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
231 // esi: offset of first field after pre-allocated fields
232 if (FLAG_debug_code) {
233 __ cmp(esi, edi);
234 __ Assert(less_equal,
danno@chromium.org59400602013-08-13 17:09:37 +0000235 kUnexpectedNumberOfPreAllocatedPropertyFields);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000236 }
237 __ InitializeFieldsWithFiller(ecx, esi, edx);
238 __ mov(edx, factory->one_pointer_filler_map());
239 }
240 __ InitializeFieldsWithFiller(ecx, edi, edx);
241
242 // Add the object tag to make the JSObject real, so that we can continue
243 // and jump into the continuation code at any time from now on. Any
244 // failures need to undo the allocation, so that the heap is in a
245 // consistent state and verifiable.
246 // eax: initial map
247 // ebx: JSObject
248 // edi: start of next object
249 __ or_(ebx, Immediate(kHeapObjectTag));
250
251 // Check if a non-empty properties array is needed.
252 // Allocate and initialize a FixedArray if it is.
253 // eax: initial map
254 // ebx: JSObject
255 // edi: start of next object
256 // Calculate the total number of properties described by the map.
257 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
258 __ movzx_b(ecx,
259 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
260 __ add(edx, ecx);
261 // Calculate unused properties past the end of the in-object properties.
262 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
263 __ sub(edx, ecx);
264 // Done if no extra properties are to be allocated.
265 __ j(zero, &allocated);
danno@chromium.org59400602013-08-13 17:09:37 +0000266 __ Assert(positive, kPropertyAllocationCountFailed);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000267
268 // Scale the number of elements by pointer size and add the header for
269 // FixedArrays to the start of the next object calculation from above.
270 // ebx: JSObject
271 // edi: start of next object (will be start of FixedArray)
272 // edx: number of elements in properties array
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000273 __ Allocate(FixedArray::kHeaderSize,
274 times_pointer_size,
275 edx,
276 REGISTER_VALUE_IS_INT32,
277 edi,
278 ecx,
279 no_reg,
280 &undo_allocation,
281 RESULT_CONTAINS_TOP);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000282
283 // Initialize the FixedArray.
284 // ebx: JSObject
285 // edi: FixedArray
286 // edx: number of elements
287 // ecx: start of next object
288 __ mov(eax, factory->fixed_array_map());
289 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
290 __ SmiTag(edx);
291 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
292
293 // Initialize the fields to undefined.
294 // ebx: JSObject
295 // edi: FixedArray
296 // ecx: start of next object
297 { Label loop, entry;
298 __ mov(edx, factory->undefined_value());
299 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
300 __ jmp(&entry);
301 __ bind(&loop);
302 __ mov(Operand(eax, 0), edx);
303 __ add(eax, Immediate(kPointerSize));
304 __ bind(&entry);
305 __ cmp(eax, ecx);
306 __ j(below, &loop);
307 }
308
309 // Store the initialized FixedArray into the properties field of
310 // the JSObject
311 // ebx: JSObject
312 // edi: FixedArray
313 __ or_(edi, Immediate(kHeapObjectTag)); // add the heap tag
314 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
315
316
317 // Continue with JSObject being successfully allocated
318 // ebx: JSObject
319 __ jmp(&allocated);
320
321 // Undo the setting of the new top so that the heap is verifiable. For
322 // example, the map's unused properties potentially do not match the
323 // allocated objects unused properties.
324 // ebx: JSObject (previous new top)
325 __ bind(&undo_allocation);
326 __ UndoAllocationInNewSpace(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327 }
328
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000329 // Allocate the new receiver object using the runtime call.
330 __ bind(&rt_call);
331 // Must restore edi (constructor) before calling runtime.
332 __ mov(edi, Operand(esp, 0));
333 // edi: function (constructor)
334 __ push(edi);
335 __ CallRuntime(Runtime::kNewObject, 1);
336 __ mov(ebx, eax); // store result in ebx
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000338 // New object allocated.
339 // ebx: newly allocated object
340 __ bind(&allocated);
341 // Retrieve the function from the stack.
342 __ pop(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000344 // Retrieve smi-tagged arguments count from the stack.
345 __ mov(eax, Operand(esp, 0));
346 __ SmiUntag(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000347
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000348 // Push the allocated receiver to the stack. We need two copies
349 // because we may have to return the original one and the calling
350 // conventions dictate that the called function pops the receiver.
351 __ push(ebx);
352 __ push(ebx);
353
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000354 // Set up pointer to last argument.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000355 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
356
357 // Copy arguments and receiver to the expression stack.
358 Label loop, entry;
359 __ mov(ecx, eax);
360 __ jmp(&entry);
361 __ bind(&loop);
362 __ push(Operand(ebx, ecx, times_4, 0));
363 __ bind(&entry);
364 __ dec(ecx);
365 __ j(greater_equal, &loop);
366
367 // Call the function.
368 if (is_api_function) {
369 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
370 Handle<Code> code =
371 masm->isolate()->builtins()->HandleApiCallConstruct();
372 ParameterCount expected(0);
373 __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
374 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
375 } else {
376 ParameterCount actual(eax);
377 __ InvokeFunction(edi, actual, CALL_FUNCTION,
378 NullCallWrapper(), CALL_AS_METHOD);
379 }
380
ulan@chromium.org967e2702012-02-28 09:49:15 +0000381 // Store offset of return address for deoptimizer.
382 if (!is_api_function && !count_constructions) {
383 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
384 }
385
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000386 // Restore context from the frame.
387 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
388
389 // If the result is an object (in the ECMA sense), we should get rid
390 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
391 // on page 74.
392 Label use_receiver, exit;
393
394 // If the result is a smi, it is *not* an object in the ECMA sense.
395 __ JumpIfSmi(eax, &use_receiver);
396
397 // If the type of the result (stored in its map) is less than
398 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
399 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
400 __ j(above_equal, &exit);
401
402 // Throw away the result of the constructor invocation and use the
403 // on-stack receiver as the result.
404 __ bind(&use_receiver);
405 __ mov(eax, Operand(esp, 0));
406
407 // Restore the arguments count and leave the construct frame.
408 __ bind(&exit);
409 __ mov(ebx, Operand(esp, kPointerSize)); // Get arguments count.
410
411 // Leave construct frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412 }
413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 // Remove caller arguments from the stack and return.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000415 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416 __ pop(ecx);
417 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
418 __ push(ecx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000419 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420 __ ret(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000421}
422
423
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000424void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
425 Generate_JSConstructStubHelper(masm, false, true);
426}
427
428
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000429void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000430 Generate_JSConstructStubHelper(masm, false, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000431}
432
433
434void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000435 Generate_JSConstructStubHelper(masm, true, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000436}
437
438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
440 bool is_construct) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000441 ProfileEntryHookStub::MaybeCallEntryHook(masm);
442
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000443 // Clear the context before we push it when entering the internal frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000444 __ Set(esi, Immediate(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000446 {
447 FrameScope scope(masm, StackFrame::INTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000448
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000449 // Load the previous frame pointer (ebx) to access C arguments
450 __ mov(ebx, Operand(ebp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000451
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000452 // Get the function from the frame and setup the context.
453 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
454 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000456 // Push the function and the receiver onto the stack.
457 __ push(ecx);
458 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000460 // Load the number of arguments and setup pointer to the arguments.
461 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
462 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000464 // Copy arguments to the stack in a loop.
465 Label loop, entry;
466 __ Set(ecx, Immediate(0));
467 __ jmp(&entry);
468 __ bind(&loop);
469 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
470 __ push(Operand(edx, 0)); // dereference handle
471 __ inc(ecx);
472 __ bind(&entry);
473 __ cmp(ecx, eax);
474 __ j(not_equal, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000476 // Get the function from the stack and call it.
477 // kPointerSize for the receiver.
478 __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000479
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000480 // Invoke the code.
481 if (is_construct) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000482 // No type feedback cell is available
483 Handle<Object> undefined_sentinel(
484 masm->isolate()->heap()->undefined_value(), masm->isolate());
485 __ mov(ebx, Immediate(undefined_sentinel));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000486 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
487 __ CallStub(&stub);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000488 } else {
489 ParameterCount actual(eax);
490 __ InvokeFunction(edi, actual, CALL_FUNCTION,
491 NullCallWrapper(), CALL_AS_METHOD);
492 }
493
494 // Exit the internal frame. Notice that this also removes the empty.
495 // context and the function left on the stack by the code
496 // invocation.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000498 __ ret(kPointerSize); // Remove receiver.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000499}
500
501
502void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
503 Generate_JSEntryTrampolineHelper(masm, false);
504}
505
506
507void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
508 Generate_JSEntryTrampolineHelper(masm, true);
509}
510
511
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000512void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000513 CallRuntimePassFunction(masm, Runtime::kLazyCompile);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000514 // Do a tail-call of the compiled function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000515 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000516 __ jmp(eax);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000517}
518
519
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000520void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000521 CallRuntimePassFunction(masm, Runtime::kLazyRecompile);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000522 // Do a tail-call of the compiled function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000523 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000524 __ jmp(eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000525}
526
527
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000528static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
529 // For now, we are relying on the fact that make_code_young doesn't do any
530 // garbage collection which allows us to save/restore the registers without
531 // worrying about which of them contain pointers. We also don't build an
532 // internal frame to make the code faster, since we shouldn't have to do stack
533 // crawls in MakeCodeYoung. This seems a bit fragile.
534
535 // Re-execute the code that was patched back to the young age when
536 // the stub returns.
537 __ sub(Operand(esp, 0), Immediate(5));
538 __ pushad();
539 __ mov(eax, Operand(esp, 8 * kPointerSize));
540 {
541 FrameScope scope(masm, StackFrame::MANUAL);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000542 __ PrepareCallCFunction(2, ebx);
543 __ mov(Operand(esp, 1 * kPointerSize),
544 Immediate(ExternalReference::isolate_address(masm->isolate())));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000545 __ mov(Operand(esp, 0), eax);
546 __ CallCFunction(
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000547 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000548 }
549 __ popad();
550 __ ret(0);
551}
552
553#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
554void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
555 MacroAssembler* masm) { \
556 GenerateMakeCodeYoungAgainCommon(masm); \
557} \
558void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
559 MacroAssembler* masm) { \
560 GenerateMakeCodeYoungAgainCommon(masm); \
561}
562CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
563#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
564
565
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000566void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000567 // Enter an internal frame.
568 {
569 FrameScope scope(masm, StackFrame::INTERNAL);
570
571 // Preserve registers across notification, this is important for compiled
572 // stubs that tail call the runtime on deopts passing their parameters in
573 // registers.
574 __ pushad();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000575 __ CallRuntime(Runtime::kNotifyStubFailure, 0);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000576 __ popad();
577 // Tear down internal frame.
578 }
579
580 __ pop(MemOperand(esp, 0)); // Ignore state offset
581 __ ret(0); // Return to IC Miss stub, continuation still on stack.
582}
583
584
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000585static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
586 Deoptimizer::BailoutType type) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000587 {
588 FrameScope scope(masm, StackFrame::INTERNAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000589
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000590 // Pass deoptimization type to the runtime system.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000591 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
592 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000593
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000594 // Tear down internal frame.
595 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000596
597 // Get the full codegen state from the stack and untag it.
598 __ mov(ecx, Operand(esp, 1 * kPointerSize));
599 __ SmiUntag(ecx);
600
601 // Switch on the state.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000602 Label not_no_registers, not_tos_eax;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000603 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000604 __ j(not_equal, &not_no_registers, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000605 __ ret(1 * kPointerSize); // Remove state.
606
607 __ bind(&not_no_registers);
608 __ mov(eax, Operand(esp, 2 * kPointerSize));
609 __ cmp(ecx, FullCodeGenerator::TOS_REG);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000610 __ j(not_equal, &not_tos_eax, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000611 __ ret(2 * kPointerSize); // Remove state, eax.
612
613 __ bind(&not_tos_eax);
danno@chromium.org59400602013-08-13 17:09:37 +0000614 __ Abort(kNoCasesLeft);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000615}
616
617
618void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
619 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
620}
621
622
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000623void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
624 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
625}
626
627
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000628void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
629 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
630}
631
632
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000633void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000634 Factory* factory = masm->isolate()->factory();
635
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000636 // 1. Make sure we have at least one argument.
637 { Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000638 __ test(eax, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000639 __ j(not_zero, &done);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000640 __ pop(ebx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000641 __ push(Immediate(factory->undefined_value()));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000642 __ push(ebx);
643 __ inc(eax);
644 __ bind(&done);
645 }
646
ager@chromium.org5c838252010-02-19 08:53:10 +0000647 // 2. Get the function to call (passed as receiver) from the stack, check
648 // if it is a function.
lrn@chromium.org34e60782011-09-15 07:25:40 +0000649 Label slow, non_function;
ager@chromium.org5c838252010-02-19 08:53:10 +0000650 // 1 ~ return address.
651 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000652 __ JumpIfSmi(edi, &non_function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000653 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000654 __ j(not_equal, &slow);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000655
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000656
ager@chromium.org5c838252010-02-19 08:53:10 +0000657 // 3a. Patch the first argument if necessary when calling a function.
658 Label shift_arguments;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000659 __ Set(edx, Immediate(0)); // indicate regular JS_FUNCTION
ager@chromium.org5c838252010-02-19 08:53:10 +0000660 { Label convert_to_object, use_global_receiver, patch_receiver;
661 // Change context eagerly in case we need the global receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000662 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
663
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000664 // Do not transform the receiver for strict mode functions.
665 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
666 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
667 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
668 __ j(not_equal, &shift_arguments);
669
lrn@chromium.org1c092762011-05-09 09:42:16 +0000670 // Do not transform the receiver for natives (shared already in ebx).
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000671 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
672 1 << SharedFunctionInfo::kNativeBitWithinByte);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +0000673 __ j(not_equal, &shift_arguments);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000674
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000675 // Compute the receiver in non-strict mode.
ager@chromium.org5c838252010-02-19 08:53:10 +0000676 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000677
678 // Call ToObject on the receiver if it is not an object, or use the
679 // global object if it is null or undefined.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000680 __ JumpIfSmi(ebx, &convert_to_object);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000681 __ cmp(ebx, factory->null_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000682 __ j(equal, &use_global_receiver);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000683 __ cmp(ebx, factory->undefined_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000684 __ j(equal, &use_global_receiver);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000685 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
686 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000687 __ j(above_equal, &shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000688
ager@chromium.org5c838252010-02-19 08:53:10 +0000689 __ bind(&convert_to_object);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000690
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000691 { // In order to preserve argument count.
692 FrameScope scope(masm, StackFrame::INTERNAL);
693 __ SmiTag(eax);
694 __ push(eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000695
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000696 __ push(ebx);
697 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
698 __ mov(ebx, eax);
699 __ Set(edx, Immediate(0)); // restore
700
701 __ pop(eax);
702 __ SmiUntag(eax);
703 }
704
ager@chromium.org5c838252010-02-19 08:53:10 +0000705 // Restore the function to edi.
706 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000707 __ jmp(&patch_receiver);
708
ager@chromium.org5c838252010-02-19 08:53:10 +0000709 // Use the global receiver object from the called function as the
710 // receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000711 __ bind(&use_global_receiver);
712 const int kGlobalIndex =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000713 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000714 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000715 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
ager@chromium.org3811b432009-10-28 14:53:37 +0000716 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000717 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000718
719 __ bind(&patch_receiver);
720 __ mov(Operand(esp, eax, times_4, 0), ebx);
721
ager@chromium.org5c838252010-02-19 08:53:10 +0000722 __ jmp(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000723 }
724
lrn@chromium.org34e60782011-09-15 07:25:40 +0000725 // 3b. Check for function proxy.
726 __ bind(&slow);
727 __ Set(edx, Immediate(1)); // indicate function proxy
728 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
729 __ j(equal, &shift_arguments);
730 __ bind(&non_function);
731 __ Set(edx, Immediate(2)); // indicate non-function
732
733 // 3c. Patch the first argument when calling a non-function. The
ager@chromium.org5c838252010-02-19 08:53:10 +0000734 // CALL_NON_FUNCTION builtin expects the non-function callee as
735 // receiver, so overwrite the first argument which will ultimately
736 // become the receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +0000737 __ mov(Operand(esp, eax, times_4, 0), edi);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000738
ager@chromium.org5c838252010-02-19 08:53:10 +0000739 // 4. Shift arguments and return address one slot down on the stack
740 // (overwriting the original receiver). Adjust argument count to make
741 // the original first argument the new receiver.
742 __ bind(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000743 { Label loop;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000744 __ mov(ecx, eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000745 __ bind(&loop);
746 __ mov(ebx, Operand(esp, ecx, times_4, 0));
747 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
748 __ dec(ecx);
ager@chromium.org5c838252010-02-19 08:53:10 +0000749 __ j(not_sign, &loop); // While non-negative (to copy return address).
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000750 __ pop(ebx); // Discard copy of return address.
751 __ dec(eax); // One fewer argument (first argument is new receiver).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000752 }
753
lrn@chromium.org34e60782011-09-15 07:25:40 +0000754 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
755 // or a function proxy via CALL_FUNCTION_PROXY.
756 { Label function, non_proxy;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000757 __ test(edx, edx);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000758 __ j(zero, &function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000759 __ Set(ebx, Immediate(0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000760 __ cmp(edx, Immediate(1));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000761 __ j(not_equal, &non_proxy);
762
763 __ pop(edx); // return address
764 __ push(edi); // re-add proxy object as additional argument
765 __ push(edx);
766 __ inc(eax);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000767 __ SetCallKind(ecx, CALL_AS_FUNCTION);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000768 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
769 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
770 RelocInfo::CODE_TARGET);
771
772 __ bind(&non_proxy);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000773 __ SetCallKind(ecx, CALL_AS_METHOD);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000774 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000775 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
776 RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000777 __ bind(&function);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000778 }
779
ager@chromium.org5c838252010-02-19 08:53:10 +0000780 // 5b. Get the code to call from the function and check that the number of
781 // expected arguments matches what we're providing. If so, jump
782 // (tail-call) to the code in register edx without checking arguments.
783 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
784 __ mov(ebx,
785 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000786 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000787 __ SmiUntag(ebx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000788 __ SetCallKind(ecx, CALL_AS_METHOD);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000789 __ cmp(eax, ebx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000790 __ j(not_equal,
791 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
ager@chromium.org5c838252010-02-19 08:53:10 +0000792
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000793 ParameterCount expected(0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000794 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper(),
795 CALL_AS_METHOD);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000796}
797
798
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000799void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
lrn@chromium.org34e60782011-09-15 07:25:40 +0000800 static const int kArgumentsOffset = 2 * kPointerSize;
801 static const int kReceiverOffset = 3 * kPointerSize;
802 static const int kFunctionOffset = 4 * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000803 {
804 FrameScope frame_scope(masm, StackFrame::INTERNAL);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000805
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000806 __ push(Operand(ebp, kFunctionOffset)); // push this
807 __ push(Operand(ebp, kArgumentsOffset)); // push arguments
808 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000809
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000810 // Check the stack for overflow. We are not trying to catch
811 // interruptions (e.g. debug break and preemption) here, so the "real stack
812 // limit" is checked.
813 Label okay;
814 ExternalReference real_stack_limit =
815 ExternalReference::address_of_real_stack_limit(masm->isolate());
816 __ mov(edi, Operand::StaticVariable(real_stack_limit));
817 // Make ecx the space we have left. The stack might already be overflowed
818 // here which will cause ecx to become negative.
819 __ mov(ecx, esp);
820 __ sub(ecx, edi);
821 // Make edx the space we need for the array when it is unrolled onto the
822 // stack.
823 __ mov(edx, eax);
824 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
825 // Check if the arguments will overflow the stack.
826 __ cmp(ecx, edx);
827 __ j(greater, &okay); // Signed comparison.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000828
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000829 // Out of stack space.
830 __ push(Operand(ebp, 4 * kPointerSize)); // push this
831 __ push(eax);
832 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
833 __ bind(&okay);
834 // End of stack check.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000835
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000836 // Push current index and limit.
837 const int kLimitOffset =
838 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
839 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
840 __ push(eax); // limit
841 __ push(Immediate(0)); // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000843 // Get the receiver.
844 __ mov(ebx, Operand(ebp, kReceiverOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000846 // Check that the function is a JS function (otherwise it must be a proxy).
847 Label push_receiver;
848 __ mov(edi, Operand(ebp, kFunctionOffset));
849 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
850 __ j(not_equal, &push_receiver);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000851
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000852 // Change context eagerly to get the right global object if necessary.
853 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000854
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000855 // Compute the receiver.
856 // Do not transform the receiver for strict mode functions.
857 Label call_to_object, use_global_receiver;
858 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
859 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
860 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
861 __ j(not_equal, &push_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000863 Factory* factory = masm->isolate()->factory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000864
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000865 // Do not transform the receiver for natives (shared already in ecx).
866 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
867 1 << SharedFunctionInfo::kNativeBitWithinByte);
868 __ j(not_equal, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000869
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000870 // Compute the receiver in non-strict mode.
871 // Call ToObject on the receiver if it is not an object, or use the
872 // global object if it is null or undefined.
873 __ JumpIfSmi(ebx, &call_to_object);
874 __ cmp(ebx, factory->null_value());
875 __ j(equal, &use_global_receiver);
876 __ cmp(ebx, factory->undefined_value());
877 __ j(equal, &use_global_receiver);
878 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
879 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
880 __ j(above_equal, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000881
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000882 __ bind(&call_to_object);
883 __ push(ebx);
884 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
885 __ mov(ebx, eax);
886 __ jmp(&push_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000888 // Use the current global receiver object as the receiver.
889 __ bind(&use_global_receiver);
890 const int kGlobalOffset =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000891 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000892 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000893 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000894 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
895 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000897 // Push the receiver.
898 __ bind(&push_receiver);
899 __ push(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000901 // Copy all arguments from the array to the stack.
902 Label entry, loop;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000903 __ mov(ecx, Operand(ebp, kIndexOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000904 __ jmp(&entry);
905 __ bind(&loop);
906 __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000908 // Use inline caching to speed up access to arguments.
909 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
910 __ call(ic, RelocInfo::CODE_TARGET);
911 // It is important that we do not have a test instruction after the
912 // call. A test instruction after the call is used to indicate that
913 // we have generated an inline version of the keyed load. In this
914 // case, we know that we are not generating a test instruction next.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000916 // Push the nth argument.
917 __ push(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000918
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000919 // Update the index on the stack and in register eax.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000920 __ mov(ecx, Operand(ebp, kIndexOffset));
921 __ add(ecx, Immediate(1 << kSmiTagSize));
922 __ mov(Operand(ebp, kIndexOffset), ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000924 __ bind(&entry);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000925 __ cmp(ecx, Operand(ebp, kLimitOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000926 __ j(not_equal, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000928 // Invoke the function.
929 Label call_proxy;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000930 __ mov(eax, ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000931 ParameterCount actual(eax);
932 __ SmiUntag(eax);
933 __ mov(edi, Operand(ebp, kFunctionOffset));
934 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
935 __ j(not_equal, &call_proxy);
936 __ InvokeFunction(edi, actual, CALL_FUNCTION,
937 NullCallWrapper(), CALL_AS_METHOD);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000939 frame_scope.GenerateLeaveFrame();
940 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000941
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000942 // Invoke the function proxy.
943 __ bind(&call_proxy);
944 __ push(edi); // add function proxy as last argument
945 __ inc(eax);
946 __ Set(ebx, Immediate(0));
947 __ SetCallKind(ecx, CALL_AS_METHOD);
948 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
949 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
950 RelocInfo::CODE_TARGET);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000951
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000952 // Leave internal frame.
953 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000954 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000955}
956
957
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000958void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
959 // ----------- S t a t e -------------
960 // -- eax : argc
961 // -- esp[0] : return address
962 // -- esp[4] : last argument
963 // -----------------------------------
964 Label generic_array_code;
965
966 // Get the InternalArray function.
967 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
968
969 if (FLAG_debug_code) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000970 // Initial map for the builtin InternalArray function should be a map.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000971 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
972 // Will both indicate a NULL and a Smi.
973 __ test(ebx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +0000974 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000975 __ CmpObjectType(ebx, MAP_TYPE, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +0000976 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000977 }
978
979 // Run the native code for the InternalArray function called as a normal
980 // function.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000981 // tail call a stub
982 InternalArrayConstructorStub stub(masm->isolate());
983 __ TailCallStub(&stub);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000984}
985
986
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000987void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
988 // ----------- S t a t e -------------
989 // -- eax : argc
990 // -- esp[0] : return address
991 // -- esp[4] : last argument
992 // -----------------------------------
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000993 Label generic_array_code;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000994
995 // Get the Array function.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000996 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000997
998 if (FLAG_debug_code) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000999 // Initial map for the builtin Array function should be a map.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001000 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1001 // Will both indicate a NULL and a Smi.
1002 __ test(ebx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001003 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001004 __ CmpObjectType(ebx, MAP_TYPE, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +00001005 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001006 }
1007
1008 // Run the native code for the Array function called as a normal function.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001009 // tail call a stub
1010 Handle<Object> undefined_sentinel(
1011 masm->isolate()->heap()->undefined_value(),
1012 masm->isolate());
1013 __ mov(ebx, Immediate(undefined_sentinel));
1014 ArrayConstructorStub stub(masm->isolate());
1015 __ TailCallStub(&stub);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001016}
1017
1018
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001019void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1020 // ----------- S t a t e -------------
1021 // -- eax : number of arguments
1022 // -- edi : constructor function
1023 // -- esp[0] : return address
1024 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1025 // -- esp[(argc + 1) * 4] : receiver
1026 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001027 Counters* counters = masm->isolate()->counters();
1028 __ IncrementCounter(counters->string_ctor_calls(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001029
1030 if (FLAG_debug_code) {
1031 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001032 __ cmp(edi, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +00001033 __ Assert(equal, kUnexpectedStringFunction);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001034 }
1035
1036 // Load the first argument into eax and get rid of the rest
1037 // (including the receiver).
1038 Label no_arguments;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001039 __ test(eax, eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001040 __ j(zero, &no_arguments);
1041 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1042 __ pop(ecx);
1043 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1044 __ push(ecx);
1045 __ mov(eax, ebx);
1046
1047 // Lookup the argument in the number to string cache.
1048 Label not_cached, argument_is_string;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001049 __ LookupNumberStringCache(eax, // Input.
1050 ebx, // Result.
1051 ecx, // Scratch 1.
1052 edx, // Scratch 2.
1053 &not_cached);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001054 __ IncrementCounter(counters->string_ctor_cached_number(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001055 __ bind(&argument_is_string);
1056 // ----------- S t a t e -------------
1057 // -- ebx : argument converted to string
1058 // -- edi : constructor function
1059 // -- esp[0] : return address
1060 // -----------------------------------
1061
1062 // Allocate a JSValue and put the tagged pointer into eax.
1063 Label gc_required;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001064 __ Allocate(JSValue::kSize,
1065 eax, // Result.
1066 ecx, // New allocation top (we ignore it).
1067 no_reg,
1068 &gc_required,
1069 TAG_OBJECT);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001070
1071 // Set the map.
1072 __ LoadGlobalFunctionInitialMap(edi, ecx);
1073 if (FLAG_debug_code) {
1074 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1075 JSValue::kSize >> kPointerSizeLog2);
danno@chromium.org59400602013-08-13 17:09:37 +00001076 __ Assert(equal, kUnexpectedStringWrapperInstanceSize);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001077 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
danno@chromium.org59400602013-08-13 17:09:37 +00001078 __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001079 }
1080 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1081
1082 // Set properties and elements.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001083 Factory* factory = masm->isolate()->factory();
1084 __ Set(ecx, Immediate(factory->empty_fixed_array()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001085 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1086 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1087
1088 // Set the value.
1089 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1090
1091 // Ensure the object is fully initialized.
1092 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1093
1094 // We're done. Return.
1095 __ ret(0);
1096
1097 // The argument was not found in the number to string cache. Check
1098 // if it's a string already before calling the conversion builtin.
1099 Label convert_argument;
1100 __ bind(&not_cached);
1101 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001102 __ JumpIfSmi(eax, &convert_argument);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001103 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1104 __ j(NegateCondition(is_string), &convert_argument);
1105 __ mov(ebx, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001106 __ IncrementCounter(counters->string_ctor_string_value(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001107 __ jmp(&argument_is_string);
1108
1109 // Invoke the conversion builtin and put the result into ebx.
1110 __ bind(&convert_argument);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001111 __ IncrementCounter(counters->string_ctor_conversions(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001112 {
1113 FrameScope scope(masm, StackFrame::INTERNAL);
1114 __ push(edi); // Preserve the function.
1115 __ push(eax);
1116 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1117 __ pop(edi);
1118 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001119 __ mov(ebx, eax);
1120 __ jmp(&argument_is_string);
1121
1122 // Load the empty string into ebx, remove the receiver from the
1123 // stack, and jump back to the case where the argument is a string.
1124 __ bind(&no_arguments);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001125 __ Set(ebx, Immediate(factory->empty_string()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001126 __ pop(ecx);
1127 __ lea(esp, Operand(esp, kPointerSize));
1128 __ push(ecx);
1129 __ jmp(&argument_is_string);
1130
1131 // At this point the argument is already a string. Call runtime to
1132 // create a string wrapper.
1133 __ bind(&gc_required);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001134 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001135 {
1136 FrameScope scope(masm, StackFrame::INTERNAL);
1137 __ push(ebx);
1138 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1139 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001140 __ ret(0);
1141}
1142
1143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001144static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1145 __ push(ebp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001146 __ mov(ebp, esp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147
1148 // Store the arguments adaptor context sentinel.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001149 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150
1151 // Push the function on the stack.
1152 __ push(edi);
1153
danno@chromium.org40cb8782011-05-25 07:58:50 +00001154 // Preserve the number of arguments on the stack. Must preserve eax,
1155 // ebx and ecx because these registers are used when copying the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156 // arguments and the receiver.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001157 STATIC_ASSERT(kSmiTagSize == 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001158 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1159 __ push(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001160}
1161
1162
ager@chromium.org7c537e22008-10-16 08:43:32 +00001163static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164 // Retrieve the number of arguments from the stack.
1165 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1166
1167 // Leave the frame.
1168 __ leave();
1169
1170 // Remove caller arguments from the stack.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001171 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 __ pop(ecx);
1173 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1174 __ push(ecx);
1175}
1176
1177
1178void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1179 // ----------- S t a t e -------------
1180 // -- eax : actual number of arguments
1181 // -- ebx : expected number of arguments
danno@chromium.org40cb8782011-05-25 07:58:50 +00001182 // -- ecx : call kind information
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183 // -- edx : code entry to call
1184 // -----------------------------------
1185
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001186 Label invoke, dont_adapt_arguments;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001187 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188
1189 Label enough, too_few;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001190 __ cmp(eax, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 __ j(less, &too_few);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001192 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1193 __ j(equal, &dont_adapt_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001194
1195 { // Enough parameters: Actual >= expected.
1196 __ bind(&enough);
1197 EnterArgumentsAdaptorFrame(masm);
1198
1199 // Copy receiver and all expected arguments.
1200 const int offset = StandardFrameConstants::kCallerSPOffset;
1201 __ lea(eax, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001202 __ mov(edi, -1); // account for receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203
1204 Label copy;
1205 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001206 __ inc(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207 __ push(Operand(eax, 0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001208 __ sub(eax, Immediate(kPointerSize));
1209 __ cmp(edi, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001210 __ j(less, &copy);
1211 __ jmp(&invoke);
1212 }
1213
1214 { // Too few parameters: Actual < expected.
1215 __ bind(&too_few);
1216 EnterArgumentsAdaptorFrame(masm);
1217
1218 // Copy receiver and all actual arguments.
1219 const int offset = StandardFrameConstants::kCallerSPOffset;
1220 __ lea(edi, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001221 // ebx = expected - actual.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001222 __ sub(ebx, eax);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001223 // eax = -actual - 1
1224 __ neg(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001225 __ sub(eax, Immediate(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226
1227 Label copy;
1228 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001229 __ inc(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 __ push(Operand(edi, 0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001231 __ sub(edi, Immediate(kPointerSize));
1232 __ test(eax, eax);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001233 __ j(not_zero, &copy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234
1235 // Fill remaining expected arguments with undefined values.
1236 Label fill;
1237 __ bind(&fill);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001238 __ inc(eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001239 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001240 __ cmp(eax, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 __ j(less, &fill);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242 }
1243
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001244 // Call the entry point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 __ bind(&invoke);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001246 // Restore function pointer.
1247 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001248 __ call(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
ulan@chromium.org967e2702012-02-28 09:49:15 +00001250 // Store offset of return address for deoptimizer.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001251 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
ulan@chromium.org967e2702012-02-28 09:49:15 +00001252
ager@chromium.org7c537e22008-10-16 08:43:32 +00001253 // Leave frame and return.
1254 LeaveArgumentsAdaptorFrame(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 __ ret(0);
1256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001258 // Dont adapt arguments.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001260 __ bind(&dont_adapt_arguments);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001261 __ jmp(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262}
1263
1264
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001265void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001266 // Lookup the function in the JavaScript frame.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001267 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001268 {
1269 FrameScope scope(masm, StackFrame::INTERNAL);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001270 // Lookup and calculate pc offset.
1271 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerPCOffset));
1272 __ mov(ebx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
1273 __ sub(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1274 __ sub(edx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset));
1275 __ SmiTag(edx);
1276
1277 // Pass both function and pc offset as arguments.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001278 __ push(eax);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001279 __ push(edx);
1280 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001281 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001282
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001283 Label skip;
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00001284 // If the code object is null, just return to the unoptimized code.
1285 __ cmp(eax, Immediate(0));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001286 __ j(not_equal, &skip, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001287 __ ret(0);
1288
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001289 __ bind(&skip);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001290
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00001291 // Load deoptimization data from the code object.
1292 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1293
1294 // Load the OSR entrypoint offset from the deoptimization data.
1295 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
1296 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
1297 __ SmiUntag(ebx);
1298
1299 // Compute the target address = code_obj + header_size + osr_offset
1300 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
1301
1302 // Overwrite the return address on the stack.
1303 __ mov(Operand(esp, 0), eax);
1304
1305 // And "return" to the OSR entry point of the function.
1306 __ ret(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001307}
1308
1309
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00001310void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1311 // We check the stack limit as indicator that recompilation might be done.
1312 Label ok;
1313 ExternalReference stack_limit =
1314 ExternalReference::address_of_stack_limit(masm->isolate());
1315 __ cmp(esp, Operand::StaticVariable(stack_limit));
1316 __ j(above_equal, &ok, Label::kNear);
1317 {
1318 FrameScope scope(masm, StackFrame::INTERNAL);
1319 __ CallRuntime(Runtime::kStackGuard, 0);
1320 }
1321 __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
1322 RelocInfo::CODE_TARGET);
1323
1324 __ bind(&ok);
1325 __ ret(0);
1326}
1327
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328#undef __
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001329}
1330} // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001331
1332#endif // V8_TARGET_ARCH_IA32