1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include "src/code-factory.h"
10 #include "src/code-stubs.h"
11 #include "src/codegen.h"
12 #include "src/compiler.h"
13 #include "src/debug.h"
14 #include "src/full-codegen.h"
15 #include "src/ic/ic.h"
16 #include "src/isolate-inl.h"
17 #include "src/parser.h"
18 #include "src/scopes.h"
23 #define __ ACCESS_MASM(masm_)
26 class JumpPatchSite BASE_EMBEDDED {
28 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
30 info_emitted_ = false;
35 DCHECK(patch_site_.is_bound() == info_emitted_);
38 void EmitJumpIfNotSmi(Register reg,
40 Label::Distance near_jump = Label::kFar) {
41 __ testb(reg, Immediate(kSmiTagMask));
42 EmitJump(not_carry, target, near_jump); // Always taken before patched.
45 void EmitJumpIfSmi(Register reg,
47 Label::Distance near_jump = Label::kFar) {
48 __ testb(reg, Immediate(kSmiTagMask));
49 EmitJump(carry, target, near_jump); // Never taken before patched.
52 void EmitPatchInfo() {
53 if (patch_site_.is_bound()) {
54 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
55 DCHECK(is_uint8(delta_to_patch_site));
56 __ testl(rax, Immediate(delta_to_patch_site));
61 __ nop(); // Signals no inlined code.
66 // jc will be patched with jz, jnc will become jnz.
67 void EmitJump(Condition cc, Label* target, Label::Distance near_jump) {
68 DCHECK(!patch_site_.is_bound() && !info_emitted_);
69 DCHECK(cc == carry || cc == not_carry);
70 __ bind(&patch_site_);
71 __ j(cc, target, near_jump);
74 MacroAssembler* masm_;
82 // Generate code for a JS function. On entry to the function the receiver
83 // and arguments have been pushed on the stack left to right, with the
84 // return address on top of them. The actual argument count matches the
85 // formal parameter count expected by the function.
87 // The live registers are:
88 // o rdi: the JS function object being called (i.e. ourselves)
90 // o rbp: our caller's frame pointer
91 // o rsp: stack pointer (pointing to return address)
93 // The function builds a JS frame. Please see JavaScriptFrameConstants in
94 // frames-x64.h for its layout.
95 void FullCodeGenerator::Generate() {
96 CompilationInfo* info = info_;
98 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
100 profiling_counter_ = isolate()->factory()->NewCell(
101 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
102 SetFunctionPosition(function());
103 Comment cmnt(masm_, "[ function compiled by full code generator");
105 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
108 if (strlen(FLAG_stop_at) > 0 &&
109 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
114 // Sloppy mode functions and builtins need to replace the receiver with the
115 // global proxy when called as functions (without an explicit receiver
117 if (is_sloppy(info->language_mode()) && !info->is_native()) {
119 // +1 for return address.
120 StackArgumentsAccessor args(rsp, info->scope()->num_parameters());
121 __ movp(rcx, args.GetReceiverOperand());
123 __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
124 __ j(not_equal, &ok, Label::kNear);
126 __ movp(rcx, GlobalObjectOperand());
127 __ movp(rcx, FieldOperand(rcx, GlobalObject::kGlobalProxyOffset));
129 __ movp(args.GetReceiverOperand(), rcx);
134 // Open a frame scope to indicate that there is a frame on the stack. The
135 // MANUAL indicates that the scope shouldn't actually generate code to set up
136 // the frame (that is done below).
137 FrameScope frame_scope(masm_, StackFrame::MANUAL);
139 info->set_prologue_offset(masm_->pc_offset());
140 __ Prologue(info->IsCodePreAgingActive());
141 info->AddNoFrameRange(0, masm_->pc_offset());
143 { Comment cmnt(masm_, "[ Allocate locals");
144 int locals_count = info->scope()->num_stack_slots();
145 // Generators allocate locals, if any, in context slots.
146 DCHECK(!IsGeneratorFunction(info->function()->kind()) || locals_count == 0);
147 if (locals_count == 1) {
148 __ PushRoot(Heap::kUndefinedValueRootIndex);
149 } else if (locals_count > 1) {
150 if (locals_count >= 128) {
153 __ subp(rcx, Immediate(locals_count * kPointerSize));
154 __ CompareRoot(rcx, Heap::kRealStackLimitRootIndex);
155 __ j(above_equal, &ok, Label::kNear);
156 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
159 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
160 const int kMaxPushes = 32;
161 if (locals_count >= kMaxPushes) {
162 int loop_iterations = locals_count / kMaxPushes;
163 __ movp(rcx, Immediate(loop_iterations));
165 __ bind(&loop_header);
167 for (int i = 0; i < kMaxPushes; i++) {
170 // Continue loop if not done.
172 __ j(not_zero, &loop_header, Label::kNear);
174 int remaining = locals_count % kMaxPushes;
175 // Emit the remaining pushes.
176 for (int i = 0; i < remaining; i++) {
182 bool function_in_register = true;
184 // Possibly allocate a local context.
185 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
186 if (heap_slots > 0) {
187 Comment cmnt(masm_, "[ Allocate context");
188 bool need_write_barrier = true;
189 // Argument to NewContext is the function, which is still in rdi.
190 if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
192 __ Push(info->scope()->GetScopeInfo(info->isolate()));
193 __ CallRuntime(Runtime::kNewScriptContext, 2);
194 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
195 FastNewContextStub stub(isolate(), heap_slots);
197 // Result of FastNewContextStub is always in new space.
198 need_write_barrier = false;
201 __ CallRuntime(Runtime::kNewFunctionContext, 1);
203 function_in_register = false;
204 // Context is returned in rax. It replaces the context passed to us.
205 // It's saved in the stack and kept live in rsi.
207 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rax);
209 // Copy any necessary parameters into the context.
210 int num_parameters = info->scope()->num_parameters();
211 for (int i = 0; i < num_parameters; i++) {
212 Variable* var = scope()->parameter(i);
213 if (var->IsContextSlot()) {
214 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
215 (num_parameters - 1 - i) * kPointerSize;
216 // Load parameter from stack.
217 __ movp(rax, Operand(rbp, parameter_offset));
218 // Store it in the context.
219 int context_offset = Context::SlotOffset(var->index());
220 __ movp(Operand(rsi, context_offset), rax);
221 // Update the write barrier. This clobbers rax and rbx.
222 if (need_write_barrier) {
223 __ RecordWriteContextSlot(
224 rsi, context_offset, rax, rbx, kDontSaveFPRegs);
225 } else if (FLAG_debug_code) {
227 __ JumpIfInNewSpace(rsi, rax, &done, Label::kNear);
228 __ Abort(kExpectedNewSpaceObject);
235 // Possibly allocate RestParameters
237 Variable* rest_param = scope()->rest_parameter(&rest_index);
239 Comment cmnt(masm_, "[ Allocate rest parameter array");
241 int num_parameters = info->scope()->num_parameters();
242 int offset = num_parameters * kPointerSize;
244 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
246 __ Push(Smi::FromInt(num_parameters));
247 __ Push(Smi::FromInt(rest_index));
249 RestParamAccessStub stub(isolate());
252 SetVar(rest_param, rax, rbx, rdx);
255 // Possibly allocate an arguments object.
256 Variable* arguments = scope()->arguments();
257 if (arguments != NULL) {
258 // Arguments object must be allocated after the context object, in
259 // case the "arguments" or ".arguments" variables are in the context.
260 Comment cmnt(masm_, "[ Allocate arguments object");
261 if (function_in_register) {
264 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
266 // The receiver is just before the parameters on the caller's stack.
267 int num_parameters = info->scope()->num_parameters();
268 int offset = num_parameters * kPointerSize;
270 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
272 __ Push(Smi::FromInt(num_parameters));
273 // Arguments to ArgumentsAccessStub:
274 // function, receiver address, parameter count.
275 // The stub will rewrite receiver and parameter count if the previous
276 // stack frame was an arguments adapter frame.
278 ArgumentsAccessStub::HasNewTarget has_new_target =
279 IsSubclassConstructor(info->function()->kind())
280 ? ArgumentsAccessStub::HAS_NEW_TARGET
281 : ArgumentsAccessStub::NO_NEW_TARGET;
282 ArgumentsAccessStub::Type type;
283 if (is_strict(language_mode()) || !is_simple_parameter_list()) {
284 type = ArgumentsAccessStub::NEW_STRICT;
285 } else if (function()->has_duplicate_parameters()) {
286 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW;
288 type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
290 ArgumentsAccessStub stub(isolate(), type, has_new_target);
293 SetVar(arguments, rax, rbx, rdx);
297 __ CallRuntime(Runtime::kTraceEnter, 0);
300 // Visit the declarations and body unless there is an illegal
302 if (scope()->HasIllegalRedeclaration()) {
303 Comment cmnt(masm_, "[ Declarations");
304 scope()->VisitIllegalRedeclaration(this);
307 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
308 { Comment cmnt(masm_, "[ Declarations");
309 // For named function expressions, declare the function name as a
311 if (scope()->is_function_scope() && scope()->function() != NULL) {
312 VariableDeclaration* function = scope()->function();
313 DCHECK(function->proxy()->var()->mode() == CONST ||
314 function->proxy()->var()->mode() == CONST_LEGACY);
315 DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
316 VisitVariableDeclaration(function);
318 VisitDeclarations(scope()->declarations());
321 { Comment cmnt(masm_, "[ Stack check");
322 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
324 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
325 __ j(above_equal, &ok, Label::kNear);
326 __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
330 { Comment cmnt(masm_, "[ Body");
331 DCHECK(loop_depth() == 0);
332 VisitStatements(function()->body());
333 DCHECK(loop_depth() == 0);
337 // Always emit a 'return undefined' in case control fell off the end of
339 { Comment cmnt(masm_, "[ return <undefined>;");
340 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
341 EmitReturnSequence();
346 void FullCodeGenerator::ClearAccumulator() {
351 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
352 __ Move(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
353 __ SmiAddConstant(FieldOperand(rbx, Cell::kValueOffset),
354 Smi::FromInt(-delta));
358 void FullCodeGenerator::EmitProfilingCounterReset() {
359 int reset_value = FLAG_interrupt_budget;
360 __ Move(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
361 __ Move(kScratchRegister, Smi::FromInt(reset_value));
362 __ movp(FieldOperand(rbx, Cell::kValueOffset), kScratchRegister);
366 static const byte kJnsOffset = kPointerSize == kInt64Size ? 0x1d : 0x14;
369 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
370 Label* back_edge_target) {
371 Comment cmnt(masm_, "[ Back edge bookkeeping");
374 DCHECK(back_edge_target->is_bound());
375 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
376 int weight = Min(kMaxBackEdgeWeight,
377 Max(1, distance / kCodeSizeMultiplier));
378 EmitProfilingCounterDecrement(weight);
380 __ j(positive, &ok, Label::kNear);
382 PredictableCodeSizeScope predictible_code_size_scope(masm_, kJnsOffset);
383 DontEmitDebugCodeScope dont_emit_debug_code_scope(masm_);
384 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
386 // Record a mapping of this PC offset to the OSR id. This is used to find
387 // the AST id from the unoptimized code in order to use it as a key into
388 // the deoptimization input data found in the optimized code.
389 RecordBackEdge(stmt->OsrEntryId());
391 EmitProfilingCounterReset();
395 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
396 // Record a mapping of the OSR id to this PC. This is used if the OSR
397 // entry becomes the target of a bailout. We don't expect it to be, but
398 // we want it to work if it is.
399 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
403 void FullCodeGenerator::EmitReturnSequence() {
404 Comment cmnt(masm_, "[ Return sequence");
405 if (return_label_.is_bound()) {
406 __ jmp(&return_label_);
408 __ bind(&return_label_);
411 __ CallRuntime(Runtime::kTraceExit, 1);
413 // Pretend that the exit is a backwards jump to the entry.
415 if (info_->ShouldSelfOptimize()) {
416 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
418 int distance = masm_->pc_offset();
419 weight = Min(kMaxBackEdgeWeight,
420 Max(1, distance / kCodeSizeMultiplier));
422 EmitProfilingCounterDecrement(weight);
424 __ j(positive, &ok, Label::kNear);
426 __ call(isolate()->builtins()->InterruptCheck(),
427 RelocInfo::CODE_TARGET);
429 EmitProfilingCounterReset();
432 // Add a label for checking the size of the code used for returning.
433 Label check_exit_codesize;
434 masm_->bind(&check_exit_codesize);
436 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
438 // Do not use the leave instruction here because it is too short to
439 // patch with the code required by the debugger.
442 int no_frame_start = masm_->pc_offset();
444 int arg_count = info_->scope()->num_parameters() + 1;
445 if (IsSubclassConstructor(info_->function()->kind())) {
448 int arguments_bytes = arg_count * kPointerSize;
449 __ Ret(arguments_bytes, rcx);
451 // Add padding that will be overwritten by a debugger breakpoint. We
452 // have just generated at least 7 bytes: "movp rsp, rbp; pop rbp; ret k"
453 // (3 + 1 + 3) for x64 and at least 6 (2 + 1 + 3) bytes for x32.
454 const int kPadding = Assembler::kJSReturnSequenceLength -
455 kPointerSize == kInt64Size ? 7 : 6;
456 for (int i = 0; i < kPadding; ++i) {
459 // Check that the size of the code used for returning is large enough
460 // for the debugger's requirements.
461 DCHECK(Assembler::kJSReturnSequenceLength <=
462 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
464 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
469 void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
470 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
474 void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
475 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
476 codegen()->GetVar(result_register(), var);
480 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
481 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
482 MemOperand operand = codegen()->VarOperand(var, result_register());
487 void FullCodeGenerator::TestContext::Plug(Variable* var) const {
488 codegen()->GetVar(result_register(), var);
489 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
490 codegen()->DoTest(this);
494 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
498 void FullCodeGenerator::AccumulatorValueContext::Plug(
499 Heap::RootListIndex index) const {
500 __ LoadRoot(result_register(), index);
504 void FullCodeGenerator::StackValueContext::Plug(
505 Heap::RootListIndex index) const {
510 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
511 codegen()->PrepareForBailoutBeforeSplit(condition(),
515 if (index == Heap::kUndefinedValueRootIndex ||
516 index == Heap::kNullValueRootIndex ||
517 index == Heap::kFalseValueRootIndex) {
518 if (false_label_ != fall_through_) __ jmp(false_label_);
519 } else if (index == Heap::kTrueValueRootIndex) {
520 if (true_label_ != fall_through_) __ jmp(true_label_);
522 __ LoadRoot(result_register(), index);
523 codegen()->DoTest(this);
528 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
532 void FullCodeGenerator::AccumulatorValueContext::Plug(
533 Handle<Object> lit) const {
535 __ SafeMove(result_register(), Smi::cast(*lit));
537 __ Move(result_register(), lit);
542 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
544 __ SafePush(Smi::cast(*lit));
551 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
552 codegen()->PrepareForBailoutBeforeSplit(condition(),
556 DCHECK(!lit->IsUndetectableObject()); // There are no undetectable literals.
557 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
558 if (false_label_ != fall_through_) __ jmp(false_label_);
559 } else if (lit->IsTrue() || lit->IsJSObject()) {
560 if (true_label_ != fall_through_) __ jmp(true_label_);
561 } else if (lit->IsString()) {
562 if (String::cast(*lit)->length() == 0) {
563 if (false_label_ != fall_through_) __ jmp(false_label_);
565 if (true_label_ != fall_through_) __ jmp(true_label_);
567 } else if (lit->IsSmi()) {
568 if (Smi::cast(*lit)->value() == 0) {
569 if (false_label_ != fall_through_) __ jmp(false_label_);
571 if (true_label_ != fall_through_) __ jmp(true_label_);
574 // For simplicity we always test the accumulator register.
575 __ Move(result_register(), lit);
576 codegen()->DoTest(this);
581 void FullCodeGenerator::EffectContext::DropAndPlug(int count,
582 Register reg) const {
588 void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
590 Register reg) const {
593 __ Move(result_register(), reg);
597 void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
598 Register reg) const {
600 if (count > 1) __ Drop(count - 1);
601 __ movp(Operand(rsp, 0), reg);
605 void FullCodeGenerator::TestContext::DropAndPlug(int count,
606 Register reg) const {
608 // For simplicity we always test the accumulator register.
610 __ Move(result_register(), reg);
611 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
612 codegen()->DoTest(this);
616 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
617 Label* materialize_false) const {
618 DCHECK(materialize_true == materialize_false);
619 __ bind(materialize_true);
623 void FullCodeGenerator::AccumulatorValueContext::Plug(
624 Label* materialize_true,
625 Label* materialize_false) const {
627 __ bind(materialize_true);
628 __ Move(result_register(), isolate()->factory()->true_value());
629 __ jmp(&done, Label::kNear);
630 __ bind(materialize_false);
631 __ Move(result_register(), isolate()->factory()->false_value());
636 void FullCodeGenerator::StackValueContext::Plug(
637 Label* materialize_true,
638 Label* materialize_false) const {
640 __ bind(materialize_true);
641 __ Push(isolate()->factory()->true_value());
642 __ jmp(&done, Label::kNear);
643 __ bind(materialize_false);
644 __ Push(isolate()->factory()->false_value());
649 void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
650 Label* materialize_false) const {
651 DCHECK(materialize_true == true_label_);
652 DCHECK(materialize_false == false_label_);
656 void FullCodeGenerator::EffectContext::Plug(bool flag) const {
660 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
661 Heap::RootListIndex value_root_index =
662 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
663 __ LoadRoot(result_register(), value_root_index);
667 void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
668 Heap::RootListIndex value_root_index =
669 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
670 __ PushRoot(value_root_index);
674 void FullCodeGenerator::TestContext::Plug(bool flag) const {
675 codegen()->PrepareForBailoutBeforeSplit(condition(),
680 if (true_label_ != fall_through_) __ jmp(true_label_);
682 if (false_label_ != fall_through_) __ jmp(false_label_);
687 void FullCodeGenerator::DoTest(Expression* condition,
690 Label* fall_through) {
691 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
692 CallIC(ic, condition->test_id());
693 __ testp(result_register(), result_register());
694 // The stub returns nonzero for true.
695 Split(not_zero, if_true, if_false, fall_through);
699 void FullCodeGenerator::Split(Condition cc,
702 Label* fall_through) {
703 if (if_false == fall_through) {
705 } else if (if_true == fall_through) {
706 __ j(NegateCondition(cc), if_false);
714 MemOperand FullCodeGenerator::StackOperand(Variable* var) {
715 DCHECK(var->IsStackAllocated());
716 // Offset is negative because higher indexes are at lower addresses.
717 int offset = -var->index() * kPointerSize;
718 // Adjust by a (parameter or local) base offset.
719 if (var->IsParameter()) {
720 offset += kFPOnStackSize + kPCOnStackSize +
721 (info_->scope()->num_parameters() - 1) * kPointerSize;
723 offset += JavaScriptFrameConstants::kLocal0Offset;
725 return Operand(rbp, offset);
729 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
730 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
731 if (var->IsContextSlot()) {
732 int context_chain_length = scope()->ContextChainLength(var->scope());
733 __ LoadContext(scratch, context_chain_length);
734 return ContextOperand(scratch, var->index());
736 return StackOperand(var);
741 void FullCodeGenerator::GetVar(Register dest, Variable* var) {
742 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
743 MemOperand location = VarOperand(var, dest);
744 __ movp(dest, location);
748 void FullCodeGenerator::SetVar(Variable* var,
752 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
753 DCHECK(!scratch0.is(src));
754 DCHECK(!scratch0.is(scratch1));
755 DCHECK(!scratch1.is(src));
756 MemOperand location = VarOperand(var, scratch0);
757 __ movp(location, src);
759 // Emit the write barrier code if the location is in the heap.
760 if (var->IsContextSlot()) {
761 int offset = Context::SlotOffset(var->index());
762 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
767 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
768 bool should_normalize,
771 // Only prepare for bailouts before splits if we're in a test
772 // context. Otherwise, we let the Visit function deal with the
773 // preparation to avoid preparing with the same AST id twice.
774 if (!context()->IsTest() || !info_->IsOptimizable()) return;
777 if (should_normalize) __ jmp(&skip, Label::kNear);
778 PrepareForBailout(expr, TOS_REG);
779 if (should_normalize) {
780 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
781 Split(equal, if_true, if_false, NULL);
787 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
788 // The variable in the declaration always resides in the current context.
789 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
790 if (generate_debug_code_) {
791 // Check that we're not inside a with or catch context.
792 __ movp(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
793 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
794 __ Check(not_equal, kDeclarationInWithContext);
795 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
796 __ Check(not_equal, kDeclarationInCatchContext);
801 void FullCodeGenerator::VisitVariableDeclaration(
802 VariableDeclaration* declaration) {
803 // If it was not possible to allocate the variable at compile time, we
804 // need to "declare" it at runtime to make sure it actually exists in the
806 VariableProxy* proxy = declaration->proxy();
807 VariableMode mode = declaration->mode();
808 Variable* variable = proxy->var();
809 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
810 switch (variable->location()) {
811 case Variable::UNALLOCATED:
812 globals_->Add(variable->name(), zone());
813 globals_->Add(variable->binding_needs_init()
814 ? isolate()->factory()->the_hole_value()
815 : isolate()->factory()->undefined_value(),
819 case Variable::PARAMETER:
820 case Variable::LOCAL:
822 Comment cmnt(masm_, "[ VariableDeclaration");
823 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
824 __ movp(StackOperand(variable), kScratchRegister);
828 case Variable::CONTEXT:
830 Comment cmnt(masm_, "[ VariableDeclaration");
831 EmitDebugCheckDeclarationContext(variable);
832 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
833 __ movp(ContextOperand(rsi, variable->index()), kScratchRegister);
834 // No write barrier since the hole value is in old space.
835 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
839 case Variable::LOOKUP: {
840 Comment cmnt(masm_, "[ VariableDeclaration");
842 __ Push(variable->name());
843 // Declaration nodes are always introduced in one of four modes.
844 DCHECK(IsDeclaredVariableMode(mode));
845 PropertyAttributes attr =
846 IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
847 __ Push(Smi::FromInt(attr));
848 // Push initial value, if any.
849 // Note: For variables we must not push an initial value (such as
850 // 'undefined') because we may have a (legal) redeclaration and we
851 // must not destroy the current value.
853 __ PushRoot(Heap::kTheHoleValueRootIndex);
855 __ Push(Smi::FromInt(0)); // Indicates no initial value.
857 __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
864 void FullCodeGenerator::VisitFunctionDeclaration(
865 FunctionDeclaration* declaration) {
866 VariableProxy* proxy = declaration->proxy();
867 Variable* variable = proxy->var();
868 switch (variable->location()) {
869 case Variable::UNALLOCATED: {
870 globals_->Add(variable->name(), zone());
871 Handle<SharedFunctionInfo> function =
872 Compiler::BuildFunctionInfo(declaration->fun(), script(), info_);
873 // Check for stack-overflow exception.
874 if (function.is_null()) return SetStackOverflow();
875 globals_->Add(function, zone());
879 case Variable::PARAMETER:
880 case Variable::LOCAL: {
881 Comment cmnt(masm_, "[ FunctionDeclaration");
882 VisitForAccumulatorValue(declaration->fun());
883 __ movp(StackOperand(variable), result_register());
887 case Variable::CONTEXT: {
888 Comment cmnt(masm_, "[ FunctionDeclaration");
889 EmitDebugCheckDeclarationContext(variable);
890 VisitForAccumulatorValue(declaration->fun());
891 __ movp(ContextOperand(rsi, variable->index()), result_register());
892 int offset = Context::SlotOffset(variable->index());
893 // We know that we have written a function, which is not a smi.
894 __ RecordWriteContextSlot(rsi,
901 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
905 case Variable::LOOKUP: {
906 Comment cmnt(masm_, "[ FunctionDeclaration");
908 __ Push(variable->name());
909 __ Push(Smi::FromInt(NONE));
910 VisitForStackValue(declaration->fun());
911 __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
918 void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
919 Variable* variable = declaration->proxy()->var();
920 ModuleDescriptor* descriptor = declaration->module()->descriptor();
921 DCHECK(variable->location() == Variable::CONTEXT);
922 DCHECK(descriptor->IsFrozen());
924 Comment cmnt(masm_, "[ ModuleDeclaration");
925 EmitDebugCheckDeclarationContext(variable);
927 // Load instance object.
928 __ LoadContext(rax, scope_->ContextChainLength(scope_->ScriptScope()));
929 __ movp(rax, ContextOperand(rax, descriptor->Index()));
930 __ movp(rax, ContextOperand(rax, Context::EXTENSION_INDEX));
933 __ movp(ContextOperand(rsi, variable->index()), rax);
934 // We know that we have written a module, which is not a smi.
935 __ RecordWriteContextSlot(rsi,
936 Context::SlotOffset(variable->index()),
942 PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
944 // Traverse into body.
945 Visit(declaration->module());
949 void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
950 VariableProxy* proxy = declaration->proxy();
951 Variable* variable = proxy->var();
952 switch (variable->location()) {
953 case Variable::UNALLOCATED:
957 case Variable::CONTEXT: {
958 Comment cmnt(masm_, "[ ImportDeclaration");
959 EmitDebugCheckDeclarationContext(variable);
964 case Variable::PARAMETER:
965 case Variable::LOCAL:
966 case Variable::LOOKUP:
972 void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
977 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
978 // Call the runtime to declare the globals.
979 __ Push(rsi); // The context is the first argument.
981 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
982 __ CallRuntime(Runtime::kDeclareGlobals, 3);
983 // Return value is ignored.
987 void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
988 // Call the runtime to declare the modules.
989 __ Push(descriptions);
990 __ CallRuntime(Runtime::kDeclareModules, 1);
991 // Return value is ignored.
995 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
996 Comment cmnt(masm_, "[ SwitchStatement");
997 Breakable nested_statement(this, stmt);
998 SetStatementPosition(stmt);
1000 // Keep the switch value on the stack until a case matches.
1001 VisitForStackValue(stmt->tag());
1002 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
1004 ZoneList<CaseClause*>* clauses = stmt->cases();
1005 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
1007 Label next_test; // Recycled for each test.
1008 // Compile all the tests with branches to their bodies.
1009 for (int i = 0; i < clauses->length(); i++) {
1010 CaseClause* clause = clauses->at(i);
1011 clause->body_target()->Unuse();
1013 // The default is not a test, but remember it as final fall through.
1014 if (clause->is_default()) {
1015 default_clause = clause;
1019 Comment cmnt(masm_, "[ Case comparison");
1020 __ bind(&next_test);
1023 // Compile the label expression.
1024 VisitForAccumulatorValue(clause->label());
1026 // Perform the comparison as if via '==='.
1027 __ movp(rdx, Operand(rsp, 0)); // Switch value.
1028 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
1029 JumpPatchSite patch_site(masm_);
1030 if (inline_smi_code) {
1034 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
1037 __ j(not_equal, &next_test);
1038 __ Drop(1); // Switch value is no longer needed.
1039 __ jmp(clause->body_target());
1040 __ bind(&slow_case);
1043 // Record position before stub call for type feedback.
1044 SetSourcePosition(clause->position());
1046 CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
1047 CallIC(ic, clause->CompareId());
1048 patch_site.EmitPatchInfo();
1051 __ jmp(&skip, Label::kNear);
1052 PrepareForBailout(clause, TOS_REG);
1053 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
1054 __ j(not_equal, &next_test);
1056 __ jmp(clause->body_target());
1060 __ j(not_equal, &next_test);
1061 __ Drop(1); // Switch value is no longer needed.
1062 __ jmp(clause->body_target());
1065 // Discard the test value and jump to the default if present, otherwise to
1066 // the end of the statement.
1067 __ bind(&next_test);
1068 __ Drop(1); // Switch value is no longer needed.
1069 if (default_clause == NULL) {
1070 __ jmp(nested_statement.break_label());
1072 __ jmp(default_clause->body_target());
1075 // Compile all the case bodies.
1076 for (int i = 0; i < clauses->length(); i++) {
1077 Comment cmnt(masm_, "[ Case body");
1078 CaseClause* clause = clauses->at(i);
1079 __ bind(clause->body_target());
1080 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
1081 VisitStatements(clause->statements());
1084 __ bind(nested_statement.break_label());
1085 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1089 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1090 Comment cmnt(masm_, "[ ForInStatement");
1091 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
1092 SetStatementPosition(stmt);
1095 ForIn loop_statement(this, stmt);
1096 increment_loop_depth();
1098 // Get the object to enumerate over. If the object is null or undefined, skip
1099 // over the loop. See ECMA-262 version 5, section 12.6.4.
1100 SetExpressionPosition(stmt->enumerable());
1101 VisitForAccumulatorValue(stmt->enumerable());
1102 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
1104 Register null_value = rdi;
1105 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
1106 __ cmpp(rax, null_value);
1109 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1111 // Convert the object to a JS object.
1112 Label convert, done_convert;
1113 __ JumpIfSmi(rax, &convert);
1114 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
1115 __ j(above_equal, &done_convert);
1118 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1119 __ bind(&done_convert);
1120 PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
1123 // Check for proxies.
1125 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1126 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
1127 __ j(below_equal, &call_runtime);
1129 // Check cache validity in generated code. This is a fast case for
1130 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1131 // guarantee cache validity, call the runtime system to check cache
1132 // validity or get the property names in a fixed array.
1133 __ CheckEnumCache(null_value, &call_runtime);
1135 // The enum cache is valid. Load the map of the object being
1136 // iterated over and use the cache for the iteration.
1138 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset));
1139 __ jmp(&use_cache, Label::kNear);
1141 // Get the set of properties to enumerate.
1142 __ bind(&call_runtime);
1143 __ Push(rax); // Duplicate the enumerable object on the stack.
1144 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1145 PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
1147 // If we got a map from the runtime call, we can do a fast
1148 // modification check. Otherwise, we got a fixed array, and we have
1149 // to do a slow check.
1151 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1152 Heap::kMetaMapRootIndex);
1153 __ j(not_equal, &fixed_array);
1155 // We got a map in register rax. Get the enumeration cache from it.
1156 __ bind(&use_cache);
1158 Label no_descriptors;
1160 __ EnumLength(rdx, rax);
1161 __ Cmp(rdx, Smi::FromInt(0));
1162 __ j(equal, &no_descriptors);
1164 __ LoadInstanceDescriptors(rax, rcx);
1165 __ movp(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheOffset));
1166 __ movp(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1168 // Set up the four remaining stack slots.
1169 __ Push(rax); // Map.
1170 __ Push(rcx); // Enumeration cache.
1171 __ Push(rdx); // Number of valid entries for the map in the enum cache.
1172 __ Push(Smi::FromInt(0)); // Initial index.
1175 __ bind(&no_descriptors);
1176 __ addp(rsp, Immediate(kPointerSize));
1179 // We got a fixed array in register rax. Iterate through that.
1181 __ bind(&fixed_array);
1183 // No need for a write barrier, we are storing a Smi in the feedback vector.
1184 __ Move(rbx, FeedbackVector());
1185 int vector_index = FeedbackVector()->GetIndex(slot);
1186 __ Move(FieldOperand(rbx, FixedArray::OffsetOfElementAt(vector_index)),
1187 TypeFeedbackVector::MegamorphicSentinel(isolate()));
1188 __ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check
1189 __ movp(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
1190 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1191 __ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx);
1192 __ j(above, &non_proxy);
1193 __ Move(rbx, Smi::FromInt(0)); // Zero indicates proxy
1194 __ bind(&non_proxy);
1195 __ Push(rbx); // Smi
1196 __ Push(rax); // Array
1197 __ movp(rax, FieldOperand(rax, FixedArray::kLengthOffset));
1198 __ Push(rax); // Fixed array length (as smi).
1199 __ Push(Smi::FromInt(0)); // Initial index.
1201 // Generate code for doing the condition check.
1202 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
1204 SetExpressionPosition(stmt->each());
1206 __ movp(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
1207 __ cmpp(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
1208 __ j(above_equal, loop_statement.break_label());
1210 // Get the current entry of the array into register rbx.
1211 __ movp(rbx, Operand(rsp, 2 * kPointerSize));
1212 SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2);
1213 __ movp(rbx, FieldOperand(rbx,
1216 FixedArray::kHeaderSize));
1218 // Get the expected map from the stack or a smi in the
1219 // permanent slow case into register rdx.
1220 __ movp(rdx, Operand(rsp, 3 * kPointerSize));
1222 // Check if the expected map still matches that of the enumerable.
1223 // If not, we may have to filter the key.
1225 __ movp(rcx, Operand(rsp, 4 * kPointerSize));
1226 __ cmpp(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
1227 __ j(equal, &update_each, Label::kNear);
1229 // For proxies, no filtering is done.
1230 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1231 __ Cmp(rdx, Smi::FromInt(0));
1232 __ j(equal, &update_each, Label::kNear);
1234 // Convert the entry to a string or null if it isn't a property
1235 // anymore. If the property has been removed while iterating, we
1237 __ Push(rcx); // Enumerable.
1238 __ Push(rbx); // Current entry.
1239 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
1240 __ Cmp(rax, Smi::FromInt(0));
1241 __ j(equal, loop_statement.continue_label());
1244 // Update the 'each' property or variable from the possibly filtered
1245 // entry in register rbx.
1246 __ bind(&update_each);
1247 __ movp(result_register(), rbx);
1248 // Perform the assignment as if via '='.
1249 { EffectContext context(this);
1250 EmitAssignment(stmt->each());
1251 PrepareForBailoutForId(stmt->AssignmentId(), NO_REGISTERS);
1254 // Generate code for the body of the loop.
1255 Visit(stmt->body());
1257 // Generate code for going to the next element by incrementing the
1258 // index (smi) stored on top of the stack.
1259 __ bind(loop_statement.continue_label());
1260 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
1262 EmitBackEdgeBookkeeping(stmt, &loop);
1265 // Remove the pointers stored on the stack.
1266 __ bind(loop_statement.break_label());
1267 __ addp(rsp, Immediate(5 * kPointerSize));
1269 // Exit and decrement the loop depth.
1270 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1272 decrement_loop_depth();
1276 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1278 // Use the fast case closure allocation code that allocates in new
1279 // space for nested functions that don't need literals cloning. If
1280 // we're running with the --always-opt or the --prepare-always-opt
1281 // flag, we need to use the runtime function so that the new function
1282 // we are creating here gets a chance to have its code optimized and
1283 // doesn't just get a copy of the existing unoptimized code.
1284 if (!FLAG_always_opt &&
1285 !FLAG_prepare_always_opt &&
1287 scope()->is_function_scope() &&
1288 info->num_literals() == 0) {
1289 FastNewClosureStub stub(isolate(), info->language_mode(), info->kind());
1296 ? isolate()->factory()->true_value()
1297 : isolate()->factory()->false_value());
1298 __ CallRuntime(Runtime::kNewClosure, 3);
1300 context()->Plug(rax);
1304 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1305 Comment cmnt(masm_, "[ VariableProxy");
1306 EmitVariableLoad(expr);
1310 void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
1311 Comment cnmt(masm_, "[ SuperReference ");
1313 __ movp(LoadDescriptor::ReceiverRegister(),
1314 Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1316 Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
1317 __ Move(LoadDescriptor::NameRegister(), home_object_symbol);
1319 if (FLAG_vector_ics) {
1320 __ Move(VectorLoadICDescriptor::SlotRegister(),
1321 SmiFromSlot(expr->HomeObjectFeedbackSlot()));
1322 CallLoadIC(NOT_CONTEXTUAL);
1324 CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
1328 __ Cmp(rax, isolate()->factory()->undefined_value());
1330 __ j(not_equal, &done);
1331 __ CallRuntime(Runtime::kThrowNonMethodError, 0);
1336 void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
1338 if (NeedsHomeObject(initializer)) {
1339 __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0));
1340 __ Move(StoreDescriptor::NameRegister(),
1341 isolate()->factory()->home_object_symbol());
1342 __ movp(StoreDescriptor::ValueRegister(),
1343 Operand(rsp, offset * kPointerSize));
1349 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
1350 TypeofState typeof_state,
1352 Register context = rsi;
1353 Register temp = rdx;
1357 if (s->num_heap_slots() > 0) {
1358 if (s->calls_sloppy_eval()) {
1359 // Check that extension is NULL.
1360 __ cmpp(ContextOperand(context, Context::EXTENSION_INDEX),
1362 __ j(not_equal, slow);
1364 // Load next context in chain.
1365 __ movp(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1366 // Walk the rest of the chain without clobbering rsi.
1369 // If no outer scope calls eval, we do not need to check more
1370 // context extensions. If we have reached an eval scope, we check
1371 // all extensions from this point.
1372 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
1373 s = s->outer_scope();
1376 if (s != NULL && s->is_eval_scope()) {
1377 // Loop up the context chain. There is no frame effect so it is
1378 // safe to use raw labels here.
1380 if (!context.is(temp)) {
1381 __ movp(temp, context);
1383 // Load map for comparison into register, outside loop.
1384 __ LoadRoot(kScratchRegister, Heap::kNativeContextMapRootIndex);
1386 // Terminate at native context.
1387 __ cmpp(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset));
1388 __ j(equal, &fast, Label::kNear);
1389 // Check that extension is NULL.
1390 __ cmpp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1391 __ j(not_equal, slow);
1392 // Load next context in chain.
1393 __ movp(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
1398 // All extension objects were empty and it is safe to use a global
1400 __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
1401 __ Move(LoadDescriptor::NameRegister(), proxy->var()->name());
1402 if (FLAG_vector_ics) {
1403 __ Move(VectorLoadICDescriptor::SlotRegister(),
1404 SmiFromSlot(proxy->VariableFeedbackSlot()));
1407 ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
1414 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1416 DCHECK(var->IsContextSlot());
1417 Register context = rsi;
1418 Register temp = rbx;
1420 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1421 if (s->num_heap_slots() > 0) {
1422 if (s->calls_sloppy_eval()) {
1423 // Check that extension is NULL.
1424 __ cmpp(ContextOperand(context, Context::EXTENSION_INDEX),
1426 __ j(not_equal, slow);
1428 __ movp(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1429 // Walk the rest of the chain without clobbering rsi.
1433 // Check that last extension is NULL.
1434 __ cmpp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1435 __ j(not_equal, slow);
1437 // This function is used only for loads, not stores, so it's safe to
1438 // return an rsi-based operand (the write barrier cannot be allowed to
1439 // destroy the rsi register).
1440 return ContextOperand(context, var->index());
1444 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
1445 TypeofState typeof_state,
1448 // Generate fast-case code for variables that might be shadowed by
1449 // eval-introduced variables. Eval is used a lot without
1450 // introducing variables. In those cases, we do not want to
1451 // perform a runtime call for all variables in the scope
1452 // containing the eval.
1453 Variable* var = proxy->var();
1454 if (var->mode() == DYNAMIC_GLOBAL) {
1455 EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow);
1457 } else if (var->mode() == DYNAMIC_LOCAL) {
1458 Variable* local = var->local_if_not_shadowed();
1459 __ movp(rax, ContextSlotOperandCheckExtensions(local, slow));
1460 if (local->mode() == LET || local->mode() == CONST ||
1461 local->mode() == CONST_LEGACY) {
1462 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1463 __ j(not_equal, done);
1464 if (local->mode() == CONST_LEGACY) {
1465 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1466 } else { // LET || CONST
1467 __ Push(var->name());
1468 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1476 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1477 // Record position before possible IC call.
1478 SetSourcePosition(proxy->position());
1479 Variable* var = proxy->var();
1481 // Three cases: global variables, lookup variables, and all other types of
1483 switch (var->location()) {
1484 case Variable::UNALLOCATED: {
1485 Comment cmnt(masm_, "[ Global variable");
1486 __ Move(LoadDescriptor::NameRegister(), var->name());
1487 __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
1488 if (FLAG_vector_ics) {
1489 __ Move(VectorLoadICDescriptor::SlotRegister(),
1490 SmiFromSlot(proxy->VariableFeedbackSlot()));
1492 CallLoadIC(CONTEXTUAL);
1493 context()->Plug(rax);
1497 case Variable::PARAMETER:
1498 case Variable::LOCAL:
1499 case Variable::CONTEXT: {
1500 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot"
1502 if (var->binding_needs_init()) {
1503 // var->scope() may be NULL when the proxy is located in eval code and
1504 // refers to a potential outside binding. Currently those bindings are
1505 // always looked up dynamically, i.e. in that case
1506 // var->location() == LOOKUP.
1508 DCHECK(var->scope() != NULL);
1510 // Check if the binding really needs an initialization check. The check
1511 // can be skipped in the following situation: we have a LET or CONST
1512 // binding in harmony mode, both the Variable and the VariableProxy have
1513 // the same declaration scope (i.e. they are both in global code, in the
1514 // same function or in the same eval code) and the VariableProxy is in
1515 // the source physically located after the initializer of the variable.
1517 // We cannot skip any initialization checks for CONST in non-harmony
1518 // mode because const variables may be declared but never initialized:
1519 // if (false) { const x; }; var y = x;
1521 // The condition on the declaration scopes is a conservative check for
1522 // nested functions that access a binding and are called before the
1523 // binding is initialized:
1524 // function() { f(); let x = 1; function f() { x = 2; } }
1526 bool skip_init_check;
1527 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1528 skip_init_check = false;
1529 } else if (var->is_this()) {
1530 CHECK(info_->function() != nullptr &&
1531 (info_->function()->kind() & kSubclassConstructor) != 0);
1532 // TODO(dslomov): implement 'this' hole check elimination.
1533 skip_init_check = false;
1535 // Check that we always have valid source position.
1536 DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
1537 DCHECK(proxy->position() != RelocInfo::kNoPosition);
1538 skip_init_check = var->mode() != CONST_LEGACY &&
1539 var->initializer_position() < proxy->position();
1542 if (!skip_init_check) {
1543 // Let and const need a read barrier.
1546 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1547 __ j(not_equal, &done, Label::kNear);
1548 if (var->mode() == LET || var->mode() == CONST) {
1549 // Throw a reference error when using an uninitialized let/const
1550 // binding in harmony mode.
1551 __ Push(var->name());
1552 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1554 // Uninitalized const bindings outside of harmony mode are unholed.
1555 DCHECK(var->mode() == CONST_LEGACY);
1556 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1559 context()->Plug(rax);
1563 context()->Plug(var);
1567 case Variable::LOOKUP: {
1568 Comment cmnt(masm_, "[ Lookup slot");
1570 // Generate code for loading from variables potentially shadowed
1571 // by eval-introduced variables.
1572 EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
1574 __ Push(rsi); // Context.
1575 __ Push(var->name());
1576 __ CallRuntime(Runtime::kLoadLookupSlot, 2);
1578 context()->Plug(rax);
1585 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1586 Comment cmnt(masm_, "[ RegExpLiteral");
1588 // Registers will be used as follows:
1589 // rdi = JS function.
1590 // rcx = literals array.
1591 // rbx = regexp literal.
1592 // rax = regexp literal clone.
1593 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1594 __ movp(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
1595 int literal_offset =
1596 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
1597 __ movp(rbx, FieldOperand(rcx, literal_offset));
1598 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
1599 __ j(not_equal, &materialized, Label::kNear);
1601 // Create regexp literal using runtime function
1602 // Result will be in rax.
1604 __ Push(Smi::FromInt(expr->literal_index()));
1605 __ Push(expr->pattern());
1606 __ Push(expr->flags());
1607 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
1610 __ bind(&materialized);
1611 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1612 Label allocated, runtime_allocate;
1613 __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
1616 __ bind(&runtime_allocate);
1618 __ Push(Smi::FromInt(size));
1619 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1622 __ bind(&allocated);
1623 // Copy the content into the newly allocated memory.
1624 // (Unroll copy loop once for better throughput).
1625 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1626 __ movp(rdx, FieldOperand(rbx, i));
1627 __ movp(rcx, FieldOperand(rbx, i + kPointerSize));
1628 __ movp(FieldOperand(rax, i), rdx);
1629 __ movp(FieldOperand(rax, i + kPointerSize), rcx);
1631 if ((size % (2 * kPointerSize)) != 0) {
1632 __ movp(rdx, FieldOperand(rbx, size - kPointerSize));
1633 __ movp(FieldOperand(rax, size - kPointerSize), rdx);
1635 context()->Plug(rax);
1639 void FullCodeGenerator::EmitAccessor(Expression* expression) {
1640 if (expression == NULL) {
1641 __ PushRoot(Heap::kNullValueRootIndex);
1643 VisitForStackValue(expression);
1648 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1649 Comment cmnt(masm_, "[ ObjectLiteral");
1651 expr->BuildConstantProperties(isolate());
1652 Handle<FixedArray> constant_properties = expr->constant_properties();
1653 int flags = expr->ComputeFlags();
1654 if (MustCreateObjectLiteralWithRuntime(expr)) {
1655 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1656 __ Push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
1657 __ Push(Smi::FromInt(expr->literal_index()));
1658 __ Push(constant_properties);
1659 __ Push(Smi::FromInt(flags));
1660 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
1662 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1663 __ movp(rax, FieldOperand(rdi, JSFunction::kLiteralsOffset));
1664 __ Move(rbx, Smi::FromInt(expr->literal_index()));
1665 __ Move(rcx, constant_properties);
1666 __ Move(rdx, Smi::FromInt(flags));
1667 FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
1670 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
1672 // If result_saved is true the result is on top of the stack. If
1673 // result_saved is false the result is in rax.
1674 bool result_saved = false;
1676 // Mark all computed expressions that are bound to a key that
1677 // is shadowed by a later occurrence of the same key. For the
1678 // marked expressions, no store code is emitted.
1679 expr->CalculateEmitStore(zone());
1681 AccessorTable accessor_table(zone());
1682 int property_index = 0;
1683 for (; property_index < expr->properties()->length(); property_index++) {
1684 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1685 if (property->is_computed_name()) break;
1686 if (property->IsCompileTimeValue()) continue;
1688 Literal* key = property->key()->AsLiteral();
1689 Expression* value = property->value();
1690 if (!result_saved) {
1691 __ Push(rax); // Save result on the stack
1692 result_saved = true;
1694 switch (property->kind()) {
1695 case ObjectLiteral::Property::CONSTANT:
1697 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1698 DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
1700 case ObjectLiteral::Property::COMPUTED:
1701 // It is safe to use [[Put]] here because the boilerplate already
1702 // contains computed properties with an uninitialized value.
1703 if (key->value()->IsInternalizedString()) {
1704 if (property->emit_store()) {
1705 VisitForAccumulatorValue(value);
1706 DCHECK(StoreDescriptor::ValueRegister().is(rax));
1707 __ Move(StoreDescriptor::NameRegister(), key->value());
1708 __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0));
1709 CallStoreIC(key->LiteralFeedbackId());
1710 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1712 if (NeedsHomeObject(value)) {
1713 __ movp(StoreDescriptor::ReceiverRegister(), rax);
1714 __ Move(StoreDescriptor::NameRegister(),
1715 isolate()->factory()->home_object_symbol());
1716 __ movp(StoreDescriptor::ValueRegister(), Operand(rsp, 0));
1720 VisitForEffect(value);
1724 __ Push(Operand(rsp, 0)); // Duplicate receiver.
1725 VisitForStackValue(key);
1726 VisitForStackValue(value);
1727 if (property->emit_store()) {
1728 EmitSetHomeObjectIfNeeded(value, 2);
1729 __ Push(Smi::FromInt(SLOPPY)); // Language mode
1730 __ CallRuntime(Runtime::kSetProperty, 4);
1735 case ObjectLiteral::Property::PROTOTYPE:
1736 __ Push(Operand(rsp, 0)); // Duplicate receiver.
1737 VisitForStackValue(value);
1738 DCHECK(property->emit_store());
1739 __ CallRuntime(Runtime::kInternalSetPrototype, 2);
1741 case ObjectLiteral::Property::GETTER:
1742 if (property->emit_store()) {
1743 accessor_table.lookup(key)->second->getter = value;
1746 case ObjectLiteral::Property::SETTER:
1747 if (property->emit_store()) {
1748 accessor_table.lookup(key)->second->setter = value;
1754 // Emit code to define accessors, using only a single call to the runtime for
1755 // each pair of corresponding getters and setters.
1756 for (AccessorTable::Iterator it = accessor_table.begin();
1757 it != accessor_table.end();
1759 __ Push(Operand(rsp, 0)); // Duplicate receiver.
1760 VisitForStackValue(it->first);
1761 EmitAccessor(it->second->getter);
1762 EmitSetHomeObjectIfNeeded(it->second->getter, 2);
1763 EmitAccessor(it->second->setter);
1764 EmitSetHomeObjectIfNeeded(it->second->setter, 3);
1765 __ Push(Smi::FromInt(NONE));
1766 __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
1769 // Object literals have two parts. The "static" part on the left contains no
1770 // computed property names, and so we can compute its map ahead of time; see
1771 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
1772 // starts with the first computed property name, and continues with all
1773 // properties to its right. All the code from above initializes the static
1774 // component of the object literal, and arranges for the map of the result to
1775 // reflect the static order in which the keys appear. For the dynamic
1776 // properties, we compile them into a series of "SetOwnProperty" runtime
1777 // calls. This will preserve insertion order.
1778 for (; property_index < expr->properties()->length(); property_index++) {
1779 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1781 Expression* value = property->value();
1782 if (!result_saved) {
1783 __ Push(rax); // Save result on the stack
1784 result_saved = true;
1787 __ Push(Operand(rsp, 0)); // Duplicate receiver.
1789 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1790 DCHECK(!property->is_computed_name());
1791 VisitForStackValue(value);
1792 DCHECK(property->emit_store());
1793 __ CallRuntime(Runtime::kInternalSetPrototype, 2);
1795 EmitPropertyKey(property, expr->GetIdForProperty(property_index));
1796 VisitForStackValue(value);
1797 EmitSetHomeObjectIfNeeded(value, 2);
1799 switch (property->kind()) {
1800 case ObjectLiteral::Property::CONSTANT:
1801 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1802 case ObjectLiteral::Property::COMPUTED:
1803 if (property->emit_store()) {
1804 __ Push(Smi::FromInt(NONE));
1805 __ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
1811 case ObjectLiteral::Property::PROTOTYPE:
1815 case ObjectLiteral::Property::GETTER:
1816 __ Push(Smi::FromInt(NONE));
1817 __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 4);
1820 case ObjectLiteral::Property::SETTER:
1821 __ Push(Smi::FromInt(NONE));
1822 __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 4);
1828 if (expr->has_function()) {
1829 DCHECK(result_saved);
1830 __ Push(Operand(rsp, 0));
1831 __ CallRuntime(Runtime::kToFastProperties, 1);
1835 context()->PlugTOS();
1837 context()->Plug(rax);
1842 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1843 Comment cmnt(masm_, "[ ArrayLiteral");
1845 expr->BuildConstantElements(isolate());
1846 Handle<FixedArray> constant_elements = expr->constant_elements();
1847 bool has_constant_fast_elements =
1848 IsFastObjectElementsKind(expr->constant_elements_kind());
1850 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1851 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1852 // If the only customer of allocation sites is transitioning, then
1853 // we can turn it off if we don't have anywhere else to transition to.
1854 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1857 if (MustCreateArrayLiteralWithRuntime(expr)) {
1858 __ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1859 __ Push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1860 __ Push(Smi::FromInt(expr->literal_index()));
1861 __ Push(constant_elements);
1862 __ Push(Smi::FromInt(expr->ComputeFlags()));
1863 __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
1865 __ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1866 __ movp(rax, FieldOperand(rbx, JSFunction::kLiteralsOffset));
1867 __ Move(rbx, Smi::FromInt(expr->literal_index()));
1868 __ Move(rcx, constant_elements);
1869 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
1872 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
1874 bool result_saved = false; // Is the result saved to the stack?
1875 ZoneList<Expression*>* subexprs = expr->values();
1876 int length = subexprs->length();
1878 // Emit code to evaluate all the non-constant subexpressions and to store
1879 // them into the newly cloned array.
1880 for (int i = 0; i < length; i++) {
1881 Expression* subexpr = subexprs->at(i);
1882 // If the subexpression is a literal or a simple materialized literal it
1883 // is already set in the cloned array.
1884 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1886 if (!result_saved) {
1887 __ Push(rax); // array literal
1888 __ Push(Smi::FromInt(expr->literal_index()));
1889 result_saved = true;
1891 VisitForAccumulatorValue(subexpr);
1893 if (has_constant_fast_elements) {
1894 // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
1895 // cannot transition and don't need to call the runtime stub.
1896 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1897 __ movp(rbx, Operand(rsp, kPointerSize)); // Copy of array literal.
1898 __ movp(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
1899 // Store the subexpression value in the array's elements.
1900 __ movp(FieldOperand(rbx, offset), result_register());
1901 // Update the write barrier for the array store.
1902 __ RecordWriteField(rbx, offset, result_register(), rcx,
1904 EMIT_REMEMBERED_SET,
1907 // Store the subexpression value in the array's elements.
1908 __ Move(rcx, Smi::FromInt(i));
1909 StoreArrayLiteralElementStub stub(isolate());
1913 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
1917 __ addp(rsp, Immediate(kPointerSize)); // literal index
1918 context()->PlugTOS();
1920 context()->Plug(rax);
1925 void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1926 DCHECK(expr->target()->IsValidReferenceExpression());
1928 Comment cmnt(masm_, "[ Assignment");
1930 Property* property = expr->target()->AsProperty();
1931 LhsKind assign_type = GetAssignType(property);
1933 // Evaluate LHS expression.
1934 switch (assign_type) {
1936 // Nothing to do here.
1938 case NAMED_PROPERTY:
1939 if (expr->is_compound()) {
1940 // We need the receiver both on the stack and in the register.
1941 VisitForStackValue(property->obj());
1942 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
1944 VisitForStackValue(property->obj());
1947 case NAMED_SUPER_PROPERTY:
1948 VisitForStackValue(property->obj()->AsSuperReference()->this_var());
1949 EmitLoadHomeObject(property->obj()->AsSuperReference());
1950 __ Push(result_register());
1951 if (expr->is_compound()) {
1952 __ Push(MemOperand(rsp, kPointerSize));
1953 __ Push(result_register());
1956 case KEYED_SUPER_PROPERTY:
1957 VisitForStackValue(property->obj()->AsSuperReference()->this_var());
1958 EmitLoadHomeObject(property->obj()->AsSuperReference());
1959 __ Push(result_register());
1960 VisitForAccumulatorValue(property->key());
1961 __ Push(result_register());
1962 if (expr->is_compound()) {
1963 __ Push(MemOperand(rsp, 2 * kPointerSize));
1964 __ Push(MemOperand(rsp, 2 * kPointerSize));
1965 __ Push(result_register());
1968 case KEYED_PROPERTY: {
1969 if (expr->is_compound()) {
1970 VisitForStackValue(property->obj());
1971 VisitForStackValue(property->key());
1972 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
1973 __ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
1975 VisitForStackValue(property->obj());
1976 VisitForStackValue(property->key());
1982 // For compound assignments we need another deoptimization point after the
1983 // variable/property load.
1984 if (expr->is_compound()) {
1985 { AccumulatorValueContext context(this);
1986 switch (assign_type) {
1988 EmitVariableLoad(expr->target()->AsVariableProxy());
1989 PrepareForBailout(expr->target(), TOS_REG);
1991 case NAMED_PROPERTY:
1992 EmitNamedPropertyLoad(property);
1993 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1995 case NAMED_SUPER_PROPERTY:
1996 EmitNamedSuperPropertyLoad(property);
1997 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1999 case KEYED_SUPER_PROPERTY:
2000 EmitKeyedSuperPropertyLoad(property);
2001 PrepareForBailoutForId(property->LoadId(), TOS_REG);
2003 case KEYED_PROPERTY:
2004 EmitKeyedPropertyLoad(property);
2005 PrepareForBailoutForId(property->LoadId(), TOS_REG);
2010 Token::Value op = expr->binary_op();
2011 __ Push(rax); // Left operand goes on the stack.
2012 VisitForAccumulatorValue(expr->value());
2014 SetSourcePosition(expr->position() + 1);
2015 AccumulatorValueContext context(this);
2016 if (ShouldInlineSmiCase(op)) {
2017 EmitInlineSmiBinaryOp(expr->binary_operation(),
2022 EmitBinaryOp(expr->binary_operation(), op);
2024 // Deoptimization point in case the binary operation may have side effects.
2025 PrepareForBailout(expr->binary_operation(), TOS_REG);
2027 VisitForAccumulatorValue(expr->value());
2030 // Record source position before possible IC call.
2031 SetSourcePosition(expr->position());
2034 switch (assign_type) {
2036 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
2038 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2039 context()->Plug(rax);
2041 case NAMED_PROPERTY:
2042 EmitNamedPropertyAssignment(expr);
2044 case NAMED_SUPER_PROPERTY:
2045 EmitNamedSuperPropertyStore(property);
2046 context()->Plug(rax);
2048 case KEYED_SUPER_PROPERTY:
2049 EmitKeyedSuperPropertyStore(property);
2050 context()->Plug(rax);
2052 case KEYED_PROPERTY:
2053 EmitKeyedPropertyAssignment(expr);
2059 void FullCodeGenerator::VisitYield(Yield* expr) {
2060 Comment cmnt(masm_, "[ Yield");
2061 // Evaluate yielded value first; the initial iterator definition depends on
2062 // this. It stays on the stack while we update the iterator.
2063 VisitForStackValue(expr->expression());
2065 switch (expr->yield_kind()) {
2066 case Yield::kSuspend:
2067 // Pop value from top-of-stack slot; box result into result register.
2068 EmitCreateIteratorResult(false);
2069 __ Push(result_register());
2071 case Yield::kInitial: {
2072 Label suspend, continuation, post_runtime, resume;
2076 __ bind(&continuation);
2080 VisitForAccumulatorValue(expr->generator_object());
2081 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
2082 __ Move(FieldOperand(rax, JSGeneratorObject::kContinuationOffset),
2083 Smi::FromInt(continuation.pos()));
2084 __ movp(FieldOperand(rax, JSGeneratorObject::kContextOffset), rsi);
2086 __ RecordWriteField(rax, JSGeneratorObject::kContextOffset, rcx, rdx,
2088 __ leap(rbx, Operand(rbp, StandardFrameConstants::kExpressionsOffset));
2090 __ j(equal, &post_runtime);
2091 __ Push(rax); // generator object
2092 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
2093 __ movp(context_register(),
2094 Operand(rbp, StandardFrameConstants::kContextOffset));
2095 __ bind(&post_runtime);
2097 __ Pop(result_register());
2098 EmitReturnSequence();
2101 context()->Plug(result_register());
2105 case Yield::kFinal: {
2106 VisitForAccumulatorValue(expr->generator_object());
2107 __ Move(FieldOperand(result_register(),
2108 JSGeneratorObject::kContinuationOffset),
2109 Smi::FromInt(JSGeneratorObject::kGeneratorClosed));
2110 // Pop value from top-of-stack slot, box result into result register.
2111 EmitCreateIteratorResult(true);
2112 EmitUnwindBeforeReturn();
2113 EmitReturnSequence();
2117 case Yield::kDelegating: {
2118 VisitForStackValue(expr->generator_object());
2120 // Initial stack layout is as follows:
2121 // [sp + 1 * kPointerSize] iter
2122 // [sp + 0 * kPointerSize] g
2124 Label l_catch, l_try, l_suspend, l_continuation, l_resume;
2125 Label l_next, l_call, l_loop;
2126 Register load_receiver = LoadDescriptor::ReceiverRegister();
2127 Register load_name = LoadDescriptor::NameRegister();
2129 // Initial send value is undefined.
2130 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2133 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
2135 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
2136 __ LoadRoot(load_name, Heap::kthrow_stringRootIndex); // "throw"
2138 __ Push(Operand(rsp, 2 * kPointerSize)); // iter
2139 __ Push(rax); // exception
2142 // try { received = %yield result }
2143 // Shuffle the received result above a try handler and yield it without
2146 __ Pop(rax); // result
2147 __ PushTryHandler(StackHandler::CATCH, expr->index());
2148 const int handler_size = StackHandlerConstants::kSize;
2149 __ Push(rax); // result
2151 __ bind(&l_continuation);
2153 __ bind(&l_suspend);
2154 const int generator_object_depth = kPointerSize + handler_size;
2155 __ movp(rax, Operand(rsp, generator_object_depth));
2157 DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
2158 __ Move(FieldOperand(rax, JSGeneratorObject::kContinuationOffset),
2159 Smi::FromInt(l_continuation.pos()));
2160 __ movp(FieldOperand(rax, JSGeneratorObject::kContextOffset), rsi);
2162 __ RecordWriteField(rax, JSGeneratorObject::kContextOffset, rcx, rdx,
2164 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
2165 __ movp(context_register(),
2166 Operand(rbp, StandardFrameConstants::kContextOffset));
2167 __ Pop(rax); // result
2168 EmitReturnSequence();
2169 __ bind(&l_resume); // received in rax
2172 // receiver = iter; f = 'next'; arg = received;
2175 __ LoadRoot(load_name, Heap::knext_stringRootIndex);
2176 __ Push(load_name); // "next"
2177 __ Push(Operand(rsp, 2 * kPointerSize)); // iter
2178 __ Push(rax); // received
2180 // result = receiver[f](arg);
2182 __ movp(load_receiver, Operand(rsp, kPointerSize));
2183 if (FLAG_vector_ics) {
2184 __ Move(VectorLoadICDescriptor::SlotRegister(),
2185 SmiFromSlot(expr->KeyedLoadFeedbackSlot()));
2187 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
2188 CallIC(ic, TypeFeedbackId::None());
2190 __ movp(Operand(rsp, 2 * kPointerSize), rdi);
2191 CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
2194 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2195 __ Drop(1); // The function is still on the stack; drop it.
2197 // if (!result.done) goto l_try;
2199 __ Move(load_receiver, rax);
2200 __ Push(load_receiver); // save result
2201 __ LoadRoot(load_name, Heap::kdone_stringRootIndex); // "done"
2202 if (FLAG_vector_ics) {
2203 __ Move(VectorLoadICDescriptor::SlotRegister(),
2204 SmiFromSlot(expr->DoneFeedbackSlot()));
2206 CallLoadIC(NOT_CONTEXTUAL); // rax=result.done
2207 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
2209 __ testp(result_register(), result_register());
2213 __ Pop(load_receiver); // result
2214 __ LoadRoot(load_name, Heap::kvalue_stringRootIndex); // "value"
2215 if (FLAG_vector_ics) {
2216 __ Move(VectorLoadICDescriptor::SlotRegister(),
2217 SmiFromSlot(expr->ValueFeedbackSlot()));
2219 CallLoadIC(NOT_CONTEXTUAL); // result.value in rax
2220 context()->DropAndPlug(2, rax); // drop iter and g
2227 void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
2229 JSGeneratorObject::ResumeMode resume_mode) {
2230 // The value stays in rax, and is ultimately read by the resumed generator, as
2231 // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
2232 // is read to throw the value when the resumed generator is already closed.
2233 // rbx will hold the generator object until the activation has been resumed.
2234 VisitForStackValue(generator);
2235 VisitForAccumulatorValue(value);
2238 // Load suspended function and context.
2239 __ movp(rsi, FieldOperand(rbx, JSGeneratorObject::kContextOffset));
2240 __ movp(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset));
2243 __ Push(FieldOperand(rbx, JSGeneratorObject::kReceiverOffset));
2245 // Push holes for arguments to generator function.
2246 __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
2247 __ LoadSharedFunctionInfoSpecialField(rdx, rdx,
2248 SharedFunctionInfo::kFormalParameterCountOffset);
2249 __ LoadRoot(rcx, Heap::kTheHoleValueRootIndex);
2250 Label push_argument_holes, push_frame;
2251 __ bind(&push_argument_holes);
2252 __ subp(rdx, Immediate(1));
2253 __ j(carry, &push_frame);
2255 __ jmp(&push_argument_holes);
2257 // Enter a new JavaScript frame, and initialize its slots as they were when
2258 // the generator was suspended.
2259 Label resume_frame, done;
2260 __ bind(&push_frame);
2261 __ call(&resume_frame);
2263 __ bind(&resume_frame);
2264 __ pushq(rbp); // Caller's frame pointer.
2266 __ Push(rsi); // Callee's context.
2267 __ Push(rdi); // Callee's JS Function.
2269 // Load the operand stack size.
2270 __ movp(rdx, FieldOperand(rbx, JSGeneratorObject::kOperandStackOffset));
2271 __ movp(rdx, FieldOperand(rdx, FixedArray::kLengthOffset));
2272 __ SmiToInteger32(rdx, rdx);
2274 // If we are sending a value and there is no operand stack, we can jump back
2276 if (resume_mode == JSGeneratorObject::NEXT) {
2278 __ cmpp(rdx, Immediate(0));
2279 __ j(not_zero, &slow_resume);
2280 __ movp(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2281 __ SmiToInteger64(rcx,
2282 FieldOperand(rbx, JSGeneratorObject::kContinuationOffset));
2284 __ Move(FieldOperand(rbx, JSGeneratorObject::kContinuationOffset),
2285 Smi::FromInt(JSGeneratorObject::kGeneratorExecuting));
2287 __ bind(&slow_resume);
2290 // Otherwise, we push holes for the operand stack and call the runtime to fix
2291 // up the stack and the handlers.
2292 Label push_operand_holes, call_resume;
2293 __ bind(&push_operand_holes);
2294 __ subp(rdx, Immediate(1));
2295 __ j(carry, &call_resume);
2297 __ jmp(&push_operand_holes);
2298 __ bind(&call_resume);
2300 __ Push(result_register());
2301 __ Push(Smi::FromInt(resume_mode));
2302 __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
2303 // Not reached: the runtime call returns elsewhere.
2304 __ Abort(kGeneratorFailedToResume);
2307 context()->Plug(result_register());
2311 void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
2315 const int instance_size = 5 * kPointerSize;
2316 DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
2319 __ Allocate(instance_size, rax, rcx, rdx, &gc_required, TAG_OBJECT);
2322 __ bind(&gc_required);
2323 __ Push(Smi::FromInt(instance_size));
2324 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
2325 __ movp(context_register(),
2326 Operand(rbp, StandardFrameConstants::kContextOffset));
2328 __ bind(&allocated);
2329 __ movp(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2330 __ movp(rbx, FieldOperand(rbx, GlobalObject::kNativeContextOffset));
2331 __ movp(rbx, ContextOperand(rbx, Context::ITERATOR_RESULT_MAP_INDEX));
2333 __ Move(rdx, isolate()->factory()->ToBoolean(done));
2334 __ movp(FieldOperand(rax, HeapObject::kMapOffset), rbx);
2335 __ Move(FieldOperand(rax, JSObject::kPropertiesOffset),
2336 isolate()->factory()->empty_fixed_array());
2337 __ Move(FieldOperand(rax, JSObject::kElementsOffset),
2338 isolate()->factory()->empty_fixed_array());
2339 __ movp(FieldOperand(rax, JSGeneratorObject::kResultValuePropertyOffset),
2341 __ movp(FieldOperand(rax, JSGeneratorObject::kResultDonePropertyOffset),
2344 // Only the value field needs a write barrier, as the other values are in the
2346 __ RecordWriteField(rax, JSGeneratorObject::kResultValuePropertyOffset,
2347 rcx, rdx, kDontSaveFPRegs);
2351 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
2352 SetSourcePosition(prop->position());
2353 Literal* key = prop->key()->AsLiteral();
2354 DCHECK(!prop->IsSuperAccess());
2356 __ Move(LoadDescriptor::NameRegister(), key->value());
2357 if (FLAG_vector_ics) {
2358 __ Move(VectorLoadICDescriptor::SlotRegister(),
2359 SmiFromSlot(prop->PropertyFeedbackSlot()));
2360 CallLoadIC(NOT_CONTEXTUAL);
2362 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
2367 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
2368 // Stack: receiver, home_object
2369 SetSourcePosition(prop->position());
2370 Literal* key = prop->key()->AsLiteral();
2371 DCHECK(!key->value()->IsSmi());
2372 DCHECK(prop->IsSuperAccess());
2374 __ Push(key->value());
2375 __ CallRuntime(Runtime::kLoadFromSuper, 3);
2379 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
2380 SetSourcePosition(prop->position());
2381 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
2382 if (FLAG_vector_ics) {
2383 __ Move(VectorLoadICDescriptor::SlotRegister(),
2384 SmiFromSlot(prop->PropertyFeedbackSlot()));
2387 CallIC(ic, prop->PropertyFeedbackId());
2392 void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
2393 // Stack: receiver, home_object, key.
2394 SetSourcePosition(prop->position());
2396 __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
2400 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
2403 Expression* right) {
2404 // Do combined smi check of the operands. Left operand is on the
2405 // stack (popped into rdx). Right operand is in rax but moved into
2406 // rcx to make the shifts easier.
2407 Label done, stub_call, smi_case;
2411 JumpPatchSite patch_site(masm_);
2412 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear);
2414 __ bind(&stub_call);
2416 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
2417 CallIC(code, expr->BinaryOperationFeedbackId());
2418 patch_site.EmitPatchInfo();
2419 __ jmp(&done, Label::kNear);
2424 __ SmiShiftArithmeticRight(rax, rdx, rcx);
2427 __ SmiShiftLeft(rax, rdx, rcx, &stub_call);
2430 __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
2433 __ SmiAdd(rax, rdx, rcx, &stub_call);
2436 __ SmiSub(rax, rdx, rcx, &stub_call);
2439 __ SmiMul(rax, rdx, rcx, &stub_call);
2442 __ SmiOr(rax, rdx, rcx);
2444 case Token::BIT_AND:
2445 __ SmiAnd(rax, rdx, rcx);
2447 case Token::BIT_XOR:
2448 __ SmiXor(rax, rdx, rcx);
2456 context()->Plug(rax);
2460 void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
2461 // Constructor is in rax.
2462 DCHECK(lit != NULL);
2465 // No access check is needed here since the constructor is created by the
2467 Register scratch = rbx;
2468 __ movp(scratch, FieldOperand(rax, JSFunction::kPrototypeOrInitialMapOffset));
2471 for (int i = 0; i < lit->properties()->length(); i++) {
2472 ObjectLiteral::Property* property = lit->properties()->at(i);
2473 Expression* value = property->value();
2475 if (property->is_static()) {
2476 __ Push(Operand(rsp, kPointerSize)); // constructor
2478 __ Push(Operand(rsp, 0)); // prototype
2480 EmitPropertyKey(property, lit->GetIdForProperty(i));
2481 VisitForStackValue(value);
2482 EmitSetHomeObjectIfNeeded(value, 2);
2484 switch (property->kind()) {
2485 case ObjectLiteral::Property::CONSTANT:
2486 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2487 case ObjectLiteral::Property::PROTOTYPE:
2489 case ObjectLiteral::Property::COMPUTED:
2490 __ CallRuntime(Runtime::kDefineClassMethod, 3);
2493 case ObjectLiteral::Property::GETTER:
2494 __ Push(Smi::FromInt(DONT_ENUM));
2495 __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 4);
2498 case ObjectLiteral::Property::SETTER:
2499 __ Push(Smi::FromInt(DONT_ENUM));
2500 __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 4);
2509 __ CallRuntime(Runtime::kToFastProperties, 1);
2512 __ CallRuntime(Runtime::kToFastProperties, 1);
2516 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
2518 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
2519 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
2520 CallIC(code, expr->BinaryOperationFeedbackId());
2521 patch_site.EmitPatchInfo();
2522 context()->Plug(rax);
2526 void FullCodeGenerator::EmitAssignment(Expression* expr) {
2527 DCHECK(expr->IsValidReferenceExpression());
2529 Property* prop = expr->AsProperty();
2530 LhsKind assign_type = GetAssignType(prop);
2532 switch (assign_type) {
2534 Variable* var = expr->AsVariableProxy()->var();
2535 EffectContext context(this);
2536 EmitVariableAssignment(var, Token::ASSIGN);
2539 case NAMED_PROPERTY: {
2540 __ Push(rax); // Preserve value.
2541 VisitForAccumulatorValue(prop->obj());
2542 __ Move(StoreDescriptor::ReceiverRegister(), rax);
2543 __ Pop(StoreDescriptor::ValueRegister()); // Restore value.
2544 __ Move(StoreDescriptor::NameRegister(),
2545 prop->key()->AsLiteral()->value());
2549 case NAMED_SUPER_PROPERTY: {
2551 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
2552 EmitLoadHomeObject(prop->obj()->AsSuperReference());
2553 // stack: value, this; rax: home_object
2554 Register scratch = rcx;
2555 Register scratch2 = rdx;
2556 __ Move(scratch, result_register()); // home_object
2557 __ movp(rax, MemOperand(rsp, kPointerSize)); // value
2558 __ movp(scratch2, MemOperand(rsp, 0)); // this
2559 __ movp(MemOperand(rsp, kPointerSize), scratch2); // this
2560 __ movp(MemOperand(rsp, 0), scratch); // home_object
2561 // stack: this, home_object; rax: value
2562 EmitNamedSuperPropertyStore(prop);
2565 case KEYED_SUPER_PROPERTY: {
2567 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
2568 EmitLoadHomeObject(prop->obj()->AsSuperReference());
2569 __ Push(result_register());
2570 VisitForAccumulatorValue(prop->key());
2571 Register scratch = rcx;
2572 Register scratch2 = rdx;
2573 __ movp(scratch2, MemOperand(rsp, 2 * kPointerSize)); // value
2574 // stack: value, this, home_object; rax: key, rdx: value
2575 __ movp(scratch, MemOperand(rsp, kPointerSize)); // this
2576 __ movp(MemOperand(rsp, 2 * kPointerSize), scratch);
2577 __ movp(scratch, MemOperand(rsp, 0)); // home_object
2578 __ movp(MemOperand(rsp, kPointerSize), scratch);
2579 __ movp(MemOperand(rsp, 0), rax);
2580 __ Move(rax, scratch2);
2581 // stack: this, home_object, key; rax: value.
2582 EmitKeyedSuperPropertyStore(prop);
2585 case KEYED_PROPERTY: {
2586 __ Push(rax); // Preserve value.
2587 VisitForStackValue(prop->obj());
2588 VisitForAccumulatorValue(prop->key());
2589 __ Move(StoreDescriptor::NameRegister(), rax);
2590 __ Pop(StoreDescriptor::ReceiverRegister());
2591 __ Pop(StoreDescriptor::ValueRegister()); // Restore value.
2593 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2598 context()->Plug(rax);
2602 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2603 Variable* var, MemOperand location) {
2604 __ movp(location, rax);
2605 if (var->IsContextSlot()) {
2607 __ RecordWriteContextSlot(
2608 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
2613 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
2615 if (var->IsUnallocated()) {
2616 // Global var, const, or let.
2617 __ Move(StoreDescriptor::NameRegister(), var->name());
2618 __ movp(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
2621 } else if (op == Token::INIT_CONST_LEGACY) {
2622 // Const initializers need a write barrier.
2623 DCHECK(!var->IsParameter()); // No const parameters.
2624 if (var->IsLookupSlot()) {
2627 __ Push(var->name());
2628 __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
2630 DCHECK(var->IsStackLocal() || var->IsContextSlot());
2632 MemOperand location = VarOperand(var, rcx);
2633 __ movp(rdx, location);
2634 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2635 __ j(not_equal, &skip);
2636 EmitStoreToStackLocalOrContextSlot(var, location);
2640 } else if (var->mode() == LET && op != Token::INIT_LET) {
2641 // Non-initializing assignment to let variable needs a write barrier.
2642 DCHECK(!var->IsLookupSlot());
2643 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2645 MemOperand location = VarOperand(var, rcx);
2646 __ movp(rdx, location);
2647 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2648 __ j(not_equal, &assign, Label::kNear);
2649 __ Push(var->name());
2650 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2652 EmitStoreToStackLocalOrContextSlot(var, location);
2654 } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
2655 if (var->IsLookupSlot()) {
2656 // Assignment to var.
2657 __ Push(rax); // Value.
2658 __ Push(rsi); // Context.
2659 __ Push(var->name());
2660 __ Push(Smi::FromInt(language_mode()));
2661 __ CallRuntime(Runtime::kStoreLookupSlot, 4);
2663 // Assignment to var or initializing assignment to let/const in harmony
2665 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2666 MemOperand location = VarOperand(var, rcx);
2667 if (generate_debug_code_ && op == Token::INIT_LET) {
2668 // Check for an uninitialized let binding.
2669 __ movp(rdx, location);
2670 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2671 __ Check(equal, kLetBindingReInitialization);
2673 EmitStoreToStackLocalOrContextSlot(var, location);
2675 } else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
2676 __ CallRuntime(Runtime::kThrowConstAssignError, 0);
2681 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2682 // Assignment to a property, using a named store IC.
2683 Property* prop = expr->target()->AsProperty();
2684 DCHECK(prop != NULL);
2685 DCHECK(prop->key()->IsLiteral());
2687 // Record source code position before IC call.
2688 SetSourcePosition(expr->position());
2689 __ Move(StoreDescriptor::NameRegister(), prop->key()->AsLiteral()->value());
2690 __ Pop(StoreDescriptor::ReceiverRegister());
2691 CallStoreIC(expr->AssignmentFeedbackId());
2693 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2694 context()->Plug(rax);
2698 void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2699 // Assignment to named property of super.
2701 // stack : receiver ('this'), home_object
2702 DCHECK(prop != NULL);
2703 Literal* key = prop->key()->AsLiteral();
2704 DCHECK(key != NULL);
2706 __ Push(key->value());
2708 __ CallRuntime((is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict
2709 : Runtime::kStoreToSuper_Sloppy),
2714 void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2715 // Assignment to named property of super.
2717 // stack : receiver ('this'), home_object, key
2718 DCHECK(prop != NULL);
2722 (is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict
2723 : Runtime::kStoreKeyedToSuper_Sloppy),
2728 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2729 // Assignment to a property, using a keyed store IC.
2731 __ Pop(StoreDescriptor::NameRegister()); // Key.
2732 __ Pop(StoreDescriptor::ReceiverRegister());
2733 DCHECK(StoreDescriptor::ValueRegister().is(rax));
2734 // Record source code position before IC call.
2735 SetSourcePosition(expr->position());
2737 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2738 CallIC(ic, expr->AssignmentFeedbackId());
2740 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2741 context()->Plug(rax);
2745 void FullCodeGenerator::VisitProperty(Property* expr) {
2746 Comment cmnt(masm_, "[ Property");
2747 Expression* key = expr->key();
2749 if (key->IsPropertyName()) {
2750 if (!expr->IsSuperAccess()) {
2751 VisitForAccumulatorValue(expr->obj());
2752 DCHECK(!rax.is(LoadDescriptor::ReceiverRegister()));
2753 __ movp(LoadDescriptor::ReceiverRegister(), rax);
2754 EmitNamedPropertyLoad(expr);
2756 VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
2757 EmitLoadHomeObject(expr->obj()->AsSuperReference());
2758 __ Push(result_register());
2759 EmitNamedSuperPropertyLoad(expr);
2762 if (!expr->IsSuperAccess()) {
2763 VisitForStackValue(expr->obj());
2764 VisitForAccumulatorValue(expr->key());
2765 __ Move(LoadDescriptor::NameRegister(), rax);
2766 __ Pop(LoadDescriptor::ReceiverRegister());
2767 EmitKeyedPropertyLoad(expr);
2769 VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
2770 EmitLoadHomeObject(expr->obj()->AsSuperReference());
2771 __ Push(result_register());
2772 VisitForStackValue(expr->key());
2773 EmitKeyedSuperPropertyLoad(expr);
2776 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
2777 context()->Plug(rax);
2781 void FullCodeGenerator::CallIC(Handle<Code> code,
2782 TypeFeedbackId ast_id) {
2784 __ call(code, RelocInfo::CODE_TARGET, ast_id);
2788 // Code common for calls using the IC.
2789 void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2790 Expression* callee = expr->expression();
2792 CallICState::CallType call_type =
2793 callee->IsVariableProxy() ? CallICState::FUNCTION : CallICState::METHOD;
2794 // Get the target function.
2795 if (call_type == CallICState::FUNCTION) {
2796 { StackValueContext context(this);
2797 EmitVariableLoad(callee->AsVariableProxy());
2798 PrepareForBailout(callee, NO_REGISTERS);
2800 // Push undefined as receiver. This is patched in the method prologue if it
2801 // is a sloppy mode method.
2802 __ Push(isolate()->factory()->undefined_value());
2804 // Load the function from the receiver.
2805 DCHECK(callee->IsProperty());
2806 DCHECK(!callee->AsProperty()->IsSuperAccess());
2807 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
2808 EmitNamedPropertyLoad(callee->AsProperty());
2809 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2810 // Push the target function under the receiver.
2811 __ Push(Operand(rsp, 0));
2812 __ movp(Operand(rsp, kPointerSize), rax);
2815 EmitCall(expr, call_type);
2819 void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2820 Expression* callee = expr->expression();
2821 DCHECK(callee->IsProperty());
2822 Property* prop = callee->AsProperty();
2823 DCHECK(prop->IsSuperAccess());
2825 SetSourcePosition(prop->position());
2826 Literal* key = prop->key()->AsLiteral();
2827 DCHECK(!key->value()->IsSmi());
2828 // Load the function from the receiver.
2829 SuperReference* super_ref = prop->obj()->AsSuperReference();
2830 EmitLoadHomeObject(super_ref);
2832 VisitForAccumulatorValue(super_ref->this_var());
2835 __ Push(Operand(rsp, kPointerSize * 2));
2836 __ Push(key->value());
2840 // - this (receiver)
2841 // - this (receiver) <-- LoadFromSuper will pop here and below.
2844 __ CallRuntime(Runtime::kLoadFromSuper, 3);
2846 // Replace home_object with target function.
2847 __ movp(Operand(rsp, kPointerSize), rax);
2850 // - target function
2851 // - this (receiver)
2852 EmitCall(expr, CallICState::METHOD);
2856 // Common code for calls using the IC.
2857 void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2860 VisitForAccumulatorValue(key);
2862 Expression* callee = expr->expression();
2864 // Load the function from the receiver.
2865 DCHECK(callee->IsProperty());
2866 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
2867 __ Move(LoadDescriptor::NameRegister(), rax);
2868 EmitKeyedPropertyLoad(callee->AsProperty());
2869 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2871 // Push the target function under the receiver.
2872 __ Push(Operand(rsp, 0));
2873 __ movp(Operand(rsp, kPointerSize), rax);
2875 EmitCall(expr, CallICState::METHOD);
2879 void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2880 Expression* callee = expr->expression();
2881 DCHECK(callee->IsProperty());
2882 Property* prop = callee->AsProperty();
2883 DCHECK(prop->IsSuperAccess());
2885 SetSourcePosition(prop->position());
2886 // Load the function from the receiver.
2887 SuperReference* super_ref = prop->obj()->AsSuperReference();
2888 EmitLoadHomeObject(super_ref);
2890 VisitForAccumulatorValue(super_ref->this_var());
2893 __ Push(Operand(rsp, kPointerSize * 2));
2894 VisitForStackValue(prop->key());
2898 // - this (receiver)
2899 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2902 __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
2904 // Replace home_object with target function.
2905 __ movp(Operand(rsp, kPointerSize), rax);
2908 // - target function
2909 // - this (receiver)
2910 EmitCall(expr, CallICState::METHOD);
2914 void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
2915 // Load the arguments.
2916 ZoneList<Expression*>* args = expr->arguments();
2917 int arg_count = args->length();
2918 { PreservePositionScope scope(masm()->positions_recorder());
2919 for (int i = 0; i < arg_count; i++) {
2920 VisitForStackValue(args->at(i));
2924 // Record source position of the IC call.
2925 SetSourcePosition(expr->position());
2926 Handle<Code> ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code();
2927 __ Move(rdx, SmiFromSlot(expr->CallFeedbackICSlot()));
2928 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
2929 // Don't assign a type feedback id to the IC, since type feedback is provided
2930 // by the vector above.
2933 RecordJSReturnSite(expr);
2935 // Restore context register.
2936 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2937 // Discard the function left on TOS.
2938 context()->DropAndPlug(1, rax);
2942 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
2943 // Push copy of the first argument or undefined if it doesn't exist.
2944 if (arg_count > 0) {
2945 __ Push(Operand(rsp, arg_count * kPointerSize));
2947 __ PushRoot(Heap::kUndefinedValueRootIndex);
2950 // Push the enclosing function.
2951 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
2953 // Push the receiver of the enclosing function and do runtime call.
2954 StackArgumentsAccessor args(rbp, info_->scope()->num_parameters());
2955 __ Push(args.GetReceiverOperand());
2957 // Push the language mode.
2958 __ Push(Smi::FromInt(language_mode()));
2960 // Push the start position of the scope the calls resides in.
2961 __ Push(Smi::FromInt(scope()->start_position()));
2963 // Do the runtime call.
2964 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
2968 void FullCodeGenerator::EmitLoadSuperConstructor() {
2969 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
2970 __ CallRuntime(Runtime::kGetPrototype, 1);
2974 void FullCodeGenerator::VisitCall(Call* expr) {
2976 // We want to verify that RecordJSReturnSite gets called on all paths
2977 // through this function. Avoid early returns.
2978 expr->return_is_recorded_ = false;
2981 Comment cmnt(masm_, "[ Call");
2982 Expression* callee = expr->expression();
2983 Call::CallType call_type = expr->GetCallType(isolate());
2985 if (call_type == Call::POSSIBLY_EVAL_CALL) {
2986 // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
2987 // to resolve the function we need to call and the receiver of the call.
2988 // Then we call the resolved function using the given arguments.
2989 ZoneList<Expression*>* args = expr->arguments();
2990 int arg_count = args->length();
2991 { PreservePositionScope pos_scope(masm()->positions_recorder());
2992 VisitForStackValue(callee);
2993 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
2995 // Push the arguments.
2996 for (int i = 0; i < arg_count; i++) {
2997 VisitForStackValue(args->at(i));
3000 // Push a copy of the function (found below the arguments) and resolve
3002 __ Push(Operand(rsp, (arg_count + 1) * kPointerSize));
3003 EmitResolvePossiblyDirectEval(arg_count);
3005 // The runtime call returns a pair of values in rax (function) and
3006 // rdx (receiver). Touch up the stack with the right values.
3007 __ movp(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
3008 __ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
3010 PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
3012 // Record source position for debugger.
3013 SetSourcePosition(expr->position());
3014 CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
3015 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
3017 RecordJSReturnSite(expr);
3018 // Restore context register.
3019 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3020 context()->DropAndPlug(1, rax);
3021 } else if (call_type == Call::GLOBAL_CALL) {
3022 EmitCallWithLoadIC(expr);
3024 } else if (call_type == Call::LOOKUP_SLOT_CALL) {
3025 // Call to a lookup slot (dynamically introduced variable).
3026 VariableProxy* proxy = callee->AsVariableProxy();
3029 { PreservePositionScope scope(masm()->positions_recorder());
3030 // Generate code for loading from variables potentially shadowed by
3031 // eval-introduced variables.
3032 EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
3035 // Call the runtime to find the function to call (returned in rax) and
3036 // the object holding it (returned in rdx).
3037 __ Push(context_register());
3038 __ Push(proxy->name());
3039 __ CallRuntime(Runtime::kLoadLookupSlot, 2);
3040 __ Push(rax); // Function.
3041 __ Push(rdx); // Receiver.
3042 PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
3044 // If fast case code has been generated, emit code to push the function
3045 // and receiver and have the slow path jump around this code.
3046 if (done.is_linked()) {
3048 __ jmp(&call, Label::kNear);
3052 // The receiver is implicitly the global receiver. Indicate this by
3053 // passing the hole to the call function stub.
3054 __ PushRoot(Heap::kUndefinedValueRootIndex);
3058 // The receiver is either the global receiver or an object found by
3061 } else if (call_type == Call::PROPERTY_CALL) {
3062 Property* property = callee->AsProperty();
3063 bool is_named_call = property->key()->IsPropertyName();
3064 if (property->IsSuperAccess()) {
3065 if (is_named_call) {
3066 EmitSuperCallWithLoadIC(expr);
3068 EmitKeyedSuperCallWithLoadIC(expr);
3072 PreservePositionScope scope(masm()->positions_recorder());
3073 VisitForStackValue(property->obj());
3075 if (is_named_call) {
3076 EmitCallWithLoadIC(expr);
3078 EmitKeyedCallWithLoadIC(expr, property->key());
3081 } else if (call_type == Call::SUPER_CALL) {
3082 EmitSuperConstructorCall(expr);
3084 DCHECK(call_type == Call::OTHER_CALL);
3085 // Call to an arbitrary expression not handled specially above.
3086 { PreservePositionScope scope(masm()->positions_recorder());
3087 VisitForStackValue(callee);
3089 __ PushRoot(Heap::kUndefinedValueRootIndex);
3090 // Emit function call.
3095 // RecordJSReturnSite should have been called.
3096 DCHECK(expr->return_is_recorded_);
3101 void FullCodeGenerator::VisitCallNew(CallNew* expr) {
3102 Comment cmnt(masm_, "[ CallNew");
3103 // According to ECMA-262, section 11.2.2, page 44, the function
3104 // expression in new calls must be evaluated before the
3107 // Push constructor on the stack. If it's not a function it's used as
3108 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
3110 DCHECK(!expr->expression()->IsSuperReference());
3111 VisitForStackValue(expr->expression());
3113 // Push the arguments ("left-to-right") on the stack.
3114 ZoneList<Expression*>* args = expr->arguments();
3115 int arg_count = args->length();
3116 for (int i = 0; i < arg_count; i++) {
3117 VisitForStackValue(args->at(i));
3120 // Call the construct call builtin that handles allocation and
3121 // constructor invocation.
3122 SetSourcePosition(expr->position());
3124 // Load function and argument count into rdi and rax.
3125 __ Set(rax, arg_count);
3126 __ movp(rdi, Operand(rsp, arg_count * kPointerSize));
3128 // Record call targets in unoptimized code, but not in the snapshot.
3129 if (FLAG_pretenuring_call_new) {
3130 EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
3131 DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
3132 expr->CallNewFeedbackSlot().ToInt() + 1);
3135 __ Move(rbx, FeedbackVector());
3136 __ Move(rdx, SmiFromSlot(expr->CallNewFeedbackSlot()));
3138 CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
3139 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
3140 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
3141 context()->Plug(rax);
3145 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
3146 if (!ValidateSuperCall(expr)) return;
3148 Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
3149 GetVar(result_register(), new_target_var);
3150 __ Push(result_register());
3152 EmitLoadSuperConstructor();
3153 __ Push(result_register());
3155 // Push the arguments ("left-to-right") on the stack.
3156 ZoneList<Expression*>* args = expr->arguments();
3157 int arg_count = args->length();
3158 for (int i = 0; i < arg_count; i++) {
3159 VisitForStackValue(args->at(i));
3162 // Call the construct call builtin that handles allocation and
3163 // constructor invocation.
3164 SetSourcePosition(expr->position());
3166 // Load function and argument count into edi and eax.
3167 __ Set(rax, arg_count);
3168 __ movp(rdi, Operand(rsp, arg_count * kPointerSize));
3170 // Record call targets in unoptimized code.
3171 if (FLAG_pretenuring_call_new) {
3173 /* TODO(dslomov): support pretenuring.
3174 EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
3175 DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
3176 expr->CallNewFeedbackSlot().ToInt() + 1);
3180 __ Move(rbx, FeedbackVector());
3181 __ Move(rdx, SmiFromSlot(expr->CallFeedbackSlot()));
3183 CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
3184 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
3188 RecordJSReturnSite(expr);
3190 SuperReference* super_ref = expr->expression()->AsSuperReference();
3191 Variable* this_var = super_ref->this_var()->var();
3192 GetVar(rcx, this_var);
3193 __ CompareRoot(rcx, Heap::kTheHoleValueRootIndex);
3194 Label uninitialized_this;
3195 __ j(equal, &uninitialized_this);
3196 __ Push(this_var->name());
3197 __ CallRuntime(Runtime::kThrowReferenceError, 1);
3198 __ bind(&uninitialized_this);
3200 EmitVariableAssignment(this_var, Token::INIT_CONST);
3201 context()->Plug(rax);
3205 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
3206 ZoneList<Expression*>* args = expr->arguments();
3207 DCHECK(args->length() == 1);
3209 VisitForAccumulatorValue(args->at(0));
3211 Label materialize_true, materialize_false;
3212 Label* if_true = NULL;
3213 Label* if_false = NULL;
3214 Label* fall_through = NULL;
3215 context()->PrepareTest(&materialize_true, &materialize_false,
3216 &if_true, &if_false, &fall_through);
3218 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3219 __ JumpIfSmi(rax, if_true);
3222 context()->Plug(if_true, if_false);
3226 void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
3227 ZoneList<Expression*>* args = expr->arguments();
3228 DCHECK(args->length() == 1);
3230 VisitForAccumulatorValue(args->at(0));
3232 Label materialize_true, materialize_false;
3233 Label* if_true = NULL;
3234 Label* if_false = NULL;
3235 Label* fall_through = NULL;
3236 context()->PrepareTest(&materialize_true, &materialize_false,
3237 &if_true, &if_false, &fall_through);
3239 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3240 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
3241 Split(non_negative_smi, if_true, if_false, fall_through);
3243 context()->Plug(if_true, if_false);
3247 void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
3248 ZoneList<Expression*>* args = expr->arguments();
3249 DCHECK(args->length() == 1);
3251 VisitForAccumulatorValue(args->at(0));
3253 Label materialize_true, materialize_false;
3254 Label* if_true = NULL;
3255 Label* if_false = NULL;
3256 Label* fall_through = NULL;
3257 context()->PrepareTest(&materialize_true, &materialize_false,
3258 &if_true, &if_false, &fall_through);
3260 __ JumpIfSmi(rax, if_false);
3261 __ CompareRoot(rax, Heap::kNullValueRootIndex);
3262 __ j(equal, if_true);
3263 __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
3264 // Undetectable objects behave like undefined when tested with typeof.
3265 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
3266 Immediate(1 << Map::kIsUndetectable));
3267 __ j(not_zero, if_false);
3268 __ movzxbp(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
3269 __ cmpp(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
3270 __ j(below, if_false);
3271 __ cmpp(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
3272 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3273 Split(below_equal, if_true, if_false, fall_through);
3275 context()->Plug(if_true, if_false);
3279 void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
3280 ZoneList<Expression*>* args = expr->arguments();
3281 DCHECK(args->length() == 1);
3283 VisitForAccumulatorValue(args->at(0));
3285 Label materialize_true, materialize_false;
3286 Label* if_true = NULL;
3287 Label* if_false = NULL;
3288 Label* fall_through = NULL;
3289 context()->PrepareTest(&materialize_true, &materialize_false,
3290 &if_true, &if_false, &fall_through);
3292 __ JumpIfSmi(rax, if_false);
3293 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
3294 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3295 Split(above_equal, if_true, if_false, fall_through);
3297 context()->Plug(if_true, if_false);
3301 void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
3302 ZoneList<Expression*>* args = expr->arguments();
3303 DCHECK(args->length() == 1);
3305 VisitForAccumulatorValue(args->at(0));
3307 Label materialize_true, materialize_false;
3308 Label* if_true = NULL;
3309 Label* if_false = NULL;
3310 Label* fall_through = NULL;
3311 context()->PrepareTest(&materialize_true, &materialize_false,
3312 &if_true, &if_false, &fall_through);
3314 __ JumpIfSmi(rax, if_false);
3315 __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
3316 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
3317 Immediate(1 << Map::kIsUndetectable));
3318 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3319 Split(not_zero, if_true, if_false, fall_through);
3321 context()->Plug(if_true, if_false);
3325 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
3326 CallRuntime* expr) {
3327 ZoneList<Expression*>* args = expr->arguments();
3328 DCHECK(args->length() == 1);
3330 VisitForAccumulatorValue(args->at(0));
3332 Label materialize_true, materialize_false, skip_lookup;
3333 Label* if_true = NULL;
3334 Label* if_false = NULL;
3335 Label* fall_through = NULL;
3336 context()->PrepareTest(&materialize_true, &materialize_false,
3337 &if_true, &if_false, &fall_through);
3339 __ AssertNotSmi(rax);
3341 // Check whether this map has already been checked to be safe for default
3343 __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
3344 __ testb(FieldOperand(rbx, Map::kBitField2Offset),
3345 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
3346 __ j(not_zero, &skip_lookup);
3348 // Check for fast case object. Generate false result for slow case object.
3349 __ movp(rcx, FieldOperand(rax, JSObject::kPropertiesOffset));
3350 __ movp(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
3351 __ CompareRoot(rcx, Heap::kHashTableMapRootIndex);
3352 __ j(equal, if_false);
3354 // Look for valueOf string in the descriptor array, and indicate false if
3355 // found. Since we omit an enumeration index check, if it is added via a
3356 // transition that shares its descriptor array, this is a false positive.
3357 Label entry, loop, done;
3359 // Skip loop if no descriptors are valid.
3360 __ NumberOfOwnDescriptors(rcx, rbx);
3361 __ cmpp(rcx, Immediate(0));
3364 __ LoadInstanceDescriptors(rbx, r8);
3365 // rbx: descriptor array.
3366 // rcx: valid entries in the descriptor array.
3367 // Calculate the end of the descriptor array.
3368 __ imulp(rcx, rcx, Immediate(DescriptorArray::kDescriptorSize));
3370 Operand(r8, rcx, times_pointer_size, DescriptorArray::kFirstOffset));
3371 // Calculate location of the first key name.
3372 __ addp(r8, Immediate(DescriptorArray::kFirstOffset));
3373 // Loop through all the keys in the descriptor array. If one of these is the
3374 // internalized string "valueOf" the result is false.
3377 __ movp(rdx, FieldOperand(r8, 0));
3378 __ Cmp(rdx, isolate()->factory()->value_of_string());
3379 __ j(equal, if_false);
3380 __ addp(r8, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
3383 __ j(not_equal, &loop);
3387 // Set the bit in the map to indicate that there is no local valueOf field.
3388 __ orp(FieldOperand(rbx, Map::kBitField2Offset),
3389 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
3391 __ bind(&skip_lookup);
3393 // If a valueOf property is not found on the object check that its
3394 // prototype is the un-modified String prototype. If not result is false.
3395 __ movp(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
3396 __ testp(rcx, Immediate(kSmiTagMask));
3397 __ j(zero, if_false);
3398 __ movp(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
3399 __ movp(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
3400 __ movp(rdx, FieldOperand(rdx, GlobalObject::kNativeContextOffset));
3402 ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
3403 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3404 Split(equal, if_true, if_false, fall_through);
3406 context()->Plug(if_true, if_false);
3410 void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
3411 ZoneList<Expression*>* args = expr->arguments();
3412 DCHECK(args->length() == 1);
3414 VisitForAccumulatorValue(args->at(0));
3416 Label materialize_true, materialize_false;
3417 Label* if_true = NULL;
3418 Label* if_false = NULL;
3419 Label* fall_through = NULL;
3420 context()->PrepareTest(&materialize_true, &materialize_false,
3421 &if_true, &if_false, &fall_through);
3423 __ JumpIfSmi(rax, if_false);
3424 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
3425 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3426 Split(equal, if_true, if_false, fall_through);
3428 context()->Plug(if_true, if_false);
3432 void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
3433 ZoneList<Expression*>* args = expr->arguments();
3434 DCHECK(args->length() == 1);
3436 VisitForAccumulatorValue(args->at(0));
3438 Label materialize_true, materialize_false;
3439 Label* if_true = NULL;
3440 Label* if_false = NULL;
3441 Label* fall_through = NULL;
3442 context()->PrepareTest(&materialize_true, &materialize_false,
3443 &if_true, &if_false, &fall_through);
3445 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
3446 __ CheckMap(rax, map, if_false, DO_SMI_CHECK);
3447 __ cmpl(FieldOperand(rax, HeapNumber::kExponentOffset),
3449 __ j(no_overflow, if_false);
3450 __ cmpl(FieldOperand(rax, HeapNumber::kMantissaOffset),
3451 Immediate(0x00000000));
3452 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3453 Split(equal, if_true, if_false, fall_through);
3455 context()->Plug(if_true, if_false);
3459 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
3460 ZoneList<Expression*>* args = expr->arguments();
3461 DCHECK(args->length() == 1);
3463 VisitForAccumulatorValue(args->at(0));
3465 Label materialize_true, materialize_false;
3466 Label* if_true = NULL;
3467 Label* if_false = NULL;
3468 Label* fall_through = NULL;
3469 context()->PrepareTest(&materialize_true, &materialize_false,
3470 &if_true, &if_false, &fall_through);
3472 __ JumpIfSmi(rax, if_false);
3473 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
3474 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3475 Split(equal, if_true, if_false, fall_through);
3477 context()->Plug(if_true, if_false);
3481 void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
3482 ZoneList<Expression*>* args = expr->arguments();
3483 DCHECK(args->length() == 1);
3485 VisitForAccumulatorValue(args->at(0));
3487 Label materialize_true, materialize_false;
3488 Label* if_true = NULL;
3489 Label* if_false = NULL;
3490 Label* fall_through = NULL;
3491 context()->PrepareTest(&materialize_true, &materialize_false,
3492 &if_true, &if_false, &fall_through);
3494 __ JumpIfSmi(rax, if_false);
3495 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
3496 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3497 Split(equal, if_true, if_false, fall_through);
3499 context()->Plug(if_true, if_false);
3503 void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
3504 ZoneList<Expression*>* args = expr->arguments();
3505 DCHECK(args->length() == 1);
3507 VisitForAccumulatorValue(args->at(0));
3509 Label materialize_true, materialize_false;
3510 Label* if_true = NULL;
3511 Label* if_false = NULL;
3512 Label* fall_through = NULL;
3513 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3514 &if_false, &fall_through);
3516 __ JumpIfSmi(rax, if_false);
3518 __ movp(map, FieldOperand(rax, HeapObject::kMapOffset));
3519 __ CmpInstanceType(map, FIRST_JS_PROXY_TYPE);
3520 __ j(less, if_false);
3521 __ CmpInstanceType(map, LAST_JS_PROXY_TYPE);
3522 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3523 Split(less_equal, if_true, if_false, fall_through);
3525 context()->Plug(if_true, if_false);
3529 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
3530 DCHECK(expr->arguments()->length() == 0);
3532 Label materialize_true, materialize_false;
3533 Label* if_true = NULL;
3534 Label* if_false = NULL;
3535 Label* fall_through = NULL;
3536 context()->PrepareTest(&materialize_true, &materialize_false,
3537 &if_true, &if_false, &fall_through);
3539 // Get the frame pointer for the calling frame.
3540 __ movp(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
3542 // Skip the arguments adaptor frame if it exists.
3543 Label check_frame_marker;
3544 __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset),
3545 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
3546 __ j(not_equal, &check_frame_marker);
3547 __ movp(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
3549 // Check the marker in the calling frame.
3550 __ bind(&check_frame_marker);
3551 __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
3552 Smi::FromInt(StackFrame::CONSTRUCT));
3553 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3554 Split(equal, if_true, if_false, fall_through);
3556 context()->Plug(if_true, if_false);
3560 void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
3561 ZoneList<Expression*>* args = expr->arguments();
3562 DCHECK(args->length() == 2);
3564 // Load the two objects into registers and perform the comparison.
3565 VisitForStackValue(args->at(0));
3566 VisitForAccumulatorValue(args->at(1));
3568 Label materialize_true, materialize_false;
3569 Label* if_true = NULL;
3570 Label* if_false = NULL;
3571 Label* fall_through = NULL;
3572 context()->PrepareTest(&materialize_true, &materialize_false,
3573 &if_true, &if_false, &fall_through);
3577 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3578 Split(equal, if_true, if_false, fall_through);
3580 context()->Plug(if_true, if_false);
3584 void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3585 ZoneList<Expression*>* args = expr->arguments();
3586 DCHECK(args->length() == 1);
3588 // ArgumentsAccessStub expects the key in rdx and the formal
3589 // parameter count in rax.
3590 VisitForAccumulatorValue(args->at(0));
3592 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
3593 ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
3595 context()->Plug(rax);
3599 void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
3600 DCHECK(expr->arguments()->length() == 0);
3603 // Get the number of formal parameters.
3604 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
3606 // Check if the calling frame is an arguments adaptor frame.
3607 __ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
3608 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
3609 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
3610 __ j(not_equal, &exit, Label::kNear);
3612 // Arguments adaptor case: Read the arguments length from the
3614 __ movp(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
3618 context()->Plug(rax);
3622 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3623 ZoneList<Expression*>* args = expr->arguments();
3624 DCHECK(args->length() == 1);
3625 Label done, null, function, non_function_constructor;
3627 VisitForAccumulatorValue(args->at(0));
3629 // If the object is a smi, we return null.
3630 __ JumpIfSmi(rax, &null);
3632 // Check that the object is a JS object but take special care of JS
3633 // functions to make sure they have 'Function' as their class.
3634 // Assume that there are only two callable types, and one of them is at
3635 // either end of the type range for JS object types. Saves extra comparisons.
3636 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
3637 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
3638 // Map is now in rax.
3640 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3641 FIRST_SPEC_OBJECT_TYPE + 1);
3642 __ j(equal, &function);
3644 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
3645 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3646 LAST_SPEC_OBJECT_TYPE - 1);
3647 __ j(equal, &function);
3648 // Assume that there is no larger type.
3649 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
3651 // Check if the constructor in the map is a JS function.
3652 __ movp(rax, FieldOperand(rax, Map::kConstructorOffset));
3653 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
3654 __ j(not_equal, &non_function_constructor);
3656 // rax now contains the constructor function. Grab the
3657 // instance class name from there.
3658 __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
3659 __ movp(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
3662 // Functions have class 'Function'.
3664 __ Move(rax, isolate()->factory()->Function_string());
3667 // Objects with a non-function constructor have class 'Object'.
3668 __ bind(&non_function_constructor);
3669 __ Move(rax, isolate()->factory()->Object_string());
3672 // Non-JS objects have class null.
3674 __ LoadRoot(rax, Heap::kNullValueRootIndex);
3679 context()->Plug(rax);
3683 void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
3684 // Load the arguments on the stack and call the stub.
3685 SubStringStub stub(isolate());
3686 ZoneList<Expression*>* args = expr->arguments();
3687 DCHECK(args->length() == 3);
3688 VisitForStackValue(args->at(0));
3689 VisitForStackValue(args->at(1));
3690 VisitForStackValue(args->at(2));
3692 context()->Plug(rax);
3696 void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
3697 // Load the arguments on the stack and call the stub.
3698 RegExpExecStub stub(isolate());
3699 ZoneList<Expression*>* args = expr->arguments();
3700 DCHECK(args->length() == 4);
3701 VisitForStackValue(args->at(0));
3702 VisitForStackValue(args->at(1));
3703 VisitForStackValue(args->at(2));
3704 VisitForStackValue(args->at(3));
3706 context()->Plug(rax);
3710 void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3711 ZoneList<Expression*>* args = expr->arguments();
3712 DCHECK(args->length() == 1);
3714 VisitForAccumulatorValue(args->at(0)); // Load the object.
3717 // If the object is a smi return the object.
3718 __ JumpIfSmi(rax, &done);
3719 // If the object is not a value type, return the object.
3720 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
3721 __ j(not_equal, &done);
3722 __ movp(rax, FieldOperand(rax, JSValue::kValueOffset));
3725 context()->Plug(rax);
3729 void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3730 ZoneList<Expression*>* args = expr->arguments();
3731 DCHECK(args->length() == 2);
3732 DCHECK_NOT_NULL(args->at(1)->AsLiteral());
3733 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
3735 VisitForAccumulatorValue(args->at(0)); // Load the object.
3737 Label runtime, done, not_date_object;
3738 Register object = rax;
3739 Register result = rax;
3740 Register scratch = rcx;
3742 __ JumpIfSmi(object, ¬_date_object);
3743 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
3744 __ j(not_equal, ¬_date_object);
3746 if (index->value() == 0) {
3747 __ movp(result, FieldOperand(object, JSDate::kValueOffset));
3750 if (index->value() < JSDate::kFirstUncachedField) {
3751 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3752 Operand stamp_operand = __ ExternalOperand(stamp);
3753 __ movp(scratch, stamp_operand);
3754 __ cmpp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
3755 __ j(not_equal, &runtime, Label::kNear);
3756 __ movp(result, FieldOperand(object, JSDate::kValueOffset +
3757 kPointerSize * index->value()));
3761 __ PrepareCallCFunction(2);
3762 __ movp(arg_reg_1, object);
3763 __ Move(arg_reg_2, index, Assembler::RelocInfoNone());
3764 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
3765 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3769 __ bind(¬_date_object);
3770 __ CallRuntime(Runtime::kThrowNotDateError, 0);
3772 context()->Plug(rax);
3776 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3777 ZoneList<Expression*>* args = expr->arguments();
3778 DCHECK_EQ(3, args->length());
3780 Register string = rax;
3781 Register index = rbx;
3782 Register value = rcx;
3784 VisitForStackValue(args->at(0)); // index
3785 VisitForStackValue(args->at(1)); // value
3786 VisitForAccumulatorValue(args->at(2)); // string
3790 if (FLAG_debug_code) {
3791 __ Check(__ CheckSmi(value), kNonSmiValue);
3792 __ Check(__ CheckSmi(index), kNonSmiValue);
3795 __ SmiToInteger32(value, value);
3796 __ SmiToInteger32(index, index);
3798 if (FLAG_debug_code) {
3799 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
3800 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
3803 __ movb(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
3805 context()->Plug(string);
3809 void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3810 ZoneList<Expression*>* args = expr->arguments();
3811 DCHECK_EQ(3, args->length());
3813 Register string = rax;
3814 Register index = rbx;
3815 Register value = rcx;
3817 VisitForStackValue(args->at(0)); // index
3818 VisitForStackValue(args->at(1)); // value
3819 VisitForAccumulatorValue(args->at(2)); // string
3823 if (FLAG_debug_code) {
3824 __ Check(__ CheckSmi(value), kNonSmiValue);
3825 __ Check(__ CheckSmi(index), kNonSmiValue);
3828 __ SmiToInteger32(value, value);
3829 __ SmiToInteger32(index, index);
3831 if (FLAG_debug_code) {
3832 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
3833 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
3836 __ movw(FieldOperand(string, index, times_2, SeqTwoByteString::kHeaderSize),
3838 context()->Plug(rax);
3842 void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
3843 // Load the arguments on the stack and call the runtime function.
3844 ZoneList<Expression*>* args = expr->arguments();
3845 DCHECK(args->length() == 2);
3846 VisitForStackValue(args->at(0));
3847 VisitForStackValue(args->at(1));
3848 MathPowStub stub(isolate(), MathPowStub::ON_STACK);
3850 context()->Plug(rax);
3854 void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3855 ZoneList<Expression*>* args = expr->arguments();
3856 DCHECK(args->length() == 2);
3858 VisitForStackValue(args->at(0)); // Load the object.
3859 VisitForAccumulatorValue(args->at(1)); // Load the value.
3860 __ Pop(rbx); // rax = value. rbx = object.
3863 // If the object is a smi, return the value.
3864 __ JumpIfSmi(rbx, &done);
3866 // If the object is not a value type, return the value.
3867 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
3868 __ j(not_equal, &done);
3871 __ movp(FieldOperand(rbx, JSValue::kValueOffset), rax);
3872 // Update the write barrier. Save the value as it will be
3873 // overwritten by the write barrier code and is needed afterward.
3875 __ RecordWriteField(rbx, JSValue::kValueOffset, rdx, rcx, kDontSaveFPRegs);
3878 context()->Plug(rax);
3882 void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3883 ZoneList<Expression*>* args = expr->arguments();
3884 DCHECK_EQ(args->length(), 1);
3886 // Load the argument into rax and call the stub.
3887 VisitForAccumulatorValue(args->at(0));
3889 NumberToStringStub stub(isolate());
3891 context()->Plug(rax);
3895 void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3896 ZoneList<Expression*>* args = expr->arguments();
3897 DCHECK(args->length() == 1);
3899 VisitForAccumulatorValue(args->at(0));
3902 StringCharFromCodeGenerator generator(rax, rbx);
3903 generator.GenerateFast(masm_);
3906 NopRuntimeCallHelper call_helper;
3907 generator.GenerateSlow(masm_, call_helper);
3910 context()->Plug(rbx);
3914 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3915 ZoneList<Expression*>* args = expr->arguments();
3916 DCHECK(args->length() == 2);
3918 VisitForStackValue(args->at(0));
3919 VisitForAccumulatorValue(args->at(1));
3921 Register object = rbx;
3922 Register index = rax;
3923 Register result = rdx;
3927 Label need_conversion;
3928 Label index_out_of_range;
3930 StringCharCodeAtGenerator generator(object,
3935 &index_out_of_range,
3936 STRING_INDEX_IS_NUMBER);
3937 generator.GenerateFast(masm_);
3940 __ bind(&index_out_of_range);
3941 // When the index is out of range, the spec requires us to return
3943 __ LoadRoot(result, Heap::kNanValueRootIndex);
3946 __ bind(&need_conversion);
3947 // Move the undefined value into the result register, which will
3948 // trigger conversion.
3949 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
3952 NopRuntimeCallHelper call_helper;
3953 generator.GenerateSlow(masm_, call_helper);
3956 context()->Plug(result);
3960 void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3961 ZoneList<Expression*>* args = expr->arguments();
3962 DCHECK(args->length() == 2);
3964 VisitForStackValue(args->at(0));
3965 VisitForAccumulatorValue(args->at(1));
3967 Register object = rbx;
3968 Register index = rax;
3969 Register scratch = rdx;
3970 Register result = rax;
3974 Label need_conversion;
3975 Label index_out_of_range;
3977 StringCharAtGenerator generator(object,
3983 &index_out_of_range,
3984 STRING_INDEX_IS_NUMBER);
3985 generator.GenerateFast(masm_);
3988 __ bind(&index_out_of_range);
3989 // When the index is out of range, the spec requires us to return
3990 // the empty string.
3991 __ LoadRoot(result, Heap::kempty_stringRootIndex);
3994 __ bind(&need_conversion);
3995 // Move smi zero into the result register, which will trigger
3997 __ Move(result, Smi::FromInt(0));
4000 NopRuntimeCallHelper call_helper;
4001 generator.GenerateSlow(masm_, call_helper);
4004 context()->Plug(result);
4008 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
4009 ZoneList<Expression*>* args = expr->arguments();
4010 DCHECK_EQ(2, args->length());
4011 VisitForStackValue(args->at(0));
4012 VisitForAccumulatorValue(args->at(1));
4015 StringAddStub stub(isolate(), STRING_ADD_CHECK_BOTH, NOT_TENURED);
4017 context()->Plug(rax);
4021 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
4022 ZoneList<Expression*>* args = expr->arguments();
4023 DCHECK_EQ(2, args->length());
4025 VisitForStackValue(args->at(0));
4026 VisitForStackValue(args->at(1));
4028 StringCompareStub stub(isolate());
4030 context()->Plug(rax);
4034 void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
4035 ZoneList<Expression*>* args = expr->arguments();
4036 DCHECK(args->length() >= 2);
4038 int arg_count = args->length() - 2; // 2 ~ receiver and function.
4039 for (int i = 0; i < arg_count + 1; i++) {
4040 VisitForStackValue(args->at(i));
4042 VisitForAccumulatorValue(args->last()); // Function.
4044 Label runtime, done;
4045 // Check for non-function argument (including proxy).
4046 __ JumpIfSmi(rax, &runtime);
4047 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
4048 __ j(not_equal, &runtime);
4050 // InvokeFunction requires the function in rdi. Move it in there.
4051 __ movp(rdi, result_register());
4052 ParameterCount count(arg_count);
4053 __ InvokeFunction(rdi, count, CALL_FUNCTION, NullCallWrapper());
4054 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
4059 __ CallRuntime(Runtime::kCall, args->length());
4062 context()->Plug(rax);
4066 void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
4067 Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
4068 GetVar(result_register(), new_target_var);
4069 __ Push(result_register());
4071 EmitLoadSuperConstructor();
4072 __ Push(result_register());
4074 // Check if the calling frame is an arguments adaptor frame.
4075 Label adaptor_frame, args_set_up, runtime;
4076 __ movp(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
4077 __ movp(rcx, Operand(rdx, StandardFrameConstants::kContextOffset));
4078 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
4079 __ j(equal, &adaptor_frame);
4080 // default constructor has no arguments, so no adaptor frame means no args.
4081 __ movp(rax, Immediate(0));
4082 __ jmp(&args_set_up);
4084 // Copy arguments from adaptor frame.
4086 __ bind(&adaptor_frame);
4087 __ movp(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
4088 __ SmiToInteger64(rcx, rcx);
4090 // Subtract 1 from arguments count, for new.target.
4091 __ subp(rcx, Immediate(1));
4093 __ leap(rdx, Operand(rdx, rcx, times_pointer_size,
4094 StandardFrameConstants::kCallerSPOffset));
4097 __ Push(Operand(rdx, -1 * kPointerSize));
4098 __ subp(rdx, Immediate(kPointerSize));
4100 __ j(not_zero, &loop);
4103 __ bind(&args_set_up);
4104 __ movp(rdi, Operand(rsp, rax, times_pointer_size, 0));
4105 __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
4107 CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
4108 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
4112 context()->Plug(result_register());
4116 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
4117 RegExpConstructResultStub stub(isolate());
4118 ZoneList<Expression*>* args = expr->arguments();
4119 DCHECK(args->length() == 3);
4120 VisitForStackValue(args->at(0));
4121 VisitForStackValue(args->at(1));
4122 VisitForAccumulatorValue(args->at(2));
4126 context()->Plug(rax);
4130 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
4131 ZoneList<Expression*>* args = expr->arguments();
4132 DCHECK_EQ(2, args->length());
4134 DCHECK_NOT_NULL(args->at(0)->AsLiteral());
4135 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
4137 Handle<FixedArray> jsfunction_result_caches(
4138 isolate()->native_context()->jsfunction_result_caches());
4139 if (jsfunction_result_caches->length() <= cache_id) {
4140 __ Abort(kAttemptToUseUndefinedCache);
4141 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
4142 context()->Plug(rax);
4146 VisitForAccumulatorValue(args->at(1));
4149 Register cache = rbx;
4151 __ movp(cache, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX));
4153 FieldOperand(cache, GlobalObject::kNativeContextOffset));
4155 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
4157 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
4159 Label done, not_found;
4160 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
4161 __ movp(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
4162 // tmp now holds finger offset as a smi.
4164 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
4165 __ cmpp(key, FieldOperand(cache,
4168 FixedArray::kHeaderSize));
4169 __ j(not_equal, ¬_found, Label::kNear);
4170 __ movp(rax, FieldOperand(cache,
4173 FixedArray::kHeaderSize + kPointerSize));
4174 __ jmp(&done, Label::kNear);
4176 __ bind(¬_found);
4177 // Call runtime to perform the lookup.
4180 __ CallRuntime(Runtime::kGetFromCache, 2);
4183 context()->Plug(rax);
4187 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
4188 ZoneList<Expression*>* args = expr->arguments();
4189 DCHECK(args->length() == 1);
4191 VisitForAccumulatorValue(args->at(0));
4193 Label materialize_true, materialize_false;
4194 Label* if_true = NULL;
4195 Label* if_false = NULL;
4196 Label* fall_through = NULL;
4197 context()->PrepareTest(&materialize_true, &materialize_false,
4198 &if_true, &if_false, &fall_through);
4200 __ testl(FieldOperand(rax, String::kHashFieldOffset),
4201 Immediate(String::kContainsCachedArrayIndexMask));
4202 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4203 __ j(zero, if_true);
4206 context()->Plug(if_true, if_false);
4210 void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
4211 ZoneList<Expression*>* args = expr->arguments();
4212 DCHECK(args->length() == 1);
4213 VisitForAccumulatorValue(args->at(0));
4215 __ AssertString(rax);
4217 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
4218 DCHECK(String::kHashShift >= kSmiTagSize);
4219 __ IndexFromHash(rax, rax);
4221 context()->Plug(rax);
4225 void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) {
4226 Label bailout, return_result, done, one_char_separator, long_separator,
4227 non_trivial_array, not_size_one_array, loop,
4228 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
4229 ZoneList<Expression*>* args = expr->arguments();
4230 DCHECK(args->length() == 2);
4231 // We will leave the separator on the stack until the end of the function.
4232 VisitForStackValue(args->at(1));
4233 // Load this to rax (= array)
4234 VisitForAccumulatorValue(args->at(0));
4235 // All aliases of the same register have disjoint lifetimes.
4236 Register array = rax;
4237 Register elements = no_reg; // Will be rax.
4239 Register index = rdx;
4241 Register string_length = rcx;
4243 Register string = rsi;
4245 Register scratch = rbx;
4247 Register array_length = rdi;
4248 Register result_pos = no_reg; // Will be rdi.
4250 Operand separator_operand = Operand(rsp, 2 * kPointerSize);
4251 Operand result_operand = Operand(rsp, 1 * kPointerSize);
4252 Operand array_length_operand = Operand(rsp, 0 * kPointerSize);
4253 // Separator operand is already pushed. Make room for the two
4254 // other stack fields, and clear the direction flag in anticipation
4255 // of calling CopyBytes.
4256 __ subp(rsp, Immediate(2 * kPointerSize));
4258 // Check that the array is a JSArray
4259 __ JumpIfSmi(array, &bailout);
4260 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
4261 __ j(not_equal, &bailout);
4263 // Check that the array has fast elements.
4264 __ CheckFastElements(scratch, &bailout);
4266 // Array has fast elements, so its length must be a smi.
4267 // If the array has length zero, return the empty string.
4268 __ movp(array_length, FieldOperand(array, JSArray::kLengthOffset));
4269 __ SmiCompare(array_length, Smi::FromInt(0));
4270 __ j(not_zero, &non_trivial_array);
4271 __ LoadRoot(rax, Heap::kempty_stringRootIndex);
4272 __ jmp(&return_result);
4274 // Save the array length on the stack.
4275 __ bind(&non_trivial_array);
4276 __ SmiToInteger32(array_length, array_length);
4277 __ movl(array_length_operand, array_length);
4279 // Save the FixedArray containing array's elements.
4280 // End of array's live range.
4282 __ movp(elements, FieldOperand(array, JSArray::kElementsOffset));
4286 // Check that all array elements are sequential one-byte strings, and
4287 // accumulate the sum of their lengths, as a smi-encoded value.
4289 __ Set(string_length, 0);
4290 // Loop condition: while (index < array_length).
4291 // Live loop registers: index(int32), array_length(int32), string(String*),
4292 // scratch, string_length(int32), elements(FixedArray*).
4293 if (generate_debug_code_) {
4294 __ cmpp(index, array_length);
4295 __ Assert(below, kNoEmptyArraysHereInEmitFastOneByteArrayJoin);
4298 __ movp(string, FieldOperand(elements,
4301 FixedArray::kHeaderSize));
4302 __ JumpIfSmi(string, &bailout);
4303 __ movp(scratch, FieldOperand(string, HeapObject::kMapOffset));
4304 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
4305 __ andb(scratch, Immediate(
4306 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
4307 __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag));
4308 __ j(not_equal, &bailout);
4309 __ AddSmiField(string_length,
4310 FieldOperand(string, SeqOneByteString::kLengthOffset));
4311 __ j(overflow, &bailout);
4313 __ cmpl(index, array_length);
4317 // string_length: Sum of string lengths.
4318 // elements: FixedArray of strings.
4319 // index: Array length.
4320 // array_length: Array length.
4322 // If array_length is 1, return elements[0], a string.
4323 __ cmpl(array_length, Immediate(1));
4324 __ j(not_equal, ¬_size_one_array);
4325 __ movp(rax, FieldOperand(elements, FixedArray::kHeaderSize));
4326 __ jmp(&return_result);
4328 __ bind(¬_size_one_array);
4330 // End of array_length live range.
4331 result_pos = array_length;
4332 array_length = no_reg;
4335 // string_length: Sum of string lengths.
4336 // elements: FixedArray of strings.
4337 // index: Array length.
4339 // Check that the separator is a sequential one-byte string.
4340 __ movp(string, separator_operand);
4341 __ JumpIfSmi(string, &bailout);
4342 __ movp(scratch, FieldOperand(string, HeapObject::kMapOffset));
4343 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
4344 __ andb(scratch, Immediate(
4345 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
4346 __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag));
4347 __ j(not_equal, &bailout);
4350 // string_length: Sum of string lengths.
4351 // elements: FixedArray of strings.
4352 // index: Array length.
4353 // string: Separator string.
4355 // Add (separator length times (array_length - 1)) to string_length.
4356 __ SmiToInteger32(scratch,
4357 FieldOperand(string, SeqOneByteString::kLengthOffset));
4359 __ imull(scratch, index);
4360 __ j(overflow, &bailout);
4361 __ addl(string_length, scratch);
4362 __ j(overflow, &bailout);
4364 // Live registers and stack values:
4365 // string_length: Total length of result string.
4366 // elements: FixedArray of strings.
4367 __ AllocateOneByteString(result_pos, string_length, scratch, index, string,
4369 __ movp(result_operand, result_pos);
4370 __ leap(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize));
4372 __ movp(string, separator_operand);
4373 __ SmiCompare(FieldOperand(string, SeqOneByteString::kLengthOffset),
4375 __ j(equal, &one_char_separator);
4376 __ j(greater, &long_separator);
4379 // Empty separator case:
4381 __ movl(scratch, array_length_operand);
4382 __ jmp(&loop_1_condition);
4383 // Loop condition: while (index < array_length).
4385 // Each iteration of the loop concatenates one string to the result.
4386 // Live values in registers:
4387 // index: which element of the elements array we are adding to the result.
4388 // result_pos: the position to which we are currently copying characters.
4389 // elements: the FixedArray of strings we are joining.
4390 // scratch: array length.
4392 // Get string = array[index].
4393 __ movp(string, FieldOperand(elements, index,
4395 FixedArray::kHeaderSize));
4396 __ SmiToInteger32(string_length,
4397 FieldOperand(string, String::kLengthOffset));
4399 FieldOperand(string, SeqOneByteString::kHeaderSize));
4400 __ CopyBytes(result_pos, string, string_length);
4402 __ bind(&loop_1_condition);
4403 __ cmpl(index, scratch);
4404 __ j(less, &loop_1); // Loop while (index < array_length).
4407 // Generic bailout code used from several places.
4409 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
4410 __ jmp(&return_result);
4413 // One-character separator case
4414 __ bind(&one_char_separator);
4415 // Get the separator one-byte character value.
4416 // Register "string" holds the separator.
4417 __ movzxbl(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize));
4419 // Jump into the loop after the code that copies the separator, so the first
4420 // element is not preceded by a separator
4421 __ jmp(&loop_2_entry);
4422 // Loop condition: while (index < length).
4424 // Each iteration of the loop concatenates one string to the result.
4425 // Live values in registers:
4426 // elements: The FixedArray of strings we are joining.
4427 // index: which element of the elements array we are adding to the result.
4428 // result_pos: the position to which we are currently copying characters.
4429 // scratch: Separator character.
4431 // Copy the separator character to the result.
4432 __ movb(Operand(result_pos, 0), scratch);
4433 __ incp(result_pos);
4435 __ bind(&loop_2_entry);
4436 // Get string = array[index].
4437 __ movp(string, FieldOperand(elements, index,
4439 FixedArray::kHeaderSize));
4440 __ SmiToInteger32(string_length,
4441 FieldOperand(string, String::kLengthOffset));
4443 FieldOperand(string, SeqOneByteString::kHeaderSize));
4444 __ CopyBytes(result_pos, string, string_length);
4446 __ cmpl(index, array_length_operand);
4447 __ j(less, &loop_2); // End while (index < length).
4451 // Long separator case (separator is more than one character).
4452 __ bind(&long_separator);
4454 // Make elements point to end of elements array, and index
4455 // count from -array_length to zero, so we don't need to maintain
4457 __ movl(index, array_length_operand);
4458 __ leap(elements, FieldOperand(elements, index, times_pointer_size,
4459 FixedArray::kHeaderSize));
4462 // Replace separator string with pointer to its first character, and
4463 // make scratch be its length.
4464 __ movp(string, separator_operand);
4465 __ SmiToInteger32(scratch,
4466 FieldOperand(string, String::kLengthOffset));
4468 FieldOperand(string, SeqOneByteString::kHeaderSize));
4469 __ movp(separator_operand, string);
4471 // Jump into the loop after the code that copies the separator, so the first
4472 // element is not preceded by a separator
4473 __ jmp(&loop_3_entry);
4474 // Loop condition: while (index < length).
4476 // Each iteration of the loop concatenates one string to the result.
4477 // Live values in registers:
4478 // index: which element of the elements array we are adding to the result.
4479 // result_pos: the position to which we are currently copying characters.
4480 // scratch: Separator length.
4481 // separator_operand (rsp[0x10]): Address of first char of separator.
4483 // Copy the separator to the result.
4484 __ movp(string, separator_operand);
4485 __ movl(string_length, scratch);
4486 __ CopyBytes(result_pos, string, string_length, 2);
4488 __ bind(&loop_3_entry);
4489 // Get string = array[index].
4490 __ movp(string, Operand(elements, index, times_pointer_size, 0));
4491 __ SmiToInteger32(string_length,
4492 FieldOperand(string, String::kLengthOffset));
4494 FieldOperand(string, SeqOneByteString::kHeaderSize));
4495 __ CopyBytes(result_pos, string, string_length);
4497 __ j(not_equal, &loop_3); // Loop while (index < 0).
4500 __ movp(rax, result_operand);
4502 __ bind(&return_result);
4503 // Drop temp values from the stack, and restore context register.
4504 __ addp(rsp, Immediate(3 * kPointerSize));
4505 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
4506 context()->Plug(rax);
4510 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
4511 DCHECK(expr->arguments()->length() == 0);
4512 ExternalReference debug_is_active =
4513 ExternalReference::debug_is_active_address(isolate());
4514 __ Move(kScratchRegister, debug_is_active);
4515 __ movzxbp(rax, Operand(kScratchRegister, 0));
4516 __ Integer32ToSmi(rax, rax);
4517 context()->Plug(rax);
4521 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
4522 if (expr->function() != NULL &&
4523 expr->function()->intrinsic_type == Runtime::INLINE) {
4524 Comment cmnt(masm_, "[ InlineRuntimeCall");
4525 EmitInlineRuntimeCall(expr);
4529 Comment cmnt(masm_, "[ CallRuntime");
4530 ZoneList<Expression*>* args = expr->arguments();
4531 int arg_count = args->length();
4533 if (expr->is_jsruntime()) {
4534 // Push the builtins object as receiver.
4535 __ movp(rax, GlobalObjectOperand());
4536 __ Push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
4538 // Load the function from the receiver.
4539 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
4540 __ Move(LoadDescriptor::NameRegister(), expr->name());
4541 if (FLAG_vector_ics) {
4542 __ Move(VectorLoadICDescriptor::SlotRegister(),
4543 SmiFromSlot(expr->CallRuntimeFeedbackSlot()));
4544 CallLoadIC(NOT_CONTEXTUAL);
4546 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
4549 // Push the target function under the receiver.
4550 __ Push(Operand(rsp, 0));
4551 __ movp(Operand(rsp, kPointerSize), rax);
4553 // Push the arguments ("left-to-right").
4554 for (int i = 0; i < arg_count; i++) {
4555 VisitForStackValue(args->at(i));
4558 // Record source position of the IC call.
4559 SetSourcePosition(expr->position());
4560 CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
4561 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
4564 // Restore context register.
4565 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
4566 context()->DropAndPlug(1, rax);
4569 // Push the arguments ("left-to-right").
4570 for (int i = 0; i < arg_count; i++) {
4571 VisitForStackValue(args->at(i));
4574 // Call the C runtime.
4575 __ CallRuntime(expr->function(), arg_count);
4576 context()->Plug(rax);
4581 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
4582 switch (expr->op()) {
4583 case Token::DELETE: {
4584 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
4585 Property* property = expr->expression()->AsProperty();
4586 VariableProxy* proxy = expr->expression()->AsVariableProxy();
4588 if (property != NULL) {
4589 VisitForStackValue(property->obj());
4590 VisitForStackValue(property->key());
4591 __ Push(Smi::FromInt(language_mode()));
4592 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4593 context()->Plug(rax);
4594 } else if (proxy != NULL) {
4595 Variable* var = proxy->var();
4596 // Delete of an unqualified identifier is disallowed in strict mode
4597 // but "delete this" is allowed.
4598 DCHECK(is_sloppy(language_mode()) || var->is_this());
4599 if (var->IsUnallocated()) {
4600 __ Push(GlobalObjectOperand());
4601 __ Push(var->name());
4602 __ Push(Smi::FromInt(SLOPPY));
4603 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4604 context()->Plug(rax);
4605 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
4606 // Result of deleting non-global variables is false. 'this' is
4607 // not really a variable, though we implement it as one. The
4608 // subexpression does not have side effects.
4609 context()->Plug(var->is_this());
4611 // Non-global variable. Call the runtime to try to delete from the
4612 // context where the variable was introduced.
4613 __ Push(context_register());
4614 __ Push(var->name());
4615 __ CallRuntime(Runtime::kDeleteLookupSlot, 2);
4616 context()->Plug(rax);
4619 // Result of deleting non-property, non-variable reference is true.
4620 // The subexpression may have side effects.
4621 VisitForEffect(expr->expression());
4622 context()->Plug(true);
4628 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
4629 VisitForEffect(expr->expression());
4630 context()->Plug(Heap::kUndefinedValueRootIndex);
4635 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
4636 if (context()->IsEffect()) {
4637 // Unary NOT has no side effects so it's only necessary to visit the
4638 // subexpression. Match the optimizing compiler by not branching.
4639 VisitForEffect(expr->expression());
4640 } else if (context()->IsTest()) {
4641 const TestContext* test = TestContext::cast(context());
4642 // The labels are swapped for the recursive call.
4643 VisitForControl(expr->expression(),
4644 test->false_label(),
4646 test->fall_through());
4647 context()->Plug(test->true_label(), test->false_label());
4649 // We handle value contexts explicitly rather than simply visiting
4650 // for control and plugging the control flow into the context,
4651 // because we need to prepare a pair of extra administrative AST ids
4652 // for the optimizing compiler.
4653 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
4654 Label materialize_true, materialize_false, done;
4655 VisitForControl(expr->expression(),
4659 __ bind(&materialize_true);
4660 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4661 if (context()->IsAccumulatorValue()) {
4662 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
4664 __ PushRoot(Heap::kTrueValueRootIndex);
4666 __ jmp(&done, Label::kNear);
4667 __ bind(&materialize_false);
4668 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4669 if (context()->IsAccumulatorValue()) {
4670 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
4672 __ PushRoot(Heap::kFalseValueRootIndex);
4679 case Token::TYPEOF: {
4680 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
4681 { StackValueContext context(this);
4682 VisitForTypeofValue(expr->expression());
4684 __ CallRuntime(Runtime::kTypeof, 1);
4685 context()->Plug(rax);
4695 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
4696 DCHECK(expr->expression()->IsValidReferenceExpression());
4698 Comment cmnt(masm_, "[ CountOperation");
4699 SetSourcePosition(expr->position());
4701 Property* prop = expr->expression()->AsProperty();
4702 LhsKind assign_type = GetAssignType(prop);
4704 // Evaluate expression and get value.
4705 if (assign_type == VARIABLE) {
4706 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
4707 AccumulatorValueContext context(this);
4708 EmitVariableLoad(expr->expression()->AsVariableProxy());
4710 // Reserve space for result of postfix operation.
4711 if (expr->is_postfix() && !context()->IsEffect()) {
4712 __ Push(Smi::FromInt(0));
4714 switch (assign_type) {
4715 case NAMED_PROPERTY: {
4716 VisitForStackValue(prop->obj());
4717 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
4718 EmitNamedPropertyLoad(prop);
4722 case NAMED_SUPER_PROPERTY: {
4723 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
4724 EmitLoadHomeObject(prop->obj()->AsSuperReference());
4725 __ Push(result_register());
4726 __ Push(MemOperand(rsp, kPointerSize));
4727 __ Push(result_register());
4728 EmitNamedSuperPropertyLoad(prop);
4732 case KEYED_SUPER_PROPERTY: {
4733 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
4734 EmitLoadHomeObject(prop->obj()->AsSuperReference());
4735 __ Push(result_register());
4736 VisitForAccumulatorValue(prop->key());
4737 __ Push(result_register());
4738 __ Push(MemOperand(rsp, 2 * kPointerSize));
4739 __ Push(MemOperand(rsp, 2 * kPointerSize));
4740 __ Push(result_register());
4741 EmitKeyedSuperPropertyLoad(prop);
4745 case KEYED_PROPERTY: {
4746 VisitForStackValue(prop->obj());
4747 VisitForStackValue(prop->key());
4748 // Leave receiver on stack
4749 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
4750 // Copy of key, needed for later store.
4751 __ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
4752 EmitKeyedPropertyLoad(prop);
4761 // We need a second deoptimization point after loading the value
4762 // in case evaluating the property load my have a side effect.
4763 if (assign_type == VARIABLE) {
4764 PrepareForBailout(expr->expression(), TOS_REG);
4766 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
4769 // Inline smi case if we are in a loop.
4770 Label done, stub_call;
4771 JumpPatchSite patch_site(masm_);
4772 if (ShouldInlineSmiCase(expr->op())) {
4774 patch_site.EmitJumpIfNotSmi(rax, &slow, Label::kNear);
4776 // Save result for postfix expressions.
4777 if (expr->is_postfix()) {
4778 if (!context()->IsEffect()) {
4779 // Save the result on the stack. If we have a named or keyed property
4780 // we store the result under the receiver that is currently on top
4782 switch (assign_type) {
4786 case NAMED_PROPERTY:
4787 __ movp(Operand(rsp, kPointerSize), rax);
4789 case NAMED_SUPER_PROPERTY:
4790 __ movp(Operand(rsp, 2 * kPointerSize), rax);
4792 case KEYED_PROPERTY:
4793 __ movp(Operand(rsp, 2 * kPointerSize), rax);
4795 case KEYED_SUPER_PROPERTY:
4796 __ movp(Operand(rsp, 3 * kPointerSize), rax);
4802 SmiOperationExecutionMode mode;
4803 mode.Add(PRESERVE_SOURCE_REGISTER);
4804 mode.Add(BAILOUT_ON_NO_OVERFLOW);
4805 if (expr->op() == Token::INC) {
4806 __ SmiAddConstant(rax, rax, Smi::FromInt(1), mode, &done, Label::kNear);
4808 __ SmiSubConstant(rax, rax, Smi::FromInt(1), mode, &done, Label::kNear);
4810 __ jmp(&stub_call, Label::kNear);
4814 ToNumberStub convert_stub(isolate());
4815 __ CallStub(&convert_stub);
4816 PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
4818 // Save result for postfix expressions.
4819 if (expr->is_postfix()) {
4820 if (!context()->IsEffect()) {
4821 // Save the result on the stack. If we have a named or keyed property
4822 // we store the result under the receiver that is currently on top
4824 switch (assign_type) {
4828 case NAMED_PROPERTY:
4829 __ movp(Operand(rsp, kPointerSize), rax);
4831 case NAMED_SUPER_PROPERTY:
4832 __ movp(Operand(rsp, 2 * kPointerSize), rax);
4834 case KEYED_PROPERTY:
4835 __ movp(Operand(rsp, 2 * kPointerSize), rax);
4837 case KEYED_SUPER_PROPERTY:
4838 __ movp(Operand(rsp, 3 * kPointerSize), rax);
4844 // Record position before stub call.
4845 SetSourcePosition(expr->position());
4847 // Call stub for +1/-1.
4848 __ bind(&stub_call);
4850 __ Move(rax, Smi::FromInt(1));
4852 CodeFactory::BinaryOpIC(isolate(), expr->binary_op()).code();
4853 CallIC(code, expr->CountBinOpFeedbackId());
4854 patch_site.EmitPatchInfo();
4857 // Store the value returned in rax.
4858 switch (assign_type) {
4860 if (expr->is_postfix()) {
4861 // Perform the assignment as if via '='.
4862 { EffectContext context(this);
4863 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4865 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4868 // For all contexts except kEffect: We have the result on
4869 // top of the stack.
4870 if (!context()->IsEffect()) {
4871 context()->PlugTOS();
4874 // Perform the assignment as if via '='.
4875 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4877 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4878 context()->Plug(rax);
4881 case NAMED_PROPERTY: {
4882 __ Move(StoreDescriptor::NameRegister(),
4883 prop->key()->AsLiteral()->value());
4884 __ Pop(StoreDescriptor::ReceiverRegister());
4885 CallStoreIC(expr->CountStoreFeedbackId());
4886 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4887 if (expr->is_postfix()) {
4888 if (!context()->IsEffect()) {
4889 context()->PlugTOS();
4892 context()->Plug(rax);
4896 case NAMED_SUPER_PROPERTY: {
4897 EmitNamedSuperPropertyStore(prop);
4898 if (expr->is_postfix()) {
4899 if (!context()->IsEffect()) {
4900 context()->PlugTOS();
4903 context()->Plug(rax);
4907 case KEYED_SUPER_PROPERTY: {
4908 EmitKeyedSuperPropertyStore(prop);
4909 if (expr->is_postfix()) {
4910 if (!context()->IsEffect()) {
4911 context()->PlugTOS();
4914 context()->Plug(rax);
4918 case KEYED_PROPERTY: {
4919 __ Pop(StoreDescriptor::NameRegister());
4920 __ Pop(StoreDescriptor::ReceiverRegister());
4922 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
4923 CallIC(ic, expr->CountStoreFeedbackId());
4924 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4925 if (expr->is_postfix()) {
4926 if (!context()->IsEffect()) {
4927 context()->PlugTOS();
4930 context()->Plug(rax);
4938 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
4939 VariableProxy* proxy = expr->AsVariableProxy();
4940 DCHECK(!context()->IsEffect());
4941 DCHECK(!context()->IsTest());
4943 if (proxy != NULL && proxy->var()->IsUnallocated()) {
4944 Comment cmnt(masm_, "[ Global variable");
4945 __ Move(LoadDescriptor::NameRegister(), proxy->name());
4946 __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
4947 if (FLAG_vector_ics) {
4948 __ Move(VectorLoadICDescriptor::SlotRegister(),
4949 SmiFromSlot(proxy->VariableFeedbackSlot()));
4951 // Use a regular load, not a contextual load, to avoid a reference
4953 CallLoadIC(NOT_CONTEXTUAL);
4954 PrepareForBailout(expr, TOS_REG);
4955 context()->Plug(rax);
4956 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
4957 Comment cmnt(masm_, "[ Lookup slot");
4960 // Generate code for loading from variables potentially shadowed
4961 // by eval-introduced variables.
4962 EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done);
4966 __ Push(proxy->name());
4967 __ CallRuntime(Runtime::kLoadLookupSlotNoReferenceError, 2);
4968 PrepareForBailout(expr, TOS_REG);
4971 context()->Plug(rax);
4973 // This expression cannot throw a reference error at the top level.
4974 VisitInDuplicateContext(expr);
4979 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
4980 Expression* sub_expr,
4981 Handle<String> check) {
4982 Label materialize_true, materialize_false;
4983 Label* if_true = NULL;
4984 Label* if_false = NULL;
4985 Label* fall_through = NULL;
4986 context()->PrepareTest(&materialize_true, &materialize_false,
4987 &if_true, &if_false, &fall_through);
4989 { AccumulatorValueContext context(this);
4990 VisitForTypeofValue(sub_expr);
4992 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4994 Factory* factory = isolate()->factory();
4995 if (String::Equals(check, factory->number_string())) {
4996 __ JumpIfSmi(rax, if_true);
4997 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset));
4998 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
4999 Split(equal, if_true, if_false, fall_through);
5000 } else if (String::Equals(check, factory->string_string())) {
5001 __ JumpIfSmi(rax, if_false);
5002 // Check for undetectable objects => false.
5003 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
5004 __ j(above_equal, if_false);
5005 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
5006 Immediate(1 << Map::kIsUndetectable));
5007 Split(zero, if_true, if_false, fall_through);
5008 } else if (String::Equals(check, factory->symbol_string())) {
5009 __ JumpIfSmi(rax, if_false);
5010 __ CmpObjectType(rax, SYMBOL_TYPE, rdx);
5011 Split(equal, if_true, if_false, fall_through);
5012 } else if (String::Equals(check, factory->boolean_string())) {
5013 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
5014 __ j(equal, if_true);
5015 __ CompareRoot(rax, Heap::kFalseValueRootIndex);
5016 Split(equal, if_true, if_false, fall_through);
5017 } else if (String::Equals(check, factory->undefined_string())) {
5018 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
5019 __ j(equal, if_true);
5020 __ JumpIfSmi(rax, if_false);
5021 // Check for undetectable objects => true.
5022 __ movp(rdx, FieldOperand(rax, HeapObject::kMapOffset));
5023 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
5024 Immediate(1 << Map::kIsUndetectable));
5025 Split(not_zero, if_true, if_false, fall_through);
5026 } else if (String::Equals(check, factory->function_string())) {
5027 __ JumpIfSmi(rax, if_false);
5028 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
5029 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx);
5030 __ j(equal, if_true);
5031 __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
5032 Split(equal, if_true, if_false, fall_through);
5033 } else if (String::Equals(check, factory->object_string())) {
5034 __ JumpIfSmi(rax, if_false);
5035 __ CompareRoot(rax, Heap::kNullValueRootIndex);
5036 __ j(equal, if_true);
5037 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
5038 __ j(below, if_false);
5039 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
5040 __ j(above, if_false);
5041 // Check for undetectable objects => false.
5042 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
5043 Immediate(1 << Map::kIsUndetectable));
5044 Split(zero, if_true, if_false, fall_through);
5046 if (if_false != fall_through) __ jmp(if_false);
5048 context()->Plug(if_true, if_false);
5052 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
5053 Comment cmnt(masm_, "[ CompareOperation");
5054 SetSourcePosition(expr->position());
5056 // First we try a fast inlined version of the compare when one of
5057 // the operands is a literal.
5058 if (TryLiteralCompare(expr)) return;
5060 // Always perform the comparison for its control flow. Pack the result
5061 // into the expression's context after the comparison is performed.
5062 Label materialize_true, materialize_false;
5063 Label* if_true = NULL;
5064 Label* if_false = NULL;
5065 Label* fall_through = NULL;
5066 context()->PrepareTest(&materialize_true, &materialize_false,
5067 &if_true, &if_false, &fall_through);
5069 Token::Value op = expr->op();
5070 VisitForStackValue(expr->left());
5073 VisitForStackValue(expr->right());
5074 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
5075 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
5076 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
5077 Split(equal, if_true, if_false, fall_through);
5080 case Token::INSTANCEOF: {
5081 VisitForStackValue(expr->right());
5082 InstanceofStub stub(isolate(), InstanceofStub::kNoFlags);
5084 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
5086 // The stub returns 0 for true.
5087 Split(zero, if_true, if_false, fall_through);
5092 VisitForAccumulatorValue(expr->right());
5093 Condition cc = CompareIC::ComputeCondition(op);
5096 bool inline_smi_code = ShouldInlineSmiCase(op);
5097 JumpPatchSite patch_site(masm_);
5098 if (inline_smi_code) {
5102 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
5104 Split(cc, if_true, if_false, NULL);
5105 __ bind(&slow_case);
5108 // Record position and call the compare IC.
5109 SetSourcePosition(expr->position());
5110 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
5111 CallIC(ic, expr->CompareOperationFeedbackId());
5112 patch_site.EmitPatchInfo();
5114 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
5116 Split(cc, if_true, if_false, fall_through);
5120 // Convert the result of the comparison into one expected for this
5121 // expression's context.
5122 context()->Plug(if_true, if_false);
5126 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
5127 Expression* sub_expr,
5129 Label materialize_true, materialize_false;
5130 Label* if_true = NULL;
5131 Label* if_false = NULL;
5132 Label* fall_through = NULL;
5133 context()->PrepareTest(&materialize_true, &materialize_false,
5134 &if_true, &if_false, &fall_through);
5136 VisitForAccumulatorValue(sub_expr);
5137 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
5138 if (expr->op() == Token::EQ_STRICT) {
5139 Heap::RootListIndex nil_value = nil == kNullValue ?
5140 Heap::kNullValueRootIndex :
5141 Heap::kUndefinedValueRootIndex;
5142 __ CompareRoot(rax, nil_value);
5143 Split(equal, if_true, if_false, fall_through);
5145 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
5146 CallIC(ic, expr->CompareOperationFeedbackId());
5148 Split(not_zero, if_true, if_false, fall_through);
5150 context()->Plug(if_true, if_false);
5154 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
5155 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
5156 context()->Plug(rax);
5160 Register FullCodeGenerator::result_register() {
5165 Register FullCodeGenerator::context_register() {
5170 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
5171 DCHECK(IsAligned(frame_offset, kPointerSize));
5172 __ movp(Operand(rbp, frame_offset), value);
5176 void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
5177 __ movp(dst, ContextOperand(rsi, context_index));
5181 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
5182 Scope* declaration_scope = scope()->DeclarationScope();
5183 if (declaration_scope->is_script_scope() ||
5184 declaration_scope->is_module_scope()) {
5185 // Contexts nested in the native context have a canonical empty function
5186 // as their closure, not the anonymous closure containing the global
5187 // code. Pass a smi sentinel and let the runtime look up the empty
5189 __ Push(Smi::FromInt(0));
5190 } else if (declaration_scope->is_eval_scope()) {
5191 // Contexts created by a call to eval have the same closure as the
5192 // context calling eval, not the anonymous closure containing the eval
5193 // code. Fetch it from the context.
5194 __ Push(ContextOperand(rsi, Context::CLOSURE_INDEX));
5196 DCHECK(declaration_scope->is_function_scope());
5197 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
5202 // ----------------------------------------------------------------------------
5203 // Non-local control flow support.
5206 void FullCodeGenerator::EnterFinallyBlock() {
5207 DCHECK(!result_register().is(rdx));
5208 DCHECK(!result_register().is(rcx));
5209 // Cook return address on top of stack (smi encoded Code* delta)
5210 __ PopReturnAddressTo(rdx);
5211 __ Move(rcx, masm_->CodeObject());
5213 __ Integer32ToSmi(rdx, rdx);
5216 // Store result register while executing finally block.
5217 __ Push(result_register());
5219 // Store pending message while executing finally block.
5220 ExternalReference pending_message_obj =
5221 ExternalReference::address_of_pending_message_obj(isolate());
5222 __ Load(rdx, pending_message_obj);
5225 ExternalReference has_pending_message =
5226 ExternalReference::address_of_has_pending_message(isolate());
5227 __ Load(rdx, has_pending_message);
5228 __ Integer32ToSmi(rdx, rdx);
5231 ExternalReference pending_message_script =
5232 ExternalReference::address_of_pending_message_script(isolate());
5233 __ Load(rdx, pending_message_script);
5238 void FullCodeGenerator::ExitFinallyBlock() {
5239 DCHECK(!result_register().is(rdx));
5240 DCHECK(!result_register().is(rcx));
5241 // Restore pending message from stack.
5243 ExternalReference pending_message_script =
5244 ExternalReference::address_of_pending_message_script(isolate());
5245 __ Store(pending_message_script, rdx);
5248 __ SmiToInteger32(rdx, rdx);
5249 ExternalReference has_pending_message =
5250 ExternalReference::address_of_has_pending_message(isolate());
5251 __ Store(has_pending_message, rdx);
5254 ExternalReference pending_message_obj =
5255 ExternalReference::address_of_pending_message_obj(isolate());
5256 __ Store(pending_message_obj, rdx);
5258 // Restore result register from stack.
5259 __ Pop(result_register());
5261 // Uncook return address.
5263 __ SmiToInteger32(rdx, rdx);
5264 __ Move(rcx, masm_->CodeObject());
5272 #define __ ACCESS_MASM(masm())
5274 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
5276 int* context_length) {
5277 // The macros used here must preserve the result register.
5279 // Because the handler block contains the context of the finally
5280 // code, we can restore it directly from there for the finally code
5281 // rather than iteratively unwinding contexts via their previous
5283 __ Drop(*stack_depth); // Down to the handler block.
5284 if (*context_length > 0) {
5285 // Restore the context to its dedicated register and the stack.
5286 __ movp(rsi, Operand(rsp, StackHandlerConstants::kContextOffset));
5287 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
5290 __ call(finally_entry_);
5293 *context_length = 0;
5301 static const byte kJnsInstruction = 0x79;
5302 static const byte kNopByteOne = 0x66;
5303 static const byte kNopByteTwo = 0x90;
5305 static const byte kCallInstruction = 0xe8;
5309 void BackEdgeTable::PatchAt(Code* unoptimized_code,
5311 BackEdgeState target_state,
5312 Code* replacement_code) {
5313 Address call_target_address = pc - kIntSize;
5314 Address jns_instr_address = call_target_address - 3;
5315 Address jns_offset_address = call_target_address - 2;
5317 switch (target_state) {
5319 // sub <profiling_counter>, <delta> ;; Not changed
5321 // call <interrupt stub>
5323 *jns_instr_address = kJnsInstruction;
5324 *jns_offset_address = kJnsOffset;
5326 case ON_STACK_REPLACEMENT:
5327 case OSR_AFTER_STACK_CHECK:
5328 // sub <profiling_counter>, <delta> ;; Not changed
5331 // call <on-stack replacment>
5333 *jns_instr_address = kNopByteOne;
5334 *jns_offset_address = kNopByteTwo;
5338 Assembler::set_target_address_at(call_target_address,
5340 replacement_code->entry());
5341 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
5342 unoptimized_code, call_target_address, replacement_code);
5346 BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
5348 Code* unoptimized_code,
5350 Address call_target_address = pc - kIntSize;
5351 Address jns_instr_address = call_target_address - 3;
5352 DCHECK_EQ(kCallInstruction, *(call_target_address - 1));
5354 if (*jns_instr_address == kJnsInstruction) {
5355 DCHECK_EQ(kJnsOffset, *(call_target_address - 2));
5356 DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(),
5357 Assembler::target_address_at(call_target_address,
5362 DCHECK_EQ(kNopByteOne, *jns_instr_address);
5363 DCHECK_EQ(kNopByteTwo, *(call_target_address - 2));
5365 if (Assembler::target_address_at(call_target_address,
5366 unoptimized_code) ==
5367 isolate->builtins()->OnStackReplacement()->entry()) {
5368 return ON_STACK_REPLACEMENT;
5371 DCHECK_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(),
5372 Assembler::target_address_at(call_target_address,
5374 return OSR_AFTER_STACK_CHECK;
5378 } } // namespace v8::internal
5380 #endif // V8_TARGET_ARCH_X64