blob: 1f73a7dd239a2dda54b3bf7b23ad2b86eff2b7d9 [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
yangguo@chromium.org49546742013-12-23 16:17:49 +000077static void CallRuntimePassFunction(
78 MacroAssembler* masm, Runtime::FunctionId function_id) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000079 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
yangguo@chromium.org49546742013-12-23 16:17:49 +0000103static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
104 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
105 __ jmp(eax);
106}
107
108
109void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000110 // Checking whether the queued function is ready for install is optional,
111 // since we come across interrupts and stack checks elsewhere. However,
112 // not checking may delay installing ready functions, and always checking
113 // would be quite expensive. A good compromise is to first check against
114 // stack limit as a cue for an interrupt signal.
115 Label ok;
116 ExternalReference stack_limit =
117 ExternalReference::address_of_stack_limit(masm->isolate());
118 __ cmp(esp, Operand::StaticVariable(stack_limit));
119 __ j(above_equal, &ok, Label::kNear);
120
yangguo@chromium.org49546742013-12-23 16:17:49 +0000121 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
122 GenerateTailCallToReturnedCode(masm);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000123
124 __ bind(&ok);
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000125 GenerateTailCallToSharedCode(masm);
126}
127
128
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000129static void Generate_JSConstructStubHelper(MacroAssembler* masm,
130 bool is_api_function,
131 bool count_constructions) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000132 // ----------- S t a t e -------------
133 // -- eax: number of arguments
134 // -- edi: constructor function
135 // -----------------------------------
136
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000137 // Should never count constructions for api objects.
138 ASSERT(!is_api_function || !count_constructions);
139
ager@chromium.org7c537e22008-10-16 08:43:32 +0000140 // Enter a construct frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000141 {
142 FrameScope scope(masm, StackFrame::CONSTRUCT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000144 // Store a smi-tagged arguments count on the stack.
145 __ SmiTag(eax);
146 __ push(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000147
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000148 // Push the function to invoke on the stack.
149 __ push(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000150
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000151 // Try to allocate the object without transitioning into C code. If any of
152 // the preconditions is not met, the code bails out to the runtime call.
153 Label rt_call, allocated;
154 if (FLAG_inline_new) {
155 Label undo_allocation;
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000156#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000157 ExternalReference debug_step_in_fp =
158 ExternalReference::debug_step_in_fp_address(masm->isolate());
159 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
160 __ j(not_equal, &rt_call);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000161#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000163 // Verified that the constructor is a JSFunction.
164 // Load the initial map and verify that it is in fact a map.
165 // edi: constructor
166 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
167 // Will both indicate a NULL and a Smi
168 __ JumpIfSmi(eax, &rt_call);
169 // edi: constructor
170 // eax: initial map (if proven valid below)
171 __ CmpObjectType(eax, MAP_TYPE, ebx);
172 __ j(not_equal, &rt_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000174 // Check that the constructor is not constructing a JSFunction (see
175 // comments in Runtime_NewObject in runtime.cc). In which case the
176 // initial map's instance type would be JS_FUNCTION_TYPE.
177 // edi: constructor
178 // eax: initial map
179 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
180 __ j(equal, &rt_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000182 if (count_constructions) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000183 Label allocate;
184 // Decrease generous allocation count.
185 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
186 __ dec_b(FieldOperand(ecx,
187 SharedFunctionInfo::kConstructionCountOffset));
188 __ j(not_zero, &allocate);
189
190 __ push(eax);
191 __ push(edi);
192
193 __ push(edi); // constructor
194 // The call will replace the stub, so the countdown is only done once.
195 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
196
197 __ pop(edi);
198 __ pop(eax);
199
200 __ bind(&allocate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000201 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000202
203 // Now allocate the JSObject on the heap.
204 // edi: constructor
205 // eax: initial map
206 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
207 __ shl(edi, kPointerSizeLog2);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000208 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000209 // Allocated the JSObject, now initialize the fields.
210 // eax: initial map
211 // ebx: JSObject
212 // edi: start of next object
213 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
214 Factory* factory = masm->isolate()->factory();
215 __ mov(ecx, factory->empty_fixed_array());
216 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
217 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
218 // Set extra fields in the newly allocated object.
219 // eax: initial map
220 // ebx: JSObject
221 // edi: start of next object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000223 __ mov(edx, factory->undefined_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000224 if (count_constructions) {
225 __ movzx_b(esi,
226 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
227 __ lea(esi,
228 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
229 // esi: offset of first field after pre-allocated fields
230 if (FLAG_debug_code) {
231 __ cmp(esi, edi);
232 __ Assert(less_equal,
danno@chromium.org59400602013-08-13 17:09:37 +0000233 kUnexpectedNumberOfPreAllocatedPropertyFields);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000234 }
235 __ InitializeFieldsWithFiller(ecx, esi, edx);
236 __ mov(edx, factory->one_pointer_filler_map());
237 }
238 __ InitializeFieldsWithFiller(ecx, edi, edx);
239
240 // Add the object tag to make the JSObject real, so that we can continue
241 // and jump into the continuation code at any time from now on. Any
242 // failures need to undo the allocation, so that the heap is in a
243 // consistent state and verifiable.
244 // eax: initial map
245 // ebx: JSObject
246 // edi: start of next object
247 __ or_(ebx, Immediate(kHeapObjectTag));
248
249 // Check if a non-empty properties array is needed.
250 // Allocate and initialize a FixedArray if it is.
251 // eax: initial map
252 // ebx: JSObject
253 // edi: start of next object
254 // Calculate the total number of properties described by the map.
255 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
256 __ movzx_b(ecx,
257 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
258 __ add(edx, ecx);
259 // Calculate unused properties past the end of the in-object properties.
260 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
261 __ sub(edx, ecx);
262 // Done if no extra properties are to be allocated.
263 __ j(zero, &allocated);
danno@chromium.org59400602013-08-13 17:09:37 +0000264 __ Assert(positive, kPropertyAllocationCountFailed);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000265
266 // Scale the number of elements by pointer size and add the header for
267 // FixedArrays to the start of the next object calculation from above.
268 // ebx: JSObject
269 // edi: start of next object (will be start of FixedArray)
270 // edx: number of elements in properties array
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000271 __ Allocate(FixedArray::kHeaderSize,
272 times_pointer_size,
273 edx,
274 REGISTER_VALUE_IS_INT32,
275 edi,
276 ecx,
277 no_reg,
278 &undo_allocation,
279 RESULT_CONTAINS_TOP);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000280
281 // Initialize the FixedArray.
282 // ebx: JSObject
283 // edi: FixedArray
284 // edx: number of elements
285 // ecx: start of next object
286 __ mov(eax, factory->fixed_array_map());
287 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
288 __ SmiTag(edx);
289 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
290
291 // Initialize the fields to undefined.
292 // ebx: JSObject
293 // edi: FixedArray
294 // ecx: start of next object
295 { Label loop, entry;
296 __ mov(edx, factory->undefined_value());
297 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
298 __ jmp(&entry);
299 __ bind(&loop);
300 __ mov(Operand(eax, 0), edx);
301 __ add(eax, Immediate(kPointerSize));
302 __ bind(&entry);
303 __ cmp(eax, ecx);
304 __ j(below, &loop);
305 }
306
307 // Store the initialized FixedArray into the properties field of
308 // the JSObject
309 // ebx: JSObject
310 // edi: FixedArray
311 __ or_(edi, Immediate(kHeapObjectTag)); // add the heap tag
312 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
313
314
315 // Continue with JSObject being successfully allocated
316 // ebx: JSObject
317 __ jmp(&allocated);
318
319 // Undo the setting of the new top so that the heap is verifiable. For
320 // example, the map's unused properties potentially do not match the
321 // allocated objects unused properties.
322 // ebx: JSObject (previous new top)
323 __ bind(&undo_allocation);
324 __ UndoAllocationInNewSpace(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 }
326
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000327 // Allocate the new receiver object using the runtime call.
328 __ bind(&rt_call);
329 // Must restore edi (constructor) before calling runtime.
330 __ mov(edi, Operand(esp, 0));
331 // edi: function (constructor)
332 __ push(edi);
333 __ CallRuntime(Runtime::kNewObject, 1);
334 __ mov(ebx, eax); // store result in ebx
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000336 // New object allocated.
337 // ebx: newly allocated object
338 __ bind(&allocated);
339 // Retrieve the function from the stack.
340 __ pop(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000342 // Retrieve smi-tagged arguments count from the stack.
343 __ mov(eax, Operand(esp, 0));
344 __ SmiUntag(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000346 // Push the allocated receiver to the stack. We need two copies
347 // because we may have to return the original one and the calling
348 // conventions dictate that the called function pops the receiver.
349 __ push(ebx);
350 __ push(ebx);
351
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000352 // Set up pointer to last argument.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000353 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
354
355 // Copy arguments and receiver to the expression stack.
356 Label loop, entry;
357 __ mov(ecx, eax);
358 __ jmp(&entry);
359 __ bind(&loop);
360 __ push(Operand(ebx, ecx, times_4, 0));
361 __ bind(&entry);
362 __ dec(ecx);
363 __ j(greater_equal, &loop);
364
365 // Call the function.
366 if (is_api_function) {
367 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
368 Handle<Code> code =
369 masm->isolate()->builtins()->HandleApiCallConstruct();
370 ParameterCount expected(0);
371 __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
372 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
373 } else {
374 ParameterCount actual(eax);
375 __ InvokeFunction(edi, actual, CALL_FUNCTION,
376 NullCallWrapper(), CALL_AS_METHOD);
377 }
378
ulan@chromium.org967e2702012-02-28 09:49:15 +0000379 // Store offset of return address for deoptimizer.
380 if (!is_api_function && !count_constructions) {
381 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
382 }
383
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000384 // Restore context from the frame.
385 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
386
387 // If the result is an object (in the ECMA sense), we should get rid
388 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
389 // on page 74.
390 Label use_receiver, exit;
391
392 // If the result is a smi, it is *not* an object in the ECMA sense.
393 __ JumpIfSmi(eax, &use_receiver);
394
395 // If the type of the result (stored in its map) is less than
396 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
397 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
398 __ j(above_equal, &exit);
399
400 // Throw away the result of the constructor invocation and use the
401 // on-stack receiver as the result.
402 __ bind(&use_receiver);
403 __ mov(eax, Operand(esp, 0));
404
405 // Restore the arguments count and leave the construct frame.
406 __ bind(&exit);
407 __ mov(ebx, Operand(esp, kPointerSize)); // Get arguments count.
408
409 // Leave construct frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 }
411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412 // Remove caller arguments from the stack and return.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000413 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 __ pop(ecx);
415 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
416 __ push(ecx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000417 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000418 __ ret(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419}
420
421
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000422void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
423 Generate_JSConstructStubHelper(masm, false, true);
424}
425
426
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000427void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000428 Generate_JSConstructStubHelper(masm, false, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000429}
430
431
432void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000433 Generate_JSConstructStubHelper(masm, true, false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000434}
435
436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
438 bool is_construct) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000439 ProfileEntryHookStub::MaybeCallEntryHook(masm);
440
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000441 // Clear the context before we push it when entering the internal frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000442 __ Set(esi, Immediate(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000443
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000444 {
445 FrameScope scope(masm, StackFrame::INTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000447 // Load the previous frame pointer (ebx) to access C arguments
448 __ mov(ebx, Operand(ebp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000450 // Get the function from the frame and setup the context.
451 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
452 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000454 // Push the function and the receiver onto the stack.
455 __ push(ecx);
456 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000457
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000458 // Load the number of arguments and setup pointer to the arguments.
459 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
460 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000462 // Copy arguments to the stack in a loop.
463 Label loop, entry;
464 __ Set(ecx, Immediate(0));
465 __ jmp(&entry);
466 __ bind(&loop);
467 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
468 __ push(Operand(edx, 0)); // dereference handle
469 __ inc(ecx);
470 __ bind(&entry);
471 __ cmp(ecx, eax);
472 __ j(not_equal, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000474 // Get the function from the stack and call it.
475 // kPointerSize for the receiver.
476 __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000477
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000478 // Invoke the code.
479 if (is_construct) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000480 // No type feedback cell is available
481 Handle<Object> undefined_sentinel(
482 masm->isolate()->heap()->undefined_value(), masm->isolate());
483 __ mov(ebx, Immediate(undefined_sentinel));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000484 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
485 __ CallStub(&stub);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000486 } else {
487 ParameterCount actual(eax);
488 __ InvokeFunction(edi, actual, CALL_FUNCTION,
489 NullCallWrapper(), CALL_AS_METHOD);
490 }
491
492 // Exit the internal frame. Notice that this also removes the empty.
493 // context and the function left on the stack by the code
494 // invocation.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000496 __ ret(kPointerSize); // Remove receiver.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497}
498
499
500void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
501 Generate_JSEntryTrampolineHelper(masm, false);
502}
503
504
505void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
506 Generate_JSEntryTrampolineHelper(masm, true);
507}
508
509
yangguo@chromium.org49546742013-12-23 16:17:49 +0000510void Builtins::Generate_CompileUnoptimized(MacroAssembler* masm) {
511 CallRuntimePassFunction(masm, Runtime::kCompileUnoptimized);
512 GenerateTailCallToReturnedCode(masm);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000513}
514
515
yangguo@chromium.org49546742013-12-23 16:17:49 +0000516
517static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
518 FrameScope scope(masm, StackFrame::INTERNAL);
519 // Push a copy of the function.
520 __ push(edi);
521 // Push call kind information.
522 __ push(ecx);
523 // Function is also the parameter to the runtime call.
524 __ push(edi);
525 // Whether to compile in a background thread.
526 __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
527
528 __ CallRuntime(Runtime::kCompileOptimized, 2);
529 // Restore call kind information.
530 __ pop(ecx);
531 // Restore receiver.
532 __ pop(edi);
533}
534
535
536void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
537 CallCompileOptimized(masm, false);
538 GenerateTailCallToReturnedCode(masm);
539}
540
541
542void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
543 CallCompileOptimized(masm, true);
544 GenerateTailCallToReturnedCode(masm);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000545}
546
547
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000548static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
549 // For now, we are relying on the fact that make_code_young doesn't do any
550 // garbage collection which allows us to save/restore the registers without
551 // worrying about which of them contain pointers. We also don't build an
552 // internal frame to make the code faster, since we shouldn't have to do stack
553 // crawls in MakeCodeYoung. This seems a bit fragile.
554
555 // Re-execute the code that was patched back to the young age when
556 // the stub returns.
557 __ sub(Operand(esp, 0), Immediate(5));
558 __ pushad();
559 __ mov(eax, Operand(esp, 8 * kPointerSize));
560 {
561 FrameScope scope(masm, StackFrame::MANUAL);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000562 __ PrepareCallCFunction(2, ebx);
563 __ mov(Operand(esp, 1 * kPointerSize),
564 Immediate(ExternalReference::isolate_address(masm->isolate())));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000565 __ mov(Operand(esp, 0), eax);
566 __ CallCFunction(
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000567 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000568 }
569 __ popad();
570 __ ret(0);
571}
572
573#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
574void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
575 MacroAssembler* masm) { \
576 GenerateMakeCodeYoungAgainCommon(masm); \
577} \
578void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
579 MacroAssembler* masm) { \
580 GenerateMakeCodeYoungAgainCommon(masm); \
581}
582CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
583#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
584
585
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000586void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
587 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
588 // that make_code_young doesn't do any garbage collection which allows us to
589 // save/restore the registers without worrying about which of them contain
590 // pointers.
591 __ pushad();
592 __ mov(eax, Operand(esp, 8 * kPointerSize));
593 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
594 { // NOLINT
595 FrameScope scope(masm, StackFrame::MANUAL);
596 __ PrepareCallCFunction(2, ebx);
597 __ mov(Operand(esp, 1 * kPointerSize),
598 Immediate(ExternalReference::isolate_address(masm->isolate())));
599 __ mov(Operand(esp, 0), eax);
600 __ CallCFunction(
601 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
602 2);
603 }
604 __ popad();
605
606 // Perform prologue operations usually performed by the young code stub.
607 __ pop(eax); // Pop return address into scratch register.
608 __ push(ebp); // Caller's frame pointer.
609 __ mov(ebp, esp);
610 __ push(esi); // Callee's context.
611 __ push(edi); // Callee's JS Function.
612 __ push(eax); // Push return address after frame prologue.
613
614 // Jump to point after the code-age stub.
615 __ ret(0);
616}
617
618
619void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
620 GenerateMakeCodeYoungAgainCommon(masm);
621}
622
623
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000624static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
625 SaveFPRegsMode save_doubles) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000626 // Enter an internal frame.
627 {
628 FrameScope scope(masm, StackFrame::INTERNAL);
629
630 // Preserve registers across notification, this is important for compiled
631 // stubs that tail call the runtime on deopts passing their parameters in
632 // registers.
633 __ pushad();
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000634 __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000635 __ popad();
636 // Tear down internal frame.
637 }
638
639 __ pop(MemOperand(esp, 0)); // Ignore state offset
640 __ ret(0); // Return to IC Miss stub, continuation still on stack.
641}
642
643
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000644void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
645 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
646}
647
648
649void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
danno@chromium.org8ebe7d52013-12-17 22:11:46 +0000650 if (Serializer::enabled()) {
651 PlatformFeatureScope sse2(SSE2);
652 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
653 } else {
654 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
655 }
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000656}
657
658
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000659static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
660 Deoptimizer::BailoutType type) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000661 {
662 FrameScope scope(masm, StackFrame::INTERNAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000663
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000664 // Pass deoptimization type to the runtime system.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000665 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
666 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000667
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000668 // Tear down internal frame.
669 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000670
671 // Get the full codegen state from the stack and untag it.
672 __ mov(ecx, Operand(esp, 1 * kPointerSize));
673 __ SmiUntag(ecx);
674
675 // Switch on the state.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000676 Label not_no_registers, not_tos_eax;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000677 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000678 __ j(not_equal, &not_no_registers, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000679 __ ret(1 * kPointerSize); // Remove state.
680
681 __ bind(&not_no_registers);
682 __ mov(eax, Operand(esp, 2 * kPointerSize));
683 __ cmp(ecx, FullCodeGenerator::TOS_REG);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000684 __ j(not_equal, &not_tos_eax, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000685 __ ret(2 * kPointerSize); // Remove state, eax.
686
687 __ bind(&not_tos_eax);
danno@chromium.org59400602013-08-13 17:09:37 +0000688 __ Abort(kNoCasesLeft);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000689}
690
691
692void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
693 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
694}
695
696
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000697void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
698 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
699}
700
701
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000702void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
703 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
704}
705
706
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000707void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000708 Factory* factory = masm->isolate()->factory();
709
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000710 // 1. Make sure we have at least one argument.
711 { Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000712 __ test(eax, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000713 __ j(not_zero, &done);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000714 __ pop(ebx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000715 __ push(Immediate(factory->undefined_value()));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000716 __ push(ebx);
717 __ inc(eax);
718 __ bind(&done);
719 }
720
ager@chromium.org5c838252010-02-19 08:53:10 +0000721 // 2. Get the function to call (passed as receiver) from the stack, check
722 // if it is a function.
lrn@chromium.org34e60782011-09-15 07:25:40 +0000723 Label slow, non_function;
ager@chromium.org5c838252010-02-19 08:53:10 +0000724 // 1 ~ return address.
725 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000726 __ JumpIfSmi(edi, &non_function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000727 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000728 __ j(not_equal, &slow);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000729
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000730
ager@chromium.org5c838252010-02-19 08:53:10 +0000731 // 3a. Patch the first argument if necessary when calling a function.
732 Label shift_arguments;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000733 __ Set(edx, Immediate(0)); // indicate regular JS_FUNCTION
ager@chromium.org5c838252010-02-19 08:53:10 +0000734 { Label convert_to_object, use_global_receiver, patch_receiver;
735 // Change context eagerly in case we need the global receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000736 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
737
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000738 // Do not transform the receiver for strict mode functions.
739 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
740 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
741 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
742 __ j(not_equal, &shift_arguments);
743
lrn@chromium.org1c092762011-05-09 09:42:16 +0000744 // Do not transform the receiver for natives (shared already in ebx).
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000745 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
746 1 << SharedFunctionInfo::kNativeBitWithinByte);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +0000747 __ j(not_equal, &shift_arguments);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000748
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000749 // Compute the receiver in non-strict mode.
ager@chromium.org5c838252010-02-19 08:53:10 +0000750 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000751
752 // Call ToObject on the receiver if it is not an object, or use the
753 // global object if it is null or undefined.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000754 __ JumpIfSmi(ebx, &convert_to_object);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000755 __ cmp(ebx, factory->null_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000756 __ j(equal, &use_global_receiver);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000757 __ cmp(ebx, factory->undefined_value());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000758 __ j(equal, &use_global_receiver);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000759 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
760 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000761 __ j(above_equal, &shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000762
ager@chromium.org5c838252010-02-19 08:53:10 +0000763 __ bind(&convert_to_object);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000764
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000765 { // In order to preserve argument count.
766 FrameScope scope(masm, StackFrame::INTERNAL);
767 __ SmiTag(eax);
768 __ push(eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000769
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000770 __ push(ebx);
771 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
772 __ mov(ebx, eax);
773 __ Set(edx, Immediate(0)); // restore
774
775 __ pop(eax);
776 __ SmiUntag(eax);
777 }
778
ager@chromium.org5c838252010-02-19 08:53:10 +0000779 // Restore the function to edi.
780 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000781 __ jmp(&patch_receiver);
782
ager@chromium.org5c838252010-02-19 08:53:10 +0000783 // Use the global receiver object from the called function as the
784 // receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000785 __ bind(&use_global_receiver);
786 const int kGlobalIndex =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000787 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000788 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000789 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
ager@chromium.org3811b432009-10-28 14:53:37 +0000790 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000791 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000792
793 __ bind(&patch_receiver);
794 __ mov(Operand(esp, eax, times_4, 0), ebx);
795
ager@chromium.org5c838252010-02-19 08:53:10 +0000796 __ jmp(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000797 }
798
lrn@chromium.org34e60782011-09-15 07:25:40 +0000799 // 3b. Check for function proxy.
800 __ bind(&slow);
801 __ Set(edx, Immediate(1)); // indicate function proxy
802 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
803 __ j(equal, &shift_arguments);
804 __ bind(&non_function);
805 __ Set(edx, Immediate(2)); // indicate non-function
806
807 // 3c. Patch the first argument when calling a non-function. The
ager@chromium.org5c838252010-02-19 08:53:10 +0000808 // CALL_NON_FUNCTION builtin expects the non-function callee as
809 // receiver, so overwrite the first argument which will ultimately
810 // become the receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +0000811 __ mov(Operand(esp, eax, times_4, 0), edi);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000812
ager@chromium.org5c838252010-02-19 08:53:10 +0000813 // 4. Shift arguments and return address one slot down on the stack
814 // (overwriting the original receiver). Adjust argument count to make
815 // the original first argument the new receiver.
816 __ bind(&shift_arguments);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000817 { Label loop;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000818 __ mov(ecx, eax);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000819 __ bind(&loop);
820 __ mov(ebx, Operand(esp, ecx, times_4, 0));
821 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
822 __ dec(ecx);
ager@chromium.org5c838252010-02-19 08:53:10 +0000823 __ j(not_sign, &loop); // While non-negative (to copy return address).
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000824 __ pop(ebx); // Discard copy of return address.
825 __ dec(eax); // One fewer argument (first argument is new receiver).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000826 }
827
lrn@chromium.org34e60782011-09-15 07:25:40 +0000828 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
829 // or a function proxy via CALL_FUNCTION_PROXY.
830 { Label function, non_proxy;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000831 __ test(edx, edx);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000832 __ j(zero, &function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000833 __ Set(ebx, Immediate(0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000834 __ cmp(edx, Immediate(1));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000835 __ j(not_equal, &non_proxy);
836
837 __ pop(edx); // return address
838 __ push(edi); // re-add proxy object as additional argument
839 __ push(edx);
840 __ inc(eax);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000841 __ SetCallKind(ecx, CALL_AS_FUNCTION);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000842 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
843 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
844 RelocInfo::CODE_TARGET);
845
846 __ bind(&non_proxy);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000847 __ SetCallKind(ecx, CALL_AS_METHOD);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000848 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000849 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
850 RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000851 __ bind(&function);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000852 }
853
ager@chromium.org5c838252010-02-19 08:53:10 +0000854 // 5b. Get the code to call from the function and check that the number of
855 // expected arguments matches what we're providing. If so, jump
856 // (tail-call) to the code in register edx without checking arguments.
857 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
858 __ mov(ebx,
859 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000860 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000861 __ SmiUntag(ebx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000862 __ SetCallKind(ecx, CALL_AS_METHOD);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000863 __ cmp(eax, ebx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000864 __ j(not_equal,
865 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
ager@chromium.org5c838252010-02-19 08:53:10 +0000866
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000867 ParameterCount expected(0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000868 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper(),
869 CALL_AS_METHOD);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000870}
871
872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
lrn@chromium.org34e60782011-09-15 07:25:40 +0000874 static const int kArgumentsOffset = 2 * kPointerSize;
875 static const int kReceiverOffset = 3 * kPointerSize;
876 static const int kFunctionOffset = 4 * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000877 {
878 FrameScope frame_scope(masm, StackFrame::INTERNAL);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000879
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000880 __ push(Operand(ebp, kFunctionOffset)); // push this
881 __ push(Operand(ebp, kArgumentsOffset)); // push arguments
882 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000884 // Check the stack for overflow. We are not trying to catch
885 // interruptions (e.g. debug break and preemption) here, so the "real stack
886 // limit" is checked.
887 Label okay;
888 ExternalReference real_stack_limit =
889 ExternalReference::address_of_real_stack_limit(masm->isolate());
890 __ mov(edi, Operand::StaticVariable(real_stack_limit));
891 // Make ecx the space we have left. The stack might already be overflowed
892 // here which will cause ecx to become negative.
893 __ mov(ecx, esp);
894 __ sub(ecx, edi);
895 // Make edx the space we need for the array when it is unrolled onto the
896 // stack.
897 __ mov(edx, eax);
898 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
899 // Check if the arguments will overflow the stack.
900 __ cmp(ecx, edx);
901 __ j(greater, &okay); // Signed comparison.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000903 // Out of stack space.
904 __ push(Operand(ebp, 4 * kPointerSize)); // push this
905 __ push(eax);
906 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
907 __ bind(&okay);
908 // End of stack check.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000909
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000910 // Push current index and limit.
911 const int kLimitOffset =
912 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
913 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
914 __ push(eax); // limit
915 __ push(Immediate(0)); // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917 // Get the receiver.
918 __ mov(ebx, Operand(ebp, kReceiverOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000920 // Check that the function is a JS function (otherwise it must be a proxy).
921 Label push_receiver;
922 __ mov(edi, Operand(ebp, kFunctionOffset));
923 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
924 __ j(not_equal, &push_receiver);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000925
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000926 // Change context eagerly to get the right global object if necessary.
927 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
lrn@chromium.org34e60782011-09-15 07:25:40 +0000928
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000929 // Compute the receiver.
930 // Do not transform the receiver for strict mode functions.
931 Label call_to_object, use_global_receiver;
932 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
933 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
934 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
935 __ j(not_equal, &push_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000936
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000937 Factory* factory = masm->isolate()->factory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000938
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000939 // Do not transform the receiver for natives (shared already in ecx).
940 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
941 1 << SharedFunctionInfo::kNativeBitWithinByte);
942 __ j(not_equal, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000943
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000944 // Compute the receiver in non-strict mode.
945 // Call ToObject on the receiver if it is not an object, or use the
946 // global object if it is null or undefined.
947 __ JumpIfSmi(ebx, &call_to_object);
948 __ cmp(ebx, factory->null_value());
949 __ j(equal, &use_global_receiver);
950 __ cmp(ebx, factory->undefined_value());
951 __ j(equal, &use_global_receiver);
952 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
953 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
954 __ j(above_equal, &push_receiver);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000955
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000956 __ bind(&call_to_object);
957 __ push(ebx);
958 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
959 __ mov(ebx, eax);
960 __ jmp(&push_receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000962 // Use the current global receiver object as the receiver.
963 __ bind(&use_global_receiver);
964 const int kGlobalOffset =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000965 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000966 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000967 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000968 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
969 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000971 // Push the receiver.
972 __ bind(&push_receiver);
973 __ push(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000975 // Copy all arguments from the array to the stack.
976 Label entry, loop;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000977 __ mov(ecx, Operand(ebp, kIndexOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000978 __ jmp(&entry);
979 __ bind(&loop);
980 __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000982 // Use inline caching to speed up access to arguments.
983 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
984 __ call(ic, RelocInfo::CODE_TARGET);
985 // It is important that we do not have a test instruction after the
986 // call. A test instruction after the call is used to indicate that
987 // we have generated an inline version of the keyed load. In this
988 // case, we know that we are not generating a test instruction next.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000990 // Push the nth argument.
991 __ push(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000993 // Update the index on the stack and in register eax.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000994 __ mov(ecx, Operand(ebp, kIndexOffset));
995 __ add(ecx, Immediate(1 << kSmiTagSize));
996 __ mov(Operand(ebp, kIndexOffset), ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000998 __ bind(&entry);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000999 __ cmp(ecx, Operand(ebp, kLimitOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001000 __ j(not_equal, &loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001002 // Invoke the function.
1003 Label call_proxy;
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001004 __ mov(eax, ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001005 ParameterCount actual(eax);
1006 __ SmiUntag(eax);
1007 __ mov(edi, Operand(ebp, kFunctionOffset));
1008 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
1009 __ j(not_equal, &call_proxy);
1010 __ InvokeFunction(edi, actual, CALL_FUNCTION,
1011 NullCallWrapper(), CALL_AS_METHOD);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001013 frame_scope.GenerateLeaveFrame();
1014 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001016 // Invoke the function proxy.
1017 __ bind(&call_proxy);
1018 __ push(edi); // add function proxy as last argument
1019 __ inc(eax);
1020 __ Set(ebx, Immediate(0));
1021 __ SetCallKind(ecx, CALL_AS_METHOD);
1022 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
1023 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1024 RelocInfo::CODE_TARGET);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001025
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001026 // Leave internal frame.
1027 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001028 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029}
1030
1031
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001032void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1033 // ----------- S t a t e -------------
1034 // -- eax : argc
1035 // -- esp[0] : return address
1036 // -- esp[4] : last argument
1037 // -----------------------------------
1038 Label generic_array_code;
1039
1040 // Get the InternalArray function.
1041 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1042
1043 if (FLAG_debug_code) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001044 // Initial map for the builtin InternalArray function should be a map.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001045 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1046 // Will both indicate a NULL and a Smi.
1047 __ test(ebx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001048 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001049 __ CmpObjectType(ebx, MAP_TYPE, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +00001050 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001051 }
1052
1053 // Run the native code for the InternalArray function called as a normal
1054 // function.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001055 // tail call a stub
1056 InternalArrayConstructorStub stub(masm->isolate());
1057 __ TailCallStub(&stub);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00001058}
1059
1060
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001061void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1062 // ----------- S t a t e -------------
1063 // -- eax : argc
1064 // -- esp[0] : return address
1065 // -- esp[4] : last argument
1066 // -----------------------------------
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001067 Label generic_array_code;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001068
1069 // Get the Array function.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001070 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001071
1072 if (FLAG_debug_code) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001073 // Initial map for the builtin Array function should be a map.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001074 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1075 // Will both indicate a NULL and a Smi.
1076 __ test(ebx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001077 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001078 __ CmpObjectType(ebx, MAP_TYPE, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +00001079 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001080 }
1081
1082 // Run the native code for the Array function called as a normal function.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001083 // tail call a stub
1084 Handle<Object> undefined_sentinel(
1085 masm->isolate()->heap()->undefined_value(),
1086 masm->isolate());
1087 __ mov(ebx, Immediate(undefined_sentinel));
1088 ArrayConstructorStub stub(masm->isolate());
1089 __ TailCallStub(&stub);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001090}
1091
1092
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001093void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1094 // ----------- S t a t e -------------
1095 // -- eax : number of arguments
1096 // -- edi : constructor function
1097 // -- esp[0] : return address
1098 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1099 // -- esp[(argc + 1) * 4] : receiver
1100 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001101 Counters* counters = masm->isolate()->counters();
1102 __ IncrementCounter(counters->string_ctor_calls(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001103
1104 if (FLAG_debug_code) {
1105 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001106 __ cmp(edi, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +00001107 __ Assert(equal, kUnexpectedStringFunction);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001108 }
1109
1110 // Load the first argument into eax and get rid of the rest
1111 // (including the receiver).
1112 Label no_arguments;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001113 __ test(eax, eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001114 __ j(zero, &no_arguments);
1115 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1116 __ pop(ecx);
1117 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1118 __ push(ecx);
1119 __ mov(eax, ebx);
1120
1121 // Lookup the argument in the number to string cache.
1122 Label not_cached, argument_is_string;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001123 __ LookupNumberStringCache(eax, // Input.
1124 ebx, // Result.
1125 ecx, // Scratch 1.
1126 edx, // Scratch 2.
1127 &not_cached);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001128 __ IncrementCounter(counters->string_ctor_cached_number(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001129 __ bind(&argument_is_string);
1130 // ----------- S t a t e -------------
1131 // -- ebx : argument converted to string
1132 // -- edi : constructor function
1133 // -- esp[0] : return address
1134 // -----------------------------------
1135
1136 // Allocate a JSValue and put the tagged pointer into eax.
1137 Label gc_required;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001138 __ Allocate(JSValue::kSize,
1139 eax, // Result.
1140 ecx, // New allocation top (we ignore it).
1141 no_reg,
1142 &gc_required,
1143 TAG_OBJECT);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001144
1145 // Set the map.
1146 __ LoadGlobalFunctionInitialMap(edi, ecx);
1147 if (FLAG_debug_code) {
1148 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1149 JSValue::kSize >> kPointerSizeLog2);
danno@chromium.org59400602013-08-13 17:09:37 +00001150 __ Assert(equal, kUnexpectedStringWrapperInstanceSize);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001151 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
danno@chromium.org59400602013-08-13 17:09:37 +00001152 __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001153 }
1154 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1155
1156 // Set properties and elements.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001157 Factory* factory = masm->isolate()->factory();
1158 __ Set(ecx, Immediate(factory->empty_fixed_array()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001159 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1160 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1161
1162 // Set the value.
1163 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1164
1165 // Ensure the object is fully initialized.
1166 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1167
1168 // We're done. Return.
1169 __ ret(0);
1170
1171 // The argument was not found in the number to string cache. Check
1172 // if it's a string already before calling the conversion builtin.
1173 Label convert_argument;
1174 __ bind(&not_cached);
1175 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001176 __ JumpIfSmi(eax, &convert_argument);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001177 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1178 __ j(NegateCondition(is_string), &convert_argument);
1179 __ mov(ebx, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001180 __ IncrementCounter(counters->string_ctor_string_value(), 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001181 __ jmp(&argument_is_string);
1182
1183 // Invoke the conversion builtin and put the result into ebx.
1184 __ bind(&convert_argument);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001185 __ IncrementCounter(counters->string_ctor_conversions(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001186 {
1187 FrameScope scope(masm, StackFrame::INTERNAL);
1188 __ push(edi); // Preserve the function.
1189 __ push(eax);
1190 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1191 __ pop(edi);
1192 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001193 __ mov(ebx, eax);
1194 __ jmp(&argument_is_string);
1195
1196 // Load the empty string into ebx, remove the receiver from the
1197 // stack, and jump back to the case where the argument is a string.
1198 __ bind(&no_arguments);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001199 __ Set(ebx, Immediate(factory->empty_string()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001200 __ pop(ecx);
1201 __ lea(esp, Operand(esp, kPointerSize));
1202 __ push(ecx);
1203 __ jmp(&argument_is_string);
1204
1205 // At this point the argument is already a string. Call runtime to
1206 // create a string wrapper.
1207 __ bind(&gc_required);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001208 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001209 {
1210 FrameScope scope(masm, StackFrame::INTERNAL);
1211 __ push(ebx);
1212 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1213 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001214 __ ret(0);
1215}
1216
1217
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1219 __ push(ebp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001220 __ mov(ebp, esp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221
1222 // Store the arguments adaptor context sentinel.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001223 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001224
1225 // Push the function on the stack.
1226 __ push(edi);
1227
danno@chromium.org40cb8782011-05-25 07:58:50 +00001228 // Preserve the number of arguments on the stack. Must preserve eax,
1229 // ebx and ecx because these registers are used when copying the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 // arguments and the receiver.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001231 STATIC_ASSERT(kSmiTagSize == 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001232 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1233 __ push(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234}
1235
1236
ager@chromium.org7c537e22008-10-16 08:43:32 +00001237static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238 // Retrieve the number of arguments from the stack.
1239 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1240
1241 // Leave the frame.
1242 __ leave();
1243
1244 // Remove caller arguments from the stack.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001245 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246 __ pop(ecx);
1247 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1248 __ push(ecx);
1249}
1250
1251
1252void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1253 // ----------- S t a t e -------------
1254 // -- eax : actual number of arguments
1255 // -- ebx : expected number of arguments
danno@chromium.org40cb8782011-05-25 07:58:50 +00001256 // -- ecx : call kind information
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 // -- edx : code entry to call
1258 // -----------------------------------
1259
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001260 Label invoke, dont_adapt_arguments;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001261 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262
1263 Label enough, too_few;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001264 __ cmp(eax, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 __ j(less, &too_few);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001266 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1267 __ j(equal, &dont_adapt_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268
1269 { // Enough parameters: Actual >= expected.
1270 __ bind(&enough);
1271 EnterArgumentsAdaptorFrame(masm);
1272
1273 // Copy receiver and all expected arguments.
1274 const int offset = StandardFrameConstants::kCallerSPOffset;
1275 __ lea(eax, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001276 __ mov(edi, -1); // account for receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
1278 Label copy;
1279 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001280 __ inc(edi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 __ push(Operand(eax, 0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001282 __ sub(eax, Immediate(kPointerSize));
1283 __ cmp(edi, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 __ j(less, &copy);
1285 __ jmp(&invoke);
1286 }
1287
1288 { // Too few parameters: Actual < expected.
1289 __ bind(&too_few);
1290 EnterArgumentsAdaptorFrame(masm);
1291
1292 // Copy receiver and all actual arguments.
1293 const int offset = StandardFrameConstants::kCallerSPOffset;
1294 __ lea(edi, Operand(ebp, eax, times_4, offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001295 // ebx = expected - actual.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001296 __ sub(ebx, eax);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001297 // eax = -actual - 1
1298 __ neg(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001299 __ sub(eax, Immediate(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300
1301 Label copy;
1302 __ bind(&copy);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001303 __ inc(eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 __ push(Operand(edi, 0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 __ sub(edi, Immediate(kPointerSize));
1306 __ test(eax, eax);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001307 __ j(not_zero, &copy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308
1309 // Fill remaining expected arguments with undefined values.
1310 Label fill;
1311 __ bind(&fill);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001312 __ inc(eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001313 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001314 __ cmp(eax, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 __ j(less, &fill);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 }
1317
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001318 // Call the entry point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 __ bind(&invoke);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001320 // Restore function pointer.
1321 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001322 __ call(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323
ulan@chromium.org967e2702012-02-28 09:49:15 +00001324 // Store offset of return address for deoptimizer.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001325 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
ulan@chromium.org967e2702012-02-28 09:49:15 +00001326
ager@chromium.org7c537e22008-10-16 08:43:32 +00001327 // Leave frame and return.
1328 LeaveArgumentsAdaptorFrame(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 __ ret(0);
1330
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001332 // Dont adapt arguments.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333 // -------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001334 __ bind(&dont_adapt_arguments);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001335 __ jmp(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336}
1337
1338
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001339void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001340 // Lookup the function in the JavaScript frame.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001341 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001342 {
1343 FrameScope scope(masm, StackFrame::INTERNAL);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00001344 // Pass function as argument.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001345 __ push(eax);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00001346 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001347 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001348
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001349 Label skip;
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00001350 // If the code object is null, just return to the unoptimized code.
1351 __ cmp(eax, Immediate(0));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001352 __ j(not_equal, &skip, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001353 __ ret(0);
1354
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001355 __ bind(&skip);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001356
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00001357 // Load deoptimization data from the code object.
1358 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1359
1360 // Load the OSR entrypoint offset from the deoptimization data.
1361 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
1362 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
1363 __ SmiUntag(ebx);
1364
1365 // Compute the target address = code_obj + header_size + osr_offset
1366 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
1367
1368 // Overwrite the return address on the stack.
1369 __ mov(Operand(esp, 0), eax);
1370
1371 // And "return" to the OSR entry point of the function.
1372 __ ret(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001373}
1374
1375
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00001376void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1377 // We check the stack limit as indicator that recompilation might be done.
1378 Label ok;
1379 ExternalReference stack_limit =
1380 ExternalReference::address_of_stack_limit(masm->isolate());
1381 __ cmp(esp, Operand::StaticVariable(stack_limit));
1382 __ j(above_equal, &ok, Label::kNear);
1383 {
1384 FrameScope scope(masm, StackFrame::INTERNAL);
1385 __ CallRuntime(Runtime::kStackGuard, 0);
1386 }
1387 __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
1388 RelocInfo::CODE_TARGET);
1389
1390 __ bind(&ok);
1391 __ ret(0);
1392}
1393
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001394#undef __
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001395}
1396} // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001397
1398#endif // V8_TARGET_ARCH_IA32