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.
7 #include "src/code-factory.h"
8 #include "src/code-stubs.h"
9 #include "src/codegen.h"
10 #include "src/compiler.h"
11 #include "src/debug/debug.h"
12 #include "src/full-codegen/full-codegen.h"
13 #include "src/ic/ic.h"
14 #include "src/parser.h"
15 #include "src/scopes.h"
16 #include "src/x87/frames-x87.h"
21 #define __ ACCESS_MASM(masm_)
24 class JumpPatchSite BASE_EMBEDDED {
26 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
28 info_emitted_ = false;
33 DCHECK(patch_site_.is_bound() == info_emitted_);
36 void EmitJumpIfNotSmi(Register reg,
38 Label::Distance distance = Label::kFar) {
39 __ test(reg, Immediate(kSmiTagMask));
40 EmitJump(not_carry, target, distance); // Always taken before patched.
43 void EmitJumpIfSmi(Register reg,
45 Label::Distance distance = Label::kFar) {
46 __ test(reg, Immediate(kSmiTagMask));
47 EmitJump(carry, target, distance); // Never taken before patched.
50 void EmitPatchInfo() {
51 if (patch_site_.is_bound()) {
52 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
53 DCHECK(is_uint8(delta_to_patch_site));
54 __ test(eax, Immediate(delta_to_patch_site));
59 __ nop(); // Signals no inlined code.
64 // jc will be patched with jz, jnc will become jnz.
65 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
66 DCHECK(!patch_site_.is_bound() && !info_emitted_);
67 DCHECK(cc == carry || cc == not_carry);
68 __ bind(&patch_site_);
69 __ j(cc, target, distance);
72 MacroAssembler* masm_;
80 // Generate code for a JS function. On entry to the function the receiver
81 // and arguments have been pushed on the stack left to right, with the
82 // return address on top of them. The actual argument count matches the
83 // formal parameter count expected by the function.
85 // The live registers are:
86 // o edi: the JS function object being called (i.e. ourselves)
88 // o ebp: our caller's frame pointer
89 // o esp: stack pointer (pointing to return address)
91 // The function builds a JS frame. Please see JavaScriptFrameConstants in
92 // frames-x87.h for its layout.
93 void FullCodeGenerator::Generate() {
94 CompilationInfo* info = info_;
95 profiling_counter_ = isolate()->factory()->NewCell(
96 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
97 SetFunctionPosition(literal());
98 Comment cmnt(masm_, "[ function compiled by full code generator");
100 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
103 if (strlen(FLAG_stop_at) > 0 &&
104 literal()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
109 // Sloppy mode functions and builtins need to replace the receiver with the
110 // global proxy when called as functions (without an explicit receiver
112 if (info->MustReplaceUndefinedReceiverWithGlobalProxy()) {
114 // +1 for return address.
115 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
116 __ mov(ecx, Operand(esp, receiver_offset));
118 __ cmp(ecx, isolate()->factory()->undefined_value());
119 __ j(not_equal, &ok, Label::kNear);
121 __ mov(ecx, GlobalObjectOperand());
122 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalProxyOffset));
124 __ mov(Operand(esp, receiver_offset), ecx);
129 // Open a frame scope to indicate that there is a frame on the stack. The
130 // MANUAL indicates that the scope shouldn't actually generate code to set up
131 // the frame (that is done below).
132 FrameScope frame_scope(masm_, StackFrame::MANUAL);
134 info->set_prologue_offset(masm_->pc_offset());
135 __ Prologue(info->IsCodePreAgingActive());
136 info->AddNoFrameRange(0, masm_->pc_offset());
138 { Comment cmnt(masm_, "[ Allocate locals");
139 int locals_count = info->scope()->num_stack_slots();
140 // Generators allocate locals, if any, in context slots.
141 DCHECK(!IsGeneratorFunction(literal()->kind()) || locals_count == 0);
142 if (locals_count == 1) {
143 __ push(Immediate(isolate()->factory()->undefined_value()));
144 } else if (locals_count > 1) {
145 if (locals_count >= 128) {
148 __ sub(ecx, Immediate(locals_count * kPointerSize));
149 ExternalReference stack_limit =
150 ExternalReference::address_of_real_stack_limit(isolate());
151 __ cmp(ecx, Operand::StaticVariable(stack_limit));
152 __ j(above_equal, &ok, Label::kNear);
153 __ InvokeBuiltin(Context::STACK_OVERFLOW_BUILTIN_INDEX, CALL_FUNCTION);
156 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
157 const int kMaxPushes = 32;
158 if (locals_count >= kMaxPushes) {
159 int loop_iterations = locals_count / kMaxPushes;
160 __ mov(ecx, loop_iterations);
162 __ bind(&loop_header);
164 for (int i = 0; i < kMaxPushes; i++) {
168 __ j(not_zero, &loop_header, Label::kNear);
170 int remaining = locals_count % kMaxPushes;
171 // Emit the remaining pushes.
172 for (int i = 0; i < remaining; i++) {
178 bool function_in_register = true;
180 // Possibly allocate a local context.
181 if (info->scope()->num_heap_slots() > 0) {
182 Comment cmnt(masm_, "[ Allocate context");
183 bool need_write_barrier = true;
184 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
185 // Argument to NewContext is the function, which is still in edi.
186 if (info->scope()->is_script_scope()) {
188 __ Push(info->scope()->GetScopeInfo(info->isolate()));
189 __ CallRuntime(Runtime::kNewScriptContext, 2);
190 } else if (slots <= FastNewContextStub::kMaximumSlots) {
191 FastNewContextStub stub(isolate(), slots);
193 // Result of FastNewContextStub is always in new space.
194 need_write_barrier = false;
197 __ CallRuntime(Runtime::kNewFunctionContext, 1);
199 function_in_register = false;
200 // Context is returned in eax. It replaces the context passed to us.
201 // It's saved in the stack and kept live in esi.
203 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax);
205 // Copy parameters into context if necessary.
206 int num_parameters = info->scope()->num_parameters();
207 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
208 for (int i = first_parameter; i < num_parameters; i++) {
209 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
210 if (var->IsContextSlot()) {
211 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
212 (num_parameters - 1 - i) * kPointerSize;
213 // Load parameter from stack.
214 __ mov(eax, Operand(ebp, parameter_offset));
215 // Store it in the context.
216 int context_offset = Context::SlotOffset(var->index());
217 __ mov(Operand(esi, context_offset), eax);
218 // Update the write barrier. This clobbers eax and ebx.
219 if (need_write_barrier) {
220 __ RecordWriteContextSlot(esi, context_offset, eax, ebx,
222 } else if (FLAG_debug_code) {
224 __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
225 __ Abort(kExpectedNewSpaceObject);
232 // Possibly set up a local binding to the this function which is used in
233 // derived constructors with super calls.
234 Variable* this_function_var = scope()->this_function_var();
235 if (this_function_var != nullptr) {
236 Comment cmnt(masm_, "[ This function");
237 if (!function_in_register) {
238 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
239 // The write barrier clobbers register again, keep is marked as such.
241 SetVar(this_function_var, edi, ebx, edx);
244 Variable* new_target_var = scope()->new_target_var();
245 if (new_target_var != nullptr) {
246 Comment cmnt(masm_, "[ new.target");
247 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
248 Label non_adaptor_frame;
249 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
250 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
251 __ j(not_equal, &non_adaptor_frame);
252 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
254 __ bind(&non_adaptor_frame);
255 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
256 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
258 Label non_construct_frame, done;
259 __ j(not_equal, &non_construct_frame);
263 Operand(eax, ConstructFrameConstants::kOriginalConstructorOffset));
266 // Non-construct frame
267 __ bind(&non_construct_frame);
268 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
271 SetVar(new_target_var, eax, ebx, edx);
275 // Possibly allocate RestParameters
277 Variable* rest_param = scope()->rest_parameter(&rest_index);
279 Comment cmnt(masm_, "[ Allocate rest parameter array");
281 int num_parameters = info->scope()->num_parameters();
282 int offset = num_parameters * kPointerSize;
285 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
287 __ push(Immediate(Smi::FromInt(num_parameters)));
288 __ push(Immediate(Smi::FromInt(rest_index)));
289 __ push(Immediate(Smi::FromInt(language_mode())));
291 RestParamAccessStub stub(isolate());
294 SetVar(rest_param, eax, ebx, edx);
297 Variable* arguments = scope()->arguments();
298 if (arguments != NULL) {
299 // Function uses arguments object.
300 Comment cmnt(masm_, "[ Allocate arguments object");
301 if (function_in_register) {
304 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
306 // Receiver is just before the parameters on the caller's stack.
307 int num_parameters = info->scope()->num_parameters();
308 int offset = num_parameters * kPointerSize;
310 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
312 __ push(Immediate(Smi::FromInt(num_parameters)));
313 // Arguments to ArgumentsAccessStub:
314 // function, receiver address, parameter count.
315 // The stub will rewrite receiver and parameter count if the previous
316 // stack frame was an arguments adapter frame.
317 ArgumentsAccessStub::Type type;
318 if (is_strict(language_mode()) || !has_simple_parameters()) {
319 type = ArgumentsAccessStub::NEW_STRICT;
320 } else if (literal()->has_duplicate_parameters()) {
321 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW;
323 type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
326 ArgumentsAccessStub stub(isolate(), type);
329 SetVar(arguments, eax, ebx, edx);
333 __ CallRuntime(Runtime::kTraceEnter, 0);
336 // Visit the declarations and body unless there is an illegal
338 if (scope()->HasIllegalRedeclaration()) {
339 Comment cmnt(masm_, "[ Declarations");
340 scope()->VisitIllegalRedeclaration(this);
343 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
344 { Comment cmnt(masm_, "[ Declarations");
345 VisitDeclarations(scope()->declarations());
348 // Assert that the declarations do not use ICs. Otherwise the debugger
349 // won't be able to redirect a PC at an IC to the correct IC in newly
351 DCHECK_EQ(0, ic_total_count_);
353 { Comment cmnt(masm_, "[ Stack check");
354 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
356 ExternalReference stack_limit
357 = ExternalReference::address_of_stack_limit(isolate());
358 __ cmp(esp, Operand::StaticVariable(stack_limit));
359 __ j(above_equal, &ok, Label::kNear);
360 __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
364 { Comment cmnt(masm_, "[ Body");
365 DCHECK(loop_depth() == 0);
366 VisitStatements(literal()->body());
367 DCHECK(loop_depth() == 0);
371 // Always emit a 'return undefined' in case control fell off the end of
373 { Comment cmnt(masm_, "[ return <undefined>;");
374 __ mov(eax, isolate()->factory()->undefined_value());
375 EmitReturnSequence();
380 void FullCodeGenerator::ClearAccumulator() {
381 __ Move(eax, Immediate(Smi::FromInt(0)));
385 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
386 __ mov(ebx, Immediate(profiling_counter_));
387 __ sub(FieldOperand(ebx, Cell::kValueOffset),
388 Immediate(Smi::FromInt(delta)));
392 void FullCodeGenerator::EmitProfilingCounterReset() {
393 int reset_value = FLAG_interrupt_budget;
394 __ mov(ebx, Immediate(profiling_counter_));
395 __ mov(FieldOperand(ebx, Cell::kValueOffset),
396 Immediate(Smi::FromInt(reset_value)));
400 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
401 Label* back_edge_target) {
402 Comment cmnt(masm_, "[ Back edge bookkeeping");
405 DCHECK(back_edge_target->is_bound());
406 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
407 int weight = Min(kMaxBackEdgeWeight,
408 Max(1, distance / kCodeSizeMultiplier));
409 EmitProfilingCounterDecrement(weight);
410 __ j(positive, &ok, Label::kNear);
411 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
413 // Record a mapping of this PC offset to the OSR id. This is used to find
414 // the AST id from the unoptimized code in order to use it as a key into
415 // the deoptimization input data found in the optimized code.
416 RecordBackEdge(stmt->OsrEntryId());
418 EmitProfilingCounterReset();
421 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
422 // Record a mapping of the OSR id to this PC. This is used if the OSR
423 // entry becomes the target of a bailout. We don't expect it to be, but
424 // we want it to work if it is.
425 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
429 void FullCodeGenerator::EmitReturnSequence() {
430 Comment cmnt(masm_, "[ Return sequence");
431 if (return_label_.is_bound()) {
432 __ jmp(&return_label_);
434 // Common return label
435 __ bind(&return_label_);
438 __ CallRuntime(Runtime::kTraceExit, 1);
440 // Pretend that the exit is a backwards jump to the entry.
442 if (info_->ShouldSelfOptimize()) {
443 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
445 int distance = masm_->pc_offset();
446 weight = Min(kMaxBackEdgeWeight,
447 Max(1, distance / kCodeSizeMultiplier));
449 EmitProfilingCounterDecrement(weight);
451 __ j(positive, &ok, Label::kNear);
453 __ call(isolate()->builtins()->InterruptCheck(),
454 RelocInfo::CODE_TARGET);
456 EmitProfilingCounterReset();
459 SetReturnPosition(literal());
460 int no_frame_start = masm_->pc_offset();
463 int arg_count = info_->scope()->num_parameters() + 1;
464 int arguments_bytes = arg_count * kPointerSize;
465 __ Ret(arguments_bytes, ecx);
466 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
471 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
472 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
473 MemOperand operand = codegen()->VarOperand(var, result_register());
474 // Memory operands can be pushed directly.
479 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
480 UNREACHABLE(); // Not used on X87.
484 void FullCodeGenerator::AccumulatorValueContext::Plug(
485 Heap::RootListIndex index) const {
486 UNREACHABLE(); // Not used on X87.
490 void FullCodeGenerator::StackValueContext::Plug(
491 Heap::RootListIndex index) const {
492 UNREACHABLE(); // Not used on X87.
496 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
497 UNREACHABLE(); // Not used on X87.
501 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
505 void FullCodeGenerator::AccumulatorValueContext::Plug(
506 Handle<Object> lit) const {
508 __ SafeMove(result_register(), Immediate(lit));
510 __ Move(result_register(), Immediate(lit));
515 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
517 __ SafePush(Immediate(lit));
519 __ push(Immediate(lit));
524 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
525 codegen()->PrepareForBailoutBeforeSplit(condition(),
529 DCHECK(!lit->IsUndetectableObject()); // There are no undetectable literals.
530 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
531 if (false_label_ != fall_through_) __ jmp(false_label_);
532 } else if (lit->IsTrue() || lit->IsJSObject()) {
533 if (true_label_ != fall_through_) __ jmp(true_label_);
534 } else if (lit->IsString()) {
535 if (String::cast(*lit)->length() == 0) {
536 if (false_label_ != fall_through_) __ jmp(false_label_);
538 if (true_label_ != fall_through_) __ jmp(true_label_);
540 } else if (lit->IsSmi()) {
541 if (Smi::cast(*lit)->value() == 0) {
542 if (false_label_ != fall_through_) __ jmp(false_label_);
544 if (true_label_ != fall_through_) __ jmp(true_label_);
547 // For simplicity we always test the accumulator register.
548 __ mov(result_register(), lit);
549 codegen()->DoTest(this);
554 void FullCodeGenerator::EffectContext::DropAndPlug(int count,
555 Register reg) const {
561 void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
563 Register reg) const {
566 __ Move(result_register(), reg);
570 void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
571 Register reg) const {
573 if (count > 1) __ Drop(count - 1);
574 __ mov(Operand(esp, 0), reg);
578 void FullCodeGenerator::TestContext::DropAndPlug(int count,
579 Register reg) const {
581 // For simplicity we always test the accumulator register.
583 __ Move(result_register(), reg);
584 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
585 codegen()->DoTest(this);
589 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
590 Label* materialize_false) const {
591 DCHECK(materialize_true == materialize_false);
592 __ bind(materialize_true);
596 void FullCodeGenerator::AccumulatorValueContext::Plug(
597 Label* materialize_true,
598 Label* materialize_false) const {
600 __ bind(materialize_true);
601 __ mov(result_register(), isolate()->factory()->true_value());
602 __ jmp(&done, Label::kNear);
603 __ bind(materialize_false);
604 __ mov(result_register(), isolate()->factory()->false_value());
609 void FullCodeGenerator::StackValueContext::Plug(
610 Label* materialize_true,
611 Label* materialize_false) const {
613 __ bind(materialize_true);
614 __ push(Immediate(isolate()->factory()->true_value()));
615 __ jmp(&done, Label::kNear);
616 __ bind(materialize_false);
617 __ push(Immediate(isolate()->factory()->false_value()));
622 void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
623 Label* materialize_false) const {
624 DCHECK(materialize_true == true_label_);
625 DCHECK(materialize_false == false_label_);
629 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
630 Handle<Object> value = flag
631 ? isolate()->factory()->true_value()
632 : isolate()->factory()->false_value();
633 __ mov(result_register(), value);
637 void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
638 Handle<Object> value = flag
639 ? isolate()->factory()->true_value()
640 : isolate()->factory()->false_value();
641 __ push(Immediate(value));
645 void FullCodeGenerator::TestContext::Plug(bool flag) const {
646 codegen()->PrepareForBailoutBeforeSplit(condition(),
651 if (true_label_ != fall_through_) __ jmp(true_label_);
653 if (false_label_ != fall_through_) __ jmp(false_label_);
658 void FullCodeGenerator::DoTest(Expression* condition,
661 Label* fall_through) {
662 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
663 CallIC(ic, condition->test_id());
664 __ test(result_register(), result_register());
665 // The stub returns nonzero for true.
666 Split(not_zero, if_true, if_false, fall_through);
670 void FullCodeGenerator::Split(Condition cc,
673 Label* fall_through) {
674 if (if_false == fall_through) {
676 } else if (if_true == fall_through) {
677 __ j(NegateCondition(cc), if_false);
685 MemOperand FullCodeGenerator::StackOperand(Variable* var) {
686 DCHECK(var->IsStackAllocated());
687 // Offset is negative because higher indexes are at lower addresses.
688 int offset = -var->index() * kPointerSize;
689 // Adjust by a (parameter or local) base offset.
690 if (var->IsParameter()) {
691 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
693 offset += JavaScriptFrameConstants::kLocal0Offset;
695 return Operand(ebp, offset);
699 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
700 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
701 if (var->IsContextSlot()) {
702 int context_chain_length = scope()->ContextChainLength(var->scope());
703 __ LoadContext(scratch, context_chain_length);
704 return ContextOperand(scratch, var->index());
706 return StackOperand(var);
711 void FullCodeGenerator::GetVar(Register dest, Variable* var) {
712 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
713 MemOperand location = VarOperand(var, dest);
714 __ mov(dest, location);
718 void FullCodeGenerator::SetVar(Variable* var,
722 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
723 DCHECK(!scratch0.is(src));
724 DCHECK(!scratch0.is(scratch1));
725 DCHECK(!scratch1.is(src));
726 MemOperand location = VarOperand(var, scratch0);
727 __ mov(location, src);
729 // Emit the write barrier code if the location is in the heap.
730 if (var->IsContextSlot()) {
731 int offset = Context::SlotOffset(var->index());
732 DCHECK(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
733 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
738 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
739 bool should_normalize,
742 // Only prepare for bailouts before splits if we're in a test
743 // context. Otherwise, we let the Visit function deal with the
744 // preparation to avoid preparing with the same AST id twice.
745 if (!context()->IsTest()) return;
748 if (should_normalize) __ jmp(&skip, Label::kNear);
749 PrepareForBailout(expr, TOS_REG);
750 if (should_normalize) {
751 __ cmp(eax, isolate()->factory()->true_value());
752 Split(equal, if_true, if_false, NULL);
758 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
759 // The variable in the declaration always resides in the current context.
760 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
761 if (generate_debug_code_) {
762 // Check that we're not inside a with or catch context.
763 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
764 __ cmp(ebx, isolate()->factory()->with_context_map());
765 __ Check(not_equal, kDeclarationInWithContext);
766 __ cmp(ebx, isolate()->factory()->catch_context_map());
767 __ Check(not_equal, kDeclarationInCatchContext);
772 void FullCodeGenerator::VisitVariableDeclaration(
773 VariableDeclaration* declaration) {
774 // If it was not possible to allocate the variable at compile time, we
775 // need to "declare" it at runtime to make sure it actually exists in the
777 VariableProxy* proxy = declaration->proxy();
778 VariableMode mode = declaration->mode();
779 Variable* variable = proxy->var();
780 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
781 switch (variable->location()) {
782 case VariableLocation::GLOBAL:
783 case VariableLocation::UNALLOCATED:
784 globals_->Add(variable->name(), zone());
785 globals_->Add(variable->binding_needs_init()
786 ? isolate()->factory()->the_hole_value()
787 : isolate()->factory()->undefined_value(), zone());
790 case VariableLocation::PARAMETER:
791 case VariableLocation::LOCAL:
793 Comment cmnt(masm_, "[ VariableDeclaration");
794 __ mov(StackOperand(variable),
795 Immediate(isolate()->factory()->the_hole_value()));
799 case VariableLocation::CONTEXT:
801 Comment cmnt(masm_, "[ VariableDeclaration");
802 EmitDebugCheckDeclarationContext(variable);
803 __ mov(ContextOperand(esi, variable->index()),
804 Immediate(isolate()->factory()->the_hole_value()));
805 // No write barrier since the hole value is in old space.
806 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
810 case VariableLocation::LOOKUP: {
811 Comment cmnt(masm_, "[ VariableDeclaration");
812 __ push(Immediate(variable->name()));
813 // VariableDeclaration nodes are always introduced in one of four modes.
814 DCHECK(IsDeclaredVariableMode(mode));
815 // Push initial value, if any.
816 // Note: For variables we must not push an initial value (such as
817 // 'undefined') because we may have a (legal) redeclaration and we
818 // must not destroy the current value.
820 __ push(Immediate(isolate()->factory()->the_hole_value()));
822 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
824 __ CallRuntime(IsImmutableVariableMode(mode)
825 ? Runtime::kDeclareReadOnlyLookupSlot
826 : Runtime::kDeclareLookupSlot,
834 void FullCodeGenerator::VisitFunctionDeclaration(
835 FunctionDeclaration* declaration) {
836 VariableProxy* proxy = declaration->proxy();
837 Variable* variable = proxy->var();
838 switch (variable->location()) {
839 case VariableLocation::GLOBAL:
840 case VariableLocation::UNALLOCATED: {
841 globals_->Add(variable->name(), zone());
842 Handle<SharedFunctionInfo> function =
843 Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
844 // Check for stack-overflow exception.
845 if (function.is_null()) return SetStackOverflow();
846 globals_->Add(function, zone());
850 case VariableLocation::PARAMETER:
851 case VariableLocation::LOCAL: {
852 Comment cmnt(masm_, "[ FunctionDeclaration");
853 VisitForAccumulatorValue(declaration->fun());
854 __ mov(StackOperand(variable), result_register());
858 case VariableLocation::CONTEXT: {
859 Comment cmnt(masm_, "[ FunctionDeclaration");
860 EmitDebugCheckDeclarationContext(variable);
861 VisitForAccumulatorValue(declaration->fun());
862 __ mov(ContextOperand(esi, variable->index()), result_register());
863 // We know that we have written a function, which is not a smi.
864 __ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()),
865 result_register(), ecx, kDontSaveFPRegs,
866 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
867 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
871 case VariableLocation::LOOKUP: {
872 Comment cmnt(masm_, "[ FunctionDeclaration");
873 __ push(Immediate(variable->name()));
874 VisitForStackValue(declaration->fun());
875 __ CallRuntime(Runtime::kDeclareLookupSlot, 2);
882 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
883 // Call the runtime to declare the globals.
885 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
886 __ CallRuntime(Runtime::kDeclareGlobals, 2);
887 // Return value is ignored.
891 void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
892 // Call the runtime to declare the modules.
893 __ Push(descriptions);
894 __ CallRuntime(Runtime::kDeclareModules, 1);
895 // Return value is ignored.
899 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
900 Comment cmnt(masm_, "[ SwitchStatement");
901 Breakable nested_statement(this, stmt);
902 SetStatementPosition(stmt);
904 // Keep the switch value on the stack until a case matches.
905 VisitForStackValue(stmt->tag());
906 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
908 ZoneList<CaseClause*>* clauses = stmt->cases();
909 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
911 Label next_test; // Recycled for each test.
912 // Compile all the tests with branches to their bodies.
913 for (int i = 0; i < clauses->length(); i++) {
914 CaseClause* clause = clauses->at(i);
915 clause->body_target()->Unuse();
917 // The default is not a test, but remember it as final fall through.
918 if (clause->is_default()) {
919 default_clause = clause;
923 Comment cmnt(masm_, "[ Case comparison");
927 // Compile the label expression.
928 VisitForAccumulatorValue(clause->label());
930 // Perform the comparison as if via '==='.
931 __ mov(edx, Operand(esp, 0)); // Switch value.
932 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
933 JumpPatchSite patch_site(masm_);
934 if (inline_smi_code) {
938 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
941 __ j(not_equal, &next_test);
942 __ Drop(1); // Switch value is no longer needed.
943 __ jmp(clause->body_target());
947 SetExpressionPosition(clause);
948 Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
949 strength(language_mode())).code();
950 CallIC(ic, clause->CompareId());
951 patch_site.EmitPatchInfo();
954 __ jmp(&skip, Label::kNear);
955 PrepareForBailout(clause, TOS_REG);
956 __ cmp(eax, isolate()->factory()->true_value());
957 __ j(not_equal, &next_test);
959 __ jmp(clause->body_target());
963 __ j(not_equal, &next_test);
964 __ Drop(1); // Switch value is no longer needed.
965 __ jmp(clause->body_target());
968 // Discard the test value and jump to the default if present, otherwise to
969 // the end of the statement.
971 __ Drop(1); // Switch value is no longer needed.
972 if (default_clause == NULL) {
973 __ jmp(nested_statement.break_label());
975 __ jmp(default_clause->body_target());
978 // Compile all the case bodies.
979 for (int i = 0; i < clauses->length(); i++) {
980 Comment cmnt(masm_, "[ Case body");
981 CaseClause* clause = clauses->at(i);
982 __ bind(clause->body_target());
983 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
984 VisitStatements(clause->statements());
987 __ bind(nested_statement.break_label());
988 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
992 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
993 Comment cmnt(masm_, "[ ForInStatement");
994 SetStatementPosition(stmt, SKIP_BREAK);
996 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
999 ForIn loop_statement(this, stmt);
1000 increment_loop_depth();
1002 // Get the object to enumerate over. If the object is null or undefined, skip
1003 // over the loop. See ECMA-262 version 5, section 12.6.4.
1004 SetExpressionAsStatementPosition(stmt->enumerable());
1005 VisitForAccumulatorValue(stmt->enumerable());
1006 __ cmp(eax, isolate()->factory()->undefined_value());
1008 __ cmp(eax, isolate()->factory()->null_value());
1011 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1013 // Convert the object to a JS object.
1014 Label convert, done_convert;
1015 __ JumpIfSmi(eax, &convert, Label::kNear);
1016 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
1017 __ j(above_equal, &done_convert, Label::kNear);
1019 ToObjectStub stub(isolate());
1021 __ bind(&done_convert);
1022 PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
1025 // Check for proxies.
1026 Label call_runtime, use_cache, fixed_array;
1027 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1028 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
1029 __ j(below_equal, &call_runtime);
1031 // Check cache validity in generated code. This is a fast case for
1032 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1033 // guarantee cache validity, call the runtime system to check cache
1034 // validity or get the property names in a fixed array.
1035 __ CheckEnumCache(&call_runtime);
1037 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
1038 __ jmp(&use_cache, Label::kNear);
1040 // Get the set of properties to enumerate.
1041 __ bind(&call_runtime);
1043 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1044 PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
1045 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1046 isolate()->factory()->meta_map());
1047 __ j(not_equal, &fixed_array);
1050 // We got a map in register eax. Get the enumeration cache from it.
1051 Label no_descriptors;
1052 __ bind(&use_cache);
1054 __ EnumLength(edx, eax);
1055 __ cmp(edx, Immediate(Smi::FromInt(0)));
1056 __ j(equal, &no_descriptors);
1058 __ LoadInstanceDescriptors(eax, ecx);
1059 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
1060 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1062 // Set up the four remaining stack slots.
1063 __ push(eax); // Map.
1064 __ push(ecx); // Enumeration cache.
1065 __ push(edx); // Number of valid entries for the map in the enum cache.
1066 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1069 __ bind(&no_descriptors);
1070 __ add(esp, Immediate(kPointerSize));
1073 // We got a fixed array in register eax. Iterate through that.
1075 __ bind(&fixed_array);
1077 // No need for a write barrier, we are storing a Smi in the feedback vector.
1078 __ LoadHeapObject(ebx, FeedbackVector());
1079 int vector_index = FeedbackVector()->GetIndex(slot);
1080 __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(vector_index)),
1081 Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate())));
1083 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
1084 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object
1085 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1086 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx);
1087 __ j(above, &non_proxy);
1088 __ Move(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
1089 __ bind(&non_proxy);
1090 __ push(ebx); // Smi
1091 __ push(eax); // Array
1092 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
1093 __ push(eax); // Fixed array length (as smi).
1094 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1096 // Generate code for doing the condition check.
1097 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
1099 SetExpressionAsStatementPosition(stmt->each());
1101 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1102 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
1103 __ j(above_equal, loop_statement.break_label());
1105 // Get the current entry of the array into register ebx.
1106 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1107 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1109 // Get the expected map from the stack or a smi in the
1110 // permanent slow case into register edx.
1111 __ mov(edx, Operand(esp, 3 * kPointerSize));
1113 // Check if the expected map still matches that of the enumerable.
1114 // If not, we may have to filter the key.
1116 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1117 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
1118 __ j(equal, &update_each, Label::kNear);
1120 // For proxies, no filtering is done.
1121 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1122 DCHECK(Smi::FromInt(0) == 0);
1124 __ j(zero, &update_each);
1126 // Convert the entry to a string or null if it isn't a property
1127 // anymore. If the property has been removed while iterating, we
1129 __ push(ecx); // Enumerable.
1130 __ push(ebx); // Current entry.
1131 __ CallRuntime(Runtime::kForInFilter, 2);
1132 PrepareForBailoutForId(stmt->FilterId(), TOS_REG);
1133 __ cmp(eax, isolate()->factory()->undefined_value());
1134 __ j(equal, loop_statement.continue_label());
1137 // Update the 'each' property or variable from the possibly filtered
1138 // entry in register ebx.
1139 __ bind(&update_each);
1140 __ mov(result_register(), ebx);
1141 // Perform the assignment as if via '='.
1142 { EffectContext context(this);
1143 EmitAssignment(stmt->each(), stmt->EachFeedbackSlot());
1144 PrepareForBailoutForId(stmt->AssignmentId(), NO_REGISTERS);
1147 // Generate code for the body of the loop.
1148 Visit(stmt->body());
1150 // Generate code for going to the next element by incrementing the
1151 // index (smi) stored on top of the stack.
1152 __ bind(loop_statement.continue_label());
1153 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
1155 EmitBackEdgeBookkeeping(stmt, &loop);
1158 // Remove the pointers stored on the stack.
1159 __ bind(loop_statement.break_label());
1160 __ add(esp, Immediate(5 * kPointerSize));
1162 // Exit and decrement the loop depth.
1163 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1165 decrement_loop_depth();
1169 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1171 // Use the fast case closure allocation code that allocates in new
1172 // space for nested functions that don't need literals cloning. If
1173 // we're running with the --always-opt or the --prepare-always-opt
1174 // flag, we need to use the runtime function so that the new function
1175 // we are creating here gets a chance to have its code optimized and
1176 // doesn't just get a copy of the existing unoptimized code.
1177 if (!FLAG_always_opt &&
1178 !FLAG_prepare_always_opt &&
1180 scope()->is_function_scope() &&
1181 info->num_literals() == 0) {
1182 FastNewClosureStub stub(isolate(), info->language_mode(), info->kind());
1183 __ mov(ebx, Immediate(info));
1187 __ push(Immediate(info));
1188 __ push(Immediate(pretenure
1189 ? isolate()->factory()->true_value()
1190 : isolate()->factory()->false_value()));
1191 __ CallRuntime(Runtime::kNewClosure, 3);
1193 context()->Plug(eax);
1197 void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
1199 FeedbackVectorICSlot slot) {
1200 if (NeedsHomeObject(initializer)) {
1201 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1202 __ mov(StoreDescriptor::NameRegister(),
1203 Immediate(isolate()->factory()->home_object_symbol()));
1204 __ mov(StoreDescriptor::ValueRegister(),
1205 Operand(esp, offset * kPointerSize));
1206 if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
1212 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
1213 TypeofMode typeof_mode,
1215 Register context = esi;
1216 Register temp = edx;
1220 if (s->num_heap_slots() > 0) {
1221 if (s->calls_sloppy_eval()) {
1222 // Check that extension is NULL.
1223 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1225 __ j(not_equal, slow);
1227 // Load next context in chain.
1228 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1229 // Walk the rest of the chain without clobbering esi.
1232 // If no outer scope calls eval, we do not need to check more
1233 // context extensions. If we have reached an eval scope, we check
1234 // all extensions from this point.
1235 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
1236 s = s->outer_scope();
1239 if (s != NULL && s->is_eval_scope()) {
1240 // Loop up the context chain. There is no frame effect so it is
1241 // safe to use raw labels here.
1243 if (!context.is(temp)) {
1244 __ mov(temp, context);
1247 // Terminate at native context.
1248 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
1249 Immediate(isolate()->factory()->native_context_map()));
1250 __ j(equal, &fast, Label::kNear);
1251 // Check that extension is NULL.
1252 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1253 __ j(not_equal, slow);
1254 // Load next context in chain.
1255 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
1260 // All extension objects were empty and it is safe to use a normal global
1262 EmitGlobalVariableLoad(proxy, typeof_mode);
1266 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1268 DCHECK(var->IsContextSlot());
1269 Register context = esi;
1270 Register temp = ebx;
1272 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1273 if (s->num_heap_slots() > 0) {
1274 if (s->calls_sloppy_eval()) {
1275 // Check that extension is NULL.
1276 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1278 __ j(not_equal, slow);
1280 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1281 // Walk the rest of the chain without clobbering esi.
1285 // Check that last extension is NULL.
1286 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1287 __ j(not_equal, slow);
1289 // This function is used only for loads, not stores, so it's safe to
1290 // return an esi-based operand (the write barrier cannot be allowed to
1291 // destroy the esi register).
1292 return ContextOperand(context, var->index());
1296 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
1297 TypeofMode typeof_mode,
1298 Label* slow, Label* done) {
1299 // Generate fast-case code for variables that might be shadowed by
1300 // eval-introduced variables. Eval is used a lot without
1301 // introducing variables. In those cases, we do not want to
1302 // perform a runtime call for all variables in the scope
1303 // containing the eval.
1304 Variable* var = proxy->var();
1305 if (var->mode() == DYNAMIC_GLOBAL) {
1306 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow);
1308 } else if (var->mode() == DYNAMIC_LOCAL) {
1309 Variable* local = var->local_if_not_shadowed();
1310 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
1311 if (local->mode() == LET || local->mode() == CONST ||
1312 local->mode() == CONST_LEGACY) {
1313 __ cmp(eax, isolate()->factory()->the_hole_value());
1314 __ j(not_equal, done);
1315 if (local->mode() == CONST_LEGACY) {
1316 __ mov(eax, isolate()->factory()->undefined_value());
1317 } else { // LET || CONST
1318 __ push(Immediate(var->name()));
1319 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1327 void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
1328 TypeofMode typeof_mode) {
1329 Variable* var = proxy->var();
1330 DCHECK(var->IsUnallocatedOrGlobalSlot() ||
1331 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
1332 if (var->IsGlobalSlot()) {
1333 DCHECK(var->index() > 0);
1334 DCHECK(var->IsStaticGlobalObjectProperty());
1335 int const slot = var->index();
1336 int const depth = scope()->ContextChainLength(var->scope());
1337 if (depth <= LoadGlobalViaContextStub::kMaximumDepth) {
1338 __ Move(LoadGlobalViaContextDescriptor::SlotRegister(), Immediate(slot));
1339 LoadGlobalViaContextStub stub(isolate(), depth);
1342 __ Push(Smi::FromInt(slot));
1343 __ CallRuntime(Runtime::kLoadGlobalViaContext, 1);
1347 __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
1348 __ mov(LoadDescriptor::NameRegister(), var->name());
1349 __ mov(LoadDescriptor::SlotRegister(),
1350 Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
1351 CallLoadIC(typeof_mode);
1356 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
1357 TypeofMode typeof_mode) {
1358 SetExpressionPosition(proxy);
1359 PrepareForBailoutForId(proxy->BeforeId(), NO_REGISTERS);
1360 Variable* var = proxy->var();
1362 // Three cases: global variables, lookup variables, and all other types of
1364 switch (var->location()) {
1365 case VariableLocation::GLOBAL:
1366 case VariableLocation::UNALLOCATED: {
1367 Comment cmnt(masm_, "[ Global variable");
1368 EmitGlobalVariableLoad(proxy, typeof_mode);
1369 context()->Plug(eax);
1373 case VariableLocation::PARAMETER:
1374 case VariableLocation::LOCAL:
1375 case VariableLocation::CONTEXT: {
1376 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
1377 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1378 : "[ Stack variable");
1379 if (var->binding_needs_init()) {
1380 // var->scope() may be NULL when the proxy is located in eval code and
1381 // refers to a potential outside binding. Currently those bindings are
1382 // always looked up dynamically, i.e. in that case
1383 // var->location() == LOOKUP.
1385 DCHECK(var->scope() != NULL);
1387 // Check if the binding really needs an initialization check. The check
1388 // can be skipped in the following situation: we have a LET or CONST
1389 // binding in harmony mode, both the Variable and the VariableProxy have
1390 // the same declaration scope (i.e. they are both in global code, in the
1391 // same function or in the same eval code) and the VariableProxy is in
1392 // the source physically located after the initializer of the variable.
1394 // We cannot skip any initialization checks for CONST in non-harmony
1395 // mode because const variables may be declared but never initialized:
1396 // if (false) { const x; }; var y = x;
1398 // The condition on the declaration scopes is a conservative check for
1399 // nested functions that access a binding and are called before the
1400 // binding is initialized:
1401 // function() { f(); let x = 1; function f() { x = 2; } }
1403 bool skip_init_check;
1404 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1405 skip_init_check = false;
1406 } else if (var->is_this()) {
1407 CHECK(info_->has_literal() &&
1408 (info_->literal()->kind() & kSubclassConstructor) != 0);
1409 // TODO(dslomov): implement 'this' hole check elimination.
1410 skip_init_check = false;
1412 // Check that we always have valid source position.
1413 DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
1414 DCHECK(proxy->position() != RelocInfo::kNoPosition);
1415 skip_init_check = var->mode() != CONST_LEGACY &&
1416 var->initializer_position() < proxy->position();
1419 if (!skip_init_check) {
1420 // Let and const need a read barrier.
1423 __ cmp(eax, isolate()->factory()->the_hole_value());
1424 __ j(not_equal, &done, Label::kNear);
1425 if (var->mode() == LET || var->mode() == CONST) {
1426 // Throw a reference error when using an uninitialized let/const
1427 // binding in harmony mode.
1428 __ push(Immediate(var->name()));
1429 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1431 // Uninitalized const bindings outside of harmony mode are unholed.
1432 DCHECK(var->mode() == CONST_LEGACY);
1433 __ mov(eax, isolate()->factory()->undefined_value());
1436 context()->Plug(eax);
1440 context()->Plug(var);
1444 case VariableLocation::LOOKUP: {
1445 Comment cmnt(masm_, "[ Lookup variable");
1447 // Generate code for loading from variables potentially shadowed
1448 // by eval-introduced variables.
1449 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done);
1451 __ push(esi); // Context.
1452 __ push(Immediate(var->name()));
1453 Runtime::FunctionId function_id =
1454 typeof_mode == NOT_INSIDE_TYPEOF
1455 ? Runtime::kLoadLookupSlot
1456 : Runtime::kLoadLookupSlotNoReferenceError;
1457 __ CallRuntime(function_id, 2);
1459 context()->Plug(eax);
1466 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1467 Comment cmnt(masm_, "[ RegExpLiteral");
1469 // Registers will be used as follows:
1470 // edi = JS function.
1471 // ecx = literals array.
1472 // ebx = regexp literal.
1473 // eax = regexp literal clone.
1474 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1475 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
1476 int literal_offset =
1477 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
1478 __ mov(ebx, FieldOperand(ecx, literal_offset));
1479 __ cmp(ebx, isolate()->factory()->undefined_value());
1480 __ j(not_equal, &materialized, Label::kNear);
1482 // Create regexp literal using runtime function
1483 // Result will be in eax.
1485 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1486 __ push(Immediate(expr->pattern()));
1487 __ push(Immediate(expr->flags()));
1488 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
1491 __ bind(&materialized);
1492 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1493 Label allocated, runtime_allocate;
1494 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1497 __ bind(&runtime_allocate);
1499 __ push(Immediate(Smi::FromInt(size)));
1500 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1503 __ bind(&allocated);
1504 // Copy the content into the newly allocated memory.
1505 // (Unroll copy loop once for better throughput).
1506 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1507 __ mov(edx, FieldOperand(ebx, i));
1508 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1509 __ mov(FieldOperand(eax, i), edx);
1510 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1512 if ((size % (2 * kPointerSize)) != 0) {
1513 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1514 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1516 context()->Plug(eax);
1520 void FullCodeGenerator::EmitAccessor(Expression* expression) {
1521 if (expression == NULL) {
1522 __ push(Immediate(isolate()->factory()->null_value()));
1524 VisitForStackValue(expression);
1529 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1530 Comment cmnt(masm_, "[ ObjectLiteral");
1532 Handle<FixedArray> constant_properties = expr->constant_properties();
1533 int flags = expr->ComputeFlags();
1534 // If any of the keys would store to the elements array, then we shouldn't
1536 if (MustCreateObjectLiteralWithRuntime(expr)) {
1537 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1538 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1539 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1540 __ push(Immediate(constant_properties));
1541 __ push(Immediate(Smi::FromInt(flags)));
1542 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
1544 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1545 __ mov(eax, FieldOperand(edi, JSFunction::kLiteralsOffset));
1546 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1547 __ mov(ecx, Immediate(constant_properties));
1548 __ mov(edx, Immediate(Smi::FromInt(flags)));
1549 FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
1552 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
1554 // If result_saved is true the result is on top of the stack. If
1555 // result_saved is false the result is in eax.
1556 bool result_saved = false;
1558 AccessorTable accessor_table(zone());
1559 int property_index = 0;
1560 // store_slot_index points to the vector IC slot for the next store IC used.
1561 // ObjectLiteral::ComputeFeedbackRequirements controls the allocation of slots
1562 // and must be updated if the number of store ICs emitted here changes.
1563 int store_slot_index = 0;
1564 for (; property_index < expr->properties()->length(); property_index++) {
1565 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1566 if (property->is_computed_name()) break;
1567 if (property->IsCompileTimeValue()) continue;
1569 Literal* key = property->key()->AsLiteral();
1570 Expression* value = property->value();
1571 if (!result_saved) {
1572 __ push(eax); // Save result on the stack
1573 result_saved = true;
1575 switch (property->kind()) {
1576 case ObjectLiteral::Property::CONSTANT:
1578 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1579 DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
1581 case ObjectLiteral::Property::COMPUTED:
1582 // It is safe to use [[Put]] here because the boilerplate already
1583 // contains computed properties with an uninitialized value.
1584 if (key->value()->IsInternalizedString()) {
1585 if (property->emit_store()) {
1586 VisitForAccumulatorValue(value);
1587 DCHECK(StoreDescriptor::ValueRegister().is(eax));
1588 __ mov(StoreDescriptor::NameRegister(), Immediate(key->value()));
1589 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1590 if (FLAG_vector_stores) {
1591 EmitLoadStoreICSlot(expr->GetNthSlot(store_slot_index++));
1594 CallStoreIC(key->LiteralFeedbackId());
1596 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1598 if (NeedsHomeObject(value)) {
1599 __ mov(StoreDescriptor::ReceiverRegister(), eax);
1600 __ mov(StoreDescriptor::NameRegister(),
1601 Immediate(isolate()->factory()->home_object_symbol()));
1602 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, 0));
1603 if (FLAG_vector_stores) {
1604 EmitLoadStoreICSlot(expr->GetNthSlot(store_slot_index++));
1609 VisitForEffect(value);
1613 __ push(Operand(esp, 0)); // Duplicate receiver.
1614 VisitForStackValue(key);
1615 VisitForStackValue(value);
1616 if (property->emit_store()) {
1617 EmitSetHomeObjectIfNeeded(
1618 value, 2, expr->SlotForHomeObject(value, &store_slot_index));
1619 __ push(Immediate(Smi::FromInt(SLOPPY))); // Language mode
1620 __ CallRuntime(Runtime::kSetProperty, 4);
1625 case ObjectLiteral::Property::PROTOTYPE:
1626 __ push(Operand(esp, 0)); // Duplicate receiver.
1627 VisitForStackValue(value);
1628 DCHECK(property->emit_store());
1629 __ CallRuntime(Runtime::kInternalSetPrototype, 2);
1631 case ObjectLiteral::Property::GETTER:
1632 if (property->emit_store()) {
1633 accessor_table.lookup(key)->second->getter = value;
1636 case ObjectLiteral::Property::SETTER:
1637 if (property->emit_store()) {
1638 accessor_table.lookup(key)->second->setter = value;
1644 // Emit code to define accessors, using only a single call to the runtime for
1645 // each pair of corresponding getters and setters.
1646 for (AccessorTable::Iterator it = accessor_table.begin();
1647 it != accessor_table.end();
1649 __ push(Operand(esp, 0)); // Duplicate receiver.
1650 VisitForStackValue(it->first);
1651 EmitAccessor(it->second->getter);
1652 EmitSetHomeObjectIfNeeded(
1653 it->second->getter, 2,
1654 expr->SlotForHomeObject(it->second->getter, &store_slot_index));
1656 EmitAccessor(it->second->setter);
1657 EmitSetHomeObjectIfNeeded(
1658 it->second->setter, 3,
1659 expr->SlotForHomeObject(it->second->setter, &store_slot_index));
1661 __ push(Immediate(Smi::FromInt(NONE)));
1662 __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
1665 // Object literals have two parts. The "static" part on the left contains no
1666 // computed property names, and so we can compute its map ahead of time; see
1667 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
1668 // starts with the first computed property name, and continues with all
1669 // properties to its right. All the code from above initializes the static
1670 // component of the object literal, and arranges for the map of the result to
1671 // reflect the static order in which the keys appear. For the dynamic
1672 // properties, we compile them into a series of "SetOwnProperty" runtime
1673 // calls. This will preserve insertion order.
1674 for (; property_index < expr->properties()->length(); property_index++) {
1675 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1677 Expression* value = property->value();
1678 if (!result_saved) {
1679 __ push(eax); // Save result on the stack
1680 result_saved = true;
1683 __ push(Operand(esp, 0)); // Duplicate receiver.
1685 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1686 DCHECK(!property->is_computed_name());
1687 VisitForStackValue(value);
1688 DCHECK(property->emit_store());
1689 __ CallRuntime(Runtime::kInternalSetPrototype, 2);
1691 EmitPropertyKey(property, expr->GetIdForProperty(property_index));
1692 VisitForStackValue(value);
1693 EmitSetHomeObjectIfNeeded(
1694 value, 2, expr->SlotForHomeObject(value, &store_slot_index));
1696 switch (property->kind()) {
1697 case ObjectLiteral::Property::CONSTANT:
1698 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1699 case ObjectLiteral::Property::COMPUTED:
1700 if (property->emit_store()) {
1701 __ push(Immediate(Smi::FromInt(NONE)));
1702 __ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
1708 case ObjectLiteral::Property::PROTOTYPE:
1712 case ObjectLiteral::Property::GETTER:
1713 __ push(Immediate(Smi::FromInt(NONE)));
1714 __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 4);
1717 case ObjectLiteral::Property::SETTER:
1718 __ push(Immediate(Smi::FromInt(NONE)));
1719 __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 4);
1725 if (expr->has_function()) {
1726 DCHECK(result_saved);
1727 __ push(Operand(esp, 0));
1728 __ CallRuntime(Runtime::kToFastProperties, 1);
1732 context()->PlugTOS();
1734 context()->Plug(eax);
1737 // Verify that compilation exactly consumed the number of store ic slots that
1738 // the ObjectLiteral node had to offer.
1739 DCHECK(!FLAG_vector_stores || store_slot_index == expr->slot_count());
1743 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1744 Comment cmnt(masm_, "[ ArrayLiteral");
1746 expr->BuildConstantElements(isolate());
1747 Handle<FixedArray> constant_elements = expr->constant_elements();
1748 bool has_constant_fast_elements =
1749 IsFastObjectElementsKind(expr->constant_elements_kind());
1751 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1752 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1753 // If the only customer of allocation sites is transitioning, then
1754 // we can turn it off if we don't have anywhere else to transition to.
1755 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1758 if (MustCreateArrayLiteralWithRuntime(expr)) {
1759 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1760 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1761 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1762 __ push(Immediate(constant_elements));
1763 __ push(Immediate(Smi::FromInt(expr->ComputeFlags())));
1764 __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
1766 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1767 __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
1768 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1769 __ mov(ecx, Immediate(constant_elements));
1770 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
1773 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
1775 bool result_saved = false; // Is the result saved to the stack?
1776 ZoneList<Expression*>* subexprs = expr->values();
1777 int length = subexprs->length();
1779 // Emit code to evaluate all the non-constant subexpressions and to store
1780 // them into the newly cloned array.
1781 int array_index = 0;
1782 for (; array_index < length; array_index++) {
1783 Expression* subexpr = subexprs->at(array_index);
1784 if (subexpr->IsSpread()) break;
1786 // If the subexpression is a literal or a simple materialized literal it
1787 // is already set in the cloned array.
1788 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1790 if (!result_saved) {
1791 __ push(eax); // array literal.
1792 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1793 result_saved = true;
1795 VisitForAccumulatorValue(subexpr);
1797 if (has_constant_fast_elements) {
1798 // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
1799 // cannot transition and don't need to call the runtime stub.
1800 int offset = FixedArray::kHeaderSize + (array_index * kPointerSize);
1801 __ mov(ebx, Operand(esp, kPointerSize)); // Copy of array literal.
1802 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1803 // Store the subexpression value in the array's elements.
1804 __ mov(FieldOperand(ebx, offset), result_register());
1805 // Update the write barrier for the array store.
1806 __ RecordWriteField(ebx, offset, result_register(), ecx, kDontSaveFPRegs,
1807 EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
1809 // Store the subexpression value in the array's elements.
1810 __ mov(ecx, Immediate(Smi::FromInt(array_index)));
1811 StoreArrayLiteralElementStub stub(isolate());
1815 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS);
1818 // In case the array literal contains spread expressions it has two parts. The
1819 // first part is the "static" array which has a literal index is handled
1820 // above. The second part is the part after the first spread expression
1821 // (inclusive) and these elements gets appended to the array. Note that the
1822 // number elements an iterable produces is unknown ahead of time.
1823 if (array_index < length && result_saved) {
1824 __ Drop(1); // literal index
1826 result_saved = false;
1828 for (; array_index < length; array_index++) {
1829 Expression* subexpr = subexprs->at(array_index);
1832 if (subexpr->IsSpread()) {
1833 VisitForStackValue(subexpr->AsSpread()->expression());
1834 __ InvokeBuiltin(Context::CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX,
1837 VisitForStackValue(subexpr);
1838 __ CallRuntime(Runtime::kAppendElement, 2);
1841 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS);
1845 __ Drop(1); // literal index
1846 context()->PlugTOS();
1848 context()->Plug(eax);
1853 void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1854 DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
1856 Comment cmnt(masm_, "[ Assignment");
1857 SetExpressionPosition(expr, INSERT_BREAK);
1859 Property* property = expr->target()->AsProperty();
1860 LhsKind assign_type = Property::GetAssignType(property);
1862 // Evaluate LHS expression.
1863 switch (assign_type) {
1865 // Nothing to do here.
1867 case NAMED_SUPER_PROPERTY:
1869 property->obj()->AsSuperPropertyReference()->this_var());
1870 VisitForAccumulatorValue(
1871 property->obj()->AsSuperPropertyReference()->home_object());
1872 __ push(result_register());
1873 if (expr->is_compound()) {
1874 __ push(MemOperand(esp, kPointerSize));
1875 __ push(result_register());
1878 case NAMED_PROPERTY:
1879 if (expr->is_compound()) {
1880 // We need the receiver both on the stack and in the register.
1881 VisitForStackValue(property->obj());
1882 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
1884 VisitForStackValue(property->obj());
1887 case KEYED_SUPER_PROPERTY:
1889 property->obj()->AsSuperPropertyReference()->this_var());
1891 property->obj()->AsSuperPropertyReference()->home_object());
1892 VisitForAccumulatorValue(property->key());
1893 __ Push(result_register());
1894 if (expr->is_compound()) {
1895 __ push(MemOperand(esp, 2 * kPointerSize));
1896 __ push(MemOperand(esp, 2 * kPointerSize));
1897 __ push(result_register());
1900 case KEYED_PROPERTY: {
1901 if (expr->is_compound()) {
1902 VisitForStackValue(property->obj());
1903 VisitForStackValue(property->key());
1904 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, kPointerSize));
1905 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0));
1907 VisitForStackValue(property->obj());
1908 VisitForStackValue(property->key());
1914 // For compound assignments we need another deoptimization point after the
1915 // variable/property load.
1916 if (expr->is_compound()) {
1917 AccumulatorValueContext result_context(this);
1918 { AccumulatorValueContext left_operand_context(this);
1919 switch (assign_type) {
1921 EmitVariableLoad(expr->target()->AsVariableProxy());
1922 PrepareForBailout(expr->target(), TOS_REG);
1924 case NAMED_SUPER_PROPERTY:
1925 EmitNamedSuperPropertyLoad(property);
1926 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1928 case NAMED_PROPERTY:
1929 EmitNamedPropertyLoad(property);
1930 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1932 case KEYED_SUPER_PROPERTY:
1933 EmitKeyedSuperPropertyLoad(property);
1934 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1936 case KEYED_PROPERTY:
1937 EmitKeyedPropertyLoad(property);
1938 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1943 Token::Value op = expr->binary_op();
1944 __ push(eax); // Left operand goes on the stack.
1945 VisitForAccumulatorValue(expr->value());
1947 if (ShouldInlineSmiCase(op)) {
1948 EmitInlineSmiBinaryOp(expr->binary_operation(),
1953 EmitBinaryOp(expr->binary_operation(), op);
1956 // Deoptimization point in case the binary operation may have side effects.
1957 PrepareForBailout(expr->binary_operation(), TOS_REG);
1959 VisitForAccumulatorValue(expr->value());
1962 SetExpressionPosition(expr);
1965 switch (assign_type) {
1967 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1968 expr->op(), expr->AssignmentSlot());
1969 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1970 context()->Plug(eax);
1972 case NAMED_PROPERTY:
1973 EmitNamedPropertyAssignment(expr);
1975 case NAMED_SUPER_PROPERTY:
1976 EmitNamedSuperPropertyStore(property);
1977 context()->Plug(result_register());
1979 case KEYED_SUPER_PROPERTY:
1980 EmitKeyedSuperPropertyStore(property);
1981 context()->Plug(result_register());
1983 case KEYED_PROPERTY:
1984 EmitKeyedPropertyAssignment(expr);
1990 void FullCodeGenerator::VisitYield(Yield* expr) {
1991 Comment cmnt(masm_, "[ Yield");
1992 SetExpressionPosition(expr);
1994 // Evaluate yielded value first; the initial iterator definition depends on
1995 // this. It stays on the stack while we update the iterator.
1996 VisitForStackValue(expr->expression());
1998 switch (expr->yield_kind()) {
1999 case Yield::kSuspend:
2000 // Pop value from top-of-stack slot; box result into result register.
2001 EmitCreateIteratorResult(false);
2002 __ push(result_register());
2004 case Yield::kInitial: {
2005 Label suspend, continuation, post_runtime, resume;
2008 __ bind(&continuation);
2009 __ RecordGeneratorContinuation();
2013 VisitForAccumulatorValue(expr->generator_object());
2014 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
2015 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
2016 Immediate(Smi::FromInt(continuation.pos())));
2017 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
2019 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
2021 __ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
2023 __ j(equal, &post_runtime);
2024 __ push(eax); // generator object
2025 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
2026 __ mov(context_register(),
2027 Operand(ebp, StandardFrameConstants::kContextOffset));
2028 __ bind(&post_runtime);
2029 __ pop(result_register());
2030 EmitReturnSequence();
2033 context()->Plug(result_register());
2037 case Yield::kFinal: {
2038 VisitForAccumulatorValue(expr->generator_object());
2039 __ mov(FieldOperand(result_register(),
2040 JSGeneratorObject::kContinuationOffset),
2041 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
2042 // Pop value from top-of-stack slot, box result into result register.
2043 EmitCreateIteratorResult(true);
2044 EmitUnwindBeforeReturn();
2045 EmitReturnSequence();
2049 case Yield::kDelegating: {
2050 VisitForStackValue(expr->generator_object());
2052 // Initial stack layout is as follows:
2053 // [sp + 1 * kPointerSize] iter
2054 // [sp + 0 * kPointerSize] g
2056 Label l_catch, l_try, l_suspend, l_continuation, l_resume;
2057 Label l_next, l_call, l_loop;
2058 Register load_receiver = LoadDescriptor::ReceiverRegister();
2059 Register load_name = LoadDescriptor::NameRegister();
2061 // Initial send value is undefined.
2062 __ mov(eax, isolate()->factory()->undefined_value());
2065 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
2067 __ mov(load_name, isolate()->factory()->throw_string()); // "throw"
2068 __ push(load_name); // "throw"
2069 __ push(Operand(esp, 2 * kPointerSize)); // iter
2070 __ push(eax); // exception
2073 // try { received = %yield result }
2074 // Shuffle the received result above a try handler and yield it without
2077 __ pop(eax); // result
2078 int handler_index = NewHandlerTableEntry();
2079 EnterTryBlock(handler_index, &l_catch);
2080 const int try_block_size = TryCatch::kElementCount * kPointerSize;
2081 __ push(eax); // result
2084 __ bind(&l_continuation);
2085 __ RecordGeneratorContinuation();
2088 __ bind(&l_suspend);
2089 const int generator_object_depth = kPointerSize + try_block_size;
2090 __ mov(eax, Operand(esp, generator_object_depth));
2092 __ push(Immediate(Smi::FromInt(handler_index))); // handler-index
2093 DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
2094 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
2095 Immediate(Smi::FromInt(l_continuation.pos())));
2096 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
2098 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
2100 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
2101 __ mov(context_register(),
2102 Operand(ebp, StandardFrameConstants::kContextOffset));
2103 __ pop(eax); // result
2104 EmitReturnSequence();
2105 __ bind(&l_resume); // received in eax
2106 ExitTryBlock(handler_index);
2108 // receiver = iter; f = iter.next; arg = received;
2111 __ mov(load_name, isolate()->factory()->next_string());
2112 __ push(load_name); // "next"
2113 __ push(Operand(esp, 2 * kPointerSize)); // iter
2114 __ push(eax); // received
2116 // result = receiver[f](arg);
2118 __ mov(load_receiver, Operand(esp, kPointerSize));
2119 __ mov(LoadDescriptor::SlotRegister(),
2120 Immediate(SmiFromSlot(expr->KeyedLoadFeedbackSlot())));
2121 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code();
2122 CallIC(ic, TypeFeedbackId::None());
2124 __ mov(Operand(esp, 2 * kPointerSize), edi);
2125 SetCallPosition(expr, 1);
2126 CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
2129 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2130 __ Drop(1); // The function is still on the stack; drop it.
2132 // if (!result.done) goto l_try;
2134 __ push(eax); // save result
2135 __ Move(load_receiver, eax); // result
2137 isolate()->factory()->done_string()); // "done"
2138 __ mov(LoadDescriptor::SlotRegister(),
2139 Immediate(SmiFromSlot(expr->DoneFeedbackSlot())));
2140 CallLoadIC(NOT_INSIDE_TYPEOF); // result.done in eax
2141 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
2147 __ pop(load_receiver); // result
2149 isolate()->factory()->value_string()); // "value"
2150 __ mov(LoadDescriptor::SlotRegister(),
2151 Immediate(SmiFromSlot(expr->ValueFeedbackSlot())));
2152 CallLoadIC(NOT_INSIDE_TYPEOF); // result.value in eax
2153 context()->DropAndPlug(2, eax); // drop iter and g
2160 void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
2162 JSGeneratorObject::ResumeMode resume_mode) {
2163 // The value stays in eax, and is ultimately read by the resumed generator, as
2164 // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
2165 // is read to throw the value when the resumed generator is already closed.
2166 // ebx will hold the generator object until the activation has been resumed.
2167 VisitForStackValue(generator);
2168 VisitForAccumulatorValue(value);
2171 // Load suspended function and context.
2172 __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset));
2173 __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
2176 __ push(FieldOperand(ebx, JSGeneratorObject::kReceiverOffset));
2178 // Push holes for arguments to generator function.
2179 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2181 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2182 __ mov(ecx, isolate()->factory()->the_hole_value());
2183 Label push_argument_holes, push_frame;
2184 __ bind(&push_argument_holes);
2185 __ sub(edx, Immediate(Smi::FromInt(1)));
2186 __ j(carry, &push_frame);
2188 __ jmp(&push_argument_holes);
2190 // Enter a new JavaScript frame, and initialize its slots as they were when
2191 // the generator was suspended.
2192 Label resume_frame, done;
2193 __ bind(&push_frame);
2194 __ call(&resume_frame);
2196 __ bind(&resume_frame);
2197 __ push(ebp); // Caller's frame pointer.
2199 __ push(esi); // Callee's context.
2200 __ push(edi); // Callee's JS Function.
2202 // Load the operand stack size.
2203 __ mov(edx, FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset));
2204 __ mov(edx, FieldOperand(edx, FixedArray::kLengthOffset));
2207 // If we are sending a value and there is no operand stack, we can jump back
2209 if (resume_mode == JSGeneratorObject::NEXT) {
2211 __ cmp(edx, Immediate(0));
2212 __ j(not_zero, &slow_resume);
2213 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2214 __ mov(ecx, FieldOperand(ebx, JSGeneratorObject::kContinuationOffset));
2217 __ mov(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
2218 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
2220 __ bind(&slow_resume);
2223 // Otherwise, we push holes for the operand stack and call the runtime to fix
2224 // up the stack and the handlers.
2225 Label push_operand_holes, call_resume;
2226 __ bind(&push_operand_holes);
2227 __ sub(edx, Immediate(1));
2228 __ j(carry, &call_resume);
2230 __ jmp(&push_operand_holes);
2231 __ bind(&call_resume);
2233 __ push(result_register());
2234 __ Push(Smi::FromInt(resume_mode));
2235 __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
2236 // Not reached: the runtime call returns elsewhere.
2237 __ Abort(kGeneratorFailedToResume);
2240 context()->Plug(result_register());
2244 void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
2248 const int instance_size = 5 * kPointerSize;
2249 DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
2252 __ Allocate(instance_size, eax, ecx, edx, &gc_required, TAG_OBJECT);
2255 __ bind(&gc_required);
2256 __ Push(Smi::FromInt(instance_size));
2257 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
2258 __ mov(context_register(),
2259 Operand(ebp, StandardFrameConstants::kContextOffset));
2261 __ bind(&allocated);
2262 __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2263 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
2264 __ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
2266 __ mov(edx, isolate()->factory()->ToBoolean(done));
2267 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
2268 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
2269 isolate()->factory()->empty_fixed_array());
2270 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
2271 isolate()->factory()->empty_fixed_array());
2272 __ mov(FieldOperand(eax, JSGeneratorObject::kResultValuePropertyOffset), ecx);
2273 __ mov(FieldOperand(eax, JSGeneratorObject::kResultDonePropertyOffset), edx);
2275 // Only the value field needs a write barrier, as the other values are in the
2277 __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset, ecx,
2278 edx, kDontSaveFPRegs);
2282 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
2283 SetExpressionPosition(prop);
2284 Literal* key = prop->key()->AsLiteral();
2285 DCHECK(!key->value()->IsSmi());
2286 DCHECK(!prop->IsSuperAccess());
2288 __ mov(LoadDescriptor::NameRegister(), Immediate(key->value()));
2289 __ mov(LoadDescriptor::SlotRegister(),
2290 Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
2291 CallLoadIC(NOT_INSIDE_TYPEOF, language_mode());
2295 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
2296 // Stack: receiver, home_object.
2297 SetExpressionPosition(prop);
2298 Literal* key = prop->key()->AsLiteral();
2299 DCHECK(!key->value()->IsSmi());
2300 DCHECK(prop->IsSuperAccess());
2302 __ push(Immediate(key->value()));
2303 __ push(Immediate(Smi::FromInt(language_mode())));
2304 __ CallRuntime(Runtime::kLoadFromSuper, 4);
2308 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
2309 SetExpressionPosition(prop);
2310 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code();
2311 __ mov(LoadDescriptor::SlotRegister(),
2312 Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
2317 void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
2318 // Stack: receiver, home_object, key.
2319 SetExpressionPosition(prop);
2320 __ push(Immediate(Smi::FromInt(language_mode())));
2321 __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4);
2325 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
2328 Expression* right) {
2329 // Do combined smi check of the operands. Left operand is on the
2330 // stack. Right operand is in eax.
2331 Label smi_case, done, stub_call;
2335 JumpPatchSite patch_site(masm_);
2336 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
2338 __ bind(&stub_call);
2341 CodeFactory::BinaryOpIC(isolate(), op, strength(language_mode())).code();
2342 CallIC(code, expr->BinaryOperationFeedbackId());
2343 patch_site.EmitPatchInfo();
2344 __ jmp(&done, Label::kNear);
2348 __ mov(eax, edx); // Copy left operand in case of a stub call.
2353 __ sar_cl(eax); // No checks of result necessary
2354 __ and_(eax, Immediate(~kSmiTagMask));
2361 // Check that the *signed* result fits in a smi.
2362 __ cmp(eax, 0xc0000000);
2363 __ j(positive, &result_ok);
2366 __ bind(&result_ok);
2375 __ test(eax, Immediate(0xc0000000));
2376 __ j(zero, &result_ok);
2379 __ bind(&result_ok);
2385 __ j(overflow, &stub_call);
2389 __ j(overflow, &stub_call);
2394 __ j(overflow, &stub_call);
2396 __ j(not_zero, &done, Label::kNear);
2399 __ j(negative, &stub_call);
2405 case Token::BIT_AND:
2408 case Token::BIT_XOR:
2416 context()->Plug(eax);
2420 void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit,
2421 int* used_store_slots) {
2422 // Constructor is in eax.
2423 DCHECK(lit != NULL);
2426 // No access check is needed here since the constructor is created by the
2428 Register scratch = ebx;
2429 __ mov(scratch, FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset));
2432 for (int i = 0; i < lit->properties()->length(); i++) {
2433 ObjectLiteral::Property* property = lit->properties()->at(i);
2434 Expression* value = property->value();
2436 if (property->is_static()) {
2437 __ push(Operand(esp, kPointerSize)); // constructor
2439 __ push(Operand(esp, 0)); // prototype
2441 EmitPropertyKey(property, lit->GetIdForProperty(i));
2443 // The static prototype property is read only. We handle the non computed
2444 // property name case in the parser. Since this is the only case where we
2445 // need to check for an own read only property we special case this so we do
2446 // not need to do this for every property.
2447 if (property->is_static() && property->is_computed_name()) {
2448 __ CallRuntime(Runtime::kThrowIfStaticPrototype, 1);
2452 VisitForStackValue(value);
2453 EmitSetHomeObjectIfNeeded(value, 2,
2454 lit->SlotForHomeObject(value, used_store_slots));
2456 switch (property->kind()) {
2457 case ObjectLiteral::Property::CONSTANT:
2458 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2459 case ObjectLiteral::Property::PROTOTYPE:
2461 case ObjectLiteral::Property::COMPUTED:
2462 __ CallRuntime(Runtime::kDefineClassMethod, 3);
2465 case ObjectLiteral::Property::GETTER:
2466 __ push(Immediate(Smi::FromInt(DONT_ENUM)));
2467 __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 4);
2470 case ObjectLiteral::Property::SETTER:
2471 __ push(Immediate(Smi::FromInt(DONT_ENUM)));
2472 __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 4);
2477 // Set both the prototype and constructor to have fast properties, and also
2478 // freeze them in strong mode.
2479 __ CallRuntime(Runtime::kFinalizeClassDefinition, 2);
2483 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
2486 CodeFactory::BinaryOpIC(isolate(), op, strength(language_mode())).code();
2487 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
2488 CallIC(code, expr->BinaryOperationFeedbackId());
2489 patch_site.EmitPatchInfo();
2490 context()->Plug(eax);
2494 void FullCodeGenerator::EmitAssignment(Expression* expr,
2495 FeedbackVectorICSlot slot) {
2496 DCHECK(expr->IsValidReferenceExpressionOrThis());
2498 Property* prop = expr->AsProperty();
2499 LhsKind assign_type = Property::GetAssignType(prop);
2501 switch (assign_type) {
2503 Variable* var = expr->AsVariableProxy()->var();
2504 EffectContext context(this);
2505 EmitVariableAssignment(var, Token::ASSIGN, slot);
2508 case NAMED_PROPERTY: {
2509 __ push(eax); // Preserve value.
2510 VisitForAccumulatorValue(prop->obj());
2511 __ Move(StoreDescriptor::ReceiverRegister(), eax);
2512 __ pop(StoreDescriptor::ValueRegister()); // Restore value.
2513 __ mov(StoreDescriptor::NameRegister(),
2514 prop->key()->AsLiteral()->value());
2515 if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
2519 case NAMED_SUPER_PROPERTY: {
2521 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2522 VisitForAccumulatorValue(
2523 prop->obj()->AsSuperPropertyReference()->home_object());
2524 // stack: value, this; eax: home_object
2525 Register scratch = ecx;
2526 Register scratch2 = edx;
2527 __ mov(scratch, result_register()); // home_object
2528 __ mov(eax, MemOperand(esp, kPointerSize)); // value
2529 __ mov(scratch2, MemOperand(esp, 0)); // this
2530 __ mov(MemOperand(esp, kPointerSize), scratch2); // this
2531 __ mov(MemOperand(esp, 0), scratch); // home_object
2532 // stack: this, home_object. eax: value
2533 EmitNamedSuperPropertyStore(prop);
2536 case KEYED_SUPER_PROPERTY: {
2538 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2540 prop->obj()->AsSuperPropertyReference()->home_object());
2541 VisitForAccumulatorValue(prop->key());
2542 Register scratch = ecx;
2543 Register scratch2 = edx;
2544 __ mov(scratch2, MemOperand(esp, 2 * kPointerSize)); // value
2545 // stack: value, this, home_object; eax: key, edx: value
2546 __ mov(scratch, MemOperand(esp, kPointerSize)); // this
2547 __ mov(MemOperand(esp, 2 * kPointerSize), scratch);
2548 __ mov(scratch, MemOperand(esp, 0)); // home_object
2549 __ mov(MemOperand(esp, kPointerSize), scratch);
2550 __ mov(MemOperand(esp, 0), eax);
2551 __ mov(eax, scratch2);
2552 // stack: this, home_object, key; eax: value.
2553 EmitKeyedSuperPropertyStore(prop);
2556 case KEYED_PROPERTY: {
2557 __ push(eax); // Preserve value.
2558 VisitForStackValue(prop->obj());
2559 VisitForAccumulatorValue(prop->key());
2560 __ Move(StoreDescriptor::NameRegister(), eax);
2561 __ pop(StoreDescriptor::ReceiverRegister()); // Receiver.
2562 __ pop(StoreDescriptor::ValueRegister()); // Restore value.
2563 if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
2565 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2570 context()->Plug(eax);
2574 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2575 Variable* var, MemOperand location) {
2576 __ mov(location, eax);
2577 if (var->IsContextSlot()) {
2579 int offset = Context::SlotOffset(var->index());
2580 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
2585 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
2586 FeedbackVectorICSlot slot) {
2587 if (var->IsUnallocated()) {
2588 // Global var, const, or let.
2589 __ mov(StoreDescriptor::NameRegister(), var->name());
2590 __ mov(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
2591 if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
2594 } else if (var->IsGlobalSlot()) {
2595 // Global var, const, or let.
2596 DCHECK(var->index() > 0);
2597 DCHECK(var->IsStaticGlobalObjectProperty());
2598 int const slot = var->index();
2599 int const depth = scope()->ContextChainLength(var->scope());
2600 if (depth <= StoreGlobalViaContextStub::kMaximumDepth) {
2601 __ Move(StoreGlobalViaContextDescriptor::SlotRegister(), Immediate(slot));
2602 DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(eax));
2603 StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
2606 __ Push(Smi::FromInt(slot));
2608 __ CallRuntime(is_strict(language_mode())
2609 ? Runtime::kStoreGlobalViaContext_Strict
2610 : Runtime::kStoreGlobalViaContext_Sloppy,
2614 } else if (var->mode() == LET && op != Token::INIT_LET) {
2615 // Non-initializing assignment to let variable needs a write barrier.
2616 DCHECK(!var->IsLookupSlot());
2617 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2619 MemOperand location = VarOperand(var, ecx);
2620 __ mov(edx, location);
2621 __ cmp(edx, isolate()->factory()->the_hole_value());
2622 __ j(not_equal, &assign, Label::kNear);
2623 __ push(Immediate(var->name()));
2624 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2626 EmitStoreToStackLocalOrContextSlot(var, location);
2628 } else if (var->mode() == CONST && op != Token::INIT_CONST) {
2629 // Assignment to const variable needs a write barrier.
2630 DCHECK(!var->IsLookupSlot());
2631 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2633 MemOperand location = VarOperand(var, ecx);
2634 __ mov(edx, location);
2635 __ cmp(edx, isolate()->factory()->the_hole_value());
2636 __ j(not_equal, &const_error, Label::kNear);
2637 __ push(Immediate(var->name()));
2638 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2639 __ bind(&const_error);
2640 __ CallRuntime(Runtime::kThrowConstAssignError, 0);
2642 } else if (var->is_this() && op == Token::INIT_CONST) {
2643 // Initializing assignment to const {this} needs a write barrier.
2644 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2645 Label uninitialized_this;
2646 MemOperand location = VarOperand(var, ecx);
2647 __ mov(edx, location);
2648 __ cmp(edx, isolate()->factory()->the_hole_value());
2649 __ j(equal, &uninitialized_this);
2650 __ push(Immediate(var->name()));
2651 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2652 __ bind(&uninitialized_this);
2653 EmitStoreToStackLocalOrContextSlot(var, location);
2655 } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
2656 if (var->IsLookupSlot()) {
2657 // Assignment to var.
2658 __ push(eax); // Value.
2659 __ push(esi); // Context.
2660 __ push(Immediate(var->name()));
2661 __ push(Immediate(Smi::FromInt(language_mode())));
2662 __ CallRuntime(Runtime::kStoreLookupSlot, 4);
2664 // Assignment to var or initializing assignment to let/const in harmony
2666 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2667 MemOperand location = VarOperand(var, ecx);
2668 if (generate_debug_code_ && op == Token::INIT_LET) {
2669 // Check for an uninitialized let binding.
2670 __ mov(edx, location);
2671 __ cmp(edx, isolate()->factory()->the_hole_value());
2672 __ Check(equal, kLetBindingReInitialization);
2674 EmitStoreToStackLocalOrContextSlot(var, location);
2677 } else if (op == Token::INIT_CONST_LEGACY) {
2678 // Const initializers need a write barrier.
2679 DCHECK(var->mode() == CONST_LEGACY);
2680 DCHECK(!var->IsParameter()); // No const parameters.
2681 if (var->IsLookupSlot()) {
2684 __ push(Immediate(var->name()));
2685 __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
2687 DCHECK(var->IsStackLocal() || var->IsContextSlot());
2689 MemOperand location = VarOperand(var, ecx);
2690 __ mov(edx, location);
2691 __ cmp(edx, isolate()->factory()->the_hole_value());
2692 __ j(not_equal, &skip, Label::kNear);
2693 EmitStoreToStackLocalOrContextSlot(var, location);
2698 DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
2699 if (is_strict(language_mode())) {
2700 __ CallRuntime(Runtime::kThrowConstAssignError, 0);
2702 // Silently ignore store in sloppy mode.
2707 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2708 // Assignment to a property, using a named store IC.
2710 // esp[0] : receiver
2711 Property* prop = expr->target()->AsProperty();
2712 DCHECK(prop != NULL);
2713 DCHECK(prop->key()->IsLiteral());
2715 __ mov(StoreDescriptor::NameRegister(), prop->key()->AsLiteral()->value());
2716 __ pop(StoreDescriptor::ReceiverRegister());
2717 if (FLAG_vector_stores) {
2718 EmitLoadStoreICSlot(expr->AssignmentSlot());
2721 CallStoreIC(expr->AssignmentFeedbackId());
2723 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2724 context()->Plug(eax);
2728 void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2729 // Assignment to named property of super.
2731 // stack : receiver ('this'), home_object
2732 DCHECK(prop != NULL);
2733 Literal* key = prop->key()->AsLiteral();
2734 DCHECK(key != NULL);
2736 __ push(Immediate(key->value()));
2738 __ CallRuntime((is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict
2739 : Runtime::kStoreToSuper_Sloppy),
2744 void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2745 // Assignment to named property of super.
2747 // stack : receiver ('this'), home_object, key
2751 (is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict
2752 : Runtime::kStoreKeyedToSuper_Sloppy),
2757 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2758 // Assignment to a property, using a keyed store IC.
2761 // esp[kPointerSize] : receiver
2763 __ pop(StoreDescriptor::NameRegister()); // Key.
2764 __ pop(StoreDescriptor::ReceiverRegister());
2765 DCHECK(StoreDescriptor::ValueRegister().is(eax));
2767 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2768 if (FLAG_vector_stores) {
2769 EmitLoadStoreICSlot(expr->AssignmentSlot());
2772 CallIC(ic, expr->AssignmentFeedbackId());
2775 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2776 context()->Plug(eax);
2780 void FullCodeGenerator::VisitProperty(Property* expr) {
2781 Comment cmnt(masm_, "[ Property");
2782 SetExpressionPosition(expr);
2784 Expression* key = expr->key();
2786 if (key->IsPropertyName()) {
2787 if (!expr->IsSuperAccess()) {
2788 VisitForAccumulatorValue(expr->obj());
2789 __ Move(LoadDescriptor::ReceiverRegister(), result_register());
2790 EmitNamedPropertyLoad(expr);
2792 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var());
2794 expr->obj()->AsSuperPropertyReference()->home_object());
2795 EmitNamedSuperPropertyLoad(expr);
2798 if (!expr->IsSuperAccess()) {
2799 VisitForStackValue(expr->obj());
2800 VisitForAccumulatorValue(expr->key());
2801 __ pop(LoadDescriptor::ReceiverRegister()); // Object.
2802 __ Move(LoadDescriptor::NameRegister(), result_register()); // Key.
2803 EmitKeyedPropertyLoad(expr);
2805 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var());
2807 expr->obj()->AsSuperPropertyReference()->home_object());
2808 VisitForStackValue(expr->key());
2809 EmitKeyedSuperPropertyLoad(expr);
2812 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
2813 context()->Plug(eax);
2817 void FullCodeGenerator::CallIC(Handle<Code> code,
2818 TypeFeedbackId ast_id) {
2820 __ call(code, RelocInfo::CODE_TARGET, ast_id);
2824 // Code common for calls using the IC.
2825 void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2826 Expression* callee = expr->expression();
2828 CallICState::CallType call_type =
2829 callee->IsVariableProxy() ? CallICState::FUNCTION : CallICState::METHOD;
2830 // Get the target function.
2831 if (call_type == CallICState::FUNCTION) {
2832 { StackValueContext context(this);
2833 EmitVariableLoad(callee->AsVariableProxy());
2834 PrepareForBailout(callee, NO_REGISTERS);
2836 // Push undefined as receiver. This is patched in the method prologue if it
2837 // is a sloppy mode method.
2838 __ push(Immediate(isolate()->factory()->undefined_value()));
2840 // Load the function from the receiver.
2841 DCHECK(callee->IsProperty());
2842 DCHECK(!callee->AsProperty()->IsSuperAccess());
2843 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2844 EmitNamedPropertyLoad(callee->AsProperty());
2845 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2846 // Push the target function under the receiver.
2847 __ push(Operand(esp, 0));
2848 __ mov(Operand(esp, kPointerSize), eax);
2851 EmitCall(expr, call_type);
2855 void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2856 SetExpressionPosition(expr);
2857 Expression* callee = expr->expression();
2858 DCHECK(callee->IsProperty());
2859 Property* prop = callee->AsProperty();
2860 DCHECK(prop->IsSuperAccess());
2862 Literal* key = prop->key()->AsLiteral();
2863 DCHECK(!key->value()->IsSmi());
2864 // Load the function from the receiver.
2865 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2866 VisitForStackValue(super_ref->home_object());
2867 VisitForAccumulatorValue(super_ref->this_var());
2870 __ push(Operand(esp, kPointerSize * 2));
2871 __ push(Immediate(key->value()));
2872 __ push(Immediate(Smi::FromInt(language_mode())));
2875 // - this (receiver)
2876 // - this (receiver) <-- LoadFromSuper will pop here and below.
2880 __ CallRuntime(Runtime::kLoadFromSuper, 4);
2882 // Replace home_object with target function.
2883 __ mov(Operand(esp, kPointerSize), eax);
2886 // - target function
2887 // - this (receiver)
2888 EmitCall(expr, CallICState::METHOD);
2892 // Code common for calls using the IC.
2893 void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2896 VisitForAccumulatorValue(key);
2898 Expression* callee = expr->expression();
2900 // Load the function from the receiver.
2901 DCHECK(callee->IsProperty());
2902 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2903 __ mov(LoadDescriptor::NameRegister(), eax);
2904 EmitKeyedPropertyLoad(callee->AsProperty());
2905 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2907 // Push the target function under the receiver.
2908 __ push(Operand(esp, 0));
2909 __ mov(Operand(esp, kPointerSize), eax);
2911 EmitCall(expr, CallICState::METHOD);
2915 void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2916 Expression* callee = expr->expression();
2917 DCHECK(callee->IsProperty());
2918 Property* prop = callee->AsProperty();
2919 DCHECK(prop->IsSuperAccess());
2921 SetExpressionPosition(prop);
2922 // Load the function from the receiver.
2923 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2924 VisitForStackValue(super_ref->home_object());
2925 VisitForAccumulatorValue(super_ref->this_var());
2928 __ push(Operand(esp, kPointerSize * 2));
2929 VisitForStackValue(prop->key());
2930 __ push(Immediate(Smi::FromInt(language_mode())));
2933 // - this (receiver)
2934 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2938 __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4);
2940 // Replace home_object with target function.
2941 __ mov(Operand(esp, kPointerSize), eax);
2944 // - target function
2945 // - this (receiver)
2946 EmitCall(expr, CallICState::METHOD);
2950 void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
2951 // Load the arguments.
2952 ZoneList<Expression*>* args = expr->arguments();
2953 int arg_count = args->length();
2954 for (int i = 0; i < arg_count; i++) {
2955 VisitForStackValue(args->at(i));
2958 SetCallPosition(expr, arg_count);
2959 Handle<Code> ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code();
2960 __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackICSlot())));
2961 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2962 // Don't assign a type feedback id to the IC, since type feedback is provided
2963 // by the vector above.
2966 RecordJSReturnSite(expr);
2968 // Restore context register.
2969 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2971 context()->DropAndPlug(1, eax);
2975 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
2976 // Push copy of the first argument or undefined if it doesn't exist.
2977 if (arg_count > 0) {
2978 __ push(Operand(esp, arg_count * kPointerSize));
2980 __ push(Immediate(isolate()->factory()->undefined_value()));
2983 // Push the enclosing function.
2984 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2986 // Push the language mode.
2987 __ push(Immediate(Smi::FromInt(language_mode())));
2989 // Push the start position of the scope the calls resides in.
2990 __ push(Immediate(Smi::FromInt(scope()->start_position())));
2992 // Do the runtime call.
2993 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
2997 // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
2998 void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
2999 VariableProxy* callee = expr->expression()->AsVariableProxy();
3000 if (callee->var()->IsLookupSlot()) {
3002 SetExpressionPosition(callee);
3003 // Generate code for loading from variables potentially shadowed by
3004 // eval-introduced variables.
3005 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
3008 // Call the runtime to find the function to call (returned in eax) and
3009 // the object holding it (returned in edx).
3010 __ push(context_register());
3011 __ push(Immediate(callee->name()));
3012 __ CallRuntime(Runtime::kLoadLookupSlot, 2);
3013 __ push(eax); // Function.
3014 __ push(edx); // Receiver.
3015 PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
3017 // If fast case code has been generated, emit code to push the function
3018 // and receiver and have the slow path jump around this code.
3019 if (done.is_linked()) {
3021 __ jmp(&call, Label::kNear);
3025 // The receiver is implicitly the global receiver. Indicate this by
3026 // passing the hole to the call function stub.
3027 __ push(Immediate(isolate()->factory()->undefined_value()));
3031 VisitForStackValue(callee);
3032 // refEnv.WithBaseObject()
3033 __ push(Immediate(isolate()->factory()->undefined_value()));
3038 void FullCodeGenerator::VisitCall(Call* expr) {
3040 // We want to verify that RecordJSReturnSite gets called on all paths
3041 // through this function. Avoid early returns.
3042 expr->return_is_recorded_ = false;
3045 Comment cmnt(masm_, "[ Call");
3046 Expression* callee = expr->expression();
3047 Call::CallType call_type = expr->GetCallType(isolate());
3049 if (call_type == Call::POSSIBLY_EVAL_CALL) {
3050 // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
3051 // to resolve the function we need to call. Then we call the resolved
3052 // function using the given arguments.
3053 ZoneList<Expression*>* args = expr->arguments();
3054 int arg_count = args->length();
3056 PushCalleeAndWithBaseObject(expr);
3058 // Push the arguments.
3059 for (int i = 0; i < arg_count; i++) {
3060 VisitForStackValue(args->at(i));
3063 // Push a copy of the function (found below the arguments) and
3065 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
3066 EmitResolvePossiblyDirectEval(arg_count);
3068 // Touch up the stack with the resolved function.
3069 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
3071 PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
3073 SetCallPosition(expr, arg_count);
3074 CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
3075 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
3077 RecordJSReturnSite(expr);
3078 // Restore context register.
3079 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3080 context()->DropAndPlug(1, eax);
3082 } else if (call_type == Call::GLOBAL_CALL) {
3083 EmitCallWithLoadIC(expr);
3084 } else if (call_type == Call::LOOKUP_SLOT_CALL) {
3085 // Call to a lookup slot (dynamically introduced variable).
3086 PushCalleeAndWithBaseObject(expr);
3088 } else if (call_type == Call::PROPERTY_CALL) {
3089 Property* property = callee->AsProperty();
3090 bool is_named_call = property->key()->IsPropertyName();
3091 if (property->IsSuperAccess()) {
3092 if (is_named_call) {
3093 EmitSuperCallWithLoadIC(expr);
3095 EmitKeyedSuperCallWithLoadIC(expr);
3098 VisitForStackValue(property->obj());
3099 if (is_named_call) {
3100 EmitCallWithLoadIC(expr);
3102 EmitKeyedCallWithLoadIC(expr, property->key());
3105 } else if (call_type == Call::SUPER_CALL) {
3106 EmitSuperConstructorCall(expr);
3108 DCHECK(call_type == Call::OTHER_CALL);
3109 // Call to an arbitrary expression not handled specially above.
3110 VisitForStackValue(callee);
3111 __ push(Immediate(isolate()->factory()->undefined_value()));
3112 // Emit function call.
3117 // RecordJSReturnSite should have been called.
3118 DCHECK(expr->return_is_recorded_);
3123 void FullCodeGenerator::VisitCallNew(CallNew* expr) {
3124 Comment cmnt(masm_, "[ CallNew");
3125 // According to ECMA-262, section 11.2.2, page 44, the function
3126 // expression in new calls must be evaluated before the
3129 // Push constructor on the stack. If it's not a function it's used as
3130 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
3132 DCHECK(!expr->expression()->IsSuperPropertyReference());
3133 VisitForStackValue(expr->expression());
3135 // Push the arguments ("left-to-right") on the stack.
3136 ZoneList<Expression*>* args = expr->arguments();
3137 int arg_count = args->length();
3138 for (int i = 0; i < arg_count; i++) {
3139 VisitForStackValue(args->at(i));
3142 // Call the construct call builtin that handles allocation and
3143 // constructor invocation.
3144 SetConstructCallPosition(expr);
3146 // Load function and argument count into edi and eax.
3147 __ Move(eax, Immediate(arg_count));
3148 __ mov(edi, Operand(esp, arg_count * kPointerSize));
3150 // Record call targets in unoptimized code.
3151 if (FLAG_pretenuring_call_new) {
3152 EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
3153 DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
3154 expr->CallNewFeedbackSlot().ToInt() + 1);
3157 __ LoadHeapObject(ebx, FeedbackVector());
3158 __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot())));
3160 CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
3161 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
3162 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
3163 context()->Plug(eax);
3167 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
3168 SuperCallReference* super_call_ref =
3169 expr->expression()->AsSuperCallReference();
3170 DCHECK_NOT_NULL(super_call_ref);
3172 EmitLoadSuperConstructor(super_call_ref);
3173 __ push(result_register());
3175 // Push the arguments ("left-to-right") on the stack.
3176 ZoneList<Expression*>* args = expr->arguments();
3177 int arg_count = args->length();
3178 for (int i = 0; i < arg_count; i++) {
3179 VisitForStackValue(args->at(i));
3182 // Call the construct call builtin that handles allocation and
3183 // constructor invocation.
3184 SetConstructCallPosition(expr);
3186 // Load original constructor into ecx.
3187 VisitForAccumulatorValue(super_call_ref->new_target_var());
3188 __ mov(ecx, result_register());
3190 // Load function and argument count into edi and eax.
3191 __ Move(eax, Immediate(arg_count));
3192 __ mov(edi, Operand(esp, arg_count * kPointerSize));
3194 // Record call targets in unoptimized code.
3195 if (FLAG_pretenuring_call_new) {
3197 /* TODO(dslomov): support pretenuring.
3198 EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
3199 DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
3200 expr->CallNewFeedbackSlot().ToInt() + 1);
3204 __ LoadHeapObject(ebx, FeedbackVector());
3205 __ mov(edx, Immediate(SmiFromSlot(expr->CallFeedbackSlot())));
3207 CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
3208 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
3210 RecordJSReturnSite(expr);
3212 context()->Plug(eax);
3216 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
3217 ZoneList<Expression*>* args = expr->arguments();
3218 DCHECK(args->length() == 1);
3220 VisitForAccumulatorValue(args->at(0));
3222 Label materialize_true, materialize_false;
3223 Label* if_true = NULL;
3224 Label* if_false = NULL;
3225 Label* fall_through = NULL;
3226 context()->PrepareTest(&materialize_true, &materialize_false,
3227 &if_true, &if_false, &fall_through);
3229 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3230 __ test(eax, Immediate(kSmiTagMask));
3231 Split(zero, if_true, if_false, fall_through);
3233 context()->Plug(if_true, if_false);
3237 void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
3238 ZoneList<Expression*>* args = expr->arguments();
3239 DCHECK(args->length() == 1);
3241 VisitForAccumulatorValue(args->at(0));
3243 Label materialize_true, materialize_false;
3244 Label* if_true = NULL;
3245 Label* if_false = NULL;
3246 Label* fall_through = NULL;
3247 context()->PrepareTest(&materialize_true, &materialize_false,
3248 &if_true, &if_false, &fall_through);
3250 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3251 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
3252 Split(zero, if_true, if_false, fall_through);
3254 context()->Plug(if_true, if_false);
3258 void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
3259 ZoneList<Expression*>* args = expr->arguments();
3260 DCHECK(args->length() == 1);
3262 VisitForAccumulatorValue(args->at(0));
3264 Label materialize_true, materialize_false;
3265 Label* if_true = NULL;
3266 Label* if_false = NULL;
3267 Label* fall_through = NULL;
3268 context()->PrepareTest(&materialize_true, &materialize_false,
3269 &if_true, &if_false, &fall_through);
3271 __ JumpIfSmi(eax, if_false);
3272 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
3273 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3274 Split(above_equal, if_true, if_false, fall_through);
3276 context()->Plug(if_true, if_false);
3280 void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
3281 ZoneList<Expression*>* args = expr->arguments();
3282 DCHECK(args->length() == 1);
3284 VisitForAccumulatorValue(args->at(0));
3286 Label materialize_true, materialize_false;
3287 Label* if_true = NULL;
3288 Label* if_false = NULL;
3289 Label* fall_through = NULL;
3290 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3291 &if_false, &fall_through);
3293 __ JumpIfSmi(eax, if_false);
3294 __ CmpObjectType(eax, SIMD128_VALUE_TYPE, ebx);
3295 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3296 Split(equal, if_true, if_false, fall_through);
3298 context()->Plug(if_true, if_false);
3302 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
3303 CallRuntime* expr) {
3304 ZoneList<Expression*>* args = expr->arguments();
3305 DCHECK(args->length() == 1);
3307 VisitForAccumulatorValue(args->at(0));
3309 Label materialize_true, materialize_false, skip_lookup;
3310 Label* if_true = NULL;
3311 Label* if_false = NULL;
3312 Label* fall_through = NULL;
3313 context()->PrepareTest(&materialize_true, &materialize_false,
3314 &if_true, &if_false, &fall_through);
3316 __ AssertNotSmi(eax);
3318 // Check whether this map has already been checked to be safe for default
3320 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3321 __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
3322 1 << Map::kStringWrapperSafeForDefaultValueOf);
3323 __ j(not_zero, &skip_lookup);
3325 // Check for fast case object. Return false for slow case objects.
3326 __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
3327 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
3328 __ cmp(ecx, isolate()->factory()->hash_table_map());
3329 __ j(equal, if_false);
3331 // Look for valueOf string in the descriptor array, and indicate false if
3332 // found. Since we omit an enumeration index check, if it is added via a
3333 // transition that shares its descriptor array, this is a false positive.
3334 Label entry, loop, done;
3336 // Skip loop if no descriptors are valid.
3337 __ NumberOfOwnDescriptors(ecx, ebx);
3341 __ LoadInstanceDescriptors(ebx, ebx);
3342 // ebx: descriptor array.
3343 // ecx: valid entries in the descriptor array.
3344 // Calculate the end of the descriptor array.
3345 STATIC_ASSERT(kSmiTag == 0);
3346 STATIC_ASSERT(kSmiTagSize == 1);
3347 STATIC_ASSERT(kPointerSize == 4);
3348 __ imul(ecx, ecx, DescriptorArray::kDescriptorSize);
3349 __ lea(ecx, Operand(ebx, ecx, times_4, DescriptorArray::kFirstOffset));
3350 // Calculate location of the first key name.
3351 __ add(ebx, Immediate(DescriptorArray::kFirstOffset));
3352 // Loop through all the keys in the descriptor array. If one of these is the
3353 // internalized string "valueOf" the result is false.
3356 __ mov(edx, FieldOperand(ebx, 0));
3357 __ cmp(edx, isolate()->factory()->valueOf_string());
3358 __ j(equal, if_false);
3359 __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
3362 __ j(not_equal, &loop);
3366 // Reload map as register ebx was used as temporary above.
3367 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3369 // Set the bit in the map to indicate that there is no local valueOf field.
3370 __ or_(FieldOperand(ebx, Map::kBitField2Offset),
3371 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
3373 __ bind(&skip_lookup);
3375 // If a valueOf property is not found on the object check that its
3376 // prototype is the un-modified String prototype. If not result is false.
3377 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
3378 __ JumpIfSmi(ecx, if_false);
3379 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
3380 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
3382 FieldOperand(edx, GlobalObject::kNativeContextOffset));
3385 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
3386 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3387 Split(equal, if_true, if_false, fall_through);
3389 context()->Plug(if_true, if_false);
3393 void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
3394 ZoneList<Expression*>* args = expr->arguments();
3395 DCHECK(args->length() == 1);
3397 VisitForAccumulatorValue(args->at(0));
3399 Label materialize_true, materialize_false;
3400 Label* if_true = NULL;
3401 Label* if_false = NULL;
3402 Label* fall_through = NULL;
3403 context()->PrepareTest(&materialize_true, &materialize_false,
3404 &if_true, &if_false, &fall_through);
3406 __ JumpIfSmi(eax, if_false);
3407 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
3408 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3409 Split(equal, if_true, if_false, fall_through);
3411 context()->Plug(if_true, if_false);
3415 void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
3416 ZoneList<Expression*>* args = expr->arguments();
3417 DCHECK(args->length() == 1);
3419 VisitForAccumulatorValue(args->at(0));
3421 Label materialize_true, materialize_false;
3422 Label* if_true = NULL;
3423 Label* if_false = NULL;
3424 Label* fall_through = NULL;
3425 context()->PrepareTest(&materialize_true, &materialize_false,
3426 &if_true, &if_false, &fall_through);
3428 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
3429 __ CheckMap(eax, map, if_false, DO_SMI_CHECK);
3430 // Check if the exponent half is 0x80000000. Comparing against 1 and
3431 // checking for overflow is the shortest possible encoding.
3432 __ cmp(FieldOperand(eax, HeapNumber::kExponentOffset), Immediate(0x1));
3433 __ j(no_overflow, if_false);
3434 __ cmp(FieldOperand(eax, HeapNumber::kMantissaOffset), Immediate(0x0));
3435 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3436 Split(equal, if_true, if_false, fall_through);
3438 context()->Plug(if_true, if_false);
3442 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
3443 ZoneList<Expression*>* args = expr->arguments();
3444 DCHECK(args->length() == 1);
3446 VisitForAccumulatorValue(args->at(0));
3448 Label materialize_true, materialize_false;
3449 Label* if_true = NULL;
3450 Label* if_false = NULL;
3451 Label* fall_through = NULL;
3452 context()->PrepareTest(&materialize_true, &materialize_false,
3453 &if_true, &if_false, &fall_through);
3455 __ JumpIfSmi(eax, if_false);
3456 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
3457 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3458 Split(equal, if_true, if_false, fall_through);
3460 context()->Plug(if_true, if_false);
3464 void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) {
3465 ZoneList<Expression*>* args = expr->arguments();
3466 DCHECK(args->length() == 1);
3468 VisitForAccumulatorValue(args->at(0));
3470 Label materialize_true, materialize_false;
3471 Label* if_true = NULL;
3472 Label* if_false = NULL;
3473 Label* fall_through = NULL;
3474 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3475 &if_false, &fall_through);
3477 __ JumpIfSmi(eax, if_false);
3478 __ CmpObjectType(eax, JS_TYPED_ARRAY_TYPE, ebx);
3479 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3480 Split(equal, if_true, if_false, fall_through);
3482 context()->Plug(if_true, if_false);
3486 void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
3487 ZoneList<Expression*>* args = expr->arguments();
3488 DCHECK(args->length() == 1);
3490 VisitForAccumulatorValue(args->at(0));
3492 Label materialize_true, materialize_false;
3493 Label* if_true = NULL;
3494 Label* if_false = NULL;
3495 Label* fall_through = NULL;
3496 context()->PrepareTest(&materialize_true, &materialize_false,
3497 &if_true, &if_false, &fall_through);
3499 __ JumpIfSmi(eax, if_false);
3500 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
3501 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3502 Split(equal, if_true, if_false, fall_through);
3504 context()->Plug(if_true, if_false);
3508 void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
3509 ZoneList<Expression*>* args = expr->arguments();
3510 DCHECK(args->length() == 1);
3512 VisitForAccumulatorValue(args->at(0));
3514 Label materialize_true, materialize_false;
3515 Label* if_true = NULL;
3516 Label* if_false = NULL;
3517 Label* fall_through = NULL;
3518 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3519 &if_false, &fall_through);
3521 __ JumpIfSmi(eax, if_false);
3523 __ mov(map, FieldOperand(eax, HeapObject::kMapOffset));
3524 __ CmpInstanceType(map, FIRST_JS_PROXY_TYPE);
3525 __ j(less, if_false);
3526 __ CmpInstanceType(map, LAST_JS_PROXY_TYPE);
3527 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3528 Split(less_equal, if_true, if_false, fall_through);
3530 context()->Plug(if_true, if_false);
3534 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
3535 DCHECK(expr->arguments()->length() == 0);
3537 Label materialize_true, materialize_false;
3538 Label* if_true = NULL;
3539 Label* if_false = NULL;
3540 Label* fall_through = NULL;
3541 context()->PrepareTest(&materialize_true, &materialize_false,
3542 &if_true, &if_false, &fall_through);
3544 // Get the frame pointer for the calling frame.
3545 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3547 // Skip the arguments adaptor frame if it exists.
3548 Label check_frame_marker;
3549 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
3550 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3551 __ j(not_equal, &check_frame_marker);
3552 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
3554 // Check the marker in the calling frame.
3555 __ bind(&check_frame_marker);
3556 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
3557 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
3558 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3559 Split(equal, if_true, if_false, fall_through);
3561 context()->Plug(if_true, if_false);
3565 void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
3566 ZoneList<Expression*>* args = expr->arguments();
3567 DCHECK(args->length() == 2);
3569 // Load the two objects into registers and perform the comparison.
3570 VisitForStackValue(args->at(0));
3571 VisitForAccumulatorValue(args->at(1));
3573 Label materialize_true, materialize_false;
3574 Label* if_true = NULL;
3575 Label* if_false = NULL;
3576 Label* fall_through = NULL;
3577 context()->PrepareTest(&materialize_true, &materialize_false,
3578 &if_true, &if_false, &fall_through);
3582 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3583 Split(equal, if_true, if_false, fall_through);
3585 context()->Plug(if_true, if_false);
3589 void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3590 ZoneList<Expression*>* args = expr->arguments();
3591 DCHECK(args->length() == 1);
3593 // ArgumentsAccessStub expects the key in edx and the formal
3594 // parameter count in eax.
3595 VisitForAccumulatorValue(args->at(0));
3597 __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
3598 ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
3600 context()->Plug(eax);
3604 void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
3605 DCHECK(expr->arguments()->length() == 0);
3608 // Get the number of formal parameters.
3609 __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
3611 // Check if the calling frame is an arguments adaptor frame.
3612 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3613 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
3614 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3615 __ j(not_equal, &exit);
3617 // Arguments adaptor case: Read the arguments length from the
3619 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
3623 context()->Plug(eax);
3627 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3628 ZoneList<Expression*>* args = expr->arguments();
3629 DCHECK(args->length() == 1);
3630 Label done, null, function, non_function_constructor;
3632 VisitForAccumulatorValue(args->at(0));
3634 // If the object is a smi, we return null.
3635 __ JumpIfSmi(eax, &null);
3637 // Check that the object is a JS object but take special care of JS
3638 // functions to make sure they have 'Function' as their class.
3639 // Assume that there are only two callable types, and one of them is at
3640 // either end of the type range for JS object types. Saves extra comparisons.
3641 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
3642 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
3643 // Map is now in eax.
3645 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3646 FIRST_SPEC_OBJECT_TYPE + 1);
3647 __ j(equal, &function);
3649 __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
3650 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3651 LAST_SPEC_OBJECT_TYPE - 1);
3652 __ j(equal, &function);
3653 // Assume that there is no larger type.
3654 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
3656 // Check if the constructor in the map is a JS function.
3657 __ GetMapConstructor(eax, eax, ebx);
3658 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
3659 __ j(not_equal, &non_function_constructor);
3661 // eax now contains the constructor function. Grab the
3662 // instance class name from there.
3663 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
3664 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
3667 // Functions have class 'Function'.
3669 __ mov(eax, isolate()->factory()->Function_string());
3672 // Objects with a non-function constructor have class 'Object'.
3673 __ bind(&non_function_constructor);
3674 __ mov(eax, isolate()->factory()->Object_string());
3677 // Non-JS objects have class null.
3679 __ mov(eax, isolate()->factory()->null_value());
3684 context()->Plug(eax);
3688 void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3689 ZoneList<Expression*>* args = expr->arguments();
3690 DCHECK(args->length() == 1);
3692 VisitForAccumulatorValue(args->at(0)); // Load the object.
3695 // If the object is a smi return the object.
3696 __ JumpIfSmi(eax, &done, Label::kNear);
3697 // If the object is not a value type, return the object.
3698 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
3699 __ j(not_equal, &done, Label::kNear);
3700 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
3703 context()->Plug(eax);
3707 void FullCodeGenerator::EmitIsDate(CallRuntime* expr) {
3708 ZoneList<Expression*>* args = expr->arguments();
3709 DCHECK_EQ(1, args->length());
3711 VisitForAccumulatorValue(args->at(0));
3713 Label materialize_true, materialize_false;
3714 Label* if_true = nullptr;
3715 Label* if_false = nullptr;
3716 Label* fall_through = nullptr;
3717 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3718 &if_false, &fall_through);
3720 __ JumpIfSmi(eax, if_false);
3721 __ CmpObjectType(eax, JS_DATE_TYPE, ebx);
3722 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3723 Split(equal, if_true, if_false, fall_through);
3725 context()->Plug(if_true, if_false);
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 Register object = eax;
3738 Register result = eax;
3739 Register scratch = ecx;
3741 if (index->value() == 0) {
3742 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
3744 Label runtime, done;
3745 if (index->value() < JSDate::kFirstUncachedField) {
3746 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3747 __ mov(scratch, Operand::StaticVariable(stamp));
3748 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
3749 __ j(not_equal, &runtime, Label::kNear);
3750 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
3751 kPointerSize * index->value()));
3752 __ jmp(&done, Label::kNear);
3755 __ PrepareCallCFunction(2, scratch);
3756 __ mov(Operand(esp, 0), object);
3757 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
3758 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
3762 context()->Plug(result);
3766 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3767 ZoneList<Expression*>* args = expr->arguments();
3768 DCHECK_EQ(3, args->length());
3770 Register string = eax;
3771 Register index = ebx;
3772 Register value = ecx;
3774 VisitForStackValue(args->at(0)); // index
3775 VisitForStackValue(args->at(1)); // value
3776 VisitForAccumulatorValue(args->at(2)); // string
3781 if (FLAG_debug_code) {
3782 __ test(value, Immediate(kSmiTagMask));
3783 __ Check(zero, kNonSmiValue);
3784 __ test(index, Immediate(kSmiTagMask));
3785 __ Check(zero, kNonSmiValue);
3791 if (FLAG_debug_code) {
3792 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
3793 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
3796 __ mov_b(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
3798 context()->Plug(string);
3802 void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3803 ZoneList<Expression*>* args = expr->arguments();
3804 DCHECK_EQ(3, args->length());
3806 Register string = eax;
3807 Register index = ebx;
3808 Register value = ecx;
3810 VisitForStackValue(args->at(0)); // index
3811 VisitForStackValue(args->at(1)); // value
3812 VisitForAccumulatorValue(args->at(2)); // string
3816 if (FLAG_debug_code) {
3817 __ test(value, Immediate(kSmiTagMask));
3818 __ Check(zero, kNonSmiValue);
3819 __ test(index, Immediate(kSmiTagMask));
3820 __ Check(zero, kNonSmiValue);
3822 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
3823 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
3828 // No need to untag a smi for two-byte addressing.
3829 __ mov_w(FieldOperand(string, index, times_1, SeqTwoByteString::kHeaderSize),
3831 context()->Plug(string);
3835 void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3836 ZoneList<Expression*>* args = expr->arguments();
3837 DCHECK(args->length() == 2);
3839 VisitForStackValue(args->at(0)); // Load the object.
3840 VisitForAccumulatorValue(args->at(1)); // Load the value.
3841 __ pop(ebx); // eax = value. ebx = object.
3844 // If the object is a smi, return the value.
3845 __ JumpIfSmi(ebx, &done, Label::kNear);
3847 // If the object is not a value type, return the value.
3848 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
3849 __ j(not_equal, &done, Label::kNear);
3852 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
3854 // Update the write barrier. Save the value as it will be
3855 // overwritten by the write barrier code and is needed afterward.
3857 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
3860 context()->Plug(eax);
3864 void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3865 ZoneList<Expression*>* args = expr->arguments();
3866 DCHECK_EQ(args->length(), 1);
3868 // Load the argument into eax and call the stub.
3869 VisitForAccumulatorValue(args->at(0));
3871 NumberToStringStub stub(isolate());
3873 context()->Plug(eax);
3877 void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
3878 ZoneList<Expression*>* args = expr->arguments();
3879 DCHECK_EQ(1, args->length());
3881 // Load the argument into eax and convert it.
3882 VisitForAccumulatorValue(args->at(0));
3884 ToObjectStub stub(isolate());
3886 context()->Plug(eax);
3890 void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3891 ZoneList<Expression*>* args = expr->arguments();
3892 DCHECK(args->length() == 1);
3894 VisitForAccumulatorValue(args->at(0));
3897 StringCharFromCodeGenerator generator(eax, ebx);
3898 generator.GenerateFast(masm_);
3901 NopRuntimeCallHelper call_helper;
3902 generator.GenerateSlow(masm_, call_helper);
3905 context()->Plug(ebx);
3909 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3910 ZoneList<Expression*>* args = expr->arguments();
3911 DCHECK(args->length() == 2);
3913 VisitForStackValue(args->at(0));
3914 VisitForAccumulatorValue(args->at(1));
3916 Register object = ebx;
3917 Register index = eax;
3918 Register result = edx;
3922 Label need_conversion;
3923 Label index_out_of_range;
3925 StringCharCodeAtGenerator generator(object,
3930 &index_out_of_range,
3931 STRING_INDEX_IS_NUMBER);
3932 generator.GenerateFast(masm_);
3935 __ bind(&index_out_of_range);
3936 // When the index is out of range, the spec requires us to return
3938 __ Move(result, Immediate(isolate()->factory()->nan_value()));
3941 __ bind(&need_conversion);
3942 // Move the undefined value into the result register, which will
3943 // trigger conversion.
3944 __ Move(result, Immediate(isolate()->factory()->undefined_value()));
3947 NopRuntimeCallHelper call_helper;
3948 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
3951 context()->Plug(result);
3955 void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3956 ZoneList<Expression*>* args = expr->arguments();
3957 DCHECK(args->length() == 2);
3959 VisitForStackValue(args->at(0));
3960 VisitForAccumulatorValue(args->at(1));
3962 Register object = ebx;
3963 Register index = eax;
3964 Register scratch = edx;
3965 Register result = eax;
3969 Label need_conversion;
3970 Label index_out_of_range;
3972 StringCharAtGenerator generator(object,
3978 &index_out_of_range,
3979 STRING_INDEX_IS_NUMBER);
3980 generator.GenerateFast(masm_);
3983 __ bind(&index_out_of_range);
3984 // When the index is out of range, the spec requires us to return
3985 // the empty string.
3986 __ Move(result, Immediate(isolate()->factory()->empty_string()));
3989 __ bind(&need_conversion);
3990 // Move smi zero into the result register, which will trigger
3992 __ Move(result, Immediate(Smi::FromInt(0)));
3995 NopRuntimeCallHelper call_helper;
3996 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
3999 context()->Plug(result);
4003 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
4004 ZoneList<Expression*>* args = expr->arguments();
4005 DCHECK_EQ(2, args->length());
4006 VisitForStackValue(args->at(0));
4007 VisitForAccumulatorValue(args->at(1));
4010 StringAddStub stub(isolate(), STRING_ADD_CHECK_BOTH, NOT_TENURED);
4012 context()->Plug(eax);
4016 void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
4017 ZoneList<Expression*>* args = expr->arguments();
4018 DCHECK(args->length() >= 2);
4020 int arg_count = args->length() - 2; // 2 ~ receiver and function.
4021 for (int i = 0; i < arg_count + 1; ++i) {
4022 VisitForStackValue(args->at(i));
4024 VisitForAccumulatorValue(args->last()); // Function.
4026 Label runtime, done;
4027 // Check for non-function argument (including proxy).
4028 __ JumpIfSmi(eax, &runtime);
4029 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
4030 __ j(not_equal, &runtime);
4032 // InvokeFunction requires the function in edi. Move it in there.
4033 __ mov(edi, result_register());
4034 ParameterCount count(arg_count);
4035 __ InvokeFunction(edi, count, CALL_FUNCTION, NullCallWrapper());
4036 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4041 __ CallRuntime(Runtime::kCall, args->length());
4044 context()->Plug(eax);
4048 void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
4049 ZoneList<Expression*>* args = expr->arguments();
4050 DCHECK(args->length() == 2);
4053 VisitForStackValue(args->at(0));
4056 VisitForStackValue(args->at(1));
4057 __ CallRuntime(Runtime::kGetPrototype, 1);
4058 __ push(result_register());
4060 // Load original constructor into ecx.
4061 __ mov(ecx, Operand(esp, 1 * kPointerSize));
4063 // Check if the calling frame is an arguments adaptor frame.
4064 Label adaptor_frame, args_set_up, runtime;
4065 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
4066 __ mov(ebx, Operand(edx, StandardFrameConstants::kContextOffset));
4067 __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
4068 __ j(equal, &adaptor_frame);
4069 // default constructor has no arguments, so no adaptor frame means no args.
4070 __ mov(eax, Immediate(0));
4071 __ jmp(&args_set_up);
4073 // Copy arguments from adaptor frame.
4075 __ bind(&adaptor_frame);
4076 __ mov(ebx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
4080 __ lea(edx, Operand(edx, ebx, times_pointer_size,
4081 StandardFrameConstants::kCallerSPOffset));
4084 __ push(Operand(edx, -1 * kPointerSize));
4085 __ sub(edx, Immediate(kPointerSize));
4087 __ j(not_zero, &loop);
4090 __ bind(&args_set_up);
4092 __ mov(edi, Operand(esp, eax, times_pointer_size, 0));
4093 __ mov(ebx, Immediate(isolate()->factory()->undefined_value()));
4094 CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
4095 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
4099 context()->Plug(eax);
4103 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
4104 // Load the arguments on the stack and call the stub.
4105 RegExpConstructResultStub stub(isolate());
4106 ZoneList<Expression*>* args = expr->arguments();
4107 DCHECK(args->length() == 3);
4108 VisitForStackValue(args->at(0));
4109 VisitForStackValue(args->at(1));
4110 VisitForAccumulatorValue(args->at(2));
4114 context()->Plug(eax);
4118 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
4119 ZoneList<Expression*>* args = expr->arguments();
4120 DCHECK(args->length() == 1);
4122 VisitForAccumulatorValue(args->at(0));
4124 __ AssertString(eax);
4126 Label materialize_true, materialize_false;
4127 Label* if_true = NULL;
4128 Label* if_false = NULL;
4129 Label* fall_through = NULL;
4130 context()->PrepareTest(&materialize_true, &materialize_false,
4131 &if_true, &if_false, &fall_through);
4133 __ test(FieldOperand(eax, String::kHashFieldOffset),
4134 Immediate(String::kContainsCachedArrayIndexMask));
4135 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4136 Split(zero, if_true, if_false, fall_through);
4138 context()->Plug(if_true, if_false);
4142 void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
4143 ZoneList<Expression*>* args = expr->arguments();
4144 DCHECK(args->length() == 1);
4145 VisitForAccumulatorValue(args->at(0));
4147 __ AssertString(eax);
4149 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
4150 __ IndexFromHash(eax, eax);
4152 context()->Plug(eax);
4156 void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) {
4157 Label bailout, done, one_char_separator, long_separator,
4158 non_trivial_array, not_size_one_array, loop,
4159 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
4161 ZoneList<Expression*>* args = expr->arguments();
4162 DCHECK(args->length() == 2);
4163 // We will leave the separator on the stack until the end of the function.
4164 VisitForStackValue(args->at(1));
4165 // Load this to eax (= array)
4166 VisitForAccumulatorValue(args->at(0));
4167 // All aliases of the same register have disjoint lifetimes.
4168 Register array = eax;
4169 Register elements = no_reg; // Will be eax.
4171 Register index = edx;
4173 Register string_length = ecx;
4175 Register string = esi;
4177 Register scratch = ebx;
4179 Register array_length = edi;
4180 Register result_pos = no_reg; // Will be edi.
4182 // Separator operand is already pushed.
4183 Operand separator_operand = Operand(esp, 2 * kPointerSize);
4184 Operand result_operand = Operand(esp, 1 * kPointerSize);
4185 Operand array_length_operand = Operand(esp, 0);
4186 __ sub(esp, Immediate(2 * kPointerSize));
4188 // Check that the array is a JSArray
4189 __ JumpIfSmi(array, &bailout);
4190 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
4191 __ j(not_equal, &bailout);
4193 // Check that the array has fast elements.
4194 __ CheckFastElements(scratch, &bailout);
4196 // If the array has length zero, return the empty string.
4197 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
4198 __ SmiUntag(array_length);
4199 __ j(not_zero, &non_trivial_array);
4200 __ mov(result_operand, isolate()->factory()->empty_string());
4203 // Save the array length.
4204 __ bind(&non_trivial_array);
4205 __ mov(array_length_operand, array_length);
4207 // Save the FixedArray containing array's elements.
4208 // End of array's live range.
4210 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
4214 // Check that all array elements are sequential one-byte strings, and
4215 // accumulate the sum of their lengths, as a smi-encoded value.
4216 __ Move(index, Immediate(0));
4217 __ Move(string_length, Immediate(0));
4218 // Loop condition: while (index < length).
4219 // Live loop registers: index, array_length, string,
4220 // scratch, string_length, elements.
4221 if (generate_debug_code_) {
4222 __ cmp(index, array_length);
4223 __ Assert(less, kNoEmptyArraysHereInEmitFastOneByteArrayJoin);
4226 __ mov(string, FieldOperand(elements,
4229 FixedArray::kHeaderSize));
4230 __ JumpIfSmi(string, &bailout);
4231 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
4232 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
4233 __ and_(scratch, Immediate(
4234 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
4235 __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
4236 __ j(not_equal, &bailout);
4237 __ add(string_length,
4238 FieldOperand(string, SeqOneByteString::kLengthOffset));
4239 __ j(overflow, &bailout);
4240 __ add(index, Immediate(1));
4241 __ cmp(index, array_length);
4244 // If array_length is 1, return elements[0], a string.
4245 __ cmp(array_length, 1);
4246 __ j(not_equal, ¬_size_one_array);
4247 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
4248 __ mov(result_operand, scratch);
4251 __ bind(¬_size_one_array);
4253 // End of array_length live range.
4254 result_pos = array_length;
4255 array_length = no_reg;
4258 // string_length: Sum of string lengths, as a smi.
4259 // elements: FixedArray of strings.
4261 // Check that the separator is a flat one-byte string.
4262 __ mov(string, separator_operand);
4263 __ JumpIfSmi(string, &bailout);
4264 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
4265 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
4266 __ and_(scratch, Immediate(
4267 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
4268 __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
4269 __ j(not_equal, &bailout);
4271 // Add (separator length times array_length) - separator length
4272 // to string_length.
4273 __ mov(scratch, separator_operand);
4274 __ mov(scratch, FieldOperand(scratch, SeqOneByteString::kLengthOffset));
4275 __ sub(string_length, scratch); // May be negative, temporarily.
4276 __ imul(scratch, array_length_operand);
4277 __ j(overflow, &bailout);
4278 __ add(string_length, scratch);
4279 __ j(overflow, &bailout);
4281 __ shr(string_length, 1);
4282 // Live registers and stack values:
4285 __ AllocateOneByteString(result_pos, string_length, scratch, index, string,
4287 __ mov(result_operand, result_pos);
4288 __ lea(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize));
4291 __ mov(string, separator_operand);
4292 __ cmp(FieldOperand(string, SeqOneByteString::kLengthOffset),
4293 Immediate(Smi::FromInt(1)));
4294 __ j(equal, &one_char_separator);
4295 __ j(greater, &long_separator);
4298 // Empty separator case
4299 __ mov(index, Immediate(0));
4300 __ jmp(&loop_1_condition);
4301 // Loop condition: while (index < length).
4303 // Each iteration of the loop concatenates one string to the result.
4304 // Live values in registers:
4305 // index: which element of the elements array we are adding to the result.
4306 // result_pos: the position to which we are currently copying characters.
4307 // elements: the FixedArray of strings we are joining.
4309 // Get string = array[index].
4310 __ mov(string, FieldOperand(elements, index,
4312 FixedArray::kHeaderSize));
4313 __ mov(string_length,
4314 FieldOperand(string, String::kLengthOffset));
4315 __ shr(string_length, 1);
4317 FieldOperand(string, SeqOneByteString::kHeaderSize));
4318 __ CopyBytes(string, result_pos, string_length, scratch);
4319 __ add(index, Immediate(1));
4320 __ bind(&loop_1_condition);
4321 __ cmp(index, array_length_operand);
4322 __ j(less, &loop_1); // End while (index < length).
4327 // One-character separator case
4328 __ bind(&one_char_separator);
4329 // Replace separator with its one-byte character value.
4330 __ mov_b(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize));
4331 __ mov_b(separator_operand, scratch);
4333 __ Move(index, Immediate(0));
4334 // Jump into the loop after the code that copies the separator, so the first
4335 // element is not preceded by a separator
4336 __ jmp(&loop_2_entry);
4337 // Loop condition: while (index < length).
4339 // Each iteration of the loop concatenates one string to the result.
4340 // Live values in registers:
4341 // index: which element of the elements array we are adding to the result.
4342 // result_pos: the position to which we are currently copying characters.
4344 // Copy the separator character to the result.
4345 __ mov_b(scratch, separator_operand);
4346 __ mov_b(Operand(result_pos, 0), scratch);
4349 __ bind(&loop_2_entry);
4350 // Get string = array[index].
4351 __ mov(string, FieldOperand(elements, index,
4353 FixedArray::kHeaderSize));
4354 __ mov(string_length,
4355 FieldOperand(string, String::kLengthOffset));
4356 __ shr(string_length, 1);
4358 FieldOperand(string, SeqOneByteString::kHeaderSize));
4359 __ CopyBytes(string, result_pos, string_length, scratch);
4360 __ add(index, Immediate(1));
4362 __ cmp(index, array_length_operand);
4363 __ j(less, &loop_2); // End while (index < length).
4367 // Long separator case (separator is more than one character).
4368 __ bind(&long_separator);
4370 __ Move(index, Immediate(0));
4371 // Jump into the loop after the code that copies the separator, so the first
4372 // element is not preceded by a separator
4373 __ jmp(&loop_3_entry);
4374 // Loop condition: while (index < length).
4376 // Each iteration of the loop concatenates one string to the result.
4377 // Live values in registers:
4378 // index: which element of the elements array we are adding to the result.
4379 // result_pos: the position to which we are currently copying characters.
4381 // Copy the separator to the result.
4382 __ mov(string, separator_operand);
4383 __ mov(string_length,
4384 FieldOperand(string, String::kLengthOffset));
4385 __ shr(string_length, 1);
4387 FieldOperand(string, SeqOneByteString::kHeaderSize));
4388 __ CopyBytes(string, result_pos, string_length, scratch);
4390 __ bind(&loop_3_entry);
4391 // Get string = array[index].
4392 __ mov(string, FieldOperand(elements, index,
4394 FixedArray::kHeaderSize));
4395 __ mov(string_length,
4396 FieldOperand(string, String::kLengthOffset));
4397 __ shr(string_length, 1);
4399 FieldOperand(string, SeqOneByteString::kHeaderSize));
4400 __ CopyBytes(string, result_pos, string_length, scratch);
4401 __ add(index, Immediate(1));
4403 __ cmp(index, array_length_operand);
4404 __ j(less, &loop_3); // End while (index < length).
4409 __ mov(result_operand, isolate()->factory()->undefined_value());
4411 __ mov(eax, result_operand);
4412 // Drop temp values from the stack, and restore context register.
4413 __ add(esp, Immediate(3 * kPointerSize));
4415 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4416 context()->Plug(eax);
4420 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
4421 DCHECK(expr->arguments()->length() == 0);
4422 ExternalReference debug_is_active =
4423 ExternalReference::debug_is_active_address(isolate());
4424 __ movzx_b(eax, Operand::StaticVariable(debug_is_active));
4426 context()->Plug(eax);
4430 void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
4431 // Push undefined as receiver.
4432 __ push(Immediate(isolate()->factory()->undefined_value()));
4434 __ mov(eax, GlobalObjectOperand());
4435 __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
4436 __ mov(eax, ContextOperand(eax, expr->context_index()));
4440 void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) {
4441 ZoneList<Expression*>* args = expr->arguments();
4442 int arg_count = args->length();
4444 SetCallPosition(expr, arg_count);
4445 CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
4446 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
4451 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
4452 ZoneList<Expression*>* args = expr->arguments();
4453 int arg_count = args->length();
4455 if (expr->is_jsruntime()) {
4456 Comment cmnt(masm_, "[ CallRuntime");
4457 EmitLoadJSRuntimeFunction(expr);
4459 // Push the target function under the receiver.
4460 __ push(Operand(esp, 0));
4461 __ mov(Operand(esp, kPointerSize), eax);
4463 // Push the arguments ("left-to-right").
4464 for (int i = 0; i < arg_count; i++) {
4465 VisitForStackValue(args->at(i));
4468 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS);
4469 EmitCallJSRuntimeFunction(expr);
4471 // Restore context register.
4472 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4473 context()->DropAndPlug(1, eax);
4476 const Runtime::Function* function = expr->function();
4477 switch (function->function_id) {
4478 #define CALL_INTRINSIC_GENERATOR(Name) \
4479 case Runtime::kInline##Name: { \
4480 Comment cmnt(masm_, "[ Inline" #Name); \
4481 return Emit##Name(expr); \
4483 FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
4484 #undef CALL_INTRINSIC_GENERATOR
4486 Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
4487 // Push the arguments ("left-to-right").
4488 for (int i = 0; i < arg_count; i++) {
4489 VisitForStackValue(args->at(i));
4492 // Call the C runtime function.
4493 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS);
4494 __ CallRuntime(expr->function(), arg_count);
4495 context()->Plug(eax);
4502 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
4503 switch (expr->op()) {
4504 case Token::DELETE: {
4505 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
4506 Property* property = expr->expression()->AsProperty();
4507 VariableProxy* proxy = expr->expression()->AsVariableProxy();
4509 if (property != NULL) {
4510 VisitForStackValue(property->obj());
4511 VisitForStackValue(property->key());
4512 __ CallRuntime(is_strict(language_mode())
4513 ? Runtime::kDeleteProperty_Strict
4514 : Runtime::kDeleteProperty_Sloppy,
4516 context()->Plug(eax);
4517 } else if (proxy != NULL) {
4518 Variable* var = proxy->var();
4519 // Delete of an unqualified identifier is disallowed in strict mode but
4520 // "delete this" is allowed.
4521 bool is_this = var->HasThisName(isolate());
4522 DCHECK(is_sloppy(language_mode()) || is_this);
4523 if (var->IsUnallocatedOrGlobalSlot()) {
4524 __ push(GlobalObjectOperand());
4525 __ push(Immediate(var->name()));
4526 __ CallRuntime(Runtime::kDeleteProperty_Sloppy, 2);
4527 context()->Plug(eax);
4528 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
4529 // Result of deleting non-global variables is false. 'this' is
4530 // not really a variable, though we implement it as one. The
4531 // subexpression does not have side effects.
4532 context()->Plug(is_this);
4534 // Non-global variable. Call the runtime to try to delete from the
4535 // context where the variable was introduced.
4536 __ push(context_register());
4537 __ push(Immediate(var->name()));
4538 __ CallRuntime(Runtime::kDeleteLookupSlot, 2);
4539 context()->Plug(eax);
4542 // Result of deleting non-property, non-variable reference is true.
4543 // The subexpression may have side effects.
4544 VisitForEffect(expr->expression());
4545 context()->Plug(true);
4551 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
4552 VisitForEffect(expr->expression());
4553 context()->Plug(isolate()->factory()->undefined_value());
4558 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
4559 if (context()->IsEffect()) {
4560 // Unary NOT has no side effects so it's only necessary to visit the
4561 // subexpression. Match the optimizing compiler by not branching.
4562 VisitForEffect(expr->expression());
4563 } else if (context()->IsTest()) {
4564 const TestContext* test = TestContext::cast(context());
4565 // The labels are swapped for the recursive call.
4566 VisitForControl(expr->expression(),
4567 test->false_label(),
4569 test->fall_through());
4570 context()->Plug(test->true_label(), test->false_label());
4572 // We handle value contexts explicitly rather than simply visiting
4573 // for control and plugging the control flow into the context,
4574 // because we need to prepare a pair of extra administrative AST ids
4575 // for the optimizing compiler.
4576 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
4577 Label materialize_true, materialize_false, done;
4578 VisitForControl(expr->expression(),
4582 __ bind(&materialize_true);
4583 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4584 if (context()->IsAccumulatorValue()) {
4585 __ mov(eax, isolate()->factory()->true_value());
4587 __ Push(isolate()->factory()->true_value());
4589 __ jmp(&done, Label::kNear);
4590 __ bind(&materialize_false);
4591 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4592 if (context()->IsAccumulatorValue()) {
4593 __ mov(eax, isolate()->factory()->false_value());
4595 __ Push(isolate()->factory()->false_value());
4602 case Token::TYPEOF: {
4603 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
4605 AccumulatorValueContext context(this);
4606 VisitForTypeofValue(expr->expression());
4609 TypeofStub typeof_stub(isolate());
4610 __ CallStub(&typeof_stub);
4611 context()->Plug(eax);
4621 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
4622 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
4624 Comment cmnt(masm_, "[ CountOperation");
4626 Property* prop = expr->expression()->AsProperty();
4627 LhsKind assign_type = Property::GetAssignType(prop);
4629 // Evaluate expression and get value.
4630 if (assign_type == VARIABLE) {
4631 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
4632 AccumulatorValueContext context(this);
4633 EmitVariableLoad(expr->expression()->AsVariableProxy());
4635 // Reserve space for result of postfix operation.
4636 if (expr->is_postfix() && !context()->IsEffect()) {
4637 __ push(Immediate(Smi::FromInt(0)));
4639 switch (assign_type) {
4640 case NAMED_PROPERTY: {
4641 // Put the object both on the stack and in the register.
4642 VisitForStackValue(prop->obj());
4643 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
4644 EmitNamedPropertyLoad(prop);
4648 case NAMED_SUPER_PROPERTY: {
4649 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
4650 VisitForAccumulatorValue(
4651 prop->obj()->AsSuperPropertyReference()->home_object());
4652 __ push(result_register());
4653 __ push(MemOperand(esp, kPointerSize));
4654 __ push(result_register());
4655 EmitNamedSuperPropertyLoad(prop);
4659 case KEYED_SUPER_PROPERTY: {
4660 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
4662 prop->obj()->AsSuperPropertyReference()->home_object());
4663 VisitForAccumulatorValue(prop->key());
4664 __ push(result_register());
4665 __ push(MemOperand(esp, 2 * kPointerSize));
4666 __ push(MemOperand(esp, 2 * kPointerSize));
4667 __ push(result_register());
4668 EmitKeyedSuperPropertyLoad(prop);
4672 case KEYED_PROPERTY: {
4673 VisitForStackValue(prop->obj());
4674 VisitForStackValue(prop->key());
4675 __ mov(LoadDescriptor::ReceiverRegister(),
4676 Operand(esp, kPointerSize)); // Object.
4677 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key.
4678 EmitKeyedPropertyLoad(prop);
4687 // We need a second deoptimization point after loading the value
4688 // in case evaluating the property load my have a side effect.
4689 if (assign_type == VARIABLE) {
4690 PrepareForBailout(expr->expression(), TOS_REG);
4692 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
4695 // Inline smi case if we are in a loop.
4696 Label done, stub_call;
4697 JumpPatchSite patch_site(masm_);
4698 if (ShouldInlineSmiCase(expr->op())) {
4700 patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
4702 // Save result for postfix expressions.
4703 if (expr->is_postfix()) {
4704 if (!context()->IsEffect()) {
4705 // Save the result on the stack. If we have a named or keyed property
4706 // we store the result under the receiver that is currently on top
4708 switch (assign_type) {
4712 case NAMED_PROPERTY:
4713 __ mov(Operand(esp, kPointerSize), eax);
4715 case NAMED_SUPER_PROPERTY:
4716 __ mov(Operand(esp, 2 * kPointerSize), eax);
4718 case KEYED_PROPERTY:
4719 __ mov(Operand(esp, 2 * kPointerSize), eax);
4721 case KEYED_SUPER_PROPERTY:
4722 __ mov(Operand(esp, 3 * kPointerSize), eax);
4728 if (expr->op() == Token::INC) {
4729 __ add(eax, Immediate(Smi::FromInt(1)));
4731 __ sub(eax, Immediate(Smi::FromInt(1)));
4733 __ j(no_overflow, &done, Label::kNear);
4734 // Call stub. Undo operation first.
4735 if (expr->op() == Token::INC) {
4736 __ sub(eax, Immediate(Smi::FromInt(1)));
4738 __ add(eax, Immediate(Smi::FromInt(1)));
4740 __ jmp(&stub_call, Label::kNear);
4743 if (!is_strong(language_mode())) {
4744 ToNumberStub convert_stub(isolate());
4745 __ CallStub(&convert_stub);
4746 PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
4749 // Save result for postfix expressions.
4750 if (expr->is_postfix()) {
4751 if (!context()->IsEffect()) {
4752 // Save the result on the stack. If we have a named or keyed property
4753 // we store the result under the receiver that is currently on top
4755 switch (assign_type) {
4759 case NAMED_PROPERTY:
4760 __ mov(Operand(esp, kPointerSize), eax);
4762 case NAMED_SUPER_PROPERTY:
4763 __ mov(Operand(esp, 2 * kPointerSize), eax);
4765 case KEYED_PROPERTY:
4766 __ mov(Operand(esp, 2 * kPointerSize), eax);
4768 case KEYED_SUPER_PROPERTY:
4769 __ mov(Operand(esp, 3 * kPointerSize), eax);
4775 SetExpressionPosition(expr);
4777 // Call stub for +1/-1.
4778 __ bind(&stub_call);
4780 __ mov(eax, Immediate(Smi::FromInt(1)));
4781 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), expr->binary_op(),
4782 strength(language_mode())).code();
4783 CallIC(code, expr->CountBinOpFeedbackId());
4784 patch_site.EmitPatchInfo();
4787 if (is_strong(language_mode())) {
4788 PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
4790 // Store the value returned in eax.
4791 switch (assign_type) {
4793 if (expr->is_postfix()) {
4794 // Perform the assignment as if via '='.
4795 { EffectContext context(this);
4796 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4797 Token::ASSIGN, expr->CountSlot());
4798 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4801 // For all contexts except EffectContext We have the result on
4802 // top of the stack.
4803 if (!context()->IsEffect()) {
4804 context()->PlugTOS();
4807 // Perform the assignment as if via '='.
4808 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4809 Token::ASSIGN, expr->CountSlot());
4810 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4811 context()->Plug(eax);
4814 case NAMED_PROPERTY: {
4815 __ mov(StoreDescriptor::NameRegister(),
4816 prop->key()->AsLiteral()->value());
4817 __ pop(StoreDescriptor::ReceiverRegister());
4818 if (FLAG_vector_stores) {
4819 EmitLoadStoreICSlot(expr->CountSlot());
4822 CallStoreIC(expr->CountStoreFeedbackId());
4824 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4825 if (expr->is_postfix()) {
4826 if (!context()->IsEffect()) {
4827 context()->PlugTOS();
4830 context()->Plug(eax);
4834 case NAMED_SUPER_PROPERTY: {
4835 EmitNamedSuperPropertyStore(prop);
4836 if (expr->is_postfix()) {
4837 if (!context()->IsEffect()) {
4838 context()->PlugTOS();
4841 context()->Plug(eax);
4845 case KEYED_SUPER_PROPERTY: {
4846 EmitKeyedSuperPropertyStore(prop);
4847 if (expr->is_postfix()) {
4848 if (!context()->IsEffect()) {
4849 context()->PlugTOS();
4852 context()->Plug(eax);
4856 case KEYED_PROPERTY: {
4857 __ pop(StoreDescriptor::NameRegister());
4858 __ pop(StoreDescriptor::ReceiverRegister());
4860 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
4861 if (FLAG_vector_stores) {
4862 EmitLoadStoreICSlot(expr->CountSlot());
4865 CallIC(ic, expr->CountStoreFeedbackId());
4867 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4868 if (expr->is_postfix()) {
4869 // Result is on the stack
4870 if (!context()->IsEffect()) {
4871 context()->PlugTOS();
4874 context()->Plug(eax);
4882 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
4883 Expression* sub_expr,
4884 Handle<String> check) {
4885 Label materialize_true, materialize_false;
4886 Label* if_true = NULL;
4887 Label* if_false = NULL;
4888 Label* fall_through = NULL;
4889 context()->PrepareTest(&materialize_true, &materialize_false,
4890 &if_true, &if_false, &fall_through);
4892 { AccumulatorValueContext context(this);
4893 VisitForTypeofValue(sub_expr);
4895 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4897 Factory* factory = isolate()->factory();
4898 if (String::Equals(check, factory->number_string())) {
4899 __ JumpIfSmi(eax, if_true);
4900 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4901 isolate()->factory()->heap_number_map());
4902 Split(equal, if_true, if_false, fall_through);
4903 } else if (String::Equals(check, factory->string_string())) {
4904 __ JumpIfSmi(eax, if_false);
4905 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
4906 Split(below, if_true, if_false, fall_through);
4907 } else if (String::Equals(check, factory->symbol_string())) {
4908 __ JumpIfSmi(eax, if_false);
4909 __ CmpObjectType(eax, SYMBOL_TYPE, edx);
4910 Split(equal, if_true, if_false, fall_through);
4911 } else if (String::Equals(check, factory->boolean_string())) {
4912 __ cmp(eax, isolate()->factory()->true_value());
4913 __ j(equal, if_true);
4914 __ cmp(eax, isolate()->factory()->false_value());
4915 Split(equal, if_true, if_false, fall_through);
4916 } else if (String::Equals(check, factory->undefined_string())) {
4917 __ cmp(eax, isolate()->factory()->undefined_value());
4918 __ j(equal, if_true);
4919 __ JumpIfSmi(eax, if_false);
4920 // Check for undetectable objects => true.
4921 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4922 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4923 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4924 Split(not_zero, if_true, if_false, fall_through);
4925 } else if (String::Equals(check, factory->function_string())) {
4926 __ JumpIfSmi(eax, if_false);
4927 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4928 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
4929 __ j(equal, if_true);
4930 __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
4931 Split(equal, if_true, if_false, fall_through);
4932 } else if (String::Equals(check, factory->object_string())) {
4933 __ JumpIfSmi(eax, if_false);
4934 __ cmp(eax, isolate()->factory()->null_value());
4935 __ j(equal, if_true);
4936 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
4937 __ j(below, if_false);
4938 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4939 __ j(above, if_false);
4940 // Check for undetectable objects => false.
4941 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4942 1 << Map::kIsUndetectable);
4943 Split(zero, if_true, if_false, fall_through);
4945 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
4946 } else if (String::Equals(check, factory->type##_string())) { \
4947 __ JumpIfSmi(eax, if_false); \
4948 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), \
4949 isolate()->factory()->type##_map()); \
4950 Split(equal, if_true, if_false, fall_through);
4951 SIMD128_TYPES(SIMD128_TYPE)
4955 if (if_false != fall_through) __ jmp(if_false);
4957 context()->Plug(if_true, if_false);
4961 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4962 Comment cmnt(masm_, "[ CompareOperation");
4963 SetExpressionPosition(expr);
4965 // First we try a fast inlined version of the compare when one of
4966 // the operands is a literal.
4967 if (TryLiteralCompare(expr)) return;
4969 // Always perform the comparison for its control flow. Pack the result
4970 // into the expression's context after the comparison is performed.
4971 Label materialize_true, materialize_false;
4972 Label* if_true = NULL;
4973 Label* if_false = NULL;
4974 Label* fall_through = NULL;
4975 context()->PrepareTest(&materialize_true, &materialize_false,
4976 &if_true, &if_false, &fall_through);
4978 Token::Value op = expr->op();
4979 VisitForStackValue(expr->left());
4982 VisitForStackValue(expr->right());
4983 __ InvokeBuiltin(Context::IN_BUILTIN_INDEX, CALL_FUNCTION);
4984 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
4985 __ cmp(eax, isolate()->factory()->true_value());
4986 Split(equal, if_true, if_false, fall_through);
4989 case Token::INSTANCEOF: {
4990 VisitForAccumulatorValue(expr->right());
4992 InstanceOfStub stub(isolate());
4994 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
4995 __ cmp(eax, isolate()->factory()->true_value());
4996 Split(equal, if_true, if_false, fall_through);
5001 VisitForAccumulatorValue(expr->right());
5002 Condition cc = CompareIC::ComputeCondition(op);
5005 bool inline_smi_code = ShouldInlineSmiCase(op);
5006 JumpPatchSite patch_site(masm_);
5007 if (inline_smi_code) {
5011 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
5013 Split(cc, if_true, if_false, NULL);
5014 __ bind(&slow_case);
5017 Handle<Code> ic = CodeFactory::CompareIC(
5018 isolate(), op, strength(language_mode())).code();
5019 CallIC(ic, expr->CompareOperationFeedbackId());
5020 patch_site.EmitPatchInfo();
5022 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
5024 Split(cc, if_true, if_false, fall_through);
5028 // Convert the result of the comparison into one expected for this
5029 // expression's context.
5030 context()->Plug(if_true, if_false);
5034 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
5035 Expression* sub_expr,
5037 Label materialize_true, materialize_false;
5038 Label* if_true = NULL;
5039 Label* if_false = NULL;
5040 Label* fall_through = NULL;
5041 context()->PrepareTest(&materialize_true, &materialize_false,
5042 &if_true, &if_false, &fall_through);
5044 VisitForAccumulatorValue(sub_expr);
5045 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
5047 Handle<Object> nil_value = nil == kNullValue
5048 ? isolate()->factory()->null_value()
5049 : isolate()->factory()->undefined_value();
5050 if (expr->op() == Token::EQ_STRICT) {
5051 __ cmp(eax, nil_value);
5052 Split(equal, if_true, if_false, fall_through);
5054 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
5055 CallIC(ic, expr->CompareOperationFeedbackId());
5057 Split(not_zero, if_true, if_false, fall_through);
5059 context()->Plug(if_true, if_false);
5063 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
5064 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
5065 context()->Plug(eax);
5069 Register FullCodeGenerator::result_register() {
5074 Register FullCodeGenerator::context_register() {
5079 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
5080 DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
5081 __ mov(Operand(ebp, frame_offset), value);
5085 void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
5086 __ mov(dst, ContextOperand(esi, context_index));
5090 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
5091 Scope* closure_scope = scope()->ClosureScope();
5092 if (closure_scope->is_script_scope() ||
5093 closure_scope->is_module_scope()) {
5094 // Contexts nested in the native context have a canonical empty function
5095 // as their closure, not the anonymous closure containing the global
5096 // code. Pass a smi sentinel and let the runtime look up the empty
5098 __ push(Immediate(Smi::FromInt(0)));
5099 } else if (closure_scope->is_eval_scope()) {
5100 // Contexts nested inside eval code have the same closure as the context
5101 // calling eval, not the anonymous closure containing the eval code.
5102 // Fetch it from the context.
5103 __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
5105 DCHECK(closure_scope->is_function_scope());
5106 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
5111 // ----------------------------------------------------------------------------
5112 // Non-local control flow support.
5114 void FullCodeGenerator::EnterFinallyBlock() {
5115 // Cook return address on top of stack (smi encoded Code* delta)
5116 DCHECK(!result_register().is(edx));
5118 __ sub(edx, Immediate(masm_->CodeObject()));
5119 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
5120 STATIC_ASSERT(kSmiTag == 0);
5124 // Store result register while executing finally block.
5125 __ push(result_register());
5127 // Store pending message while executing finally block.
5128 ExternalReference pending_message_obj =
5129 ExternalReference::address_of_pending_message_obj(isolate());
5130 __ mov(edx, Operand::StaticVariable(pending_message_obj));
5133 ClearPendingMessage();
5137 void FullCodeGenerator::ExitFinallyBlock() {
5138 DCHECK(!result_register().is(edx));
5139 // Restore pending message from stack.
5141 ExternalReference pending_message_obj =
5142 ExternalReference::address_of_pending_message_obj(isolate());
5143 __ mov(Operand::StaticVariable(pending_message_obj), edx);
5145 // Restore result register from stack.
5146 __ pop(result_register());
5148 // Uncook return address.
5151 __ add(edx, Immediate(masm_->CodeObject()));
5156 void FullCodeGenerator::ClearPendingMessage() {
5157 DCHECK(!result_register().is(edx));
5158 ExternalReference pending_message_obj =
5159 ExternalReference::address_of_pending_message_obj(isolate());
5160 __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
5161 __ mov(Operand::StaticVariable(pending_message_obj), edx);
5165 void FullCodeGenerator::EmitLoadStoreICSlot(FeedbackVectorICSlot slot) {
5166 DCHECK(FLAG_vector_stores && !slot.IsInvalid());
5167 __ mov(VectorStoreICTrampolineDescriptor::SlotRegister(),
5168 Immediate(SmiFromSlot(slot)));
5175 static const byte kJnsInstruction = 0x79;
5176 static const byte kJnsOffset = 0x11;
5177 static const byte kNopByteOne = 0x66;
5178 static const byte kNopByteTwo = 0x90;
5180 static const byte kCallInstruction = 0xe8;
5184 void BackEdgeTable::PatchAt(Code* unoptimized_code,
5186 BackEdgeState target_state,
5187 Code* replacement_code) {
5188 Address call_target_address = pc - kIntSize;
5189 Address jns_instr_address = call_target_address - 3;
5190 Address jns_offset_address = call_target_address - 2;
5192 switch (target_state) {
5194 // sub <profiling_counter>, <delta> ;; Not changed
5196 // call <interrupt stub>
5198 *jns_instr_address = kJnsInstruction;
5199 *jns_offset_address = kJnsOffset;
5201 case ON_STACK_REPLACEMENT:
5202 case OSR_AFTER_STACK_CHECK:
5203 // sub <profiling_counter>, <delta> ;; Not changed
5206 // call <on-stack replacment>
5208 *jns_instr_address = kNopByteOne;
5209 *jns_offset_address = kNopByteTwo;
5213 Assembler::set_target_address_at(call_target_address,
5215 replacement_code->entry());
5216 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
5217 unoptimized_code, call_target_address, replacement_code);
5221 BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
5223 Code* unoptimized_code,
5225 Address call_target_address = pc - kIntSize;
5226 Address jns_instr_address = call_target_address - 3;
5227 DCHECK_EQ(kCallInstruction, *(call_target_address - 1));
5229 if (*jns_instr_address == kJnsInstruction) {
5230 DCHECK_EQ(kJnsOffset, *(call_target_address - 2));
5231 DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(),
5232 Assembler::target_address_at(call_target_address,
5237 DCHECK_EQ(kNopByteOne, *jns_instr_address);
5238 DCHECK_EQ(kNopByteTwo, *(call_target_address - 2));
5240 if (Assembler::target_address_at(call_target_address, unoptimized_code) ==
5241 isolate->builtins()->OnStackReplacement()->entry()) {
5242 return ON_STACK_REPLACEMENT;
5245 DCHECK_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(),
5246 Assembler::target_address_at(call_target_address,
5248 return OSR_AFTER_STACK_CHECK;
5252 } // namespace internal
5255 #endif // V8_TARGET_ARCH_X87