1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // 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
30 #if V8_TARGET_ARCH_IA32
31
32 #include "codegen.h"
33 #include "deoptimizer.h"
34 #include "full-codegen.h"
35
36 namespace v8 {
37 namespace internal {
38
39
40 #define __ ACCESS_MASM(masm)
41
42
Generate_Adaptor(MacroAssembler * masm,CFunctionId id,BuiltinExtraArguments extra_args)43 void 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 // -----------------------------------
57
58 // 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
70 // JumpToExternalReference expects eax to contain the number of arguments
71 // including the receiver and the extra arguments.
72 __ add(eax, Immediate(num_extra_args + 1));
73 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
74 }
75
76
CallRuntimePassFunction(MacroAssembler * masm,Runtime::FunctionId function_id)77 static 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
GenerateTailCallToSharedCode(MacroAssembler * masm)95 static 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
Generate_InRecompileQueue(MacroAssembler * masm)103 void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
104 // 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);
121 GenerateTailCallToSharedCode(masm);
122 }
123
124
Generate_ConcurrentRecompile(MacroAssembler * masm)125 void Builtins::Generate_ConcurrentRecompile(MacroAssembler* masm) {
126 CallRuntimePassFunction(masm, Runtime::kConcurrentRecompile);
127 GenerateTailCallToSharedCode(masm);
128 }
129
130
Generate_JSConstructStubHelper(MacroAssembler * masm,bool is_api_function,bool count_constructions)131 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
132 bool is_api_function,
133 bool count_constructions) {
134 // ----------- S t a t e -------------
135 // -- eax: number of arguments
136 // -- edi: constructor function
137 // -----------------------------------
138
139 // Should never count constructions for api objects.
140 ASSERT(!is_api_function || !count_constructions);
141
142 // Enter a construct frame.
143 {
144 FrameScope scope(masm, StackFrame::CONSTRUCT);
145
146 // Store a smi-tagged arguments count on the stack.
147 __ SmiTag(eax);
148 __ push(eax);
149
150 // Push the function to invoke on the stack.
151 __ push(edi);
152
153 // 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;
158 #ifdef ENABLE_DEBUGGER_SUPPORT
159 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);
163 #endif
164
165 // 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);
175
176 // 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);
183
184 if (count_constructions) {
185 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);
203 }
204
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);
210 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
211 // 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
224 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
225 __ mov(edx, factory->undefined_value());
226 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,
235 kUnexpectedNumberOfPreAllocatedPropertyFields);
236 }
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);
266 __ Assert(positive, kPropertyAllocationCountFailed);
267
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
273 __ 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);
282
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);
327 }
328
329 // 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
337
338 // New object allocated.
339 // ebx: newly allocated object
340 __ bind(&allocated);
341 // Retrieve the function from the stack.
342 __ pop(edi);
343
344 // Retrieve smi-tagged arguments count from the stack.
345 __ mov(eax, Operand(esp, 0));
346 __ SmiUntag(eax);
347
348 // 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
354 // Set up pointer to last argument.
355 __ 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
381 // Store offset of return address for deoptimizer.
382 if (!is_api_function && !count_constructions) {
383 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
384 }
385
386 // 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.
412 }
413
414 // Remove caller arguments from the stack and return.
415 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
416 __ pop(ecx);
417 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
418 __ push(ecx);
419 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
420 __ ret(0);
421 }
422
423
Generate_JSConstructStubCountdown(MacroAssembler * masm)424 void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
425 Generate_JSConstructStubHelper(masm, false, true);
426 }
427
428
Generate_JSConstructStubGeneric(MacroAssembler * masm)429 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
430 Generate_JSConstructStubHelper(masm, false, false);
431 }
432
433
Generate_JSConstructStubApi(MacroAssembler * masm)434 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
435 Generate_JSConstructStubHelper(masm, true, false);
436 }
437
438
Generate_JSEntryTrampolineHelper(MacroAssembler * masm,bool is_construct)439 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
440 bool is_construct) {
441 ProfileEntryHookStub::MaybeCallEntryHook(masm);
442
443 // Clear the context before we push it when entering the internal frame.
444 __ Set(esi, Immediate(0));
445
446 {
447 FrameScope scope(masm, StackFrame::INTERNAL);
448
449 // Load the previous frame pointer (ebx) to access C arguments
450 __ mov(ebx, Operand(ebp, 0));
451
452 // Get the function from the frame and setup the context.
453 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
454 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
455
456 // Push the function and the receiver onto the stack.
457 __ push(ecx);
458 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
459
460 // 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));
463
464 // 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);
475
476 // Get the function from the stack and call it.
477 // kPointerSize for the receiver.
478 __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
479
480 // Invoke the code.
481 if (is_construct) {
482 // 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));
486 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
487 __ CallStub(&stub);
488 } 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.
497 }
498 __ ret(kPointerSize); // Remove receiver.
499 }
500
501
Generate_JSEntryTrampoline(MacroAssembler * masm)502 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
503 Generate_JSEntryTrampolineHelper(masm, false);
504 }
505
506
Generate_JSConstructEntryTrampoline(MacroAssembler * masm)507 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
508 Generate_JSEntryTrampolineHelper(masm, true);
509 }
510
511
Generate_LazyCompile(MacroAssembler * masm)512 void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
513 CallRuntimePassFunction(masm, Runtime::kLazyCompile);
514 // Do a tail-call of the compiled function.
515 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
516 __ jmp(eax);
517 }
518
519
Generate_LazyRecompile(MacroAssembler * masm)520 void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
521 CallRuntimePassFunction(masm, Runtime::kLazyRecompile);
522 // Do a tail-call of the compiled function.
523 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
524 __ jmp(eax);
525 }
526
527
GenerateMakeCodeYoungAgainCommon(MacroAssembler * masm)528 static 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);
542 __ PrepareCallCFunction(2, ebx);
543 __ mov(Operand(esp, 1 * kPointerSize),
544 Immediate(ExternalReference::isolate_address(masm->isolate())));
545 __ mov(Operand(esp, 0), eax);
546 __ CallCFunction(
547 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
548 }
549 __ popad();
550 __ ret(0);
551 }
552
553 #define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
554 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
555 MacroAssembler* masm) { \
556 GenerateMakeCodeYoungAgainCommon(masm); \
557 } \
558 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
559 MacroAssembler* masm) { \
560 GenerateMakeCodeYoungAgainCommon(masm); \
561 }
CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)562 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
563 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
564
565
566 void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
567 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
568 // that make_code_young doesn't do any garbage collection which allows us to
569 // save/restore the registers without worrying about which of them contain
570 // pointers.
571 __ pushad();
572 __ mov(eax, Operand(esp, 8 * kPointerSize));
573 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
574 { // NOLINT
575 FrameScope scope(masm, StackFrame::MANUAL);
576 __ PrepareCallCFunction(2, ebx);
577 __ mov(Operand(esp, 1 * kPointerSize),
578 Immediate(ExternalReference::isolate_address(masm->isolate())));
579 __ mov(Operand(esp, 0), eax);
580 __ CallCFunction(
581 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
582 2);
583 }
584 __ popad();
585
586 // Perform prologue operations usually performed by the young code stub.
587 __ pop(eax); // Pop return address into scratch register.
588 __ push(ebp); // Caller's frame pointer.
589 __ mov(ebp, esp);
590 __ push(esi); // Callee's context.
591 __ push(edi); // Callee's JS Function.
592 __ push(eax); // Push return address after frame prologue.
593
594 // Jump to point after the code-age stub.
595 __ ret(0);
596 }
597
598
Generate_MarkCodeAsExecutedTwice(MacroAssembler * masm)599 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
600 GenerateMakeCodeYoungAgainCommon(masm);
601 }
602
603
Generate_NotifyStubFailureHelper(MacroAssembler * masm,SaveFPRegsMode save_doubles)604 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
605 SaveFPRegsMode save_doubles) {
606 // Enter an internal frame.
607 {
608 FrameScope scope(masm, StackFrame::INTERNAL);
609
610 // Preserve registers across notification, this is important for compiled
611 // stubs that tail call the runtime on deopts passing their parameters in
612 // registers.
613 __ pushad();
614 __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
615 __ popad();
616 // Tear down internal frame.
617 }
618
619 __ pop(MemOperand(esp, 0)); // Ignore state offset
620 __ ret(0); // Return to IC Miss stub, continuation still on stack.
621 }
622
623
Generate_NotifyStubFailure(MacroAssembler * masm)624 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
625 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
626 }
627
628
Generate_NotifyStubFailureSaveDoubles(MacroAssembler * masm)629 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
630 if (Serializer::enabled()) {
631 PlatformFeatureScope sse2(SSE2);
632 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
633 } else {
634 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
635 }
636 }
637
638
Generate_NotifyDeoptimizedHelper(MacroAssembler * masm,Deoptimizer::BailoutType type)639 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
640 Deoptimizer::BailoutType type) {
641 {
642 FrameScope scope(masm, StackFrame::INTERNAL);
643
644 // Pass deoptimization type to the runtime system.
645 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
646 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
647
648 // Tear down internal frame.
649 }
650
651 // Get the full codegen state from the stack and untag it.
652 __ mov(ecx, Operand(esp, 1 * kPointerSize));
653 __ SmiUntag(ecx);
654
655 // Switch on the state.
656 Label not_no_registers, not_tos_eax;
657 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
658 __ j(not_equal, ¬_no_registers, Label::kNear);
659 __ ret(1 * kPointerSize); // Remove state.
660
661 __ bind(¬_no_registers);
662 __ mov(eax, Operand(esp, 2 * kPointerSize));
663 __ cmp(ecx, FullCodeGenerator::TOS_REG);
664 __ j(not_equal, ¬_tos_eax, Label::kNear);
665 __ ret(2 * kPointerSize); // Remove state, eax.
666
667 __ bind(¬_tos_eax);
668 __ Abort(kNoCasesLeft);
669 }
670
671
Generate_NotifyDeoptimized(MacroAssembler * masm)672 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
673 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
674 }
675
676
Generate_NotifySoftDeoptimized(MacroAssembler * masm)677 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
678 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
679 }
680
681
Generate_NotifyLazyDeoptimized(MacroAssembler * masm)682 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
683 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
684 }
685
686
Generate_FunctionCall(MacroAssembler * masm)687 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
688 Factory* factory = masm->isolate()->factory();
689
690 // 1. Make sure we have at least one argument.
691 { Label done;
692 __ test(eax, eax);
693 __ j(not_zero, &done);
694 __ pop(ebx);
695 __ push(Immediate(factory->undefined_value()));
696 __ push(ebx);
697 __ inc(eax);
698 __ bind(&done);
699 }
700
701 // 2. Get the function to call (passed as receiver) from the stack, check
702 // if it is a function.
703 Label slow, non_function;
704 // 1 ~ return address.
705 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
706 __ JumpIfSmi(edi, &non_function);
707 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
708 __ j(not_equal, &slow);
709
710
711 // 3a. Patch the first argument if necessary when calling a function.
712 Label shift_arguments;
713 __ Set(edx, Immediate(0)); // indicate regular JS_FUNCTION
714 { Label convert_to_object, use_global_receiver, patch_receiver;
715 // Change context eagerly in case we need the global receiver.
716 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
717
718 // Do not transform the receiver for strict mode functions.
719 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
720 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
721 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
722 __ j(not_equal, &shift_arguments);
723
724 // Do not transform the receiver for natives (shared already in ebx).
725 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
726 1 << SharedFunctionInfo::kNativeBitWithinByte);
727 __ j(not_equal, &shift_arguments);
728
729 // Compute the receiver in non-strict mode.
730 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
731
732 // Call ToObject on the receiver if it is not an object, or use the
733 // global object if it is null or undefined.
734 __ JumpIfSmi(ebx, &convert_to_object);
735 __ cmp(ebx, factory->null_value());
736 __ j(equal, &use_global_receiver);
737 __ cmp(ebx, factory->undefined_value());
738 __ j(equal, &use_global_receiver);
739 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
740 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
741 __ j(above_equal, &shift_arguments);
742
743 __ bind(&convert_to_object);
744
745 { // In order to preserve argument count.
746 FrameScope scope(masm, StackFrame::INTERNAL);
747 __ SmiTag(eax);
748 __ push(eax);
749
750 __ push(ebx);
751 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
752 __ mov(ebx, eax);
753 __ Set(edx, Immediate(0)); // restore
754
755 __ pop(eax);
756 __ SmiUntag(eax);
757 }
758
759 // Restore the function to edi.
760 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
761 __ jmp(&patch_receiver);
762
763 // Use the global receiver object from the called function as the
764 // receiver.
765 __ bind(&use_global_receiver);
766 const int kGlobalIndex =
767 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
768 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
769 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
770 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
771 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
772
773 __ bind(&patch_receiver);
774 __ mov(Operand(esp, eax, times_4, 0), ebx);
775
776 __ jmp(&shift_arguments);
777 }
778
779 // 3b. Check for function proxy.
780 __ bind(&slow);
781 __ Set(edx, Immediate(1)); // indicate function proxy
782 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
783 __ j(equal, &shift_arguments);
784 __ bind(&non_function);
785 __ Set(edx, Immediate(2)); // indicate non-function
786
787 // 3c. Patch the first argument when calling a non-function. The
788 // CALL_NON_FUNCTION builtin expects the non-function callee as
789 // receiver, so overwrite the first argument which will ultimately
790 // become the receiver.
791 __ mov(Operand(esp, eax, times_4, 0), edi);
792
793 // 4. Shift arguments and return address one slot down on the stack
794 // (overwriting the original receiver). Adjust argument count to make
795 // the original first argument the new receiver.
796 __ bind(&shift_arguments);
797 { Label loop;
798 __ mov(ecx, eax);
799 __ bind(&loop);
800 __ mov(ebx, Operand(esp, ecx, times_4, 0));
801 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
802 __ dec(ecx);
803 __ j(not_sign, &loop); // While non-negative (to copy return address).
804 __ pop(ebx); // Discard copy of return address.
805 __ dec(eax); // One fewer argument (first argument is new receiver).
806 }
807
808 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
809 // or a function proxy via CALL_FUNCTION_PROXY.
810 { Label function, non_proxy;
811 __ test(edx, edx);
812 __ j(zero, &function);
813 __ Set(ebx, Immediate(0));
814 __ cmp(edx, Immediate(1));
815 __ j(not_equal, &non_proxy);
816
817 __ pop(edx); // return address
818 __ push(edi); // re-add proxy object as additional argument
819 __ push(edx);
820 __ inc(eax);
821 __ SetCallKind(ecx, CALL_AS_FUNCTION);
822 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
823 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
824 RelocInfo::CODE_TARGET);
825
826 __ bind(&non_proxy);
827 __ SetCallKind(ecx, CALL_AS_METHOD);
828 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
829 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
830 RelocInfo::CODE_TARGET);
831 __ bind(&function);
832 }
833
834 // 5b. Get the code to call from the function and check that the number of
835 // expected arguments matches what we're providing. If so, jump
836 // (tail-call) to the code in register edx without checking arguments.
837 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
838 __ mov(ebx,
839 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
840 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
841 __ SmiUntag(ebx);
842 __ SetCallKind(ecx, CALL_AS_METHOD);
843 __ cmp(eax, ebx);
844 __ j(not_equal,
845 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
846
847 ParameterCount expected(0);
848 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper(),
849 CALL_AS_METHOD);
850 }
851
852
Generate_FunctionApply(MacroAssembler * masm)853 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
854 static const int kArgumentsOffset = 2 * kPointerSize;
855 static const int kReceiverOffset = 3 * kPointerSize;
856 static const int kFunctionOffset = 4 * kPointerSize;
857 {
858 FrameScope frame_scope(masm, StackFrame::INTERNAL);
859
860 __ push(Operand(ebp, kFunctionOffset)); // push this
861 __ push(Operand(ebp, kArgumentsOffset)); // push arguments
862 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
863
864 // Check the stack for overflow. We are not trying to catch
865 // interruptions (e.g. debug break and preemption) here, so the "real stack
866 // limit" is checked.
867 Label okay;
868 ExternalReference real_stack_limit =
869 ExternalReference::address_of_real_stack_limit(masm->isolate());
870 __ mov(edi, Operand::StaticVariable(real_stack_limit));
871 // Make ecx the space we have left. The stack might already be overflowed
872 // here which will cause ecx to become negative.
873 __ mov(ecx, esp);
874 __ sub(ecx, edi);
875 // Make edx the space we need for the array when it is unrolled onto the
876 // stack.
877 __ mov(edx, eax);
878 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
879 // Check if the arguments will overflow the stack.
880 __ cmp(ecx, edx);
881 __ j(greater, &okay); // Signed comparison.
882
883 // Out of stack space.
884 __ push(Operand(ebp, 4 * kPointerSize)); // push this
885 __ push(eax);
886 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
887 __ bind(&okay);
888 // End of stack check.
889
890 // Push current index and limit.
891 const int kLimitOffset =
892 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
893 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
894 __ push(eax); // limit
895 __ push(Immediate(0)); // index
896
897 // Get the receiver.
898 __ mov(ebx, Operand(ebp, kReceiverOffset));
899
900 // Check that the function is a JS function (otherwise it must be a proxy).
901 Label push_receiver;
902 __ mov(edi, Operand(ebp, kFunctionOffset));
903 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
904 __ j(not_equal, &push_receiver);
905
906 // Change context eagerly to get the right global object if necessary.
907 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
908
909 // Compute the receiver.
910 // Do not transform the receiver for strict mode functions.
911 Label call_to_object, use_global_receiver;
912 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
913 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
914 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
915 __ j(not_equal, &push_receiver);
916
917 Factory* factory = masm->isolate()->factory();
918
919 // Do not transform the receiver for natives (shared already in ecx).
920 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
921 1 << SharedFunctionInfo::kNativeBitWithinByte);
922 __ j(not_equal, &push_receiver);
923
924 // Compute the receiver in non-strict mode.
925 // Call ToObject on the receiver if it is not an object, or use the
926 // global object if it is null or undefined.
927 __ JumpIfSmi(ebx, &call_to_object);
928 __ cmp(ebx, factory->null_value());
929 __ j(equal, &use_global_receiver);
930 __ cmp(ebx, factory->undefined_value());
931 __ j(equal, &use_global_receiver);
932 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
933 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
934 __ j(above_equal, &push_receiver);
935
936 __ bind(&call_to_object);
937 __ push(ebx);
938 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
939 __ mov(ebx, eax);
940 __ jmp(&push_receiver);
941
942 // Use the current global receiver object as the receiver.
943 __ bind(&use_global_receiver);
944 const int kGlobalOffset =
945 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
946 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
947 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
948 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
949 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
950
951 // Push the receiver.
952 __ bind(&push_receiver);
953 __ push(ebx);
954
955 // Copy all arguments from the array to the stack.
956 Label entry, loop;
957 __ mov(ecx, Operand(ebp, kIndexOffset));
958 __ jmp(&entry);
959 __ bind(&loop);
960 __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
961
962 // Use inline caching to speed up access to arguments.
963 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
964 __ call(ic, RelocInfo::CODE_TARGET);
965 // It is important that we do not have a test instruction after the
966 // call. A test instruction after the call is used to indicate that
967 // we have generated an inline version of the keyed load. In this
968 // case, we know that we are not generating a test instruction next.
969
970 // Push the nth argument.
971 __ push(eax);
972
973 // Update the index on the stack and in register eax.
974 __ mov(ecx, Operand(ebp, kIndexOffset));
975 __ add(ecx, Immediate(1 << kSmiTagSize));
976 __ mov(Operand(ebp, kIndexOffset), ecx);
977
978 __ bind(&entry);
979 __ cmp(ecx, Operand(ebp, kLimitOffset));
980 __ j(not_equal, &loop);
981
982 // Invoke the function.
983 Label call_proxy;
984 __ mov(eax, ecx);
985 ParameterCount actual(eax);
986 __ SmiUntag(eax);
987 __ mov(edi, Operand(ebp, kFunctionOffset));
988 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
989 __ j(not_equal, &call_proxy);
990 __ InvokeFunction(edi, actual, CALL_FUNCTION,
991 NullCallWrapper(), CALL_AS_METHOD);
992
993 frame_scope.GenerateLeaveFrame();
994 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
995
996 // Invoke the function proxy.
997 __ bind(&call_proxy);
998 __ push(edi); // add function proxy as last argument
999 __ inc(eax);
1000 __ Set(ebx, Immediate(0));
1001 __ SetCallKind(ecx, CALL_AS_METHOD);
1002 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
1003 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1004 RelocInfo::CODE_TARGET);
1005
1006 // Leave internal frame.
1007 }
1008 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
1009 }
1010
1011
Generate_InternalArrayCode(MacroAssembler * masm)1012 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1013 // ----------- S t a t e -------------
1014 // -- eax : argc
1015 // -- esp[0] : return address
1016 // -- esp[4] : last argument
1017 // -----------------------------------
1018 Label generic_array_code;
1019
1020 // Get the InternalArray function.
1021 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1022
1023 if (FLAG_debug_code) {
1024 // Initial map for the builtin InternalArray function should be a map.
1025 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1026 // Will both indicate a NULL and a Smi.
1027 __ test(ebx, Immediate(kSmiTagMask));
1028 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1029 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1030 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1031 }
1032
1033 // Run the native code for the InternalArray function called as a normal
1034 // function.
1035 // tail call a stub
1036 InternalArrayConstructorStub stub(masm->isolate());
1037 __ TailCallStub(&stub);
1038 }
1039
1040
Generate_ArrayCode(MacroAssembler * masm)1041 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1042 // ----------- S t a t e -------------
1043 // -- eax : argc
1044 // -- esp[0] : return address
1045 // -- esp[4] : last argument
1046 // -----------------------------------
1047 Label generic_array_code;
1048
1049 // Get the Array function.
1050 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
1051
1052 if (FLAG_debug_code) {
1053 // Initial map for the builtin Array function should be a map.
1054 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1055 // Will both indicate a NULL and a Smi.
1056 __ test(ebx, Immediate(kSmiTagMask));
1057 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1058 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1059 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1060 }
1061
1062 // Run the native code for the Array function called as a normal function.
1063 // tail call a stub
1064 Handle<Object> undefined_sentinel(
1065 masm->isolate()->heap()->undefined_value(),
1066 masm->isolate());
1067 __ mov(ebx, Immediate(undefined_sentinel));
1068 ArrayConstructorStub stub(masm->isolate());
1069 __ TailCallStub(&stub);
1070 }
1071
1072
Generate_StringConstructCode(MacroAssembler * masm)1073 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1074 // ----------- S t a t e -------------
1075 // -- eax : number of arguments
1076 // -- edi : constructor function
1077 // -- esp[0] : return address
1078 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1079 // -- esp[(argc + 1) * 4] : receiver
1080 // -----------------------------------
1081 Counters* counters = masm->isolate()->counters();
1082 __ IncrementCounter(counters->string_ctor_calls(), 1);
1083
1084 if (FLAG_debug_code) {
1085 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1086 __ cmp(edi, ecx);
1087 __ Assert(equal, kUnexpectedStringFunction);
1088 }
1089
1090 // Load the first argument into eax and get rid of the rest
1091 // (including the receiver).
1092 Label no_arguments;
1093 __ test(eax, eax);
1094 __ j(zero, &no_arguments);
1095 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1096 __ pop(ecx);
1097 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1098 __ push(ecx);
1099 __ mov(eax, ebx);
1100
1101 // Lookup the argument in the number to string cache.
1102 Label not_cached, argument_is_string;
1103 __ LookupNumberStringCache(eax, // Input.
1104 ebx, // Result.
1105 ecx, // Scratch 1.
1106 edx, // Scratch 2.
1107 ¬_cached);
1108 __ IncrementCounter(counters->string_ctor_cached_number(), 1);
1109 __ bind(&argument_is_string);
1110 // ----------- S t a t e -------------
1111 // -- ebx : argument converted to string
1112 // -- edi : constructor function
1113 // -- esp[0] : return address
1114 // -----------------------------------
1115
1116 // Allocate a JSValue and put the tagged pointer into eax.
1117 Label gc_required;
1118 __ Allocate(JSValue::kSize,
1119 eax, // Result.
1120 ecx, // New allocation top (we ignore it).
1121 no_reg,
1122 &gc_required,
1123 TAG_OBJECT);
1124
1125 // Set the map.
1126 __ LoadGlobalFunctionInitialMap(edi, ecx);
1127 if (FLAG_debug_code) {
1128 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1129 JSValue::kSize >> kPointerSizeLog2);
1130 __ Assert(equal, kUnexpectedStringWrapperInstanceSize);
1131 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1132 __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
1133 }
1134 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1135
1136 // Set properties and elements.
1137 Factory* factory = masm->isolate()->factory();
1138 __ Set(ecx, Immediate(factory->empty_fixed_array()));
1139 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1140 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1141
1142 // Set the value.
1143 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1144
1145 // Ensure the object is fully initialized.
1146 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1147
1148 // We're done. Return.
1149 __ ret(0);
1150
1151 // The argument was not found in the number to string cache. Check
1152 // if it's a string already before calling the conversion builtin.
1153 Label convert_argument;
1154 __ bind(¬_cached);
1155 STATIC_ASSERT(kSmiTag == 0);
1156 __ JumpIfSmi(eax, &convert_argument);
1157 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1158 __ j(NegateCondition(is_string), &convert_argument);
1159 __ mov(ebx, eax);
1160 __ IncrementCounter(counters->string_ctor_string_value(), 1);
1161 __ jmp(&argument_is_string);
1162
1163 // Invoke the conversion builtin and put the result into ebx.
1164 __ bind(&convert_argument);
1165 __ IncrementCounter(counters->string_ctor_conversions(), 1);
1166 {
1167 FrameScope scope(masm, StackFrame::INTERNAL);
1168 __ push(edi); // Preserve the function.
1169 __ push(eax);
1170 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1171 __ pop(edi);
1172 }
1173 __ mov(ebx, eax);
1174 __ jmp(&argument_is_string);
1175
1176 // Load the empty string into ebx, remove the receiver from the
1177 // stack, and jump back to the case where the argument is a string.
1178 __ bind(&no_arguments);
1179 __ Set(ebx, Immediate(factory->empty_string()));
1180 __ pop(ecx);
1181 __ lea(esp, Operand(esp, kPointerSize));
1182 __ push(ecx);
1183 __ jmp(&argument_is_string);
1184
1185 // At this point the argument is already a string. Call runtime to
1186 // create a string wrapper.
1187 __ bind(&gc_required);
1188 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
1189 {
1190 FrameScope scope(masm, StackFrame::INTERNAL);
1191 __ push(ebx);
1192 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1193 }
1194 __ ret(0);
1195 }
1196
1197
EnterArgumentsAdaptorFrame(MacroAssembler * masm)1198 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1199 __ push(ebp);
1200 __ mov(ebp, esp);
1201
1202 // Store the arguments adaptor context sentinel.
1203 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1204
1205 // Push the function on the stack.
1206 __ push(edi);
1207
1208 // Preserve the number of arguments on the stack. Must preserve eax,
1209 // ebx and ecx because these registers are used when copying the
1210 // arguments and the receiver.
1211 STATIC_ASSERT(kSmiTagSize == 1);
1212 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1213 __ push(edi);
1214 }
1215
1216
LeaveArgumentsAdaptorFrame(MacroAssembler * masm)1217 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1218 // Retrieve the number of arguments from the stack.
1219 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1220
1221 // Leave the frame.
1222 __ leave();
1223
1224 // Remove caller arguments from the stack.
1225 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1226 __ pop(ecx);
1227 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1228 __ push(ecx);
1229 }
1230
1231
Generate_ArgumentsAdaptorTrampoline(MacroAssembler * masm)1232 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1233 // ----------- S t a t e -------------
1234 // -- eax : actual number of arguments
1235 // -- ebx : expected number of arguments
1236 // -- ecx : call kind information
1237 // -- edx : code entry to call
1238 // -----------------------------------
1239
1240 Label invoke, dont_adapt_arguments;
1241 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
1242
1243 Label enough, too_few;
1244 __ cmp(eax, ebx);
1245 __ j(less, &too_few);
1246 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1247 __ j(equal, &dont_adapt_arguments);
1248
1249 { // Enough parameters: Actual >= expected.
1250 __ bind(&enough);
1251 EnterArgumentsAdaptorFrame(masm);
1252
1253 // Copy receiver and all expected arguments.
1254 const int offset = StandardFrameConstants::kCallerSPOffset;
1255 __ lea(eax, Operand(ebp, eax, times_4, offset));
1256 __ mov(edi, -1); // account for receiver
1257
1258 Label copy;
1259 __ bind(©);
1260 __ inc(edi);
1261 __ push(Operand(eax, 0));
1262 __ sub(eax, Immediate(kPointerSize));
1263 __ cmp(edi, ebx);
1264 __ j(less, ©);
1265 __ jmp(&invoke);
1266 }
1267
1268 { // Too few parameters: Actual < expected.
1269 __ bind(&too_few);
1270 EnterArgumentsAdaptorFrame(masm);
1271
1272 // Copy receiver and all actual arguments.
1273 const int offset = StandardFrameConstants::kCallerSPOffset;
1274 __ lea(edi, Operand(ebp, eax, times_4, offset));
1275 // ebx = expected - actual.
1276 __ sub(ebx, eax);
1277 // eax = -actual - 1
1278 __ neg(eax);
1279 __ sub(eax, Immediate(1));
1280
1281 Label copy;
1282 __ bind(©);
1283 __ inc(eax);
1284 __ push(Operand(edi, 0));
1285 __ sub(edi, Immediate(kPointerSize));
1286 __ test(eax, eax);
1287 __ j(not_zero, ©);
1288
1289 // Fill remaining expected arguments with undefined values.
1290 Label fill;
1291 __ bind(&fill);
1292 __ inc(eax);
1293 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
1294 __ cmp(eax, ebx);
1295 __ j(less, &fill);
1296 }
1297
1298 // Call the entry point.
1299 __ bind(&invoke);
1300 // Restore function pointer.
1301 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1302 __ call(edx);
1303
1304 // Store offset of return address for deoptimizer.
1305 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1306
1307 // Leave frame and return.
1308 LeaveArgumentsAdaptorFrame(masm);
1309 __ ret(0);
1310
1311 // -------------------------------------------
1312 // Dont adapt arguments.
1313 // -------------------------------------------
1314 __ bind(&dont_adapt_arguments);
1315 __ jmp(edx);
1316 }
1317
1318
Generate_OnStackReplacement(MacroAssembler * masm)1319 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1320 // Lookup the function in the JavaScript frame.
1321 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1322 {
1323 FrameScope scope(masm, StackFrame::INTERNAL);
1324 // Lookup and calculate pc offset.
1325 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerPCOffset));
1326 __ mov(ebx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
1327 __ sub(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1328 __ sub(edx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset));
1329 __ SmiTag(edx);
1330
1331 // Pass both function and pc offset as arguments.
1332 __ push(eax);
1333 __ push(edx);
1334 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 2);
1335 }
1336
1337 Label skip;
1338 // If the code object is null, just return to the unoptimized code.
1339 __ cmp(eax, Immediate(0));
1340 __ j(not_equal, &skip, Label::kNear);
1341 __ ret(0);
1342
1343 __ bind(&skip);
1344
1345 // Load deoptimization data from the code object.
1346 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1347
1348 // Load the OSR entrypoint offset from the deoptimization data.
1349 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
1350 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
1351 __ SmiUntag(ebx);
1352
1353 // Compute the target address = code_obj + header_size + osr_offset
1354 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
1355
1356 // Overwrite the return address on the stack.
1357 __ mov(Operand(esp, 0), eax);
1358
1359 // And "return" to the OSR entry point of the function.
1360 __ ret(0);
1361 }
1362
1363
Generate_OsrAfterStackCheck(MacroAssembler * masm)1364 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1365 // We check the stack limit as indicator that recompilation might be done.
1366 Label ok;
1367 ExternalReference stack_limit =
1368 ExternalReference::address_of_stack_limit(masm->isolate());
1369 __ cmp(esp, Operand::StaticVariable(stack_limit));
1370 __ j(above_equal, &ok, Label::kNear);
1371 {
1372 FrameScope scope(masm, StackFrame::INTERNAL);
1373 __ CallRuntime(Runtime::kStackGuard, 0);
1374 }
1375 __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
1376 RelocInfo::CODE_TARGET);
1377
1378 __ bind(&ok);
1379 __ ret(0);
1380 }
1381
1382 #undef __
1383 }
1384 } // namespace v8::internal
1385
1386 #endif // V8_TARGET_ARCH_IA32
1387