blob: 4ef3a0984f503ad30e687fe4825888932ad3e07a [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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.
4
5#if V8_TARGET_ARCH_IA32
6
7#include "src/ast/scopes.h"
8#include "src/code-factory.h"
9#include "src/code-stubs.h"
10#include "src/codegen.h"
11#include "src/debug/debug.h"
12#include "src/full-codegen/full-codegen.h"
13#include "src/ia32/frames-ia32.h"
14#include "src/ic/ic.h"
15#include "src/parsing/parser.h"
16
17namespace v8 {
18namespace internal {
19
20#define __ ACCESS_MASM(masm_)
21
22
23class JumpPatchSite BASE_EMBEDDED {
24 public:
25 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
26#ifdef DEBUG
27 info_emitted_ = false;
28#endif
29 }
30
31 ~JumpPatchSite() {
32 DCHECK(patch_site_.is_bound() == info_emitted_);
33 }
34
35 void EmitJumpIfNotSmi(Register reg,
36 Label* target,
37 Label::Distance distance = Label::kFar) {
38 __ test(reg, Immediate(kSmiTagMask));
39 EmitJump(not_carry, target, distance); // Always taken before patched.
40 }
41
42 void EmitJumpIfSmi(Register reg,
43 Label* target,
44 Label::Distance distance = Label::kFar) {
45 __ test(reg, Immediate(kSmiTagMask));
46 EmitJump(carry, target, distance); // Never taken before patched.
47 }
48
49 void EmitPatchInfo() {
50 if (patch_site_.is_bound()) {
51 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
52 DCHECK(is_uint8(delta_to_patch_site));
53 __ test(eax, Immediate(delta_to_patch_site));
54#ifdef DEBUG
55 info_emitted_ = true;
56#endif
57 } else {
58 __ nop(); // Signals no inlined code.
59 }
60 }
61
62 private:
63 // jc will be patched with jz, jnc will become jnz.
64 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
65 DCHECK(!patch_site_.is_bound() && !info_emitted_);
66 DCHECK(cc == carry || cc == not_carry);
67 __ bind(&patch_site_);
68 __ j(cc, target, distance);
69 }
70
71 MacroAssembler* masm_;
72 Label patch_site_;
73#ifdef DEBUG
74 bool info_emitted_;
75#endif
76};
77
78
79// Generate code for a JS function. On entry to the function the receiver
80// and arguments have been pushed on the stack left to right, with the
81// return address on top of them. The actual argument count matches the
82// formal parameter count expected by the function.
83//
84// The live registers are:
85// o edi: the JS function object being called (i.e. ourselves)
86// o edx: the new target value
87// o esi: our context
88// o ebp: our caller's frame pointer
89// o esp: stack pointer (pointing to return address)
90//
91// The function builds a JS frame. Please see JavaScriptFrameConstants in
92// frames-ia32.h for its layout.
93void 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");
99
100 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
101
102#ifdef DEBUG
103 if (strlen(FLAG_stop_at) > 0 &&
104 literal()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
105 __ int3();
106 }
107#endif
108
109 if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) {
110 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
111 __ mov(ecx, Operand(esp, receiver_offset));
112 __ AssertNotSmi(ecx);
113 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ecx);
114 __ Assert(above_equal, kSloppyFunctionExpectsJSReceiverReceiver);
115 }
116
117 // Open a frame scope to indicate that there is a frame on the stack. The
118 // MANUAL indicates that the scope shouldn't actually generate code to set up
119 // the frame (that is done below).
120 FrameScope frame_scope(masm_, StackFrame::MANUAL);
121
122 info->set_prologue_offset(masm_->pc_offset());
123 __ Prologue(info->GeneratePreagedPrologue());
124
125 { Comment cmnt(masm_, "[ Allocate locals");
126 int locals_count = info->scope()->num_stack_slots();
127 // Generators allocate locals, if any, in context slots.
128 DCHECK(!IsGeneratorFunction(literal()->kind()) || locals_count == 0);
129 if (locals_count == 1) {
130 __ push(Immediate(isolate()->factory()->undefined_value()));
131 } else if (locals_count > 1) {
132 if (locals_count >= 128) {
133 Label ok;
134 __ mov(ecx, esp);
135 __ sub(ecx, Immediate(locals_count * kPointerSize));
136 ExternalReference stack_limit =
137 ExternalReference::address_of_real_stack_limit(isolate());
138 __ cmp(ecx, Operand::StaticVariable(stack_limit));
139 __ j(above_equal, &ok, Label::kNear);
140 __ CallRuntime(Runtime::kThrowStackOverflow);
141 __ bind(&ok);
142 }
143 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
144 const int kMaxPushes = 32;
145 if (locals_count >= kMaxPushes) {
146 int loop_iterations = locals_count / kMaxPushes;
147 __ mov(ecx, loop_iterations);
148 Label loop_header;
149 __ bind(&loop_header);
150 // Do pushes.
151 for (int i = 0; i < kMaxPushes; i++) {
152 __ push(eax);
153 }
154 __ dec(ecx);
155 __ j(not_zero, &loop_header, Label::kNear);
156 }
157 int remaining = locals_count % kMaxPushes;
158 // Emit the remaining pushes.
159 for (int i = 0; i < remaining; i++) {
160 __ push(eax);
161 }
162 }
163 }
164
165 bool function_in_register = true;
166
167 // Possibly allocate a local context.
168 if (info->scope()->num_heap_slots() > 0) {
169 Comment cmnt(masm_, "[ Allocate context");
170 bool need_write_barrier = true;
171 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
172 // Argument to NewContext is the function, which is still in edi.
173 if (info->scope()->is_script_scope()) {
174 __ push(edi);
175 __ Push(info->scope()->GetScopeInfo(info->isolate()));
176 __ CallRuntime(Runtime::kNewScriptContext);
177 PrepareForBailoutForId(BailoutId::ScriptContext(), TOS_REG);
178 // The new target value is not used, clobbering is safe.
179 DCHECK_NULL(info->scope()->new_target_var());
180 } else {
181 if (info->scope()->new_target_var() != nullptr) {
182 __ push(edx); // Preserve new target.
183 }
184 if (slots <= FastNewContextStub::kMaximumSlots) {
185 FastNewContextStub stub(isolate(), slots);
186 __ CallStub(&stub);
187 // Result of FastNewContextStub is always in new space.
188 need_write_barrier = false;
189 } else {
190 __ push(edi);
191 __ CallRuntime(Runtime::kNewFunctionContext);
192 }
193 if (info->scope()->new_target_var() != nullptr) {
194 __ pop(edx); // Restore new target.
195 }
196 }
197 function_in_register = false;
198 // Context is returned in eax. It replaces the context passed to us.
199 // It's saved in the stack and kept live in esi.
200 __ mov(esi, eax);
201 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax);
202
203 // Copy parameters into context if necessary.
204 int num_parameters = info->scope()->num_parameters();
205 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
206 for (int i = first_parameter; i < num_parameters; i++) {
207 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
208 if (var->IsContextSlot()) {
209 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
210 (num_parameters - 1 - i) * kPointerSize;
211 // Load parameter from stack.
212 __ mov(eax, Operand(ebp, parameter_offset));
213 // Store it in the context.
214 int context_offset = Context::SlotOffset(var->index());
215 __ mov(Operand(esi, context_offset), eax);
216 // Update the write barrier. This clobbers eax and ebx.
217 if (need_write_barrier) {
218 __ RecordWriteContextSlot(esi,
219 context_offset,
220 eax,
221 ebx,
222 kDontSaveFPRegs);
223 } else if (FLAG_debug_code) {
224 Label done;
225 __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
226 __ Abort(kExpectedNewSpaceObject);
227 __ bind(&done);
228 }
229 }
230 }
231 }
232
233 // Register holding this function and new target are both trashed in case we
234 // bailout here. But since that can happen only when new target is not used
235 // and we allocate a context, the value of |function_in_register| is correct.
236 PrepareForBailoutForId(BailoutId::FunctionContext(), NO_REGISTERS);
237
238 // Possibly set up a local binding to the this function which is used in
239 // derived constructors with super calls.
240 Variable* this_function_var = scope()->this_function_var();
241 if (this_function_var != nullptr) {
242 Comment cmnt(masm_, "[ This function");
243 if (!function_in_register) {
244 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
245 // The write barrier clobbers register again, keep it marked as such.
246 }
247 SetVar(this_function_var, edi, ebx, ecx);
248 }
249
250 // Possibly set up a local binding to the new target value.
251 Variable* new_target_var = scope()->new_target_var();
252 if (new_target_var != nullptr) {
253 Comment cmnt(masm_, "[ new.target");
254 SetVar(new_target_var, edx, ebx, ecx);
255 }
256
257 // Possibly allocate RestParameters
258 int rest_index;
259 Variable* rest_param = scope()->rest_parameter(&rest_index);
260 if (rest_param) {
261 Comment cmnt(masm_, "[ Allocate rest parameter array");
262
263 int num_parameters = info->scope()->num_parameters();
264 int offset = num_parameters * kPointerSize;
265
266 __ mov(RestParamAccessDescriptor::parameter_count(),
267 Immediate(Smi::FromInt(num_parameters)));
268 __ lea(RestParamAccessDescriptor::parameter_pointer(),
269 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
270 __ mov(RestParamAccessDescriptor::rest_parameter_index(),
271 Immediate(Smi::FromInt(rest_index)));
272 function_in_register = false;
273
274 RestParamAccessStub stub(isolate());
275 __ CallStub(&stub);
276 SetVar(rest_param, eax, ebx, edx);
277 }
278
279 Variable* arguments = scope()->arguments();
280 if (arguments != NULL) {
281 // Function uses arguments object.
282 Comment cmnt(masm_, "[ Allocate arguments object");
283 DCHECK(edi.is(ArgumentsAccessNewDescriptor::function()));
284 if (!function_in_register) {
285 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
286 }
287 // Receiver is just before the parameters on the caller's stack.
288 int num_parameters = info->scope()->num_parameters();
289 int offset = num_parameters * kPointerSize;
290 __ mov(ArgumentsAccessNewDescriptor::parameter_count(),
291 Immediate(Smi::FromInt(num_parameters)));
292 __ lea(ArgumentsAccessNewDescriptor::parameter_pointer(),
293 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
294
295 // Arguments to ArgumentsAccessStub:
296 // function, parameter pointer, parameter count.
297 // The stub will rewrite parameter pointer and parameter count if the
298 // previous stack frame was an arguments adapter frame.
299 bool is_unmapped = is_strict(language_mode()) || !has_simple_parameters();
300 ArgumentsAccessStub::Type type = ArgumentsAccessStub::ComputeType(
301 is_unmapped, literal()->has_duplicate_parameters());
302 ArgumentsAccessStub stub(isolate(), type);
303 __ CallStub(&stub);
304
305 SetVar(arguments, eax, ebx, edx);
306 }
307
308 if (FLAG_trace) {
309 __ CallRuntime(Runtime::kTraceEnter);
310 }
311
312 // Visit the declarations and body unless there is an illegal
313 // redeclaration.
314 if (scope()->HasIllegalRedeclaration()) {
315 Comment cmnt(masm_, "[ Declarations");
316 VisitForEffect(scope()->GetIllegalRedeclaration());
317
318 } else {
319 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
320 { Comment cmnt(masm_, "[ Declarations");
321 VisitDeclarations(scope()->declarations());
322 }
323
324 // Assert that the declarations do not use ICs. Otherwise the debugger
325 // won't be able to redirect a PC at an IC to the correct IC in newly
326 // recompiled code.
327 DCHECK_EQ(0, ic_total_count_);
328
329 { Comment cmnt(masm_, "[ Stack check");
330 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
331 Label ok;
332 ExternalReference stack_limit
333 = ExternalReference::address_of_stack_limit(isolate());
334 __ cmp(esp, Operand::StaticVariable(stack_limit));
335 __ j(above_equal, &ok, Label::kNear);
336 __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
337 __ bind(&ok);
338 }
339
340 { Comment cmnt(masm_, "[ Body");
341 DCHECK(loop_depth() == 0);
342 VisitStatements(literal()->body());
343 DCHECK(loop_depth() == 0);
344 }
345 }
346
347 // Always emit a 'return undefined' in case control fell off the end of
348 // the body.
349 { Comment cmnt(masm_, "[ return <undefined>;");
350 __ mov(eax, isolate()->factory()->undefined_value());
351 EmitReturnSequence();
352 }
353}
354
355
356void FullCodeGenerator::ClearAccumulator() {
357 __ Move(eax, Immediate(Smi::FromInt(0)));
358}
359
360
361void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
362 __ mov(ebx, Immediate(profiling_counter_));
363 __ sub(FieldOperand(ebx, Cell::kValueOffset),
364 Immediate(Smi::FromInt(delta)));
365}
366
367
368void FullCodeGenerator::EmitProfilingCounterReset() {
369 int reset_value = FLAG_interrupt_budget;
370 __ mov(ebx, Immediate(profiling_counter_));
371 __ mov(FieldOperand(ebx, Cell::kValueOffset),
372 Immediate(Smi::FromInt(reset_value)));
373}
374
375
376void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
377 Label* back_edge_target) {
378 Comment cmnt(masm_, "[ Back edge bookkeeping");
379 Label ok;
380
381 DCHECK(back_edge_target->is_bound());
382 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
383 int weight = Min(kMaxBackEdgeWeight,
384 Max(1, distance / kCodeSizeMultiplier));
385 EmitProfilingCounterDecrement(weight);
386 __ j(positive, &ok, Label::kNear);
387 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
388
389 // Record a mapping of this PC offset to the OSR id. This is used to find
390 // the AST id from the unoptimized code in order to use it as a key into
391 // the deoptimization input data found in the optimized code.
392 RecordBackEdge(stmt->OsrEntryId());
393
394 EmitProfilingCounterReset();
395
396 __ bind(&ok);
397 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
398 // Record a mapping of the OSR id to this PC. This is used if the OSR
399 // entry becomes the target of a bailout. We don't expect it to be, but
400 // we want it to work if it is.
401 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
402}
403
404
405void FullCodeGenerator::EmitReturnSequence() {
406 Comment cmnt(masm_, "[ Return sequence");
407 if (return_label_.is_bound()) {
408 __ jmp(&return_label_);
409 } else {
410 // Common return label
411 __ bind(&return_label_);
412 if (FLAG_trace) {
413 __ push(eax);
414 __ CallRuntime(Runtime::kTraceExit);
415 }
416 // Pretend that the exit is a backwards jump to the entry.
417 int weight = 1;
418 if (info_->ShouldSelfOptimize()) {
419 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
420 } else {
421 int distance = masm_->pc_offset();
422 weight = Min(kMaxBackEdgeWeight,
423 Max(1, distance / kCodeSizeMultiplier));
424 }
425 EmitProfilingCounterDecrement(weight);
426 Label ok;
427 __ j(positive, &ok, Label::kNear);
428 __ push(eax);
429 __ call(isolate()->builtins()->InterruptCheck(),
430 RelocInfo::CODE_TARGET);
431 __ pop(eax);
432 EmitProfilingCounterReset();
433 __ bind(&ok);
434
435 SetReturnPosition(literal());
436 __ leave();
437
438 int arg_count = info_->scope()->num_parameters() + 1;
439 int arguments_bytes = arg_count * kPointerSize;
440 __ Ret(arguments_bytes, ecx);
441 }
442}
443
444
445void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
446 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
447 MemOperand operand = codegen()->VarOperand(var, result_register());
448 // Memory operands can be pushed directly.
449 __ push(operand);
450}
451
452
453void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
454 UNREACHABLE(); // Not used on IA32.
455}
456
457
458void FullCodeGenerator::AccumulatorValueContext::Plug(
459 Heap::RootListIndex index) const {
460 UNREACHABLE(); // Not used on IA32.
461}
462
463
464void FullCodeGenerator::StackValueContext::Plug(
465 Heap::RootListIndex index) const {
466 UNREACHABLE(); // Not used on IA32.
467}
468
469
470void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
471 UNREACHABLE(); // Not used on IA32.
472}
473
474
475void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
476}
477
478
479void FullCodeGenerator::AccumulatorValueContext::Plug(
480 Handle<Object> lit) const {
481 if (lit->IsSmi()) {
482 __ SafeMove(result_register(), Immediate(lit));
483 } else {
484 __ Move(result_register(), Immediate(lit));
485 }
486}
487
488
489void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
490 if (lit->IsSmi()) {
491 __ SafePush(Immediate(lit));
492 } else {
493 __ push(Immediate(lit));
494 }
495}
496
497
498void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
499 codegen()->PrepareForBailoutBeforeSplit(condition(),
500 true,
501 true_label_,
502 false_label_);
503 DCHECK(!lit->IsUndetectableObject()); // There are no undetectable literals.
504 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
505 if (false_label_ != fall_through_) __ jmp(false_label_);
506 } else if (lit->IsTrue() || lit->IsJSObject()) {
507 if (true_label_ != fall_through_) __ jmp(true_label_);
508 } else if (lit->IsString()) {
509 if (String::cast(*lit)->length() == 0) {
510 if (false_label_ != fall_through_) __ jmp(false_label_);
511 } else {
512 if (true_label_ != fall_through_) __ jmp(true_label_);
513 }
514 } else if (lit->IsSmi()) {
515 if (Smi::cast(*lit)->value() == 0) {
516 if (false_label_ != fall_through_) __ jmp(false_label_);
517 } else {
518 if (true_label_ != fall_through_) __ jmp(true_label_);
519 }
520 } else {
521 // For simplicity we always test the accumulator register.
522 __ mov(result_register(), lit);
523 codegen()->DoTest(this);
524 }
525}
526
527
528void FullCodeGenerator::EffectContext::DropAndPlug(int count,
529 Register reg) const {
530 DCHECK(count > 0);
531 __ Drop(count);
532}
533
534
535void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
536 int count,
537 Register reg) const {
538 DCHECK(count > 0);
539 __ Drop(count);
540 __ Move(result_register(), reg);
541}
542
543
544void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
545 Register reg) const {
546 DCHECK(count > 0);
547 if (count > 1) __ Drop(count - 1);
548 __ mov(Operand(esp, 0), reg);
549}
550
551
552void FullCodeGenerator::TestContext::DropAndPlug(int count,
553 Register reg) const {
554 DCHECK(count > 0);
555 // For simplicity we always test the accumulator register.
556 __ Drop(count);
557 __ Move(result_register(), reg);
558 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
559 codegen()->DoTest(this);
560}
561
562
563void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
564 Label* materialize_false) const {
565 DCHECK(materialize_true == materialize_false);
566 __ bind(materialize_true);
567}
568
569
570void FullCodeGenerator::AccumulatorValueContext::Plug(
571 Label* materialize_true,
572 Label* materialize_false) const {
573 Label done;
574 __ bind(materialize_true);
575 __ mov(result_register(), isolate()->factory()->true_value());
576 __ jmp(&done, Label::kNear);
577 __ bind(materialize_false);
578 __ mov(result_register(), isolate()->factory()->false_value());
579 __ bind(&done);
580}
581
582
583void FullCodeGenerator::StackValueContext::Plug(
584 Label* materialize_true,
585 Label* materialize_false) const {
586 Label done;
587 __ bind(materialize_true);
588 __ push(Immediate(isolate()->factory()->true_value()));
589 __ jmp(&done, Label::kNear);
590 __ bind(materialize_false);
591 __ push(Immediate(isolate()->factory()->false_value()));
592 __ bind(&done);
593}
594
595
596void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
597 Label* materialize_false) const {
598 DCHECK(materialize_true == true_label_);
599 DCHECK(materialize_false == false_label_);
600}
601
602
603void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
604 Handle<Object> value = flag
605 ? isolate()->factory()->true_value()
606 : isolate()->factory()->false_value();
607 __ mov(result_register(), value);
608}
609
610
611void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
612 Handle<Object> value = flag
613 ? isolate()->factory()->true_value()
614 : isolate()->factory()->false_value();
615 __ push(Immediate(value));
616}
617
618
619void FullCodeGenerator::TestContext::Plug(bool flag) const {
620 codegen()->PrepareForBailoutBeforeSplit(condition(),
621 true,
622 true_label_,
623 false_label_);
624 if (flag) {
625 if (true_label_ != fall_through_) __ jmp(true_label_);
626 } else {
627 if (false_label_ != fall_through_) __ jmp(false_label_);
628 }
629}
630
631
632void FullCodeGenerator::DoTest(Expression* condition,
633 Label* if_true,
634 Label* if_false,
635 Label* fall_through) {
636 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
637 CallIC(ic, condition->test_id());
638 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
639 Split(equal, if_true, if_false, fall_through);
640}
641
642
643void FullCodeGenerator::Split(Condition cc,
644 Label* if_true,
645 Label* if_false,
646 Label* fall_through) {
647 if (if_false == fall_through) {
648 __ j(cc, if_true);
649 } else if (if_true == fall_through) {
650 __ j(NegateCondition(cc), if_false);
651 } else {
652 __ j(cc, if_true);
653 __ jmp(if_false);
654 }
655}
656
657
658MemOperand FullCodeGenerator::StackOperand(Variable* var) {
659 DCHECK(var->IsStackAllocated());
660 // Offset is negative because higher indexes are at lower addresses.
661 int offset = -var->index() * kPointerSize;
662 // Adjust by a (parameter or local) base offset.
663 if (var->IsParameter()) {
664 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
665 } else {
666 offset += JavaScriptFrameConstants::kLocal0Offset;
667 }
668 return Operand(ebp, offset);
669}
670
671
672MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
673 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
674 if (var->IsContextSlot()) {
675 int context_chain_length = scope()->ContextChainLength(var->scope());
676 __ LoadContext(scratch, context_chain_length);
677 return ContextOperand(scratch, var->index());
678 } else {
679 return StackOperand(var);
680 }
681}
682
683
684void FullCodeGenerator::GetVar(Register dest, Variable* var) {
685 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
686 MemOperand location = VarOperand(var, dest);
687 __ mov(dest, location);
688}
689
690
691void FullCodeGenerator::SetVar(Variable* var,
692 Register src,
693 Register scratch0,
694 Register scratch1) {
695 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
696 DCHECK(!scratch0.is(src));
697 DCHECK(!scratch0.is(scratch1));
698 DCHECK(!scratch1.is(src));
699 MemOperand location = VarOperand(var, scratch0);
700 __ mov(location, src);
701
702 // Emit the write barrier code if the location is in the heap.
703 if (var->IsContextSlot()) {
704 int offset = Context::SlotOffset(var->index());
705 DCHECK(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
706 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
707 }
708}
709
710
711void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
712 bool should_normalize,
713 Label* if_true,
714 Label* if_false) {
715 // Only prepare for bailouts before splits if we're in a test
716 // context. Otherwise, we let the Visit function deal with the
717 // preparation to avoid preparing with the same AST id twice.
718 if (!context()->IsTest()) return;
719
720 Label skip;
721 if (should_normalize) __ jmp(&skip, Label::kNear);
722 PrepareForBailout(expr, TOS_REG);
723 if (should_normalize) {
724 __ cmp(eax, isolate()->factory()->true_value());
725 Split(equal, if_true, if_false, NULL);
726 __ bind(&skip);
727 }
728}
729
730
731void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
732 // The variable in the declaration always resides in the current context.
733 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
734 if (generate_debug_code_) {
735 // Check that we're not inside a with or catch context.
736 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
737 __ cmp(ebx, isolate()->factory()->with_context_map());
738 __ Check(not_equal, kDeclarationInWithContext);
739 __ cmp(ebx, isolate()->factory()->catch_context_map());
740 __ Check(not_equal, kDeclarationInCatchContext);
741 }
742}
743
744
745void FullCodeGenerator::VisitVariableDeclaration(
746 VariableDeclaration* declaration) {
747 // If it was not possible to allocate the variable at compile time, we
748 // need to "declare" it at runtime to make sure it actually exists in the
749 // local context.
750 VariableProxy* proxy = declaration->proxy();
751 VariableMode mode = declaration->mode();
752 Variable* variable = proxy->var();
753 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
754 switch (variable->location()) {
755 case VariableLocation::GLOBAL:
756 case VariableLocation::UNALLOCATED:
757 globals_->Add(variable->name(), zone());
758 globals_->Add(variable->binding_needs_init()
759 ? isolate()->factory()->the_hole_value()
760 : isolate()->factory()->undefined_value(), zone());
761 break;
762
763 case VariableLocation::PARAMETER:
764 case VariableLocation::LOCAL:
765 if (hole_init) {
766 Comment cmnt(masm_, "[ VariableDeclaration");
767 __ mov(StackOperand(variable),
768 Immediate(isolate()->factory()->the_hole_value()));
769 }
770 break;
771
772 case VariableLocation::CONTEXT:
773 if (hole_init) {
774 Comment cmnt(masm_, "[ VariableDeclaration");
775 EmitDebugCheckDeclarationContext(variable);
776 __ mov(ContextOperand(esi, variable->index()),
777 Immediate(isolate()->factory()->the_hole_value()));
778 // No write barrier since the hole value is in old space.
779 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
780 }
781 break;
782
783 case VariableLocation::LOOKUP: {
784 Comment cmnt(masm_, "[ VariableDeclaration");
785 __ push(Immediate(variable->name()));
786 // VariableDeclaration nodes are always introduced in one of four modes.
787 DCHECK(IsDeclaredVariableMode(mode));
788 // Push initial value, if any.
789 // Note: For variables we must not push an initial value (such as
790 // 'undefined') because we may have a (legal) redeclaration and we
791 // must not destroy the current value.
792 if (hole_init) {
793 __ push(Immediate(isolate()->factory()->the_hole_value()));
794 } else {
795 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
796 }
797 __ push(
798 Immediate(Smi::FromInt(variable->DeclarationPropertyAttributes())));
799 __ CallRuntime(Runtime::kDeclareLookupSlot);
800 break;
801 }
802 }
803}
804
805
806void FullCodeGenerator::VisitFunctionDeclaration(
807 FunctionDeclaration* declaration) {
808 VariableProxy* proxy = declaration->proxy();
809 Variable* variable = proxy->var();
810 switch (variable->location()) {
811 case VariableLocation::GLOBAL:
812 case VariableLocation::UNALLOCATED: {
813 globals_->Add(variable->name(), zone());
814 Handle<SharedFunctionInfo> function =
815 Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
816 // Check for stack-overflow exception.
817 if (function.is_null()) return SetStackOverflow();
818 globals_->Add(function, zone());
819 break;
820 }
821
822 case VariableLocation::PARAMETER:
823 case VariableLocation::LOCAL: {
824 Comment cmnt(masm_, "[ FunctionDeclaration");
825 VisitForAccumulatorValue(declaration->fun());
826 __ mov(StackOperand(variable), result_register());
827 break;
828 }
829
830 case VariableLocation::CONTEXT: {
831 Comment cmnt(masm_, "[ FunctionDeclaration");
832 EmitDebugCheckDeclarationContext(variable);
833 VisitForAccumulatorValue(declaration->fun());
834 __ mov(ContextOperand(esi, variable->index()), result_register());
835 // We know that we have written a function, which is not a smi.
836 __ RecordWriteContextSlot(esi,
837 Context::SlotOffset(variable->index()),
838 result_register(),
839 ecx,
840 kDontSaveFPRegs,
841 EMIT_REMEMBERED_SET,
842 OMIT_SMI_CHECK);
843 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
844 break;
845 }
846
847 case VariableLocation::LOOKUP: {
848 Comment cmnt(masm_, "[ FunctionDeclaration");
849 __ push(Immediate(variable->name()));
850 VisitForStackValue(declaration->fun());
851 __ push(
852 Immediate(Smi::FromInt(variable->DeclarationPropertyAttributes())));
853 __ CallRuntime(Runtime::kDeclareLookupSlot);
854 break;
855 }
856 }
857}
858
859
860void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
861 // Call the runtime to declare the globals.
862 __ Push(pairs);
863 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
864 __ CallRuntime(Runtime::kDeclareGlobals);
865 // Return value is ignored.
866}
867
868
869void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
870 // Call the runtime to declare the modules.
871 __ Push(descriptions);
872 __ CallRuntime(Runtime::kDeclareModules);
873 // Return value is ignored.
874}
875
876
877void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
878 Comment cmnt(masm_, "[ SwitchStatement");
879 Breakable nested_statement(this, stmt);
880 SetStatementPosition(stmt);
881
882 // Keep the switch value on the stack until a case matches.
883 VisitForStackValue(stmt->tag());
884 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
885
886 ZoneList<CaseClause*>* clauses = stmt->cases();
887 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
888
889 Label next_test; // Recycled for each test.
890 // Compile all the tests with branches to their bodies.
891 for (int i = 0; i < clauses->length(); i++) {
892 CaseClause* clause = clauses->at(i);
893 clause->body_target()->Unuse();
894
895 // The default is not a test, but remember it as final fall through.
896 if (clause->is_default()) {
897 default_clause = clause;
898 continue;
899 }
900
901 Comment cmnt(masm_, "[ Case comparison");
902 __ bind(&next_test);
903 next_test.Unuse();
904
905 // Compile the label expression.
906 VisitForAccumulatorValue(clause->label());
907
908 // Perform the comparison as if via '==='.
909 __ mov(edx, Operand(esp, 0)); // Switch value.
910 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
911 JumpPatchSite patch_site(masm_);
912 if (inline_smi_code) {
913 Label slow_case;
914 __ mov(ecx, edx);
915 __ or_(ecx, eax);
916 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
917
918 __ cmp(edx, eax);
919 __ j(not_equal, &next_test);
920 __ Drop(1); // Switch value is no longer needed.
921 __ jmp(clause->body_target());
922 __ bind(&slow_case);
923 }
924
925 SetExpressionPosition(clause);
926 Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
927 strength(language_mode())).code();
928 CallIC(ic, clause->CompareId());
929 patch_site.EmitPatchInfo();
930
931 Label skip;
932 __ jmp(&skip, Label::kNear);
933 PrepareForBailout(clause, TOS_REG);
934 __ cmp(eax, isolate()->factory()->true_value());
935 __ j(not_equal, &next_test);
936 __ Drop(1);
937 __ jmp(clause->body_target());
938 __ bind(&skip);
939
940 __ test(eax, eax);
941 __ j(not_equal, &next_test);
942 __ Drop(1); // Switch value is no longer needed.
943 __ jmp(clause->body_target());
944 }
945
946 // Discard the test value and jump to the default if present, otherwise to
947 // the end of the statement.
948 __ bind(&next_test);
949 __ Drop(1); // Switch value is no longer needed.
950 if (default_clause == NULL) {
951 __ jmp(nested_statement.break_label());
952 } else {
953 __ jmp(default_clause->body_target());
954 }
955
956 // Compile all the case bodies.
957 for (int i = 0; i < clauses->length(); i++) {
958 Comment cmnt(masm_, "[ Case body");
959 CaseClause* clause = clauses->at(i);
960 __ bind(clause->body_target());
961 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
962 VisitStatements(clause->statements());
963 }
964
965 __ bind(nested_statement.break_label());
966 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
967}
968
969
970void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
971 Comment cmnt(masm_, "[ ForInStatement");
972 SetStatementPosition(stmt, SKIP_BREAK);
973
974 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
975
976 Label loop, exit;
977 ForIn loop_statement(this, stmt);
978 increment_loop_depth();
979
980 // Get the object to enumerate over. If the object is null or undefined, skip
981 // over the loop. See ECMA-262 version 5, section 12.6.4.
982 SetExpressionAsStatementPosition(stmt->enumerable());
983 VisitForAccumulatorValue(stmt->enumerable());
984 __ cmp(eax, isolate()->factory()->undefined_value());
985 __ j(equal, &exit);
986 __ cmp(eax, isolate()->factory()->null_value());
987 __ j(equal, &exit);
988
989 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
990
991 // Convert the object to a JS object.
992 Label convert, done_convert;
993 __ JumpIfSmi(eax, &convert, Label::kNear);
994 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
995 __ j(above_equal, &done_convert, Label::kNear);
996 __ bind(&convert);
997 ToObjectStub stub(isolate());
998 __ CallStub(&stub);
999 __ bind(&done_convert);
1000 PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
1001 __ push(eax);
1002
1003 // Check for proxies.
1004 Label call_runtime, use_cache, fixed_array;
1005 __ CmpObjectType(eax, JS_PROXY_TYPE, ecx);
1006 __ j(equal, &call_runtime);
1007
1008 // Check cache validity in generated code. This is a fast case for
1009 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1010 // guarantee cache validity, call the runtime system to check cache
1011 // validity or get the property names in a fixed array.
1012 __ CheckEnumCache(&call_runtime);
1013
1014 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
1015 __ jmp(&use_cache, Label::kNear);
1016
1017 // Get the set of properties to enumerate.
1018 __ bind(&call_runtime);
1019 __ push(eax);
1020 __ CallRuntime(Runtime::kGetPropertyNamesFast);
1021 PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
1022 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1023 isolate()->factory()->meta_map());
1024 __ j(not_equal, &fixed_array);
1025
1026
1027 // We got a map in register eax. Get the enumeration cache from it.
1028 Label no_descriptors;
1029 __ bind(&use_cache);
1030
1031 __ EnumLength(edx, eax);
1032 __ cmp(edx, Immediate(Smi::FromInt(0)));
1033 __ j(equal, &no_descriptors);
1034
1035 __ LoadInstanceDescriptors(eax, ecx);
1036 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
1037 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1038
1039 // Set up the four remaining stack slots.
1040 __ push(eax); // Map.
1041 __ push(ecx); // Enumeration cache.
1042 __ push(edx); // Number of valid entries for the map in the enum cache.
1043 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1044 __ jmp(&loop);
1045
1046 __ bind(&no_descriptors);
1047 __ add(esp, Immediate(kPointerSize));
1048 __ jmp(&exit);
1049
1050 // We got a fixed array in register eax. Iterate through that.
1051 __ bind(&fixed_array);
1052
1053 // No need for a write barrier, we are storing a Smi in the feedback vector.
1054 __ EmitLoadTypeFeedbackVector(ebx);
1055 int vector_index = SmiFromSlot(slot)->value();
1056 __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(vector_index)),
1057 Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate())));
1058 __ push(Immediate(Smi::FromInt(1))); // Smi(1) indicates slow check
1059 __ push(eax); // Array
1060 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
1061 __ push(eax); // Fixed array length (as smi).
1062 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1063
1064 // Generate code for doing the condition check.
1065 __ bind(&loop);
1066 SetExpressionAsStatementPosition(stmt->each());
1067
1068 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1069 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
1070 __ j(above_equal, loop_statement.break_label());
1071
1072 // Get the current entry of the array into register ebx.
1073 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1074 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1075
1076 // Get the expected map from the stack or a smi in the
1077 // permanent slow case into register edx.
1078 __ mov(edx, Operand(esp, 3 * kPointerSize));
1079
1080 // Check if the expected map still matches that of the enumerable.
1081 // If not, we may have to filter the key.
1082 Label update_each;
1083 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1084 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
1085 __ j(equal, &update_each, Label::kNear);
1086
1087 // Convert the entry to a string or null if it isn't a property
1088 // anymore. If the property has been removed while iterating, we
1089 // just skip it.
1090 __ push(ecx); // Enumerable.
1091 __ push(ebx); // Current entry.
1092 __ CallRuntime(Runtime::kForInFilter);
1093 PrepareForBailoutForId(stmt->FilterId(), TOS_REG);
1094 __ cmp(eax, isolate()->factory()->undefined_value());
1095 __ j(equal, loop_statement.continue_label());
1096 __ mov(ebx, eax);
1097
1098 // Update the 'each' property or variable from the possibly filtered
1099 // entry in register ebx.
1100 __ bind(&update_each);
1101 __ mov(result_register(), ebx);
1102 // Perform the assignment as if via '='.
1103 { EffectContext context(this);
1104 EmitAssignment(stmt->each(), stmt->EachFeedbackSlot());
1105 PrepareForBailoutForId(stmt->AssignmentId(), NO_REGISTERS);
1106 }
1107
1108 // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body().
1109 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
1110 // Generate code for the body of the loop.
1111 Visit(stmt->body());
1112
1113 // Generate code for going to the next element by incrementing the
1114 // index (smi) stored on top of the stack.
1115 __ bind(loop_statement.continue_label());
1116 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
1117
1118 EmitBackEdgeBookkeeping(stmt, &loop);
1119 __ jmp(&loop);
1120
1121 // Remove the pointers stored on the stack.
1122 __ bind(loop_statement.break_label());
1123 __ add(esp, Immediate(5 * kPointerSize));
1124
1125 // Exit and decrement the loop depth.
1126 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1127 __ bind(&exit);
1128 decrement_loop_depth();
1129}
1130
1131
1132void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1133 bool pretenure) {
1134 // Use the fast case closure allocation code that allocates in new
1135 // space for nested functions that don't need literals cloning. If
1136 // we're running with the --always-opt or the --prepare-always-opt
1137 // flag, we need to use the runtime function so that the new function
1138 // we are creating here gets a chance to have its code optimized and
1139 // doesn't just get a copy of the existing unoptimized code.
1140 if (!FLAG_always_opt &&
1141 !FLAG_prepare_always_opt &&
1142 !pretenure &&
1143 scope()->is_function_scope() &&
1144 info->num_literals() == 0) {
1145 FastNewClosureStub stub(isolate(), info->language_mode(), info->kind());
1146 __ mov(ebx, Immediate(info));
1147 __ CallStub(&stub);
1148 } else {
1149 __ push(Immediate(info));
1150 __ CallRuntime(pretenure ? Runtime::kNewClosure_Tenured
1151 : Runtime::kNewClosure);
1152 }
1153 context()->Plug(eax);
1154}
1155
1156
1157void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset,
1158 FeedbackVectorSlot slot) {
1159 DCHECK(NeedsHomeObject(initializer));
1160 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1161 __ mov(StoreDescriptor::NameRegister(),
1162 Immediate(isolate()->factory()->home_object_symbol()));
1163 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize));
1164 EmitLoadStoreICSlot(slot);
1165 CallStoreIC();
1166}
1167
1168
1169void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer,
1170 int offset,
1171 FeedbackVectorSlot slot) {
1172 DCHECK(NeedsHomeObject(initializer));
1173 __ mov(StoreDescriptor::ReceiverRegister(), eax);
1174 __ mov(StoreDescriptor::NameRegister(),
1175 Immediate(isolate()->factory()->home_object_symbol()));
1176 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize));
1177 EmitLoadStoreICSlot(slot);
1178 CallStoreIC();
1179}
1180
1181
1182void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
1183 TypeofMode typeof_mode,
1184 Label* slow) {
1185 Register context = esi;
1186 Register temp = edx;
1187
1188 Scope* s = scope();
1189 while (s != NULL) {
1190 if (s->num_heap_slots() > 0) {
1191 if (s->calls_sloppy_eval()) {
1192 // Check that extension is "the hole".
1193 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1194 Heap::kTheHoleValueRootIndex, slow);
1195 }
1196 // Load next context in chain.
1197 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1198 // Walk the rest of the chain without clobbering esi.
1199 context = temp;
1200 }
1201 // If no outer scope calls eval, we do not need to check more
1202 // context extensions. If we have reached an eval scope, we check
1203 // all extensions from this point.
1204 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
1205 s = s->outer_scope();
1206 }
1207
1208 if (s != NULL && s->is_eval_scope()) {
1209 // Loop up the context chain. There is no frame effect so it is
1210 // safe to use raw labels here.
1211 Label next, fast;
1212 if (!context.is(temp)) {
1213 __ mov(temp, context);
1214 }
1215 __ bind(&next);
1216 // Terminate at native context.
1217 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
1218 Immediate(isolate()->factory()->native_context_map()));
1219 __ j(equal, &fast, Label::kNear);
1220 // Check that extension is "the hole".
1221 __ JumpIfNotRoot(ContextOperand(temp, Context::EXTENSION_INDEX),
1222 Heap::kTheHoleValueRootIndex, slow);
1223 // Load next context in chain.
1224 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
1225 __ jmp(&next);
1226 __ bind(&fast);
1227 }
1228
1229 // All extension objects were empty and it is safe to use a normal global
1230 // load machinery.
1231 EmitGlobalVariableLoad(proxy, typeof_mode);
1232}
1233
1234
1235MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1236 Label* slow) {
1237 DCHECK(var->IsContextSlot());
1238 Register context = esi;
1239 Register temp = ebx;
1240
1241 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1242 if (s->num_heap_slots() > 0) {
1243 if (s->calls_sloppy_eval()) {
1244 // Check that extension is "the hole".
1245 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1246 Heap::kTheHoleValueRootIndex, slow);
1247 }
1248 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1249 // Walk the rest of the chain without clobbering esi.
1250 context = temp;
1251 }
1252 }
1253 // Check that last extension is "the hole".
1254 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1255 Heap::kTheHoleValueRootIndex, slow);
1256
1257 // This function is used only for loads, not stores, so it's safe to
1258 // return an esi-based operand (the write barrier cannot be allowed to
1259 // destroy the esi register).
1260 return ContextOperand(context, var->index());
1261}
1262
1263
1264void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
1265 TypeofMode typeof_mode,
1266 Label* slow, Label* done) {
1267 // Generate fast-case code for variables that might be shadowed by
1268 // eval-introduced variables. Eval is used a lot without
1269 // introducing variables. In those cases, we do not want to
1270 // perform a runtime call for all variables in the scope
1271 // containing the eval.
1272 Variable* var = proxy->var();
1273 if (var->mode() == DYNAMIC_GLOBAL) {
1274 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow);
1275 __ jmp(done);
1276 } else if (var->mode() == DYNAMIC_LOCAL) {
1277 Variable* local = var->local_if_not_shadowed();
1278 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
1279 if (local->mode() == LET || local->mode() == CONST ||
1280 local->mode() == CONST_LEGACY) {
1281 __ cmp(eax, isolate()->factory()->the_hole_value());
1282 __ j(not_equal, done);
1283 if (local->mode() == CONST_LEGACY) {
1284 __ mov(eax, isolate()->factory()->undefined_value());
1285 } else { // LET || CONST
1286 __ push(Immediate(var->name()));
1287 __ CallRuntime(Runtime::kThrowReferenceError);
1288 }
1289 }
1290 __ jmp(done);
1291 }
1292}
1293
1294
1295void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
1296 TypeofMode typeof_mode) {
1297 Variable* var = proxy->var();
1298 DCHECK(var->IsUnallocatedOrGlobalSlot() ||
1299 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
1300 __ mov(LoadDescriptor::ReceiverRegister(), NativeContextOperand());
1301 __ mov(LoadDescriptor::ReceiverRegister(),
1302 ContextOperand(LoadDescriptor::ReceiverRegister(),
1303 Context::EXTENSION_INDEX));
1304 __ mov(LoadDescriptor::NameRegister(), var->name());
1305 __ mov(LoadDescriptor::SlotRegister(),
1306 Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
1307 CallLoadIC(typeof_mode);
1308}
1309
1310
1311void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
1312 TypeofMode typeof_mode) {
1313 SetExpressionPosition(proxy);
1314 PrepareForBailoutForId(proxy->BeforeId(), NO_REGISTERS);
1315 Variable* var = proxy->var();
1316
1317 // Three cases: global variables, lookup variables, and all other types of
1318 // variables.
1319 switch (var->location()) {
1320 case VariableLocation::GLOBAL:
1321 case VariableLocation::UNALLOCATED: {
1322 Comment cmnt(masm_, "[ Global variable");
1323 EmitGlobalVariableLoad(proxy, typeof_mode);
1324 context()->Plug(eax);
1325 break;
1326 }
1327
1328 case VariableLocation::PARAMETER:
1329 case VariableLocation::LOCAL:
1330 case VariableLocation::CONTEXT: {
1331 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
1332 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1333 : "[ Stack variable");
1334
1335 if (NeedsHoleCheckForLoad(proxy)) {
1336 // Let and const need a read barrier.
1337 Label done;
1338 GetVar(eax, var);
1339 __ cmp(eax, isolate()->factory()->the_hole_value());
1340 __ j(not_equal, &done, Label::kNear);
1341 if (var->mode() == LET || var->mode() == CONST) {
1342 // Throw a reference error when using an uninitialized let/const
1343 // binding in harmony mode.
1344 __ push(Immediate(var->name()));
1345 __ CallRuntime(Runtime::kThrowReferenceError);
1346 } else {
1347 // Uninitialized legacy const bindings are unholed.
1348 DCHECK(var->mode() == CONST_LEGACY);
1349 __ mov(eax, isolate()->factory()->undefined_value());
1350 }
1351 __ bind(&done);
1352 context()->Plug(eax);
1353 break;
1354 }
1355 context()->Plug(var);
1356 break;
1357 }
1358
1359 case VariableLocation::LOOKUP: {
1360 Comment cmnt(masm_, "[ Lookup variable");
1361 Label done, slow;
1362 // Generate code for loading from variables potentially shadowed
1363 // by eval-introduced variables.
1364 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done);
1365 __ bind(&slow);
1366 __ push(esi); // Context.
1367 __ push(Immediate(var->name()));
1368 Runtime::FunctionId function_id =
1369 typeof_mode == NOT_INSIDE_TYPEOF
1370 ? Runtime::kLoadLookupSlot
1371 : Runtime::kLoadLookupSlotNoReferenceError;
1372 __ CallRuntime(function_id);
1373 __ bind(&done);
1374 context()->Plug(eax);
1375 break;
1376 }
1377 }
1378}
1379
1380
1381void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1382 Comment cmnt(masm_, "[ RegExpLiteral");
1383 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1384 __ Move(eax, Immediate(Smi::FromInt(expr->literal_index())));
1385 __ Move(ecx, Immediate(expr->pattern()));
1386 __ Move(edx, Immediate(Smi::FromInt(expr->flags())));
1387 FastCloneRegExpStub stub(isolate());
1388 __ CallStub(&stub);
1389 context()->Plug(eax);
1390}
1391
1392
1393void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) {
1394 Expression* expression = (property == NULL) ? NULL : property->value();
1395 if (expression == NULL) {
1396 __ push(Immediate(isolate()->factory()->null_value()));
1397 } else {
1398 VisitForStackValue(expression);
1399 if (NeedsHomeObject(expression)) {
1400 DCHECK(property->kind() == ObjectLiteral::Property::GETTER ||
1401 property->kind() == ObjectLiteral::Property::SETTER);
1402 int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3;
1403 EmitSetHomeObject(expression, offset, property->GetSlot());
1404 }
1405 }
1406}
1407
1408
1409void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1410 Comment cmnt(masm_, "[ ObjectLiteral");
1411
1412 Handle<FixedArray> constant_properties = expr->constant_properties();
1413 int flags = expr->ComputeFlags();
1414 // If any of the keys would store to the elements array, then we shouldn't
1415 // allow it.
1416 if (MustCreateObjectLiteralWithRuntime(expr)) {
1417 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1418 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1419 __ push(Immediate(constant_properties));
1420 __ push(Immediate(Smi::FromInt(flags)));
1421 __ CallRuntime(Runtime::kCreateObjectLiteral);
1422 } else {
1423 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1424 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1425 __ mov(ecx, Immediate(constant_properties));
1426 __ mov(edx, Immediate(Smi::FromInt(flags)));
1427 FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
1428 __ CallStub(&stub);
1429 }
1430 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
1431
1432 // If result_saved is true the result is on top of the stack. If
1433 // result_saved is false the result is in eax.
1434 bool result_saved = false;
1435
1436 AccessorTable accessor_table(zone());
1437 int property_index = 0;
1438 for (; property_index < expr->properties()->length(); property_index++) {
1439 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1440 if (property->is_computed_name()) break;
1441 if (property->IsCompileTimeValue()) continue;
1442
1443 Literal* key = property->key()->AsLiteral();
1444 Expression* value = property->value();
1445 if (!result_saved) {
1446 __ push(eax); // Save result on the stack
1447 result_saved = true;
1448 }
1449 switch (property->kind()) {
1450 case ObjectLiteral::Property::CONSTANT:
1451 UNREACHABLE();
1452 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1453 DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
1454 // Fall through.
1455 case ObjectLiteral::Property::COMPUTED:
1456 // It is safe to use [[Put]] here because the boilerplate already
1457 // contains computed properties with an uninitialized value.
1458 if (key->value()->IsInternalizedString()) {
1459 if (property->emit_store()) {
1460 VisitForAccumulatorValue(value);
1461 DCHECK(StoreDescriptor::ValueRegister().is(eax));
1462 __ mov(StoreDescriptor::NameRegister(), Immediate(key->value()));
1463 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1464 EmitLoadStoreICSlot(property->GetSlot(0));
1465 CallStoreIC();
1466 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1467 if (NeedsHomeObject(value)) {
1468 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1));
1469 }
1470 } else {
1471 VisitForEffect(value);
1472 }
1473 break;
1474 }
1475 __ push(Operand(esp, 0)); // Duplicate receiver.
1476 VisitForStackValue(key);
1477 VisitForStackValue(value);
1478 if (property->emit_store()) {
1479 if (NeedsHomeObject(value)) {
1480 EmitSetHomeObject(value, 2, property->GetSlot());
1481 }
1482 __ push(Immediate(Smi::FromInt(SLOPPY))); // Language mode
1483 __ CallRuntime(Runtime::kSetProperty);
1484 } else {
1485 __ Drop(3);
1486 }
1487 break;
1488 case ObjectLiteral::Property::PROTOTYPE:
1489 __ push(Operand(esp, 0)); // Duplicate receiver.
1490 VisitForStackValue(value);
1491 DCHECK(property->emit_store());
1492 __ CallRuntime(Runtime::kInternalSetPrototype);
1493 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1494 NO_REGISTERS);
1495 break;
1496 case ObjectLiteral::Property::GETTER:
1497 if (property->emit_store()) {
1498 accessor_table.lookup(key)->second->getter = property;
1499 }
1500 break;
1501 case ObjectLiteral::Property::SETTER:
1502 if (property->emit_store()) {
1503 accessor_table.lookup(key)->second->setter = property;
1504 }
1505 break;
1506 }
1507 }
1508
1509 // Emit code to define accessors, using only a single call to the runtime for
1510 // each pair of corresponding getters and setters.
1511 for (AccessorTable::Iterator it = accessor_table.begin();
1512 it != accessor_table.end();
1513 ++it) {
1514 __ push(Operand(esp, 0)); // Duplicate receiver.
1515 VisitForStackValue(it->first);
1516
1517 EmitAccessor(it->second->getter);
1518 EmitAccessor(it->second->setter);
1519
1520 __ push(Immediate(Smi::FromInt(NONE)));
1521 __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked);
1522 }
1523
1524 // Object literals have two parts. The "static" part on the left contains no
1525 // computed property names, and so we can compute its map ahead of time; see
1526 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
1527 // starts with the first computed property name, and continues with all
1528 // properties to its right. All the code from above initializes the static
1529 // component of the object literal, and arranges for the map of the result to
1530 // reflect the static order in which the keys appear. For the dynamic
1531 // properties, we compile them into a series of "SetOwnProperty" runtime
1532 // calls. This will preserve insertion order.
1533 for (; property_index < expr->properties()->length(); property_index++) {
1534 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1535
1536 Expression* value = property->value();
1537 if (!result_saved) {
1538 __ push(eax); // Save result on the stack
1539 result_saved = true;
1540 }
1541
1542 __ push(Operand(esp, 0)); // Duplicate receiver.
1543
1544 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1545 DCHECK(!property->is_computed_name());
1546 VisitForStackValue(value);
1547 DCHECK(property->emit_store());
1548 __ CallRuntime(Runtime::kInternalSetPrototype);
1549 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1550 NO_REGISTERS);
1551 } else {
1552 EmitPropertyKey(property, expr->GetIdForPropertyName(property_index));
1553 VisitForStackValue(value);
1554 if (NeedsHomeObject(value)) {
1555 EmitSetHomeObject(value, 2, property->GetSlot());
1556 }
1557
1558 switch (property->kind()) {
1559 case ObjectLiteral::Property::CONSTANT:
1560 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1561 case ObjectLiteral::Property::COMPUTED:
1562 if (property->emit_store()) {
1563 __ push(Immediate(Smi::FromInt(NONE)));
1564 __ CallRuntime(Runtime::kDefineDataPropertyUnchecked);
1565 } else {
1566 __ Drop(3);
1567 }
1568 break;
1569
1570 case ObjectLiteral::Property::PROTOTYPE:
1571 UNREACHABLE();
1572 break;
1573
1574 case ObjectLiteral::Property::GETTER:
1575 __ push(Immediate(Smi::FromInt(NONE)));
1576 __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked);
1577 break;
1578
1579 case ObjectLiteral::Property::SETTER:
1580 __ push(Immediate(Smi::FromInt(NONE)));
1581 __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked);
1582 break;
1583 }
1584 }
1585 }
1586
1587 if (expr->has_function()) {
1588 DCHECK(result_saved);
1589 __ push(Operand(esp, 0));
1590 __ CallRuntime(Runtime::kToFastProperties);
1591 }
1592
1593 if (result_saved) {
1594 context()->PlugTOS();
1595 } else {
1596 context()->Plug(eax);
1597 }
1598}
1599
1600
1601void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1602 Comment cmnt(masm_, "[ ArrayLiteral");
1603
1604 Handle<FixedArray> constant_elements = expr->constant_elements();
1605 bool has_constant_fast_elements =
1606 IsFastObjectElementsKind(expr->constant_elements_kind());
1607
1608 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1609 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1610 // If the only customer of allocation sites is transitioning, then
1611 // we can turn it off if we don't have anywhere else to transition to.
1612 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1613 }
1614
1615 if (MustCreateArrayLiteralWithRuntime(expr)) {
1616 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1617 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1618 __ push(Immediate(constant_elements));
1619 __ push(Immediate(Smi::FromInt(expr->ComputeFlags())));
1620 __ CallRuntime(Runtime::kCreateArrayLiteral);
1621 } else {
1622 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1623 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1624 __ mov(ecx, Immediate(constant_elements));
1625 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
1626 __ CallStub(&stub);
1627 }
1628 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
1629
1630 bool result_saved = false; // Is the result saved to the stack?
1631 ZoneList<Expression*>* subexprs = expr->values();
1632 int length = subexprs->length();
1633
1634 // Emit code to evaluate all the non-constant subexpressions and to store
1635 // them into the newly cloned array.
1636 int array_index = 0;
1637 for (; array_index < length; array_index++) {
1638 Expression* subexpr = subexprs->at(array_index);
1639 if (subexpr->IsSpread()) break;
1640
1641 // If the subexpression is a literal or a simple materialized literal it
1642 // is already set in the cloned array.
1643 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1644
1645 if (!result_saved) {
1646 __ push(eax); // array literal.
1647 result_saved = true;
1648 }
1649 VisitForAccumulatorValue(subexpr);
1650
1651 __ mov(StoreDescriptor::NameRegister(),
1652 Immediate(Smi::FromInt(array_index)));
1653 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1654 EmitLoadStoreICSlot(expr->LiteralFeedbackSlot());
1655 Handle<Code> ic =
1656 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
1657 CallIC(ic);
1658 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS);
1659 }
1660
1661 // In case the array literal contains spread expressions it has two parts. The
1662 // first part is the "static" array which has a literal index is handled
1663 // above. The second part is the part after the first spread expression
1664 // (inclusive) and these elements gets appended to the array. Note that the
1665 // number elements an iterable produces is unknown ahead of time.
1666 if (array_index < length && result_saved) {
1667 __ Pop(eax);
1668 result_saved = false;
1669 }
1670 for (; array_index < length; array_index++) {
1671 Expression* subexpr = subexprs->at(array_index);
1672
1673 __ Push(eax);
1674 if (subexpr->IsSpread()) {
1675 VisitForStackValue(subexpr->AsSpread()->expression());
1676 __ InvokeBuiltin(Context::CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX,
1677 CALL_FUNCTION);
1678 } else {
1679 VisitForStackValue(subexpr);
1680 __ CallRuntime(Runtime::kAppendElement);
1681 }
1682
1683 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS);
1684 }
1685
1686 if (result_saved) {
1687 context()->PlugTOS();
1688 } else {
1689 context()->Plug(eax);
1690 }
1691}
1692
1693
1694void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1695 DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
1696
1697 Comment cmnt(masm_, "[ Assignment");
1698 SetExpressionPosition(expr, INSERT_BREAK);
1699
1700 Property* property = expr->target()->AsProperty();
1701 LhsKind assign_type = Property::GetAssignType(property);
1702
1703 // Evaluate LHS expression.
1704 switch (assign_type) {
1705 case VARIABLE:
1706 // Nothing to do here.
1707 break;
1708 case NAMED_SUPER_PROPERTY:
1709 VisitForStackValue(
1710 property->obj()->AsSuperPropertyReference()->this_var());
1711 VisitForAccumulatorValue(
1712 property->obj()->AsSuperPropertyReference()->home_object());
1713 __ push(result_register());
1714 if (expr->is_compound()) {
1715 __ push(MemOperand(esp, kPointerSize));
1716 __ push(result_register());
1717 }
1718 break;
1719 case NAMED_PROPERTY:
1720 if (expr->is_compound()) {
1721 // We need the receiver both on the stack and in the register.
1722 VisitForStackValue(property->obj());
1723 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
1724 } else {
1725 VisitForStackValue(property->obj());
1726 }
1727 break;
1728 case KEYED_SUPER_PROPERTY:
1729 VisitForStackValue(
1730 property->obj()->AsSuperPropertyReference()->this_var());
1731 VisitForStackValue(
1732 property->obj()->AsSuperPropertyReference()->home_object());
1733 VisitForAccumulatorValue(property->key());
1734 __ Push(result_register());
1735 if (expr->is_compound()) {
1736 __ push(MemOperand(esp, 2 * kPointerSize));
1737 __ push(MemOperand(esp, 2 * kPointerSize));
1738 __ push(result_register());
1739 }
1740 break;
1741 case KEYED_PROPERTY: {
1742 if (expr->is_compound()) {
1743 VisitForStackValue(property->obj());
1744 VisitForStackValue(property->key());
1745 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, kPointerSize));
1746 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0));
1747 } else {
1748 VisitForStackValue(property->obj());
1749 VisitForStackValue(property->key());
1750 }
1751 break;
1752 }
1753 }
1754
1755 // For compound assignments we need another deoptimization point after the
1756 // variable/property load.
1757 if (expr->is_compound()) {
1758 AccumulatorValueContext result_context(this);
1759 { AccumulatorValueContext left_operand_context(this);
1760 switch (assign_type) {
1761 case VARIABLE:
1762 EmitVariableLoad(expr->target()->AsVariableProxy());
1763 PrepareForBailout(expr->target(), TOS_REG);
1764 break;
1765 case NAMED_SUPER_PROPERTY:
1766 EmitNamedSuperPropertyLoad(property);
1767 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1768 break;
1769 case NAMED_PROPERTY:
1770 EmitNamedPropertyLoad(property);
1771 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1772 break;
1773 case KEYED_SUPER_PROPERTY:
1774 EmitKeyedSuperPropertyLoad(property);
1775 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1776 break;
1777 case KEYED_PROPERTY:
1778 EmitKeyedPropertyLoad(property);
1779 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1780 break;
1781 }
1782 }
1783
1784 Token::Value op = expr->binary_op();
1785 __ push(eax); // Left operand goes on the stack.
1786 VisitForAccumulatorValue(expr->value());
1787
1788 if (ShouldInlineSmiCase(op)) {
1789 EmitInlineSmiBinaryOp(expr->binary_operation(),
1790 op,
1791 expr->target(),
1792 expr->value());
1793 } else {
1794 EmitBinaryOp(expr->binary_operation(), op);
1795 }
1796
1797 // Deoptimization point in case the binary operation may have side effects.
1798 PrepareForBailout(expr->binary_operation(), TOS_REG);
1799 } else {
1800 VisitForAccumulatorValue(expr->value());
1801 }
1802
1803 SetExpressionPosition(expr);
1804
1805 // Store the value.
1806 switch (assign_type) {
1807 case VARIABLE:
1808 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1809 expr->op(), expr->AssignmentSlot());
1810 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1811 context()->Plug(eax);
1812 break;
1813 case NAMED_PROPERTY:
1814 EmitNamedPropertyAssignment(expr);
1815 break;
1816 case NAMED_SUPER_PROPERTY:
1817 EmitNamedSuperPropertyStore(property);
1818 context()->Plug(result_register());
1819 break;
1820 case KEYED_SUPER_PROPERTY:
1821 EmitKeyedSuperPropertyStore(property);
1822 context()->Plug(result_register());
1823 break;
1824 case KEYED_PROPERTY:
1825 EmitKeyedPropertyAssignment(expr);
1826 break;
1827 }
1828}
1829
1830
1831void FullCodeGenerator::VisitYield(Yield* expr) {
1832 Comment cmnt(masm_, "[ Yield");
1833 SetExpressionPosition(expr);
1834
1835 // Evaluate yielded value first; the initial iterator definition depends on
1836 // this. It stays on the stack while we update the iterator.
1837 VisitForStackValue(expr->expression());
1838
1839 switch (expr->yield_kind()) {
1840 case Yield::kSuspend:
1841 // Pop value from top-of-stack slot; box result into result register.
1842 EmitCreateIteratorResult(false);
1843 __ push(result_register());
1844 // Fall through.
1845 case Yield::kInitial: {
1846 Label suspend, continuation, post_runtime, resume;
1847
1848 __ jmp(&suspend);
1849 __ bind(&continuation);
1850 __ RecordGeneratorContinuation();
1851 __ jmp(&resume);
1852
1853 __ bind(&suspend);
1854 VisitForAccumulatorValue(expr->generator_object());
1855 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
1856 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
1857 Immediate(Smi::FromInt(continuation.pos())));
1858 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
1859 __ mov(ecx, esi);
1860 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
1861 kDontSaveFPRegs);
1862 __ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
1863 __ cmp(esp, ebx);
1864 __ j(equal, &post_runtime);
1865 __ push(eax); // generator object
1866 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
1867 __ mov(context_register(),
1868 Operand(ebp, StandardFrameConstants::kContextOffset));
1869 __ bind(&post_runtime);
1870 __ pop(result_register());
1871 EmitReturnSequence();
1872
1873 __ bind(&resume);
1874 context()->Plug(result_register());
1875 break;
1876 }
1877
1878 case Yield::kFinal: {
1879 VisitForAccumulatorValue(expr->generator_object());
1880 __ mov(FieldOperand(result_register(),
1881 JSGeneratorObject::kContinuationOffset),
1882 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
1883 // Pop value from top-of-stack slot, box result into result register.
1884 EmitCreateIteratorResult(true);
1885 EmitUnwindBeforeReturn();
1886 EmitReturnSequence();
1887 break;
1888 }
1889
1890 case Yield::kDelegating: {
1891 VisitForStackValue(expr->generator_object());
1892
1893 // Initial stack layout is as follows:
1894 // [sp + 1 * kPointerSize] iter
1895 // [sp + 0 * kPointerSize] g
1896
1897 Label l_catch, l_try, l_suspend, l_continuation, l_resume;
1898 Label l_next, l_call, l_loop;
1899 Register load_receiver = LoadDescriptor::ReceiverRegister();
1900 Register load_name = LoadDescriptor::NameRegister();
1901
1902 // Initial send value is undefined.
1903 __ mov(eax, isolate()->factory()->undefined_value());
1904 __ jmp(&l_next);
1905
1906 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
1907 __ bind(&l_catch);
1908 __ mov(load_name, isolate()->factory()->throw_string()); // "throw"
1909 __ push(load_name); // "throw"
1910 __ push(Operand(esp, 2 * kPointerSize)); // iter
1911 __ push(eax); // exception
1912 __ jmp(&l_call);
1913
1914 // try { received = %yield result }
1915 // Shuffle the received result above a try handler and yield it without
1916 // re-boxing.
1917 __ bind(&l_try);
1918 __ pop(eax); // result
1919 int handler_index = NewHandlerTableEntry();
1920 EnterTryBlock(handler_index, &l_catch);
1921 const int try_block_size = TryCatch::kElementCount * kPointerSize;
1922 __ push(eax); // result
1923
1924 __ jmp(&l_suspend);
1925 __ bind(&l_continuation);
1926 __ RecordGeneratorContinuation();
1927 __ jmp(&l_resume);
1928
1929 __ bind(&l_suspend);
1930 const int generator_object_depth = kPointerSize + try_block_size;
1931 __ mov(eax, Operand(esp, generator_object_depth));
1932 __ push(eax); // g
1933 __ push(Immediate(Smi::FromInt(handler_index))); // handler-index
1934 DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
1935 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
1936 Immediate(Smi::FromInt(l_continuation.pos())));
1937 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
1938 __ mov(ecx, esi);
1939 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
1940 kDontSaveFPRegs);
1941 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
1942 __ mov(context_register(),
1943 Operand(ebp, StandardFrameConstants::kContextOffset));
1944 __ pop(eax); // result
1945 EmitReturnSequence();
1946 __ bind(&l_resume); // received in eax
1947 ExitTryBlock(handler_index);
1948
1949 // receiver = iter; f = iter.next; arg = received;
1950 __ bind(&l_next);
1951
1952 __ mov(load_name, isolate()->factory()->next_string());
1953 __ push(load_name); // "next"
1954 __ push(Operand(esp, 2 * kPointerSize)); // iter
1955 __ push(eax); // received
1956
1957 // result = receiver[f](arg);
1958 __ bind(&l_call);
1959 __ mov(load_receiver, Operand(esp, kPointerSize));
1960 __ mov(LoadDescriptor::SlotRegister(),
1961 Immediate(SmiFromSlot(expr->KeyedLoadFeedbackSlot())));
1962 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code();
1963 CallIC(ic, TypeFeedbackId::None());
1964 __ mov(edi, eax);
1965 __ mov(Operand(esp, 2 * kPointerSize), edi);
1966 SetCallPosition(expr);
1967 __ Set(eax, 1);
1968 __ Call(
1969 isolate()->builtins()->Call(ConvertReceiverMode::kNotNullOrUndefined),
1970 RelocInfo::CODE_TARGET);
1971
1972 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1973 __ Drop(1); // The function is still on the stack; drop it.
1974
1975 // if (!result.done) goto l_try;
1976 __ bind(&l_loop);
1977 __ push(eax); // save result
1978 __ Move(load_receiver, eax); // result
1979 __ mov(load_name,
1980 isolate()->factory()->done_string()); // "done"
1981 __ mov(LoadDescriptor::SlotRegister(),
1982 Immediate(SmiFromSlot(expr->DoneFeedbackSlot())));
1983 CallLoadIC(NOT_INSIDE_TYPEOF); // result.done in eax
1984 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
1985 CallIC(bool_ic);
1986 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
1987 __ j(not_equal, &l_try);
1988
1989 // result.value
1990 __ pop(load_receiver); // result
1991 __ mov(load_name,
1992 isolate()->factory()->value_string()); // "value"
1993 __ mov(LoadDescriptor::SlotRegister(),
1994 Immediate(SmiFromSlot(expr->ValueFeedbackSlot())));
1995 CallLoadIC(NOT_INSIDE_TYPEOF); // result.value in eax
1996 context()->DropAndPlug(2, eax); // drop iter and g
1997 break;
1998 }
1999 }
2000}
2001
2002
2003void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
2004 Expression *value,
2005 JSGeneratorObject::ResumeMode resume_mode) {
2006 // The value stays in eax, and is ultimately read by the resumed generator, as
2007 // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
2008 // is read to throw the value when the resumed generator is already closed.
2009 // ebx will hold the generator object until the activation has been resumed.
2010 VisitForStackValue(generator);
2011 VisitForAccumulatorValue(value);
2012 __ pop(ebx);
2013
2014 // Load suspended function and context.
2015 __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset));
2016 __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
2017
2018 // Push receiver.
2019 __ push(FieldOperand(ebx, JSGeneratorObject::kReceiverOffset));
2020
2021 // Push holes for arguments to generator function.
2022 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2023 __ mov(edx,
2024 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2025 __ mov(ecx, isolate()->factory()->the_hole_value());
2026 Label push_argument_holes, push_frame;
2027 __ bind(&push_argument_holes);
2028 __ sub(edx, Immediate(Smi::FromInt(1)));
2029 __ j(carry, &push_frame);
2030 __ push(ecx);
2031 __ jmp(&push_argument_holes);
2032
2033 // Enter a new JavaScript frame, and initialize its slots as they were when
2034 // the generator was suspended.
2035 Label resume_frame, done;
2036 __ bind(&push_frame);
2037 __ call(&resume_frame);
2038 __ jmp(&done);
2039 __ bind(&resume_frame);
2040 __ push(ebp); // Caller's frame pointer.
2041 __ mov(ebp, esp);
2042 __ push(esi); // Callee's context.
2043 __ push(edi); // Callee's JS Function.
2044
2045 // Load the operand stack size.
2046 __ mov(edx, FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset));
2047 __ mov(edx, FieldOperand(edx, FixedArray::kLengthOffset));
2048 __ SmiUntag(edx);
2049
2050 // If we are sending a value and there is no operand stack, we can jump back
2051 // in directly.
2052 if (resume_mode == JSGeneratorObject::NEXT) {
2053 Label slow_resume;
2054 __ cmp(edx, Immediate(0));
2055 __ j(not_zero, &slow_resume);
2056 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2057 __ mov(ecx, FieldOperand(ebx, JSGeneratorObject::kContinuationOffset));
2058 __ SmiUntag(ecx);
2059 __ add(edx, ecx);
2060 __ mov(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
2061 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
2062 __ jmp(edx);
2063 __ bind(&slow_resume);
2064 }
2065
2066 // Otherwise, we push holes for the operand stack and call the runtime to fix
2067 // up the stack and the handlers.
2068 Label push_operand_holes, call_resume;
2069 __ bind(&push_operand_holes);
2070 __ sub(edx, Immediate(1));
2071 __ j(carry, &call_resume);
2072 __ push(ecx);
2073 __ jmp(&push_operand_holes);
2074 __ bind(&call_resume);
2075 __ push(ebx);
2076 __ push(result_register());
2077 __ Push(Smi::FromInt(resume_mode));
2078 __ CallRuntime(Runtime::kResumeJSGeneratorObject);
2079 // Not reached: the runtime call returns elsewhere.
2080 __ Abort(kGeneratorFailedToResume);
2081
2082 __ bind(&done);
2083 context()->Plug(result_register());
2084}
2085
2086
2087void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
2088 Label allocate, done_allocate;
2089
2090 __ Allocate(JSIteratorResult::kSize, eax, ecx, edx, &allocate, TAG_OBJECT);
2091 __ jmp(&done_allocate, Label::kNear);
2092
2093 __ bind(&allocate);
2094 __ Push(Smi::FromInt(JSIteratorResult::kSize));
2095 __ CallRuntime(Runtime::kAllocateInNewSpace);
2096
2097 __ bind(&done_allocate);
2098 __ mov(ebx, NativeContextOperand());
2099 __ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
2100 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
2101 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
2102 isolate()->factory()->empty_fixed_array());
2103 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
2104 isolate()->factory()->empty_fixed_array());
2105 __ pop(FieldOperand(eax, JSIteratorResult::kValueOffset));
2106 __ mov(FieldOperand(eax, JSIteratorResult::kDoneOffset),
2107 isolate()->factory()->ToBoolean(done));
2108 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
2109}
2110
2111
2112void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
2113 SetExpressionPosition(prop);
2114 Literal* key = prop->key()->AsLiteral();
2115 DCHECK(!key->value()->IsSmi());
2116 DCHECK(!prop->IsSuperAccess());
2117
2118 __ mov(LoadDescriptor::NameRegister(), Immediate(key->value()));
2119 __ mov(LoadDescriptor::SlotRegister(),
2120 Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
2121 CallLoadIC(NOT_INSIDE_TYPEOF, language_mode());
2122}
2123
2124
2125void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
2126 // Stack: receiver, home_object.
2127 SetExpressionPosition(prop);
2128 Literal* key = prop->key()->AsLiteral();
2129 DCHECK(!key->value()->IsSmi());
2130 DCHECK(prop->IsSuperAccess());
2131
2132 __ push(Immediate(key->value()));
2133 __ push(Immediate(Smi::FromInt(language_mode())));
2134 __ CallRuntime(Runtime::kLoadFromSuper);
2135}
2136
2137
2138void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
2139 SetExpressionPosition(prop);
2140 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code();
2141 __ mov(LoadDescriptor::SlotRegister(),
2142 Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
2143 CallIC(ic);
2144}
2145
2146
2147void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
2148 // Stack: receiver, home_object, key.
2149 SetExpressionPosition(prop);
2150 __ push(Immediate(Smi::FromInt(language_mode())));
2151 __ CallRuntime(Runtime::kLoadKeyedFromSuper);
2152}
2153
2154
2155void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
2156 Token::Value op,
2157 Expression* left,
2158 Expression* right) {
2159 // Do combined smi check of the operands. Left operand is on the
2160 // stack. Right operand is in eax.
2161 Label smi_case, done, stub_call;
2162 __ pop(edx);
2163 __ mov(ecx, eax);
2164 __ or_(eax, edx);
2165 JumpPatchSite patch_site(masm_);
2166 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
2167
2168 __ bind(&stub_call);
2169 __ mov(eax, ecx);
2170 Handle<Code> code =
2171 CodeFactory::BinaryOpIC(isolate(), op, strength(language_mode())).code();
2172 CallIC(code, expr->BinaryOperationFeedbackId());
2173 patch_site.EmitPatchInfo();
2174 __ jmp(&done, Label::kNear);
2175
2176 // Smi case.
2177 __ bind(&smi_case);
2178 __ mov(eax, edx); // Copy left operand in case of a stub call.
2179
2180 switch (op) {
2181 case Token::SAR:
2182 __ SmiUntag(ecx);
2183 __ sar_cl(eax); // No checks of result necessary
2184 __ and_(eax, Immediate(~kSmiTagMask));
2185 break;
2186 case Token::SHL: {
2187 Label result_ok;
2188 __ SmiUntag(eax);
2189 __ SmiUntag(ecx);
2190 __ shl_cl(eax);
2191 // Check that the *signed* result fits in a smi.
2192 __ cmp(eax, 0xc0000000);
2193 __ j(positive, &result_ok);
2194 __ SmiTag(ecx);
2195 __ jmp(&stub_call);
2196 __ bind(&result_ok);
2197 __ SmiTag(eax);
2198 break;
2199 }
2200 case Token::SHR: {
2201 Label result_ok;
2202 __ SmiUntag(eax);
2203 __ SmiUntag(ecx);
2204 __ shr_cl(eax);
2205 __ test(eax, Immediate(0xc0000000));
2206 __ j(zero, &result_ok);
2207 __ SmiTag(ecx);
2208 __ jmp(&stub_call);
2209 __ bind(&result_ok);
2210 __ SmiTag(eax);
2211 break;
2212 }
2213 case Token::ADD:
2214 __ add(eax, ecx);
2215 __ j(overflow, &stub_call);
2216 break;
2217 case Token::SUB:
2218 __ sub(eax, ecx);
2219 __ j(overflow, &stub_call);
2220 break;
2221 case Token::MUL: {
2222 __ SmiUntag(eax);
2223 __ imul(eax, ecx);
2224 __ j(overflow, &stub_call);
2225 __ test(eax, eax);
2226 __ j(not_zero, &done, Label::kNear);
2227 __ mov(ebx, edx);
2228 __ or_(ebx, ecx);
2229 __ j(negative, &stub_call);
2230 break;
2231 }
2232 case Token::BIT_OR:
2233 __ or_(eax, ecx);
2234 break;
2235 case Token::BIT_AND:
2236 __ and_(eax, ecx);
2237 break;
2238 case Token::BIT_XOR:
2239 __ xor_(eax, ecx);
2240 break;
2241 default:
2242 UNREACHABLE();
2243 }
2244
2245 __ bind(&done);
2246 context()->Plug(eax);
2247}
2248
2249
2250void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
2251 // Constructor is in eax.
2252 DCHECK(lit != NULL);
2253 __ push(eax);
2254
2255 // No access check is needed here since the constructor is created by the
2256 // class literal.
2257 Register scratch = ebx;
2258 __ mov(scratch, FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset));
2259 __ Push(scratch);
2260
2261 for (int i = 0; i < lit->properties()->length(); i++) {
2262 ObjectLiteral::Property* property = lit->properties()->at(i);
2263 Expression* value = property->value();
2264
2265 if (property->is_static()) {
2266 __ push(Operand(esp, kPointerSize)); // constructor
2267 } else {
2268 __ push(Operand(esp, 0)); // prototype
2269 }
2270 EmitPropertyKey(property, lit->GetIdForProperty(i));
2271
2272 // The static prototype property is read only. We handle the non computed
2273 // property name case in the parser. Since this is the only case where we
2274 // need to check for an own read only property we special case this so we do
2275 // not need to do this for every property.
2276 if (property->is_static() && property->is_computed_name()) {
2277 __ CallRuntime(Runtime::kThrowIfStaticPrototype);
2278 __ push(eax);
2279 }
2280
2281 VisitForStackValue(value);
2282 if (NeedsHomeObject(value)) {
2283 EmitSetHomeObject(value, 2, property->GetSlot());
2284 }
2285
2286 switch (property->kind()) {
2287 case ObjectLiteral::Property::CONSTANT:
2288 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2289 case ObjectLiteral::Property::PROTOTYPE:
2290 UNREACHABLE();
2291 case ObjectLiteral::Property::COMPUTED:
2292 __ CallRuntime(Runtime::kDefineClassMethod);
2293 break;
2294
2295 case ObjectLiteral::Property::GETTER:
2296 __ push(Immediate(Smi::FromInt(DONT_ENUM)));
2297 __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked);
2298 break;
2299
2300 case ObjectLiteral::Property::SETTER:
2301 __ push(Immediate(Smi::FromInt(DONT_ENUM)));
2302 __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked);
2303 break;
2304 }
2305 }
2306
2307 // Set both the prototype and constructor to have fast properties, and also
2308 // freeze them in strong mode.
2309 __ CallRuntime(Runtime::kFinalizeClassDefinition);
2310}
2311
2312
2313void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
2314 __ pop(edx);
2315 Handle<Code> code =
2316 CodeFactory::BinaryOpIC(isolate(), op, strength(language_mode())).code();
2317 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
2318 CallIC(code, expr->BinaryOperationFeedbackId());
2319 patch_site.EmitPatchInfo();
2320 context()->Plug(eax);
2321}
2322
2323
2324void FullCodeGenerator::EmitAssignment(Expression* expr,
2325 FeedbackVectorSlot slot) {
2326 DCHECK(expr->IsValidReferenceExpressionOrThis());
2327
2328 Property* prop = expr->AsProperty();
2329 LhsKind assign_type = Property::GetAssignType(prop);
2330
2331 switch (assign_type) {
2332 case VARIABLE: {
2333 Variable* var = expr->AsVariableProxy()->var();
2334 EffectContext context(this);
2335 EmitVariableAssignment(var, Token::ASSIGN, slot);
2336 break;
2337 }
2338 case NAMED_PROPERTY: {
2339 __ push(eax); // Preserve value.
2340 VisitForAccumulatorValue(prop->obj());
2341 __ Move(StoreDescriptor::ReceiverRegister(), eax);
2342 __ pop(StoreDescriptor::ValueRegister()); // Restore value.
2343 __ mov(StoreDescriptor::NameRegister(),
2344 prop->key()->AsLiteral()->value());
2345 EmitLoadStoreICSlot(slot);
2346 CallStoreIC();
2347 break;
2348 }
2349 case NAMED_SUPER_PROPERTY: {
2350 __ push(eax);
2351 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2352 VisitForAccumulatorValue(
2353 prop->obj()->AsSuperPropertyReference()->home_object());
2354 // stack: value, this; eax: home_object
2355 Register scratch = ecx;
2356 Register scratch2 = edx;
2357 __ mov(scratch, result_register()); // home_object
2358 __ mov(eax, MemOperand(esp, kPointerSize)); // value
2359 __ mov(scratch2, MemOperand(esp, 0)); // this
2360 __ mov(MemOperand(esp, kPointerSize), scratch2); // this
2361 __ mov(MemOperand(esp, 0), scratch); // home_object
2362 // stack: this, home_object. eax: value
2363 EmitNamedSuperPropertyStore(prop);
2364 break;
2365 }
2366 case KEYED_SUPER_PROPERTY: {
2367 __ push(eax);
2368 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2369 VisitForStackValue(
2370 prop->obj()->AsSuperPropertyReference()->home_object());
2371 VisitForAccumulatorValue(prop->key());
2372 Register scratch = ecx;
2373 Register scratch2 = edx;
2374 __ mov(scratch2, MemOperand(esp, 2 * kPointerSize)); // value
2375 // stack: value, this, home_object; eax: key, edx: value
2376 __ mov(scratch, MemOperand(esp, kPointerSize)); // this
2377 __ mov(MemOperand(esp, 2 * kPointerSize), scratch);
2378 __ mov(scratch, MemOperand(esp, 0)); // home_object
2379 __ mov(MemOperand(esp, kPointerSize), scratch);
2380 __ mov(MemOperand(esp, 0), eax);
2381 __ mov(eax, scratch2);
2382 // stack: this, home_object, key; eax: value.
2383 EmitKeyedSuperPropertyStore(prop);
2384 break;
2385 }
2386 case KEYED_PROPERTY: {
2387 __ push(eax); // Preserve value.
2388 VisitForStackValue(prop->obj());
2389 VisitForAccumulatorValue(prop->key());
2390 __ Move(StoreDescriptor::NameRegister(), eax);
2391 __ pop(StoreDescriptor::ReceiverRegister()); // Receiver.
2392 __ pop(StoreDescriptor::ValueRegister()); // Restore value.
2393 EmitLoadStoreICSlot(slot);
2394 Handle<Code> ic =
2395 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2396 CallIC(ic);
2397 break;
2398 }
2399 }
2400 context()->Plug(eax);
2401}
2402
2403
2404void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2405 Variable* var, MemOperand location) {
2406 __ mov(location, eax);
2407 if (var->IsContextSlot()) {
2408 __ mov(edx, eax);
2409 int offset = Context::SlotOffset(var->index());
2410 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
2411 }
2412}
2413
2414
2415void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
2416 FeedbackVectorSlot slot) {
2417 if (var->IsUnallocated()) {
2418 // Global var, const, or let.
2419 __ mov(StoreDescriptor::NameRegister(), var->name());
2420 __ mov(StoreDescriptor::ReceiverRegister(), NativeContextOperand());
2421 __ mov(StoreDescriptor::ReceiverRegister(),
2422 ContextOperand(StoreDescriptor::ReceiverRegister(),
2423 Context::EXTENSION_INDEX));
2424 EmitLoadStoreICSlot(slot);
2425 CallStoreIC();
2426
2427 } else if (var->mode() == LET && op != Token::INIT) {
2428 // Non-initializing assignment to let variable needs a write barrier.
2429 DCHECK(!var->IsLookupSlot());
2430 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2431 Label assign;
2432 MemOperand location = VarOperand(var, ecx);
2433 __ mov(edx, location);
2434 __ cmp(edx, isolate()->factory()->the_hole_value());
2435 __ j(not_equal, &assign, Label::kNear);
2436 __ push(Immediate(var->name()));
2437 __ CallRuntime(Runtime::kThrowReferenceError);
2438 __ bind(&assign);
2439 EmitStoreToStackLocalOrContextSlot(var, location);
2440
2441 } else if (var->mode() == CONST && op != Token::INIT) {
2442 // Assignment to const variable needs a write barrier.
2443 DCHECK(!var->IsLookupSlot());
2444 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2445 Label const_error;
2446 MemOperand location = VarOperand(var, ecx);
2447 __ mov(edx, location);
2448 __ cmp(edx, isolate()->factory()->the_hole_value());
2449 __ j(not_equal, &const_error, Label::kNear);
2450 __ push(Immediate(var->name()));
2451 __ CallRuntime(Runtime::kThrowReferenceError);
2452 __ bind(&const_error);
2453 __ CallRuntime(Runtime::kThrowConstAssignError);
2454
2455 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
2456 // Initializing assignment to const {this} needs a write barrier.
2457 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2458 Label uninitialized_this;
2459 MemOperand location = VarOperand(var, ecx);
2460 __ mov(edx, location);
2461 __ cmp(edx, isolate()->factory()->the_hole_value());
2462 __ j(equal, &uninitialized_this);
2463 __ push(Immediate(var->name()));
2464 __ CallRuntime(Runtime::kThrowReferenceError);
2465 __ bind(&uninitialized_this);
2466 EmitStoreToStackLocalOrContextSlot(var, location);
2467
2468 } else if (!var->is_const_mode() ||
2469 (var->mode() == CONST && op == Token::INIT)) {
2470 if (var->IsLookupSlot()) {
2471 // Assignment to var.
2472 __ push(eax); // Value.
2473 __ push(esi); // Context.
2474 __ push(Immediate(var->name()));
2475 __ push(Immediate(Smi::FromInt(language_mode())));
2476 __ CallRuntime(Runtime::kStoreLookupSlot);
2477 } else {
2478 // Assignment to var or initializing assignment to let/const in harmony
2479 // mode.
2480 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2481 MemOperand location = VarOperand(var, ecx);
2482 if (generate_debug_code_ && var->mode() == LET && op == Token::INIT) {
2483 // Check for an uninitialized let binding.
2484 __ mov(edx, location);
2485 __ cmp(edx, isolate()->factory()->the_hole_value());
2486 __ Check(equal, kLetBindingReInitialization);
2487 }
2488 EmitStoreToStackLocalOrContextSlot(var, location);
2489 }
2490
2491 } else if (var->mode() == CONST_LEGACY && op == Token::INIT) {
2492 // Const initializers need a write barrier.
2493 DCHECK(!var->IsParameter()); // No const parameters.
2494 if (var->IsLookupSlot()) {
2495 __ push(eax);
2496 __ push(esi);
2497 __ push(Immediate(var->name()));
2498 __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot);
2499 } else {
2500 DCHECK(var->IsStackLocal() || var->IsContextSlot());
2501 Label skip;
2502 MemOperand location = VarOperand(var, ecx);
2503 __ mov(edx, location);
2504 __ cmp(edx, isolate()->factory()->the_hole_value());
2505 __ j(not_equal, &skip, Label::kNear);
2506 EmitStoreToStackLocalOrContextSlot(var, location);
2507 __ bind(&skip);
2508 }
2509
2510 } else {
2511 DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
2512 if (is_strict(language_mode())) {
2513 __ CallRuntime(Runtime::kThrowConstAssignError);
2514 }
2515 // Silently ignore store in sloppy mode.
2516 }
2517}
2518
2519
2520void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2521 // Assignment to a property, using a named store IC.
2522 // eax : value
2523 // esp[0] : receiver
2524 Property* prop = expr->target()->AsProperty();
2525 DCHECK(prop != NULL);
2526 DCHECK(prop->key()->IsLiteral());
2527
2528 __ mov(StoreDescriptor::NameRegister(), prop->key()->AsLiteral()->value());
2529 __ pop(StoreDescriptor::ReceiverRegister());
2530 EmitLoadStoreICSlot(expr->AssignmentSlot());
2531 CallStoreIC();
2532 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2533 context()->Plug(eax);
2534}
2535
2536
2537void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2538 // Assignment to named property of super.
2539 // eax : value
2540 // stack : receiver ('this'), home_object
2541 DCHECK(prop != NULL);
2542 Literal* key = prop->key()->AsLiteral();
2543 DCHECK(key != NULL);
2544
2545 __ push(Immediate(key->value()));
2546 __ push(eax);
2547 __ CallRuntime((is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict
2548 : Runtime::kStoreToSuper_Sloppy));
2549}
2550
2551
2552void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2553 // Assignment to named property of super.
2554 // eax : value
2555 // stack : receiver ('this'), home_object, key
2556
2557 __ push(eax);
2558 __ CallRuntime((is_strict(language_mode())
2559 ? Runtime::kStoreKeyedToSuper_Strict
2560 : Runtime::kStoreKeyedToSuper_Sloppy));
2561}
2562
2563
2564void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2565 // Assignment to a property, using a keyed store IC.
2566 // eax : value
2567 // esp[0] : key
2568 // esp[kPointerSize] : receiver
2569
2570 __ pop(StoreDescriptor::NameRegister()); // Key.
2571 __ pop(StoreDescriptor::ReceiverRegister());
2572 DCHECK(StoreDescriptor::ValueRegister().is(eax));
2573 Handle<Code> ic =
2574 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2575 EmitLoadStoreICSlot(expr->AssignmentSlot());
2576 CallIC(ic);
2577 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2578 context()->Plug(eax);
2579}
2580
2581
2582void FullCodeGenerator::VisitProperty(Property* expr) {
2583 Comment cmnt(masm_, "[ Property");
2584 SetExpressionPosition(expr);
2585
2586 Expression* key = expr->key();
2587
2588 if (key->IsPropertyName()) {
2589 if (!expr->IsSuperAccess()) {
2590 VisitForAccumulatorValue(expr->obj());
2591 __ Move(LoadDescriptor::ReceiverRegister(), result_register());
2592 EmitNamedPropertyLoad(expr);
2593 } else {
2594 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var());
2595 VisitForStackValue(
2596 expr->obj()->AsSuperPropertyReference()->home_object());
2597 EmitNamedSuperPropertyLoad(expr);
2598 }
2599 } else {
2600 if (!expr->IsSuperAccess()) {
2601 VisitForStackValue(expr->obj());
2602 VisitForAccumulatorValue(expr->key());
2603 __ pop(LoadDescriptor::ReceiverRegister()); // Object.
2604 __ Move(LoadDescriptor::NameRegister(), result_register()); // Key.
2605 EmitKeyedPropertyLoad(expr);
2606 } else {
2607 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var());
2608 VisitForStackValue(
2609 expr->obj()->AsSuperPropertyReference()->home_object());
2610 VisitForStackValue(expr->key());
2611 EmitKeyedSuperPropertyLoad(expr);
2612 }
2613 }
2614 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
2615 context()->Plug(eax);
2616}
2617
2618
2619void FullCodeGenerator::CallIC(Handle<Code> code,
2620 TypeFeedbackId ast_id) {
2621 ic_total_count_++;
2622 __ call(code, RelocInfo::CODE_TARGET, ast_id);
2623}
2624
2625
2626// Code common for calls using the IC.
2627void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2628 Expression* callee = expr->expression();
2629
2630 // Get the target function.
2631 ConvertReceiverMode convert_mode;
2632 if (callee->IsVariableProxy()) {
2633 { StackValueContext context(this);
2634 EmitVariableLoad(callee->AsVariableProxy());
2635 PrepareForBailout(callee, NO_REGISTERS);
2636 }
2637 // Push undefined as receiver. This is patched in the method prologue if it
2638 // is a sloppy mode method.
2639 __ push(Immediate(isolate()->factory()->undefined_value()));
2640 convert_mode = ConvertReceiverMode::kNullOrUndefined;
2641 } else {
2642 // Load the function from the receiver.
2643 DCHECK(callee->IsProperty());
2644 DCHECK(!callee->AsProperty()->IsSuperAccess());
2645 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2646 EmitNamedPropertyLoad(callee->AsProperty());
2647 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2648 // Push the target function under the receiver.
2649 __ push(Operand(esp, 0));
2650 __ mov(Operand(esp, kPointerSize), eax);
2651 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
2652 }
2653
2654 EmitCall(expr, convert_mode);
2655}
2656
2657
2658void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2659 SetExpressionPosition(expr);
2660 Expression* callee = expr->expression();
2661 DCHECK(callee->IsProperty());
2662 Property* prop = callee->AsProperty();
2663 DCHECK(prop->IsSuperAccess());
2664
2665 Literal* key = prop->key()->AsLiteral();
2666 DCHECK(!key->value()->IsSmi());
2667 // Load the function from the receiver.
2668 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2669 VisitForStackValue(super_ref->home_object());
2670 VisitForAccumulatorValue(super_ref->this_var());
2671 __ push(eax);
2672 __ push(eax);
2673 __ push(Operand(esp, kPointerSize * 2));
2674 __ push(Immediate(key->value()));
2675 __ push(Immediate(Smi::FromInt(language_mode())));
2676 // Stack here:
2677 // - home_object
2678 // - this (receiver)
2679 // - this (receiver) <-- LoadFromSuper will pop here and below.
2680 // - home_object
2681 // - key
2682 // - language_mode
2683 __ CallRuntime(Runtime::kLoadFromSuper);
2684
2685 // Replace home_object with target function.
2686 __ mov(Operand(esp, kPointerSize), eax);
2687
2688 // Stack here:
2689 // - target function
2690 // - this (receiver)
2691 EmitCall(expr);
2692}
2693
2694
2695// Code common for calls using the IC.
2696void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2697 Expression* key) {
2698 // Load the key.
2699 VisitForAccumulatorValue(key);
2700
2701 Expression* callee = expr->expression();
2702
2703 // Load the function from the receiver.
2704 DCHECK(callee->IsProperty());
2705 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2706 __ mov(LoadDescriptor::NameRegister(), eax);
2707 EmitKeyedPropertyLoad(callee->AsProperty());
2708 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2709
2710 // Push the target function under the receiver.
2711 __ push(Operand(esp, 0));
2712 __ mov(Operand(esp, kPointerSize), eax);
2713
2714 EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined);
2715}
2716
2717
2718void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2719 Expression* callee = expr->expression();
2720 DCHECK(callee->IsProperty());
2721 Property* prop = callee->AsProperty();
2722 DCHECK(prop->IsSuperAccess());
2723
2724 SetExpressionPosition(prop);
2725 // Load the function from the receiver.
2726 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2727 VisitForStackValue(super_ref->home_object());
2728 VisitForAccumulatorValue(super_ref->this_var());
2729 __ push(eax);
2730 __ push(eax);
2731 __ push(Operand(esp, kPointerSize * 2));
2732 VisitForStackValue(prop->key());
2733 __ push(Immediate(Smi::FromInt(language_mode())));
2734 // Stack here:
2735 // - home_object
2736 // - this (receiver)
2737 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2738 // - home_object
2739 // - key
2740 // - language_mode
2741 __ CallRuntime(Runtime::kLoadKeyedFromSuper);
2742
2743 // Replace home_object with target function.
2744 __ mov(Operand(esp, kPointerSize), eax);
2745
2746 // Stack here:
2747 // - target function
2748 // - this (receiver)
2749 EmitCall(expr);
2750}
2751
2752
2753void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
2754 // Load the arguments.
2755 ZoneList<Expression*>* args = expr->arguments();
2756 int arg_count = args->length();
2757 for (int i = 0; i < arg_count; i++) {
2758 VisitForStackValue(args->at(i));
2759 }
2760
2761 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS);
2762 SetCallPosition(expr);
2763 Handle<Code> ic = CodeFactory::CallIC(isolate(), arg_count, mode).code();
2764 __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackICSlot())));
2765 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2766 // Don't assign a type feedback id to the IC, since type feedback is provided
2767 // by the vector above.
2768 CallIC(ic);
2769
2770 RecordJSReturnSite(expr);
2771
2772 // Restore context register.
2773 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2774
2775 context()->DropAndPlug(1, eax);
2776}
2777
2778
2779void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
2780 // Push copy of the first argument or undefined if it doesn't exist.
2781 if (arg_count > 0) {
2782 __ push(Operand(esp, arg_count * kPointerSize));
2783 } else {
2784 __ push(Immediate(isolate()->factory()->undefined_value()));
2785 }
2786
2787 // Push the enclosing function.
2788 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2789
2790 // Push the language mode.
2791 __ push(Immediate(Smi::FromInt(language_mode())));
2792
2793 // Push the start position of the scope the calls resides in.
2794 __ push(Immediate(Smi::FromInt(scope()->start_position())));
2795
2796 // Do the runtime call.
2797 __ CallRuntime(Runtime::kResolvePossiblyDirectEval);
2798}
2799
2800
2801// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
2802void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
2803 VariableProxy* callee = expr->expression()->AsVariableProxy();
2804 if (callee->var()->IsLookupSlot()) {
2805 Label slow, done;
2806 SetExpressionPosition(callee);
2807 // Generate code for loading from variables potentially shadowed by
2808 // eval-introduced variables.
2809 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
2810
2811 __ bind(&slow);
2812 // Call the runtime to find the function to call (returned in eax) and
2813 // the object holding it (returned in edx).
2814 __ push(context_register());
2815 __ push(Immediate(callee->name()));
2816 __ CallRuntime(Runtime::kLoadLookupSlot);
2817 __ push(eax); // Function.
2818 __ push(edx); // Receiver.
2819 PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
2820
2821 // If fast case code has been generated, emit code to push the function
2822 // and receiver and have the slow path jump around this code.
2823 if (done.is_linked()) {
2824 Label call;
2825 __ jmp(&call, Label::kNear);
2826 __ bind(&done);
2827 // Push function.
2828 __ push(eax);
2829 // The receiver is implicitly the global receiver. Indicate this by
2830 // passing the hole to the call function stub.
2831 __ push(Immediate(isolate()->factory()->undefined_value()));
2832 __ bind(&call);
2833 }
2834 } else {
2835 VisitForStackValue(callee);
2836 // refEnv.WithBaseObject()
2837 __ push(Immediate(isolate()->factory()->undefined_value()));
2838 }
2839}
2840
2841
2842void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
2843 // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
2844 // to resolve the function we need to call. Then we call the resolved
2845 // function using the given arguments.
2846 ZoneList<Expression*>* args = expr->arguments();
2847 int arg_count = args->length();
2848
2849 PushCalleeAndWithBaseObject(expr);
2850
2851 // Push the arguments.
2852 for (int i = 0; i < arg_count; i++) {
2853 VisitForStackValue(args->at(i));
2854 }
2855
2856 // Push a copy of the function (found below the arguments) and
2857 // resolve eval.
2858 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2859 EmitResolvePossiblyDirectEval(arg_count);
2860
2861 // Touch up the stack with the resolved function.
2862 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
2863
2864 PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
2865
2866 SetCallPosition(expr);
2867 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2868 __ Set(eax, arg_count);
2869 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
2870 RecordJSReturnSite(expr);
2871 // Restore context register.
2872 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2873 context()->DropAndPlug(1, eax);
2874}
2875
2876
2877void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2878 Comment cmnt(masm_, "[ CallNew");
2879 // According to ECMA-262, section 11.2.2, page 44, the function
2880 // expression in new calls must be evaluated before the
2881 // arguments.
2882
2883 // Push constructor on the stack. If it's not a function it's used as
2884 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2885 // ignored.
2886 DCHECK(!expr->expression()->IsSuperPropertyReference());
2887 VisitForStackValue(expr->expression());
2888
2889 // Push the arguments ("left-to-right") on the stack.
2890 ZoneList<Expression*>* args = expr->arguments();
2891 int arg_count = args->length();
2892 for (int i = 0; i < arg_count; i++) {
2893 VisitForStackValue(args->at(i));
2894 }
2895
2896 // Call the construct call builtin that handles allocation and
2897 // constructor invocation.
2898 SetConstructCallPosition(expr);
2899
2900 // Load function and argument count into edi and eax.
2901 __ Move(eax, Immediate(arg_count));
2902 __ mov(edi, Operand(esp, arg_count * kPointerSize));
2903
2904 // Record call targets in unoptimized code.
2905 __ EmitLoadTypeFeedbackVector(ebx);
2906 __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot())));
2907
2908 CallConstructStub stub(isolate());
2909 __ call(stub.GetCode(), RelocInfo::CODE_TARGET);
2910 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
2911 // Restore context register.
2912 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2913 context()->Plug(eax);
2914}
2915
2916
2917void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
2918 SuperCallReference* super_call_ref =
2919 expr->expression()->AsSuperCallReference();
2920 DCHECK_NOT_NULL(super_call_ref);
2921
2922 // Push the super constructor target on the stack (may be null,
2923 // but the Construct builtin can deal with that properly).
2924 VisitForAccumulatorValue(super_call_ref->this_function_var());
2925 __ AssertFunction(result_register());
2926 __ mov(result_register(),
2927 FieldOperand(result_register(), HeapObject::kMapOffset));
2928 __ Push(FieldOperand(result_register(), Map::kPrototypeOffset));
2929
2930 // Push the arguments ("left-to-right") on the stack.
2931 ZoneList<Expression*>* args = expr->arguments();
2932 int arg_count = args->length();
2933 for (int i = 0; i < arg_count; i++) {
2934 VisitForStackValue(args->at(i));
2935 }
2936
2937 // Call the construct call builtin that handles allocation and
2938 // constructor invocation.
2939 SetConstructCallPosition(expr);
2940
2941 // Load new target into edx.
2942 VisitForAccumulatorValue(super_call_ref->new_target_var());
2943 __ mov(edx, result_register());
2944
2945 // Load function and argument count into edi and eax.
2946 __ Move(eax, Immediate(arg_count));
2947 __ mov(edi, Operand(esp, arg_count * kPointerSize));
2948
2949 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
2950
2951 RecordJSReturnSite(expr);
2952
2953 // Restore context register.
2954 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2955 context()->Plug(eax);
2956}
2957
2958
2959void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2960 ZoneList<Expression*>* args = expr->arguments();
2961 DCHECK(args->length() == 1);
2962
2963 VisitForAccumulatorValue(args->at(0));
2964
2965 Label materialize_true, materialize_false;
2966 Label* if_true = NULL;
2967 Label* if_false = NULL;
2968 Label* fall_through = NULL;
2969 context()->PrepareTest(&materialize_true, &materialize_false,
2970 &if_true, &if_false, &fall_through);
2971
2972 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2973 __ test(eax, Immediate(kSmiTagMask));
2974 Split(zero, if_true, if_false, fall_through);
2975
2976 context()->Plug(if_true, if_false);
2977}
2978
2979
2980void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) {
2981 ZoneList<Expression*>* args = expr->arguments();
2982 DCHECK(args->length() == 1);
2983
2984 VisitForAccumulatorValue(args->at(0));
2985
2986 Label materialize_true, materialize_false;
2987 Label* if_true = NULL;
2988 Label* if_false = NULL;
2989 Label* fall_through = NULL;
2990 context()->PrepareTest(&materialize_true, &materialize_false,
2991 &if_true, &if_false, &fall_through);
2992
2993 __ JumpIfSmi(eax, if_false);
2994 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ebx);
2995 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2996 Split(above_equal, if_true, if_false, fall_through);
2997
2998 context()->Plug(if_true, if_false);
2999}
3000
3001
3002void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
3003 ZoneList<Expression*>* args = expr->arguments();
3004 DCHECK(args->length() == 1);
3005
3006 VisitForAccumulatorValue(args->at(0));
3007
3008 Label materialize_true, materialize_false;
3009 Label* if_true = NULL;
3010 Label* if_false = NULL;
3011 Label* fall_through = NULL;
3012 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3013 &if_false, &fall_through);
3014
3015 __ JumpIfSmi(eax, if_false);
3016 __ CmpObjectType(eax, SIMD128_VALUE_TYPE, ebx);
3017 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3018 Split(equal, if_true, if_false, fall_through);
3019
3020 context()->Plug(if_true, if_false);
3021}
3022
3023
3024void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
3025 ZoneList<Expression*>* args = expr->arguments();
3026 DCHECK(args->length() == 1);
3027
3028 VisitForAccumulatorValue(args->at(0));
3029
3030 Label materialize_true, materialize_false;
3031 Label* if_true = NULL;
3032 Label* if_false = NULL;
3033 Label* fall_through = NULL;
3034 context()->PrepareTest(&materialize_true, &materialize_false,
3035 &if_true, &if_false, &fall_through);
3036
3037 __ JumpIfSmi(eax, if_false);
3038 __ CmpObjectType(eax, FIRST_FUNCTION_TYPE, ebx);
3039 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3040 Split(above_equal, if_true, if_false, fall_through);
3041
3042 context()->Plug(if_true, if_false);
3043}
3044
3045
3046void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
3047 ZoneList<Expression*>* args = expr->arguments();
3048 DCHECK(args->length() == 1);
3049
3050 VisitForAccumulatorValue(args->at(0));
3051
3052 Label materialize_true, materialize_false;
3053 Label* if_true = NULL;
3054 Label* if_false = NULL;
3055 Label* fall_through = NULL;
3056 context()->PrepareTest(&materialize_true, &materialize_false,
3057 &if_true, &if_false, &fall_through);
3058
3059 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
3060 __ CheckMap(eax, map, if_false, DO_SMI_CHECK);
3061 // Check if the exponent half is 0x80000000. Comparing against 1 and
3062 // checking for overflow is the shortest possible encoding.
3063 __ cmp(FieldOperand(eax, HeapNumber::kExponentOffset), Immediate(0x1));
3064 __ j(no_overflow, if_false);
3065 __ cmp(FieldOperand(eax, HeapNumber::kMantissaOffset), Immediate(0x0));
3066 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3067 Split(equal, if_true, if_false, fall_through);
3068
3069 context()->Plug(if_true, if_false);
3070}
3071
3072
3073void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
3074 ZoneList<Expression*>* args = expr->arguments();
3075 DCHECK(args->length() == 1);
3076
3077 VisitForAccumulatorValue(args->at(0));
3078
3079 Label materialize_true, materialize_false;
3080 Label* if_true = NULL;
3081 Label* if_false = NULL;
3082 Label* fall_through = NULL;
3083 context()->PrepareTest(&materialize_true, &materialize_false,
3084 &if_true, &if_false, &fall_through);
3085
3086 __ JumpIfSmi(eax, if_false);
3087 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
3088 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3089 Split(equal, if_true, if_false, fall_through);
3090
3091 context()->Plug(if_true, if_false);
3092}
3093
3094
3095void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) {
3096 ZoneList<Expression*>* args = expr->arguments();
3097 DCHECK(args->length() == 1);
3098
3099 VisitForAccumulatorValue(args->at(0));
3100
3101 Label materialize_true, materialize_false;
3102 Label* if_true = NULL;
3103 Label* if_false = NULL;
3104 Label* fall_through = NULL;
3105 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3106 &if_false, &fall_through);
3107
3108 __ JumpIfSmi(eax, if_false);
3109 __ CmpObjectType(eax, JS_TYPED_ARRAY_TYPE, ebx);
3110 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3111 Split(equal, if_true, if_false, fall_through);
3112
3113 context()->Plug(if_true, if_false);
3114}
3115
3116
3117void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
3118 ZoneList<Expression*>* args = expr->arguments();
3119 DCHECK(args->length() == 1);
3120
3121 VisitForAccumulatorValue(args->at(0));
3122
3123 Label materialize_true, materialize_false;
3124 Label* if_true = NULL;
3125 Label* if_false = NULL;
3126 Label* fall_through = NULL;
3127 context()->PrepareTest(&materialize_true, &materialize_false,
3128 &if_true, &if_false, &fall_through);
3129
3130 __ JumpIfSmi(eax, if_false);
3131 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
3132 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3133 Split(equal, if_true, if_false, fall_through);
3134
3135 context()->Plug(if_true, if_false);
3136}
3137
3138
3139void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
3140 ZoneList<Expression*>* args = expr->arguments();
3141 DCHECK(args->length() == 1);
3142
3143 VisitForAccumulatorValue(args->at(0));
3144
3145 Label materialize_true, materialize_false;
3146 Label* if_true = NULL;
3147 Label* if_false = NULL;
3148 Label* fall_through = NULL;
3149 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3150 &if_false, &fall_through);
3151
3152 __ JumpIfSmi(eax, if_false);
3153 __ CmpObjectType(eax, JS_PROXY_TYPE, ebx);
3154 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3155 Split(equal, if_true, if_false, fall_through);
3156
3157 context()->Plug(if_true, if_false);
3158}
3159
3160
3161void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
3162 ZoneList<Expression*>* args = expr->arguments();
3163 DCHECK(args->length() == 2);
3164
3165 // Load the two objects into registers and perform the comparison.
3166 VisitForStackValue(args->at(0));
3167 VisitForAccumulatorValue(args->at(1));
3168
3169 Label materialize_true, materialize_false;
3170 Label* if_true = NULL;
3171 Label* if_false = NULL;
3172 Label* fall_through = NULL;
3173 context()->PrepareTest(&materialize_true, &materialize_false,
3174 &if_true, &if_false, &fall_through);
3175
3176 __ pop(ebx);
3177 __ cmp(eax, ebx);
3178 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3179 Split(equal, if_true, if_false, fall_through);
3180
3181 context()->Plug(if_true, if_false);
3182}
3183
3184
3185void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3186 ZoneList<Expression*>* args = expr->arguments();
3187 DCHECK(args->length() == 1);
3188
3189 // ArgumentsAccessStub expects the key in edx and the formal
3190 // parameter count in eax.
3191 VisitForAccumulatorValue(args->at(0));
3192 __ mov(edx, eax);
3193 __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
3194 ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
3195 __ CallStub(&stub);
3196 context()->Plug(eax);
3197}
3198
3199
3200void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
3201 DCHECK(expr->arguments()->length() == 0);
3202
3203 Label exit;
3204 // Get the number of formal parameters.
3205 __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
3206
3207 // Check if the calling frame is an arguments adaptor frame.
3208 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3209 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
3210 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3211 __ j(not_equal, &exit);
3212
3213 // Arguments adaptor case: Read the arguments length from the
3214 // adaptor frame.
3215 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
3216
3217 __ bind(&exit);
3218 __ AssertSmi(eax);
3219 context()->Plug(eax);
3220}
3221
3222
3223void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3224 ZoneList<Expression*>* args = expr->arguments();
3225 DCHECK(args->length() == 1);
3226 Label done, null, function, non_function_constructor;
3227
3228 VisitForAccumulatorValue(args->at(0));
3229
3230 // If the object is not a JSReceiver, we return null.
3231 __ JumpIfSmi(eax, &null, Label::kNear);
3232 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
3233 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax);
3234 __ j(below, &null, Label::kNear);
3235
3236 // Return 'Function' for JSFunction objects.
3237 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
3238 __ j(equal, &function, Label::kNear);
3239
3240 // Check if the constructor in the map is a JS function.
3241 __ GetMapConstructor(eax, eax, ebx);
3242 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
3243 __ j(not_equal, &non_function_constructor, Label::kNear);
3244
3245 // eax now contains the constructor function. Grab the
3246 // instance class name from there.
3247 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
3248 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
3249 __ jmp(&done, Label::kNear);
3250
3251 // Non-JS objects have class null.
3252 __ bind(&null);
3253 __ mov(eax, isolate()->factory()->null_value());
3254 __ jmp(&done, Label::kNear);
3255
3256 // Functions have class 'Function'.
3257 __ bind(&function);
3258 __ mov(eax, isolate()->factory()->Function_string());
3259 __ jmp(&done, Label::kNear);
3260
3261 // Objects with a non-function constructor have class 'Object'.
3262 __ bind(&non_function_constructor);
3263 __ mov(eax, isolate()->factory()->Object_string());
3264
3265 // All done.
3266 __ bind(&done);
3267
3268 context()->Plug(eax);
3269}
3270
3271
3272void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3273 ZoneList<Expression*>* args = expr->arguments();
3274 DCHECK(args->length() == 1);
3275
3276 VisitForAccumulatorValue(args->at(0)); // Load the object.
3277
3278 Label done;
3279 // If the object is a smi return the object.
3280 __ JumpIfSmi(eax, &done, Label::kNear);
3281 // If the object is not a value type, return the object.
3282 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
3283 __ j(not_equal, &done, Label::kNear);
3284 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
3285
3286 __ bind(&done);
3287 context()->Plug(eax);
3288}
3289
3290
3291void FullCodeGenerator::EmitIsDate(CallRuntime* expr) {
3292 ZoneList<Expression*>* args = expr->arguments();
3293 DCHECK_EQ(1, args->length());
3294
3295 VisitForAccumulatorValue(args->at(0));
3296
3297 Label materialize_true, materialize_false;
3298 Label* if_true = nullptr;
3299 Label* if_false = nullptr;
3300 Label* fall_through = nullptr;
3301 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3302 &if_false, &fall_through);
3303
3304 __ JumpIfSmi(eax, if_false);
3305 __ CmpObjectType(eax, JS_DATE_TYPE, ebx);
3306 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3307 Split(equal, if_true, if_false, fall_through);
3308
3309 context()->Plug(if_true, if_false);
3310}
3311
3312
3313void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3314 ZoneList<Expression*>* args = expr->arguments();
3315 DCHECK_EQ(3, args->length());
3316
3317 Register string = eax;
3318 Register index = ebx;
3319 Register value = ecx;
3320
3321 VisitForStackValue(args->at(0)); // index
3322 VisitForStackValue(args->at(1)); // value
3323 VisitForAccumulatorValue(args->at(2)); // string
3324
3325 __ pop(value);
3326 __ pop(index);
3327
3328 if (FLAG_debug_code) {
3329 __ test(value, Immediate(kSmiTagMask));
3330 __ Check(zero, kNonSmiValue);
3331 __ test(index, Immediate(kSmiTagMask));
3332 __ Check(zero, kNonSmiValue);
3333 }
3334
3335 __ SmiUntag(value);
3336 __ SmiUntag(index);
3337
3338 if (FLAG_debug_code) {
3339 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
3340 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
3341 }
3342
3343 __ mov_b(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
3344 value);
3345 context()->Plug(string);
3346}
3347
3348
3349void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3350 ZoneList<Expression*>* args = expr->arguments();
3351 DCHECK_EQ(3, args->length());
3352
3353 Register string = eax;
3354 Register index = ebx;
3355 Register value = ecx;
3356
3357 VisitForStackValue(args->at(0)); // index
3358 VisitForStackValue(args->at(1)); // value
3359 VisitForAccumulatorValue(args->at(2)); // string
3360 __ pop(value);
3361 __ pop(index);
3362
3363 if (FLAG_debug_code) {
3364 __ test(value, Immediate(kSmiTagMask));
3365 __ Check(zero, kNonSmiValue);
3366 __ test(index, Immediate(kSmiTagMask));
3367 __ Check(zero, kNonSmiValue);
3368 __ SmiUntag(index);
3369 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
3370 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
3371 __ SmiTag(index);
3372 }
3373
3374 __ SmiUntag(value);
3375 // No need to untag a smi for two-byte addressing.
3376 __ mov_w(FieldOperand(string, index, times_1, SeqTwoByteString::kHeaderSize),
3377 value);
3378 context()->Plug(string);
3379}
3380
3381
3382void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3383 ZoneList<Expression*>* args = expr->arguments();
3384 DCHECK(args->length() == 2);
3385
3386 VisitForStackValue(args->at(0)); // Load the object.
3387 VisitForAccumulatorValue(args->at(1)); // Load the value.
3388 __ pop(ebx); // eax = value. ebx = object.
3389
3390 Label done;
3391 // If the object is a smi, return the value.
3392 __ JumpIfSmi(ebx, &done, Label::kNear);
3393
3394 // If the object is not a value type, return the value.
3395 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
3396 __ j(not_equal, &done, Label::kNear);
3397
3398 // Store the value.
3399 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
3400
3401 // Update the write barrier. Save the value as it will be
3402 // overwritten by the write barrier code and is needed afterward.
3403 __ mov(edx, eax);
3404 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
3405
3406 __ bind(&done);
3407 context()->Plug(eax);
3408}
3409
3410
3411void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
3412 ZoneList<Expression*>* args = expr->arguments();
3413 DCHECK_EQ(1, args->length());
3414
3415 // Load the argument into eax and convert it.
3416 VisitForAccumulatorValue(args->at(0));
3417
3418 // Convert the object to an integer.
3419 Label done_convert;
3420 __ JumpIfSmi(eax, &done_convert, Label::kNear);
3421 __ Push(eax);
3422 __ CallRuntime(Runtime::kToInteger);
3423 __ bind(&done_convert);
3424 context()->Plug(eax);
3425}
3426
3427
3428void FullCodeGenerator::EmitToName(CallRuntime* expr) {
3429 ZoneList<Expression*>* args = expr->arguments();
3430 DCHECK_EQ(1, args->length());
3431
3432 // Load the argument into eax and convert it.
3433 VisitForAccumulatorValue(args->at(0));
3434
3435 // Convert the object to a name.
3436 Label convert, done_convert;
3437 __ JumpIfSmi(eax, &convert, Label::kNear);
3438 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE);
3439 __ CmpObjectType(eax, LAST_NAME_TYPE, ecx);
3440 __ j(below_equal, &done_convert, Label::kNear);
3441 __ bind(&convert);
3442 __ Push(eax);
3443 __ CallRuntime(Runtime::kToName);
3444 __ bind(&done_convert);
3445 context()->Plug(eax);
3446}
3447
3448
3449void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3450 ZoneList<Expression*>* args = expr->arguments();
3451 DCHECK(args->length() == 1);
3452
3453 VisitForAccumulatorValue(args->at(0));
3454
3455 Label done;
3456 StringCharFromCodeGenerator generator(eax, ebx);
3457 generator.GenerateFast(masm_);
3458 __ jmp(&done);
3459
3460 NopRuntimeCallHelper call_helper;
3461 generator.GenerateSlow(masm_, call_helper);
3462
3463 __ bind(&done);
3464 context()->Plug(ebx);
3465}
3466
3467
3468void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3469 ZoneList<Expression*>* args = expr->arguments();
3470 DCHECK(args->length() == 2);
3471
3472 VisitForStackValue(args->at(0));
3473 VisitForAccumulatorValue(args->at(1));
3474
3475 Register object = ebx;
3476 Register index = eax;
3477 Register result = edx;
3478
3479 __ pop(object);
3480
3481 Label need_conversion;
3482 Label index_out_of_range;
3483 Label done;
3484 StringCharCodeAtGenerator generator(object,
3485 index,
3486 result,
3487 &need_conversion,
3488 &need_conversion,
3489 &index_out_of_range,
3490 STRING_INDEX_IS_NUMBER);
3491 generator.GenerateFast(masm_);
3492 __ jmp(&done);
3493
3494 __ bind(&index_out_of_range);
3495 // When the index is out of range, the spec requires us to return
3496 // NaN.
3497 __ Move(result, Immediate(isolate()->factory()->nan_value()));
3498 __ jmp(&done);
3499
3500 __ bind(&need_conversion);
3501 // Move the undefined value into the result register, which will
3502 // trigger conversion.
3503 __ Move(result, Immediate(isolate()->factory()->undefined_value()));
3504 __ jmp(&done);
3505
3506 NopRuntimeCallHelper call_helper;
3507 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
3508
3509 __ bind(&done);
3510 context()->Plug(result);
3511}
3512
3513
3514void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3515 ZoneList<Expression*>* args = expr->arguments();
3516 DCHECK(args->length() == 2);
3517
3518 VisitForStackValue(args->at(0));
3519 VisitForAccumulatorValue(args->at(1));
3520
3521 Register object = ebx;
3522 Register index = eax;
3523 Register scratch = edx;
3524 Register result = eax;
3525
3526 __ pop(object);
3527
3528 Label need_conversion;
3529 Label index_out_of_range;
3530 Label done;
3531 StringCharAtGenerator generator(object,
3532 index,
3533 scratch,
3534 result,
3535 &need_conversion,
3536 &need_conversion,
3537 &index_out_of_range,
3538 STRING_INDEX_IS_NUMBER);
3539 generator.GenerateFast(masm_);
3540 __ jmp(&done);
3541
3542 __ bind(&index_out_of_range);
3543 // When the index is out of range, the spec requires us to return
3544 // the empty string.
3545 __ Move(result, Immediate(isolate()->factory()->empty_string()));
3546 __ jmp(&done);
3547
3548 __ bind(&need_conversion);
3549 // Move smi zero into the result register, which will trigger
3550 // conversion.
3551 __ Move(result, Immediate(Smi::FromInt(0)));
3552 __ jmp(&done);
3553
3554 NopRuntimeCallHelper call_helper;
3555 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
3556
3557 __ bind(&done);
3558 context()->Plug(result);
3559}
3560
3561
3562void FullCodeGenerator::EmitCall(CallRuntime* expr) {
3563 ZoneList<Expression*>* args = expr->arguments();
3564 DCHECK_LE(2, args->length());
3565 // Push target, receiver and arguments onto the stack.
3566 for (Expression* const arg : *args) {
3567 VisitForStackValue(arg);
3568 }
3569 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS);
3570 // Move target to edi.
3571 int const argc = args->length() - 2;
3572 __ mov(edi, Operand(esp, (argc + 1) * kPointerSize));
3573 // Call the target.
3574 __ mov(eax, Immediate(argc));
3575 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
3576 // Restore context register.
3577 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3578 // Discard the function left on TOS.
3579 context()->DropAndPlug(1, eax);
3580}
3581
3582
3583void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3584 ZoneList<Expression*>* args = expr->arguments();
3585 DCHECK(args->length() == 1);
3586
3587 VisitForAccumulatorValue(args->at(0));
3588
3589 __ AssertString(eax);
3590
3591 Label materialize_true, materialize_false;
3592 Label* if_true = NULL;
3593 Label* if_false = NULL;
3594 Label* fall_through = NULL;
3595 context()->PrepareTest(&materialize_true, &materialize_false,
3596 &if_true, &if_false, &fall_through);
3597
3598 __ test(FieldOperand(eax, String::kHashFieldOffset),
3599 Immediate(String::kContainsCachedArrayIndexMask));
3600 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3601 Split(zero, if_true, if_false, fall_through);
3602
3603 context()->Plug(if_true, if_false);
3604}
3605
3606
3607void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3608 ZoneList<Expression*>* args = expr->arguments();
3609 DCHECK(args->length() == 1);
3610 VisitForAccumulatorValue(args->at(0));
3611
3612 __ AssertString(eax);
3613
3614 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3615 __ IndexFromHash(eax, eax);
3616
3617 context()->Plug(eax);
3618}
3619
3620
3621void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) {
3622 ZoneList<Expression*>* args = expr->arguments();
3623 DCHECK_EQ(1, args->length());
3624 VisitForAccumulatorValue(args->at(0));
3625 __ AssertFunction(eax);
3626 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
3627 __ mov(eax, FieldOperand(eax, Map::kPrototypeOffset));
3628 context()->Plug(eax);
3629}
3630
3631
3632void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) {
3633 Label bailout, done, one_char_separator, long_separator,
3634 non_trivial_array, not_size_one_array, loop,
3635 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
3636
3637 ZoneList<Expression*>* args = expr->arguments();
3638 DCHECK(args->length() == 2);
3639 // We will leave the separator on the stack until the end of the function.
3640 VisitForStackValue(args->at(1));
3641 // Load this to eax (= array)
3642 VisitForAccumulatorValue(args->at(0));
3643 // All aliases of the same register have disjoint lifetimes.
3644 Register array = eax;
3645 Register elements = no_reg; // Will be eax.
3646
3647 Register index = edx;
3648
3649 Register string_length = ecx;
3650
3651 Register string = esi;
3652
3653 Register scratch = ebx;
3654
3655 Register array_length = edi;
3656 Register result_pos = no_reg; // Will be edi.
3657
3658 // Separator operand is already pushed.
3659 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3660 Operand result_operand = Operand(esp, 1 * kPointerSize);
3661 Operand array_length_operand = Operand(esp, 0);
3662 __ sub(esp, Immediate(2 * kPointerSize));
3663 __ cld();
3664 // Check that the array is a JSArray
3665 __ JumpIfSmi(array, &bailout);
3666 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3667 __ j(not_equal, &bailout);
3668
3669 // Check that the array has fast elements.
3670 __ CheckFastElements(scratch, &bailout);
3671
3672 // If the array has length zero, return the empty string.
3673 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
3674 __ SmiUntag(array_length);
3675 __ j(not_zero, &non_trivial_array);
3676 __ mov(result_operand, isolate()->factory()->empty_string());
3677 __ jmp(&done);
3678
3679 // Save the array length.
3680 __ bind(&non_trivial_array);
3681 __ mov(array_length_operand, array_length);
3682
3683 // Save the FixedArray containing array's elements.
3684 // End of array's live range.
3685 elements = array;
3686 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
3687 array = no_reg;
3688
3689
3690 // Check that all array elements are sequential one-byte strings, and
3691 // accumulate the sum of their lengths, as a smi-encoded value.
3692 __ Move(index, Immediate(0));
3693 __ Move(string_length, Immediate(0));
3694 // Loop condition: while (index < length).
3695 // Live loop registers: index, array_length, string,
3696 // scratch, string_length, elements.
3697 if (generate_debug_code_) {
3698 __ cmp(index, array_length);
3699 __ Assert(less, kNoEmptyArraysHereInEmitFastOneByteArrayJoin);
3700 }
3701 __ bind(&loop);
3702 __ mov(string, FieldOperand(elements,
3703 index,
3704 times_pointer_size,
3705 FixedArray::kHeaderSize));
3706 __ JumpIfSmi(string, &bailout);
3707 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3708 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3709 __ and_(scratch, Immediate(
3710 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3711 __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
3712 __ j(not_equal, &bailout);
3713 __ add(string_length,
3714 FieldOperand(string, SeqOneByteString::kLengthOffset));
3715 __ j(overflow, &bailout);
3716 __ add(index, Immediate(1));
3717 __ cmp(index, array_length);
3718 __ j(less, &loop);
3719
3720 // If array_length is 1, return elements[0], a string.
3721 __ cmp(array_length, 1);
3722 __ j(not_equal, &not_size_one_array);
3723 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3724 __ mov(result_operand, scratch);
3725 __ jmp(&done);
3726
3727 __ bind(&not_size_one_array);
3728
3729 // End of array_length live range.
3730 result_pos = array_length;
3731 array_length = no_reg;
3732
3733 // Live registers:
3734 // string_length: Sum of string lengths, as a smi.
3735 // elements: FixedArray of strings.
3736
3737 // Check that the separator is a flat one-byte string.
3738 __ mov(string, separator_operand);
3739 __ JumpIfSmi(string, &bailout);
3740 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3741 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3742 __ and_(scratch, Immediate(
3743 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3744 __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
3745 __ j(not_equal, &bailout);
3746
3747 // Add (separator length times array_length) - separator length
3748 // to string_length.
3749 __ mov(scratch, separator_operand);
3750 __ mov(scratch, FieldOperand(scratch, SeqOneByteString::kLengthOffset));
3751 __ sub(string_length, scratch); // May be negative, temporarily.
3752 __ imul(scratch, array_length_operand);
3753 __ j(overflow, &bailout);
3754 __ add(string_length, scratch);
3755 __ j(overflow, &bailout);
3756
3757 __ shr(string_length, 1);
3758
3759 // Bailout for large object allocations.
3760 __ cmp(string_length, Page::kMaxRegularHeapObjectSize);
3761 __ j(greater, &bailout);
3762
3763 // Live registers and stack values:
3764 // string_length
3765 // elements
3766 __ AllocateOneByteString(result_pos, string_length, scratch, index, string,
3767 &bailout);
3768 __ mov(result_operand, result_pos);
3769 __ lea(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize));
3770
3771
3772 __ mov(string, separator_operand);
3773 __ cmp(FieldOperand(string, SeqOneByteString::kLengthOffset),
3774 Immediate(Smi::FromInt(1)));
3775 __ j(equal, &one_char_separator);
3776 __ j(greater, &long_separator);
3777
3778
3779 // Empty separator case
3780 __ mov(index, Immediate(0));
3781 __ jmp(&loop_1_condition);
3782 // Loop condition: while (index < length).
3783 __ bind(&loop_1);
3784 // Each iteration of the loop concatenates one string to the result.
3785 // Live values in registers:
3786 // index: which element of the elements array we are adding to the result.
3787 // result_pos: the position to which we are currently copying characters.
3788 // elements: the FixedArray of strings we are joining.
3789
3790 // Get string = array[index].
3791 __ mov(string, FieldOperand(elements, index,
3792 times_pointer_size,
3793 FixedArray::kHeaderSize));
3794 __ mov(string_length,
3795 FieldOperand(string, String::kLengthOffset));
3796 __ shr(string_length, 1);
3797 __ lea(string,
3798 FieldOperand(string, SeqOneByteString::kHeaderSize));
3799 __ CopyBytes(string, result_pos, string_length, scratch);
3800 __ add(index, Immediate(1));
3801 __ bind(&loop_1_condition);
3802 __ cmp(index, array_length_operand);
3803 __ j(less, &loop_1); // End while (index < length).
3804 __ jmp(&done);
3805
3806
3807
3808 // One-character separator case
3809 __ bind(&one_char_separator);
3810 // Replace separator with its one-byte character value.
3811 __ mov_b(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize));
3812 __ mov_b(separator_operand, scratch);
3813
3814 __ Move(index, Immediate(0));
3815 // Jump into the loop after the code that copies the separator, so the first
3816 // element is not preceded by a separator
3817 __ jmp(&loop_2_entry);
3818 // Loop condition: while (index < length).
3819 __ bind(&loop_2);
3820 // Each iteration of the loop concatenates one string to the result.
3821 // Live values in registers:
3822 // index: which element of the elements array we are adding to the result.
3823 // result_pos: the position to which we are currently copying characters.
3824
3825 // Copy the separator character to the result.
3826 __ mov_b(scratch, separator_operand);
3827 __ mov_b(Operand(result_pos, 0), scratch);
3828 __ inc(result_pos);
3829
3830 __ bind(&loop_2_entry);
3831 // Get string = array[index].
3832 __ mov(string, FieldOperand(elements, index,
3833 times_pointer_size,
3834 FixedArray::kHeaderSize));
3835 __ mov(string_length,
3836 FieldOperand(string, String::kLengthOffset));
3837 __ shr(string_length, 1);
3838 __ lea(string,
3839 FieldOperand(string, SeqOneByteString::kHeaderSize));
3840 __ CopyBytes(string, result_pos, string_length, scratch);
3841 __ add(index, Immediate(1));
3842
3843 __ cmp(index, array_length_operand);
3844 __ j(less, &loop_2); // End while (index < length).
3845 __ jmp(&done);
3846
3847
3848 // Long separator case (separator is more than one character).
3849 __ bind(&long_separator);
3850
3851 __ Move(index, Immediate(0));
3852 // Jump into the loop after the code that copies the separator, so the first
3853 // element is not preceded by a separator
3854 __ jmp(&loop_3_entry);
3855 // Loop condition: while (index < length).
3856 __ bind(&loop_3);
3857 // Each iteration of the loop concatenates one string to the result.
3858 // Live values in registers:
3859 // index: which element of the elements array we are adding to the result.
3860 // result_pos: the position to which we are currently copying characters.
3861
3862 // Copy the separator to the result.
3863 __ mov(string, separator_operand);
3864 __ mov(string_length,
3865 FieldOperand(string, String::kLengthOffset));
3866 __ shr(string_length, 1);
3867 __ lea(string,
3868 FieldOperand(string, SeqOneByteString::kHeaderSize));
3869 __ CopyBytes(string, result_pos, string_length, scratch);
3870
3871 __ bind(&loop_3_entry);
3872 // Get string = array[index].
3873 __ mov(string, FieldOperand(elements, index,
3874 times_pointer_size,
3875 FixedArray::kHeaderSize));
3876 __ mov(string_length,
3877 FieldOperand(string, String::kLengthOffset));
3878 __ shr(string_length, 1);
3879 __ lea(string,
3880 FieldOperand(string, SeqOneByteString::kHeaderSize));
3881 __ CopyBytes(string, result_pos, string_length, scratch);
3882 __ add(index, Immediate(1));
3883
3884 __ cmp(index, array_length_operand);
3885 __ j(less, &loop_3); // End while (index < length).
3886 __ jmp(&done);
3887
3888
3889 __ bind(&bailout);
3890 __ mov(result_operand, isolate()->factory()->undefined_value());
3891 __ bind(&done);
3892 __ mov(eax, result_operand);
3893 // Drop temp values from the stack, and restore context register.
3894 __ add(esp, Immediate(3 * kPointerSize));
3895
3896 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3897 context()->Plug(eax);
3898}
3899
3900
3901void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
3902 DCHECK(expr->arguments()->length() == 0);
3903 ExternalReference debug_is_active =
3904 ExternalReference::debug_is_active_address(isolate());
3905 __ movzx_b(eax, Operand::StaticVariable(debug_is_active));
3906 __ SmiTag(eax);
3907 context()->Plug(eax);
3908}
3909
3910
3911void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
3912 ZoneList<Expression*>* args = expr->arguments();
3913 DCHECK_EQ(2, args->length());
3914 VisitForStackValue(args->at(0));
3915 VisitForStackValue(args->at(1));
3916
3917 Label runtime, done;
3918
3919 __ Allocate(JSIteratorResult::kSize, eax, ecx, edx, &runtime, TAG_OBJECT);
3920 __ mov(ebx, NativeContextOperand());
3921 __ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
3922 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
3923 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
3924 isolate()->factory()->empty_fixed_array());
3925 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
3926 isolate()->factory()->empty_fixed_array());
3927 __ pop(FieldOperand(eax, JSIteratorResult::kDoneOffset));
3928 __ pop(FieldOperand(eax, JSIteratorResult::kValueOffset));
3929 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
3930 __ jmp(&done, Label::kNear);
3931
3932 __ bind(&runtime);
3933 __ CallRuntime(Runtime::kCreateIterResultObject);
3934
3935 __ bind(&done);
3936 context()->Plug(eax);
3937}
3938
3939
3940void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
3941 // Push undefined as receiver.
3942 __ push(Immediate(isolate()->factory()->undefined_value()));
3943
3944 __ LoadGlobalFunction(expr->context_index(), eax);
3945}
3946
3947
3948void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) {
3949 ZoneList<Expression*>* args = expr->arguments();
3950 int arg_count = args->length();
3951
3952 SetCallPosition(expr);
3953 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
3954 __ Set(eax, arg_count);
3955 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined),
3956 RelocInfo::CODE_TARGET);
3957}
3958
3959
3960void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
3961 ZoneList<Expression*>* args = expr->arguments();
3962 int arg_count = args->length();
3963
3964 if (expr->is_jsruntime()) {
3965 Comment cmnt(masm_, "[ CallRuntime");
3966 EmitLoadJSRuntimeFunction(expr);
3967
3968 // Push the target function under the receiver.
3969 __ push(Operand(esp, 0));
3970 __ mov(Operand(esp, kPointerSize), eax);
3971
3972 // Push the arguments ("left-to-right").
3973 for (int i = 0; i < arg_count; i++) {
3974 VisitForStackValue(args->at(i));
3975 }
3976
3977 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS);
3978 EmitCallJSRuntimeFunction(expr);
3979
3980 // Restore context register.
3981 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3982 context()->DropAndPlug(1, eax);
3983
3984 } else {
3985 const Runtime::Function* function = expr->function();
3986 switch (function->function_id) {
3987#define CALL_INTRINSIC_GENERATOR(Name) \
3988 case Runtime::kInline##Name: { \
3989 Comment cmnt(masm_, "[ Inline" #Name); \
3990 return Emit##Name(expr); \
3991 }
3992 FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
3993#undef CALL_INTRINSIC_GENERATOR
3994 default: {
3995 Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
3996 // Push the arguments ("left-to-right").
3997 for (int i = 0; i < arg_count; i++) {
3998 VisitForStackValue(args->at(i));
3999 }
4000
4001 // Call the C runtime function.
4002 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS);
4003 __ CallRuntime(expr->function(), arg_count);
4004 context()->Plug(eax);
4005 }
4006 }
4007 }
4008}
4009
4010
4011void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
4012 switch (expr->op()) {
4013 case Token::DELETE: {
4014 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
4015 Property* property = expr->expression()->AsProperty();
4016 VariableProxy* proxy = expr->expression()->AsVariableProxy();
4017
4018 if (property != NULL) {
4019 VisitForStackValue(property->obj());
4020 VisitForStackValue(property->key());
4021 __ CallRuntime(is_strict(language_mode())
4022 ? Runtime::kDeleteProperty_Strict
4023 : Runtime::kDeleteProperty_Sloppy);
4024 context()->Plug(eax);
4025 } else if (proxy != NULL) {
4026 Variable* var = proxy->var();
4027 // Delete of an unqualified identifier is disallowed in strict mode but
4028 // "delete this" is allowed.
4029 bool is_this = var->HasThisName(isolate());
4030 DCHECK(is_sloppy(language_mode()) || is_this);
4031 if (var->IsUnallocatedOrGlobalSlot()) {
4032 __ mov(eax, NativeContextOperand());
4033 __ push(ContextOperand(eax, Context::EXTENSION_INDEX));
4034 __ push(Immediate(var->name()));
4035 __ CallRuntime(Runtime::kDeleteProperty_Sloppy);
4036 context()->Plug(eax);
4037 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
4038 // Result of deleting non-global variables is false. 'this' is
4039 // not really a variable, though we implement it as one. The
4040 // subexpression does not have side effects.
4041 context()->Plug(is_this);
4042 } else {
4043 // Non-global variable. Call the runtime to try to delete from the
4044 // context where the variable was introduced.
4045 __ push(context_register());
4046 __ push(Immediate(var->name()));
4047 __ CallRuntime(Runtime::kDeleteLookupSlot);
4048 context()->Plug(eax);
4049 }
4050 } else {
4051 // Result of deleting non-property, non-variable reference is true.
4052 // The subexpression may have side effects.
4053 VisitForEffect(expr->expression());
4054 context()->Plug(true);
4055 }
4056 break;
4057 }
4058
4059 case Token::VOID: {
4060 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
4061 VisitForEffect(expr->expression());
4062 context()->Plug(isolate()->factory()->undefined_value());
4063 break;
4064 }
4065
4066 case Token::NOT: {
4067 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
4068 if (context()->IsEffect()) {
4069 // Unary NOT has no side effects so it's only necessary to visit the
4070 // subexpression. Match the optimizing compiler by not branching.
4071 VisitForEffect(expr->expression());
4072 } else if (context()->IsTest()) {
4073 const TestContext* test = TestContext::cast(context());
4074 // The labels are swapped for the recursive call.
4075 VisitForControl(expr->expression(),
4076 test->false_label(),
4077 test->true_label(),
4078 test->fall_through());
4079 context()->Plug(test->true_label(), test->false_label());
4080 } else {
4081 // We handle value contexts explicitly rather than simply visiting
4082 // for control and plugging the control flow into the context,
4083 // because we need to prepare a pair of extra administrative AST ids
4084 // for the optimizing compiler.
4085 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
4086 Label materialize_true, materialize_false, done;
4087 VisitForControl(expr->expression(),
4088 &materialize_false,
4089 &materialize_true,
4090 &materialize_true);
4091 __ bind(&materialize_true);
4092 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4093 if (context()->IsAccumulatorValue()) {
4094 __ mov(eax, isolate()->factory()->true_value());
4095 } else {
4096 __ Push(isolate()->factory()->true_value());
4097 }
4098 __ jmp(&done, Label::kNear);
4099 __ bind(&materialize_false);
4100 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4101 if (context()->IsAccumulatorValue()) {
4102 __ mov(eax, isolate()->factory()->false_value());
4103 } else {
4104 __ Push(isolate()->factory()->false_value());
4105 }
4106 __ bind(&done);
4107 }
4108 break;
4109 }
4110
4111 case Token::TYPEOF: {
4112 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
4113 {
4114 AccumulatorValueContext context(this);
4115 VisitForTypeofValue(expr->expression());
4116 }
4117 __ mov(ebx, eax);
4118 TypeofStub typeof_stub(isolate());
4119 __ CallStub(&typeof_stub);
4120 context()->Plug(eax);
4121 break;
4122 }
4123
4124 default:
4125 UNREACHABLE();
4126 }
4127}
4128
4129
4130void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
4131 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
4132
4133 Comment cmnt(masm_, "[ CountOperation");
4134
4135 Property* prop = expr->expression()->AsProperty();
4136 LhsKind assign_type = Property::GetAssignType(prop);
4137
4138 // Evaluate expression and get value.
4139 if (assign_type == VARIABLE) {
4140 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
4141 AccumulatorValueContext context(this);
4142 EmitVariableLoad(expr->expression()->AsVariableProxy());
4143 } else {
4144 // Reserve space for result of postfix operation.
4145 if (expr->is_postfix() && !context()->IsEffect()) {
4146 __ push(Immediate(Smi::FromInt(0)));
4147 }
4148 switch (assign_type) {
4149 case NAMED_PROPERTY: {
4150 // Put the object both on the stack and in the register.
4151 VisitForStackValue(prop->obj());
4152 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
4153 EmitNamedPropertyLoad(prop);
4154 break;
4155 }
4156
4157 case NAMED_SUPER_PROPERTY: {
4158 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
4159 VisitForAccumulatorValue(
4160 prop->obj()->AsSuperPropertyReference()->home_object());
4161 __ push(result_register());
4162 __ push(MemOperand(esp, kPointerSize));
4163 __ push(result_register());
4164 EmitNamedSuperPropertyLoad(prop);
4165 break;
4166 }
4167
4168 case KEYED_SUPER_PROPERTY: {
4169 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
4170 VisitForStackValue(
4171 prop->obj()->AsSuperPropertyReference()->home_object());
4172 VisitForAccumulatorValue(prop->key());
4173 __ push(result_register());
4174 __ push(MemOperand(esp, 2 * kPointerSize));
4175 __ push(MemOperand(esp, 2 * kPointerSize));
4176 __ push(result_register());
4177 EmitKeyedSuperPropertyLoad(prop);
4178 break;
4179 }
4180
4181 case KEYED_PROPERTY: {
4182 VisitForStackValue(prop->obj());
4183 VisitForStackValue(prop->key());
4184 __ mov(LoadDescriptor::ReceiverRegister(),
4185 Operand(esp, kPointerSize)); // Object.
4186 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key.
4187 EmitKeyedPropertyLoad(prop);
4188 break;
4189 }
4190
4191 case VARIABLE:
4192 UNREACHABLE();
4193 }
4194 }
4195
4196 // We need a second deoptimization point after loading the value
4197 // in case evaluating the property load my have a side effect.
4198 if (assign_type == VARIABLE) {
4199 PrepareForBailout(expr->expression(), TOS_REG);
4200 } else {
4201 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
4202 }
4203
4204 // Inline smi case if we are in a loop.
4205 Label done, stub_call;
4206 JumpPatchSite patch_site(masm_);
4207 if (ShouldInlineSmiCase(expr->op())) {
4208 Label slow;
4209 patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
4210
4211 // Save result for postfix expressions.
4212 if (expr->is_postfix()) {
4213 if (!context()->IsEffect()) {
4214 // Save the result on the stack. If we have a named or keyed property
4215 // we store the result under the receiver that is currently on top
4216 // of the stack.
4217 switch (assign_type) {
4218 case VARIABLE:
4219 __ push(eax);
4220 break;
4221 case NAMED_PROPERTY:
4222 __ mov(Operand(esp, kPointerSize), eax);
4223 break;
4224 case NAMED_SUPER_PROPERTY:
4225 __ mov(Operand(esp, 2 * kPointerSize), eax);
4226 break;
4227 case KEYED_PROPERTY:
4228 __ mov(Operand(esp, 2 * kPointerSize), eax);
4229 break;
4230 case KEYED_SUPER_PROPERTY:
4231 __ mov(Operand(esp, 3 * kPointerSize), eax);
4232 break;
4233 }
4234 }
4235 }
4236
4237 if (expr->op() == Token::INC) {
4238 __ add(eax, Immediate(Smi::FromInt(1)));
4239 } else {
4240 __ sub(eax, Immediate(Smi::FromInt(1)));
4241 }
4242 __ j(no_overflow, &done, Label::kNear);
4243 // Call stub. Undo operation first.
4244 if (expr->op() == Token::INC) {
4245 __ sub(eax, Immediate(Smi::FromInt(1)));
4246 } else {
4247 __ add(eax, Immediate(Smi::FromInt(1)));
4248 }
4249 __ jmp(&stub_call, Label::kNear);
4250 __ bind(&slow);
4251 }
4252 if (!is_strong(language_mode())) {
4253 ToNumberStub convert_stub(isolate());
4254 __ CallStub(&convert_stub);
4255 PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
4256 }
4257
4258 // Save result for postfix expressions.
4259 if (expr->is_postfix()) {
4260 if (!context()->IsEffect()) {
4261 // Save the result on the stack. If we have a named or keyed property
4262 // we store the result under the receiver that is currently on top
4263 // of the stack.
4264 switch (assign_type) {
4265 case VARIABLE:
4266 __ push(eax);
4267 break;
4268 case NAMED_PROPERTY:
4269 __ mov(Operand(esp, kPointerSize), eax);
4270 break;
4271 case NAMED_SUPER_PROPERTY:
4272 __ mov(Operand(esp, 2 * kPointerSize), eax);
4273 break;
4274 case KEYED_PROPERTY:
4275 __ mov(Operand(esp, 2 * kPointerSize), eax);
4276 break;
4277 case KEYED_SUPER_PROPERTY:
4278 __ mov(Operand(esp, 3 * kPointerSize), eax);
4279 break;
4280 }
4281 }
4282 }
4283
4284 SetExpressionPosition(expr);
4285
4286 // Call stub for +1/-1.
4287 __ bind(&stub_call);
4288 __ mov(edx, eax);
4289 __ mov(eax, Immediate(Smi::FromInt(1)));
4290 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), expr->binary_op(),
4291 strength(language_mode())).code();
4292 CallIC(code, expr->CountBinOpFeedbackId());
4293 patch_site.EmitPatchInfo();
4294 __ bind(&done);
4295
4296 if (is_strong(language_mode())) {
4297 PrepareForBailoutForId(expr->ToNumberId(), TOS_REG);
4298 }
4299 // Store the value returned in eax.
4300 switch (assign_type) {
4301 case VARIABLE:
4302 if (expr->is_postfix()) {
4303 // Perform the assignment as if via '='.
4304 { EffectContext context(this);
4305 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4306 Token::ASSIGN, expr->CountSlot());
4307 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4308 context.Plug(eax);
4309 }
4310 // For all contexts except EffectContext We have the result on
4311 // top of the stack.
4312 if (!context()->IsEffect()) {
4313 context()->PlugTOS();
4314 }
4315 } else {
4316 // Perform the assignment as if via '='.
4317 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4318 Token::ASSIGN, expr->CountSlot());
4319 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4320 context()->Plug(eax);
4321 }
4322 break;
4323 case NAMED_PROPERTY: {
4324 __ mov(StoreDescriptor::NameRegister(),
4325 prop->key()->AsLiteral()->value());
4326 __ pop(StoreDescriptor::ReceiverRegister());
4327 EmitLoadStoreICSlot(expr->CountSlot());
4328 CallStoreIC();
4329 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4330 if (expr->is_postfix()) {
4331 if (!context()->IsEffect()) {
4332 context()->PlugTOS();
4333 }
4334 } else {
4335 context()->Plug(eax);
4336 }
4337 break;
4338 }
4339 case NAMED_SUPER_PROPERTY: {
4340 EmitNamedSuperPropertyStore(prop);
4341 if (expr->is_postfix()) {
4342 if (!context()->IsEffect()) {
4343 context()->PlugTOS();
4344 }
4345 } else {
4346 context()->Plug(eax);
4347 }
4348 break;
4349 }
4350 case KEYED_SUPER_PROPERTY: {
4351 EmitKeyedSuperPropertyStore(prop);
4352 if (expr->is_postfix()) {
4353 if (!context()->IsEffect()) {
4354 context()->PlugTOS();
4355 }
4356 } else {
4357 context()->Plug(eax);
4358 }
4359 break;
4360 }
4361 case KEYED_PROPERTY: {
4362 __ pop(StoreDescriptor::NameRegister());
4363 __ pop(StoreDescriptor::ReceiverRegister());
4364 Handle<Code> ic =
4365 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
4366 EmitLoadStoreICSlot(expr->CountSlot());
4367 CallIC(ic);
4368 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4369 if (expr->is_postfix()) {
4370 // Result is on the stack
4371 if (!context()->IsEffect()) {
4372 context()->PlugTOS();
4373 }
4374 } else {
4375 context()->Plug(eax);
4376 }
4377 break;
4378 }
4379 }
4380}
4381
4382
4383void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
4384 Expression* sub_expr,
4385 Handle<String> check) {
4386 Label materialize_true, materialize_false;
4387 Label* if_true = NULL;
4388 Label* if_false = NULL;
4389 Label* fall_through = NULL;
4390 context()->PrepareTest(&materialize_true, &materialize_false,
4391 &if_true, &if_false, &fall_through);
4392
4393 { AccumulatorValueContext context(this);
4394 VisitForTypeofValue(sub_expr);
4395 }
4396 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4397
4398 Factory* factory = isolate()->factory();
4399 if (String::Equals(check, factory->number_string())) {
4400 __ JumpIfSmi(eax, if_true);
4401 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4402 isolate()->factory()->heap_number_map());
4403 Split(equal, if_true, if_false, fall_through);
4404 } else if (String::Equals(check, factory->string_string())) {
4405 __ JumpIfSmi(eax, if_false);
4406 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
4407 Split(below, if_true, if_false, fall_through);
4408 } else if (String::Equals(check, factory->symbol_string())) {
4409 __ JumpIfSmi(eax, if_false);
4410 __ CmpObjectType(eax, SYMBOL_TYPE, edx);
4411 Split(equal, if_true, if_false, fall_through);
4412 } else if (String::Equals(check, factory->boolean_string())) {
4413 __ cmp(eax, isolate()->factory()->true_value());
4414 __ j(equal, if_true);
4415 __ cmp(eax, isolate()->factory()->false_value());
4416 Split(equal, if_true, if_false, fall_through);
4417 } else if (String::Equals(check, factory->undefined_string())) {
4418 __ cmp(eax, isolate()->factory()->undefined_value());
4419 __ j(equal, if_true);
4420 __ JumpIfSmi(eax, if_false);
4421 // Check for undetectable objects => true.
4422 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4423 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4424 1 << Map::kIsUndetectable);
4425 Split(not_zero, if_true, if_false, fall_through);
4426 } else if (String::Equals(check, factory->function_string())) {
4427 __ JumpIfSmi(eax, if_false);
4428 // Check for callable and not undetectable objects => true.
4429 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4430 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4431 __ and_(ecx, (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable));
4432 __ cmp(ecx, 1 << Map::kIsCallable);
4433 Split(equal, if_true, if_false, fall_through);
4434 } else if (String::Equals(check, factory->object_string())) {
4435 __ JumpIfSmi(eax, if_false);
4436 __ cmp(eax, isolate()->factory()->null_value());
4437 __ j(equal, if_true);
4438 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
4439 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, edx);
4440 __ j(below, if_false);
4441 // Check for callable or undetectable objects => false.
4442 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4443 (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable));
4444 Split(zero, if_true, if_false, fall_through);
4445// clang-format off
4446#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
4447 } else if (String::Equals(check, factory->type##_string())) { \
4448 __ JumpIfSmi(eax, if_false); \
4449 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), \
4450 isolate()->factory()->type##_map()); \
4451 Split(equal, if_true, if_false, fall_through);
4452 SIMD128_TYPES(SIMD128_TYPE)
4453#undef SIMD128_TYPE
4454 // clang-format on
4455 } else {
4456 if (if_false != fall_through) __ jmp(if_false);
4457 }
4458 context()->Plug(if_true, if_false);
4459}
4460
4461
4462void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4463 Comment cmnt(masm_, "[ CompareOperation");
4464 SetExpressionPosition(expr);
4465
4466 // First we try a fast inlined version of the compare when one of
4467 // the operands is a literal.
4468 if (TryLiteralCompare(expr)) return;
4469
4470 // Always perform the comparison for its control flow. Pack the result
4471 // into the expression's context after the comparison is performed.
4472 Label materialize_true, materialize_false;
4473 Label* if_true = NULL;
4474 Label* if_false = NULL;
4475 Label* fall_through = NULL;
4476 context()->PrepareTest(&materialize_true, &materialize_false,
4477 &if_true, &if_false, &fall_through);
4478
4479 Token::Value op = expr->op();
4480 VisitForStackValue(expr->left());
4481 switch (op) {
4482 case Token::IN:
4483 VisitForStackValue(expr->right());
4484 __ CallRuntime(Runtime::kHasProperty);
4485 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
4486 __ cmp(eax, isolate()->factory()->true_value());
4487 Split(equal, if_true, if_false, fall_through);
4488 break;
4489
4490 case Token::INSTANCEOF: {
4491 VisitForAccumulatorValue(expr->right());
4492 __ Pop(edx);
4493 InstanceOfStub stub(isolate());
4494 __ CallStub(&stub);
4495 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
4496 __ cmp(eax, isolate()->factory()->true_value());
4497 Split(equal, if_true, if_false, fall_through);
4498 break;
4499 }
4500
4501 default: {
4502 VisitForAccumulatorValue(expr->right());
4503 Condition cc = CompareIC::ComputeCondition(op);
4504 __ pop(edx);
4505
4506 bool inline_smi_code = ShouldInlineSmiCase(op);
4507 JumpPatchSite patch_site(masm_);
4508 if (inline_smi_code) {
4509 Label slow_case;
4510 __ mov(ecx, edx);
4511 __ or_(ecx, eax);
4512 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
4513 __ cmp(edx, eax);
4514 Split(cc, if_true, if_false, NULL);
4515 __ bind(&slow_case);
4516 }
4517
4518 Handle<Code> ic = CodeFactory::CompareIC(
4519 isolate(), op, strength(language_mode())).code();
4520 CallIC(ic, expr->CompareOperationFeedbackId());
4521 patch_site.EmitPatchInfo();
4522
4523 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4524 __ test(eax, eax);
4525 Split(cc, if_true, if_false, fall_through);
4526 }
4527 }
4528
4529 // Convert the result of the comparison into one expected for this
4530 // expression's context.
4531 context()->Plug(if_true, if_false);
4532}
4533
4534
4535void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4536 Expression* sub_expr,
4537 NilValue nil) {
4538 Label materialize_true, materialize_false;
4539 Label* if_true = NULL;
4540 Label* if_false = NULL;
4541 Label* fall_through = NULL;
4542 context()->PrepareTest(&materialize_true, &materialize_false,
4543 &if_true, &if_false, &fall_through);
4544
4545 VisitForAccumulatorValue(sub_expr);
4546 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4547
4548 Handle<Object> nil_value = nil == kNullValue
4549 ? isolate()->factory()->null_value()
4550 : isolate()->factory()->undefined_value();
4551 if (expr->op() == Token::EQ_STRICT) {
4552 __ cmp(eax, nil_value);
4553 Split(equal, if_true, if_false, fall_through);
4554 } else {
4555 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
4556 CallIC(ic, expr->CompareOperationFeedbackId());
4557 __ cmp(eax, isolate()->factory()->true_value());
4558 Split(equal, if_true, if_false, fall_through);
4559 }
4560 context()->Plug(if_true, if_false);
4561}
4562
4563
4564void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4565 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4566 context()->Plug(eax);
4567}
4568
4569
4570Register FullCodeGenerator::result_register() {
4571 return eax;
4572}
4573
4574
4575Register FullCodeGenerator::context_register() {
4576 return esi;
4577}
4578
4579
4580void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4581 DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4582 __ mov(Operand(ebp, frame_offset), value);
4583}
4584
4585
4586void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
4587 __ mov(dst, ContextOperand(esi, context_index));
4588}
4589
4590
4591void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
4592 Scope* closure_scope = scope()->ClosureScope();
4593 if (closure_scope->is_script_scope() ||
4594 closure_scope->is_module_scope()) {
4595 // Contexts nested in the native context have a canonical empty function
4596 // as their closure, not the anonymous closure containing the global
4597 // code.
4598 __ mov(eax, NativeContextOperand());
4599 __ push(ContextOperand(eax, Context::CLOSURE_INDEX));
4600 } else if (closure_scope->is_eval_scope()) {
4601 // Contexts nested inside eval code have the same closure as the context
4602 // calling eval, not the anonymous closure containing the eval code.
4603 // Fetch it from the context.
4604 __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
4605 } else {
4606 DCHECK(closure_scope->is_function_scope());
4607 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4608 }
4609}
4610
4611
4612// ----------------------------------------------------------------------------
4613// Non-local control flow support.
4614
4615void FullCodeGenerator::EnterFinallyBlock() {
4616 // Cook return address on top of stack (smi encoded Code* delta)
4617 DCHECK(!result_register().is(edx));
4618 __ pop(edx);
4619 __ sub(edx, Immediate(masm_->CodeObject()));
4620 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
4621 STATIC_ASSERT(kSmiTag == 0);
4622 __ SmiTag(edx);
4623 __ push(edx);
4624
4625 // Store result register while executing finally block.
4626 __ push(result_register());
4627
4628 // Store pending message while executing finally block.
4629 ExternalReference pending_message_obj =
4630 ExternalReference::address_of_pending_message_obj(isolate());
4631 __ mov(edx, Operand::StaticVariable(pending_message_obj));
4632 __ push(edx);
4633
4634 ClearPendingMessage();
4635}
4636
4637
4638void FullCodeGenerator::ExitFinallyBlock() {
4639 DCHECK(!result_register().is(edx));
4640 // Restore pending message from stack.
4641 __ pop(edx);
4642 ExternalReference pending_message_obj =
4643 ExternalReference::address_of_pending_message_obj(isolate());
4644 __ mov(Operand::StaticVariable(pending_message_obj), edx);
4645
4646 // Restore result register from stack.
4647 __ pop(result_register());
4648
4649 // Uncook return address.
4650 __ pop(edx);
4651 __ SmiUntag(edx);
4652 __ add(edx, Immediate(masm_->CodeObject()));
4653 __ jmp(edx);
4654}
4655
4656
4657void FullCodeGenerator::ClearPendingMessage() {
4658 DCHECK(!result_register().is(edx));
4659 ExternalReference pending_message_obj =
4660 ExternalReference::address_of_pending_message_obj(isolate());
4661 __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
4662 __ mov(Operand::StaticVariable(pending_message_obj), edx);
4663}
4664
4665
4666void FullCodeGenerator::EmitLoadStoreICSlot(FeedbackVectorSlot slot) {
4667 DCHECK(!slot.IsInvalid());
4668 __ mov(VectorStoreICTrampolineDescriptor::SlotRegister(),
4669 Immediate(SmiFromSlot(slot)));
4670}
4671
4672
4673#undef __
4674
4675
4676static const byte kJnsInstruction = 0x79;
4677static const byte kJnsOffset = 0x11;
4678static const byte kNopByteOne = 0x66;
4679static const byte kNopByteTwo = 0x90;
4680#ifdef DEBUG
4681static const byte kCallInstruction = 0xe8;
4682#endif
4683
4684
4685void BackEdgeTable::PatchAt(Code* unoptimized_code,
4686 Address pc,
4687 BackEdgeState target_state,
4688 Code* replacement_code) {
4689 Address call_target_address = pc - kIntSize;
4690 Address jns_instr_address = call_target_address - 3;
4691 Address jns_offset_address = call_target_address - 2;
4692
4693 switch (target_state) {
4694 case INTERRUPT:
4695 // sub <profiling_counter>, <delta> ;; Not changed
4696 // jns ok
4697 // call <interrupt stub>
4698 // ok:
4699 *jns_instr_address = kJnsInstruction;
4700 *jns_offset_address = kJnsOffset;
4701 break;
4702 case ON_STACK_REPLACEMENT:
4703 case OSR_AFTER_STACK_CHECK:
4704 // sub <profiling_counter>, <delta> ;; Not changed
4705 // nop
4706 // nop
4707 // call <on-stack replacment>
4708 // ok:
4709 *jns_instr_address = kNopByteOne;
4710 *jns_offset_address = kNopByteTwo;
4711 break;
4712 }
4713
4714 Assembler::set_target_address_at(unoptimized_code->GetIsolate(),
4715 call_target_address, unoptimized_code,
4716 replacement_code->entry());
4717 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
4718 unoptimized_code, call_target_address, replacement_code);
4719}
4720
4721
4722BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
4723 Isolate* isolate,
4724 Code* unoptimized_code,
4725 Address pc) {
4726 Address call_target_address = pc - kIntSize;
4727 Address jns_instr_address = call_target_address - 3;
4728 DCHECK_EQ(kCallInstruction, *(call_target_address - 1));
4729
4730 if (*jns_instr_address == kJnsInstruction) {
4731 DCHECK_EQ(kJnsOffset, *(call_target_address - 2));
4732 DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(),
4733 Assembler::target_address_at(call_target_address,
4734 unoptimized_code));
4735 return INTERRUPT;
4736 }
4737
4738 DCHECK_EQ(kNopByteOne, *jns_instr_address);
4739 DCHECK_EQ(kNopByteTwo, *(call_target_address - 2));
4740
4741 if (Assembler::target_address_at(call_target_address, unoptimized_code) ==
4742 isolate->builtins()->OnStackReplacement()->entry()) {
4743 return ON_STACK_REPLACEMENT;
4744 }
4745
4746 DCHECK_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(),
4747 Assembler::target_address_at(call_target_address,
4748 unoptimized_code));
4749 return OSR_AFTER_STACK_CHECK;
4750}
4751
4752
4753} // namespace internal
4754} // namespace v8
4755
4756#endif // V8_TARGET_ARCH_IA32