blob: eabb2f1e1698b782536a237bd77b7eea37a5afab [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_X64
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/ic/ic.h"
14#include "src/parsing/parser.h"
15
16namespace v8 {
17namespace internal {
18
Ben Murdoch097c5b22016-05-18 11:27:45 +010019#define __ ACCESS_MASM(masm())
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020
21class JumpPatchSite BASE_EMBEDDED {
22 public:
23 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
24#ifdef DEBUG
25 info_emitted_ = false;
26#endif
27 }
28
29 ~JumpPatchSite() {
30 DCHECK(patch_site_.is_bound() == info_emitted_);
31 }
32
33 void EmitJumpIfNotSmi(Register reg,
34 Label* target,
35 Label::Distance near_jump = Label::kFar) {
36 __ testb(reg, Immediate(kSmiTagMask));
37 EmitJump(not_carry, target, near_jump); // Always taken before patched.
38 }
39
40 void EmitJumpIfSmi(Register reg,
41 Label* target,
42 Label::Distance near_jump = Label::kFar) {
43 __ testb(reg, Immediate(kSmiTagMask));
44 EmitJump(carry, target, near_jump); // Never taken before patched.
45 }
46
47 void EmitPatchInfo() {
48 if (patch_site_.is_bound()) {
49 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
50 DCHECK(is_uint8(delta_to_patch_site));
51 __ testl(rax, Immediate(delta_to_patch_site));
52#ifdef DEBUG
53 info_emitted_ = true;
54#endif
55 } else {
56 __ nop(); // Signals no inlined code.
57 }
58 }
59
60 private:
61 // jc will be patched with jz, jnc will become jnz.
62 void EmitJump(Condition cc, Label* target, Label::Distance near_jump) {
63 DCHECK(!patch_site_.is_bound() && !info_emitted_);
64 DCHECK(cc == carry || cc == not_carry);
65 __ bind(&patch_site_);
66 __ j(cc, target, near_jump);
67 }
68
Ben Murdoch097c5b22016-05-18 11:27:45 +010069 MacroAssembler* masm() { return masm_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070 MacroAssembler* masm_;
71 Label patch_site_;
72#ifdef DEBUG
73 bool info_emitted_;
74#endif
75};
76
77
78// Generate code for a JS function. On entry to the function the receiver
79// and arguments have been pushed on the stack left to right, with the
80// return address on top of them. The actual argument count matches the
81// formal parameter count expected by the function.
82//
83// The live registers are:
84// o rdi: the JS function object being called (i.e. ourselves)
85// o rdx: the new target value
86// o rsi: our context
87// o rbp: our caller's frame pointer
88// o rsp: stack pointer (pointing to return address)
89//
90// The function builds a JS frame. Please see JavaScriptFrameConstants in
91// frames-x64.h for its layout.
92void FullCodeGenerator::Generate() {
93 CompilationInfo* info = info_;
94 profiling_counter_ = isolate()->factory()->NewCell(
95 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
96 SetFunctionPosition(literal());
97 Comment cmnt(masm_, "[ function compiled by full code generator");
98
99 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000101 if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) {
102 StackArgumentsAccessor args(rsp, info->scope()->num_parameters());
103 __ movp(rcx, args.GetReceiverOperand());
104 __ AssertNotSmi(rcx);
105 __ CmpObjectType(rcx, FIRST_JS_RECEIVER_TYPE, rcx);
106 __ Assert(above_equal, kSloppyFunctionExpectsJSReceiverReceiver);
107 }
108
109 // Open a frame scope to indicate that there is a frame on the stack. The
110 // MANUAL indicates that the scope shouldn't actually generate code to set up
111 // the frame (that is done below).
112 FrameScope frame_scope(masm_, StackFrame::MANUAL);
113
114 info->set_prologue_offset(masm_->pc_offset());
115 __ Prologue(info->GeneratePreagedPrologue());
116
117 { Comment cmnt(masm_, "[ Allocate locals");
118 int locals_count = info->scope()->num_stack_slots();
119 // Generators allocate locals, if any, in context slots.
120 DCHECK(!IsGeneratorFunction(info->literal()->kind()) || locals_count == 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100121 OperandStackDepthIncrement(locals_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 if (locals_count == 1) {
123 __ PushRoot(Heap::kUndefinedValueRootIndex);
124 } else if (locals_count > 1) {
125 if (locals_count >= 128) {
126 Label ok;
127 __ movp(rcx, rsp);
128 __ subp(rcx, Immediate(locals_count * kPointerSize));
129 __ CompareRoot(rcx, Heap::kRealStackLimitRootIndex);
130 __ j(above_equal, &ok, Label::kNear);
131 __ CallRuntime(Runtime::kThrowStackOverflow);
132 __ bind(&ok);
133 }
134 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
135 const int kMaxPushes = 32;
136 if (locals_count >= kMaxPushes) {
137 int loop_iterations = locals_count / kMaxPushes;
138 __ movp(rcx, Immediate(loop_iterations));
139 Label loop_header;
140 __ bind(&loop_header);
141 // Do pushes.
142 for (int i = 0; i < kMaxPushes; i++) {
143 __ Push(rax);
144 }
145 // Continue loop if not done.
146 __ decp(rcx);
147 __ j(not_zero, &loop_header, Label::kNear);
148 }
149 int remaining = locals_count % kMaxPushes;
150 // Emit the remaining pushes.
151 for (int i = 0; i < remaining; i++) {
152 __ Push(rax);
153 }
154 }
155 }
156
157 bool function_in_register = true;
158
159 // Possibly allocate a local context.
160 if (info->scope()->num_heap_slots() > 0) {
161 Comment cmnt(masm_, "[ Allocate context");
162 bool need_write_barrier = true;
163 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
164 // Argument to NewContext is the function, which is still in rdi.
165 if (info->scope()->is_script_scope()) {
166 __ Push(rdi);
167 __ Push(info->scope()->GetScopeInfo(info->isolate()));
168 __ CallRuntime(Runtime::kNewScriptContext);
Ben Murdochc5610432016-08-08 18:44:38 +0100169 PrepareForBailoutForId(BailoutId::ScriptContext(),
170 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 // The new target value is not used, clobbering is safe.
172 DCHECK_NULL(info->scope()->new_target_var());
173 } else {
174 if (info->scope()->new_target_var() != nullptr) {
175 __ Push(rdx); // Preserve new target.
176 }
177 if (slots <= FastNewContextStub::kMaximumSlots) {
178 FastNewContextStub stub(isolate(), slots);
179 __ CallStub(&stub);
180 // Result of FastNewContextStub is always in new space.
181 need_write_barrier = false;
182 } else {
183 __ Push(rdi);
184 __ CallRuntime(Runtime::kNewFunctionContext);
185 }
186 if (info->scope()->new_target_var() != nullptr) {
187 __ Pop(rdx); // Restore new target.
188 }
189 }
190 function_in_register = false;
191 // Context is returned in rax. It replaces the context passed to us.
192 // It's saved in the stack and kept live in rsi.
193 __ movp(rsi, rax);
194 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rax);
195
196 // Copy any necessary parameters into the context.
197 int num_parameters = info->scope()->num_parameters();
198 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
199 for (int i = first_parameter; i < num_parameters; i++) {
200 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
201 if (var->IsContextSlot()) {
202 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
203 (num_parameters - 1 - i) * kPointerSize;
204 // Load parameter from stack.
205 __ movp(rax, Operand(rbp, parameter_offset));
206 // Store it in the context.
207 int context_offset = Context::SlotOffset(var->index());
208 __ movp(Operand(rsi, context_offset), rax);
209 // Update the write barrier. This clobbers rax and rbx.
210 if (need_write_barrier) {
211 __ RecordWriteContextSlot(
212 rsi, context_offset, rax, rbx, kDontSaveFPRegs);
213 } else if (FLAG_debug_code) {
214 Label done;
215 __ JumpIfInNewSpace(rsi, rax, &done, Label::kNear);
216 __ Abort(kExpectedNewSpaceObject);
217 __ bind(&done);
218 }
219 }
220 }
221 }
222
223 // Register holding this function and new target are both trashed in case we
224 // bailout here. But since that can happen only when new target is not used
225 // and we allocate a context, the value of |function_in_register| is correct.
Ben Murdochc5610432016-08-08 18:44:38 +0100226 PrepareForBailoutForId(BailoutId::FunctionContext(),
227 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228
229 // Possibly set up a local binding to the this function which is used in
230 // derived constructors with super calls.
231 Variable* this_function_var = scope()->this_function_var();
232 if (this_function_var != nullptr) {
233 Comment cmnt(masm_, "[ This function");
234 if (!function_in_register) {
235 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
236 // The write barrier clobbers register again, keep it marked as such.
237 }
238 SetVar(this_function_var, rdi, rbx, rcx);
239 }
240
241 // Possibly set up a local binding to the new target value.
242 Variable* new_target_var = scope()->new_target_var();
243 if (new_target_var != nullptr) {
244 Comment cmnt(masm_, "[ new.target");
245 SetVar(new_target_var, rdx, rbx, rcx);
246 }
247
248 // Possibly allocate RestParameters
249 int rest_index;
250 Variable* rest_param = scope()->rest_parameter(&rest_index);
251 if (rest_param) {
252 Comment cmnt(masm_, "[ Allocate rest parameter array");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100253 if (!function_in_register) {
254 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
255 }
256 FastNewRestParameterStub stub(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000257 __ CallStub(&stub);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100258 function_in_register = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 SetVar(rest_param, rax, rbx, rdx);
260 }
261
262 // Possibly allocate an arguments object.
263 Variable* arguments = scope()->arguments();
264 if (arguments != NULL) {
265 // Arguments object must be allocated after the context object, in
266 // case the "arguments" or ".arguments" variables are in the context.
267 Comment cmnt(masm_, "[ Allocate arguments object");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268 if (!function_in_register) {
269 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
270 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100271 if (is_strict(language_mode()) || !has_simple_parameters()) {
272 FastNewStrictArgumentsStub stub(isolate());
273 __ CallStub(&stub);
274 } else if (literal()->has_duplicate_parameters()) {
275 __ Push(rdi);
276 __ CallRuntime(Runtime::kNewSloppyArguments_Generic);
277 } else {
278 FastNewSloppyArgumentsStub stub(isolate());
279 __ CallStub(&stub);
280 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000281
282 SetVar(arguments, rax, rbx, rdx);
283 }
284
285 if (FLAG_trace) {
286 __ CallRuntime(Runtime::kTraceEnter);
287 }
288
289 // Visit the declarations and body unless there is an illegal
290 // redeclaration.
Ben Murdochc5610432016-08-08 18:44:38 +0100291 PrepareForBailoutForId(BailoutId::FunctionEntry(),
292 BailoutState::NO_REGISTERS);
Ben Murdochda12d292016-06-02 14:46:10 +0100293 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294 Comment cmnt(masm_, "[ Declarations");
Ben Murdochda12d292016-06-02 14:46:10 +0100295 VisitDeclarations(scope()->declarations());
296 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297
Ben Murdochda12d292016-06-02 14:46:10 +0100298 // Assert that the declarations do not use ICs. Otherwise the debugger
299 // won't be able to redirect a PC at an IC to the correct IC in newly
300 // recompiled code.
301 DCHECK_EQ(0, ic_total_count_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302
Ben Murdochda12d292016-06-02 14:46:10 +0100303 {
304 Comment cmnt(masm_, "[ Stack check");
Ben Murdochc5610432016-08-08 18:44:38 +0100305 PrepareForBailoutForId(BailoutId::Declarations(),
306 BailoutState::NO_REGISTERS);
Ben Murdochda12d292016-06-02 14:46:10 +0100307 Label ok;
308 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
309 __ j(above_equal, &ok, Label::kNear);
310 __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
311 __ bind(&ok);
312 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313
Ben Murdochda12d292016-06-02 14:46:10 +0100314 {
315 Comment cmnt(masm_, "[ Body");
316 DCHECK(loop_depth() == 0);
317 VisitStatements(literal()->body());
318 DCHECK(loop_depth() == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 }
320
321 // Always emit a 'return undefined' in case control fell off the end of
322 // the body.
323 { Comment cmnt(masm_, "[ return <undefined>;");
324 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
325 EmitReturnSequence();
326 }
327}
328
329
330void FullCodeGenerator::ClearAccumulator() {
331 __ Set(rax, 0);
332}
333
334
335void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
336 __ Move(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
337 __ SmiAddConstant(FieldOperand(rbx, Cell::kValueOffset),
338 Smi::FromInt(-delta));
339}
340
341
342void FullCodeGenerator::EmitProfilingCounterReset() {
343 int reset_value = FLAG_interrupt_budget;
344 __ Move(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
345 __ Move(kScratchRegister, Smi::FromInt(reset_value));
346 __ movp(FieldOperand(rbx, Cell::kValueOffset), kScratchRegister);
347}
348
349
350static const byte kJnsOffset = kPointerSize == kInt64Size ? 0x1d : 0x14;
351
352
353void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
354 Label* back_edge_target) {
355 Comment cmnt(masm_, "[ Back edge bookkeeping");
356 Label ok;
357
358 DCHECK(back_edge_target->is_bound());
359 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
360 int weight = Min(kMaxBackEdgeWeight,
361 Max(1, distance / kCodeSizeMultiplier));
362 EmitProfilingCounterDecrement(weight);
363
364 __ j(positive, &ok, Label::kNear);
365 {
366 PredictableCodeSizeScope predictible_code_size_scope(masm_, kJnsOffset);
367 DontEmitDebugCodeScope dont_emit_debug_code_scope(masm_);
368 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
369
370 // Record a mapping of this PC offset to the OSR id. This is used to find
371 // the AST id from the unoptimized code in order to use it as a key into
372 // the deoptimization input data found in the optimized code.
373 RecordBackEdge(stmt->OsrEntryId());
374
375 EmitProfilingCounterReset();
376 }
377 __ bind(&ok);
378
Ben Murdochc5610432016-08-08 18:44:38 +0100379 PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000380 // Record a mapping of the OSR id to this PC. This is used if the OSR
381 // entry becomes the target of a bailout. We don't expect it to be, but
382 // we want it to work if it is.
Ben Murdochc5610432016-08-08 18:44:38 +0100383 PrepareForBailoutForId(stmt->OsrEntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384}
385
Ben Murdoch097c5b22016-05-18 11:27:45 +0100386void FullCodeGenerator::EmitProfilingCounterHandlingForReturnSequence(
387 bool is_tail_call) {
388 // Pretend that the exit is a backwards jump to the entry.
389 int weight = 1;
390 if (info_->ShouldSelfOptimize()) {
391 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
392 } else {
393 int distance = masm_->pc_offset();
394 weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier));
395 }
396 EmitProfilingCounterDecrement(weight);
397 Label ok;
398 __ j(positive, &ok, Label::kNear);
399 // Don't need to save result register if we are going to do a tail call.
400 if (!is_tail_call) {
401 __ Push(rax);
402 }
403 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
404 if (!is_tail_call) {
405 __ Pop(rax);
406 }
407 EmitProfilingCounterReset();
408 __ bind(&ok);
409}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410
411void FullCodeGenerator::EmitReturnSequence() {
412 Comment cmnt(masm_, "[ Return sequence");
413 if (return_label_.is_bound()) {
414 __ jmp(&return_label_);
415 } else {
416 __ bind(&return_label_);
417 if (FLAG_trace) {
418 __ Push(rax);
419 __ CallRuntime(Runtime::kTraceExit);
420 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100421 EmitProfilingCounterHandlingForReturnSequence(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000422
423 SetReturnPosition(literal());
424 __ leave();
425
426 int arg_count = info_->scope()->num_parameters() + 1;
427 int arguments_bytes = arg_count * kPointerSize;
428 __ Ret(arguments_bytes, rcx);
429 }
430}
431
Ben Murdochc5610432016-08-08 18:44:38 +0100432void FullCodeGenerator::RestoreContext() {
433 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
434}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000435
436void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
437 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
438 MemOperand operand = codegen()->VarOperand(var, result_register());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100439 codegen()->PushOperand(operand);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440}
441
442
443void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
444}
445
446
447void FullCodeGenerator::AccumulatorValueContext::Plug(
448 Heap::RootListIndex index) const {
449 __ LoadRoot(result_register(), index);
450}
451
452
453void FullCodeGenerator::StackValueContext::Plug(
454 Heap::RootListIndex index) const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100455 codegen()->OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456 __ PushRoot(index);
457}
458
459
460void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
461 codegen()->PrepareForBailoutBeforeSplit(condition(),
462 true,
463 true_label_,
464 false_label_);
465 if (index == Heap::kUndefinedValueRootIndex ||
466 index == Heap::kNullValueRootIndex ||
467 index == Heap::kFalseValueRootIndex) {
468 if (false_label_ != fall_through_) __ jmp(false_label_);
469 } else if (index == Heap::kTrueValueRootIndex) {
470 if (true_label_ != fall_through_) __ jmp(true_label_);
471 } else {
472 __ LoadRoot(result_register(), index);
473 codegen()->DoTest(this);
474 }
475}
476
477
478void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
479}
480
481
482void FullCodeGenerator::AccumulatorValueContext::Plug(
483 Handle<Object> lit) const {
484 if (lit->IsSmi()) {
485 __ SafeMove(result_register(), Smi::cast(*lit));
486 } else {
487 __ Move(result_register(), lit);
488 }
489}
490
491
492void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100493 codegen()->OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 if (lit->IsSmi()) {
495 __ SafePush(Smi::cast(*lit));
496 } else {
497 __ Push(lit);
498 }
499}
500
501
502void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
503 codegen()->PrepareForBailoutBeforeSplit(condition(),
504 true,
505 true_label_,
506 false_label_);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100507 DCHECK(lit->IsNull(isolate()) || lit->IsUndefined(isolate()) ||
508 !lit->IsUndetectable());
509 if (lit->IsUndefined(isolate()) || lit->IsNull(isolate()) ||
510 lit->IsFalse(isolate())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000511 if (false_label_ != fall_through_) __ jmp(false_label_);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100512 } else if (lit->IsTrue(isolate()) || lit->IsJSObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000513 if (true_label_ != fall_through_) __ jmp(true_label_);
514 } else if (lit->IsString()) {
515 if (String::cast(*lit)->length() == 0) {
516 if (false_label_ != fall_through_) __ jmp(false_label_);
517 } else {
518 if (true_label_ != fall_through_) __ jmp(true_label_);
519 }
520 } else if (lit->IsSmi()) {
521 if (Smi::cast(*lit)->value() == 0) {
522 if (false_label_ != fall_through_) __ jmp(false_label_);
523 } else {
524 if (true_label_ != fall_through_) __ jmp(true_label_);
525 }
526 } else {
527 // For simplicity we always test the accumulator register.
528 __ Move(result_register(), lit);
529 codegen()->DoTest(this);
530 }
531}
532
533
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
535 Register reg) const {
536 DCHECK(count > 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100537 if (count > 1) codegen()->DropOperands(count - 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 __ movp(Operand(rsp, 0), reg);
539}
540
541
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
543 Label* materialize_false) const {
544 DCHECK(materialize_true == materialize_false);
545 __ bind(materialize_true);
546}
547
548
549void FullCodeGenerator::AccumulatorValueContext::Plug(
550 Label* materialize_true,
551 Label* materialize_false) const {
552 Label done;
553 __ bind(materialize_true);
554 __ Move(result_register(), isolate()->factory()->true_value());
555 __ jmp(&done, Label::kNear);
556 __ bind(materialize_false);
557 __ Move(result_register(), isolate()->factory()->false_value());
558 __ bind(&done);
559}
560
561
562void FullCodeGenerator::StackValueContext::Plug(
563 Label* materialize_true,
564 Label* materialize_false) const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 codegen()->OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 Label done;
567 __ bind(materialize_true);
568 __ Push(isolate()->factory()->true_value());
569 __ jmp(&done, Label::kNear);
570 __ bind(materialize_false);
571 __ Push(isolate()->factory()->false_value());
572 __ bind(&done);
573}
574
575
576void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
577 Label* materialize_false) const {
578 DCHECK(materialize_true == true_label_);
579 DCHECK(materialize_false == false_label_);
580}
581
582
583void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
584 Heap::RootListIndex value_root_index =
585 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
586 __ LoadRoot(result_register(), value_root_index);
587}
588
589
590void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100591 codegen()->OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592 Heap::RootListIndex value_root_index =
593 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
594 __ PushRoot(value_root_index);
595}
596
597
598void FullCodeGenerator::TestContext::Plug(bool flag) const {
599 codegen()->PrepareForBailoutBeforeSplit(condition(),
600 true,
601 true_label_,
602 false_label_);
603 if (flag) {
604 if (true_label_ != fall_through_) __ jmp(true_label_);
605 } else {
606 if (false_label_ != fall_through_) __ jmp(false_label_);
607 }
608}
609
610
611void FullCodeGenerator::DoTest(Expression* condition,
612 Label* if_true,
613 Label* if_false,
614 Label* fall_through) {
Ben Murdochda12d292016-06-02 14:46:10 +0100615 Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000616 CallIC(ic, condition->test_id());
617 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
618 Split(equal, if_true, if_false, fall_through);
619}
620
621
622void FullCodeGenerator::Split(Condition cc,
623 Label* if_true,
624 Label* if_false,
625 Label* fall_through) {
626 if (if_false == fall_through) {
627 __ j(cc, if_true);
628 } else if (if_true == fall_through) {
629 __ j(NegateCondition(cc), if_false);
630 } else {
631 __ j(cc, if_true);
632 __ jmp(if_false);
633 }
634}
635
636
637MemOperand FullCodeGenerator::StackOperand(Variable* var) {
638 DCHECK(var->IsStackAllocated());
639 // Offset is negative because higher indexes are at lower addresses.
640 int offset = -var->index() * kPointerSize;
641 // Adjust by a (parameter or local) base offset.
642 if (var->IsParameter()) {
643 offset += kFPOnStackSize + kPCOnStackSize +
644 (info_->scope()->num_parameters() - 1) * kPointerSize;
645 } else {
646 offset += JavaScriptFrameConstants::kLocal0Offset;
647 }
648 return Operand(rbp, offset);
649}
650
651
652MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
653 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
654 if (var->IsContextSlot()) {
655 int context_chain_length = scope()->ContextChainLength(var->scope());
656 __ LoadContext(scratch, context_chain_length);
657 return ContextOperand(scratch, var->index());
658 } else {
659 return StackOperand(var);
660 }
661}
662
663
664void FullCodeGenerator::GetVar(Register dest, Variable* var) {
665 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
666 MemOperand location = VarOperand(var, dest);
667 __ movp(dest, location);
668}
669
670
671void FullCodeGenerator::SetVar(Variable* var,
672 Register src,
673 Register scratch0,
674 Register scratch1) {
675 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
676 DCHECK(!scratch0.is(src));
677 DCHECK(!scratch0.is(scratch1));
678 DCHECK(!scratch1.is(src));
679 MemOperand location = VarOperand(var, scratch0);
680 __ movp(location, src);
681
682 // Emit the write barrier code if the location is in the heap.
683 if (var->IsContextSlot()) {
684 int offset = Context::SlotOffset(var->index());
685 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
686 }
687}
688
689
690void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
691 bool should_normalize,
692 Label* if_true,
693 Label* if_false) {
694 // Only prepare for bailouts before splits if we're in a test
695 // context. Otherwise, we let the Visit function deal with the
696 // preparation to avoid preparing with the same AST id twice.
697 if (!context()->IsTest()) return;
698
699 Label skip;
700 if (should_normalize) __ jmp(&skip, Label::kNear);
Ben Murdochc5610432016-08-08 18:44:38 +0100701 PrepareForBailout(expr, BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000702 if (should_normalize) {
703 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
704 Split(equal, if_true, if_false, NULL);
705 __ bind(&skip);
706 }
707}
708
709
710void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
711 // The variable in the declaration always resides in the current context.
712 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100713 if (FLAG_debug_code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000714 // Check that we're not inside a with or catch context.
715 __ movp(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
716 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
717 __ Check(not_equal, kDeclarationInWithContext);
718 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
719 __ Check(not_equal, kDeclarationInCatchContext);
720 }
721}
722
723
724void FullCodeGenerator::VisitVariableDeclaration(
725 VariableDeclaration* declaration) {
726 // If it was not possible to allocate the variable at compile time, we
727 // need to "declare" it at runtime to make sure it actually exists in the
728 // local context.
729 VariableProxy* proxy = declaration->proxy();
730 VariableMode mode = declaration->mode();
731 Variable* variable = proxy->var();
Ben Murdochc5610432016-08-08 18:44:38 +0100732 bool hole_init = mode == LET || mode == CONST;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000733 switch (variable->location()) {
734 case VariableLocation::GLOBAL:
735 case VariableLocation::UNALLOCATED:
Ben Murdochc5610432016-08-08 18:44:38 +0100736 DCHECK(!variable->binding_needs_init());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000737 globals_->Add(variable->name(), zone());
Ben Murdochc5610432016-08-08 18:44:38 +0100738 globals_->Add(isolate()->factory()->undefined_value(), zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000739 break;
740
741 case VariableLocation::PARAMETER:
742 case VariableLocation::LOCAL:
743 if (hole_init) {
744 Comment cmnt(masm_, "[ VariableDeclaration");
745 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
746 __ movp(StackOperand(variable), kScratchRegister);
747 }
748 break;
749
750 case VariableLocation::CONTEXT:
751 if (hole_init) {
752 Comment cmnt(masm_, "[ VariableDeclaration");
753 EmitDebugCheckDeclarationContext(variable);
754 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
755 __ movp(ContextOperand(rsi, variable->index()), kScratchRegister);
756 // No write barrier since the hole value is in old space.
Ben Murdochc5610432016-08-08 18:44:38 +0100757 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000758 }
759 break;
760
761 case VariableLocation::LOOKUP: {
762 Comment cmnt(masm_, "[ VariableDeclaration");
Ben Murdoch61f157c2016-09-16 13:49:30 +0100763 DCHECK_EQ(VAR, mode);
764 DCHECK(!hole_init);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000765 __ Push(variable->name());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100766 __ CallRuntime(Runtime::kDeclareEvalVar);
Ben Murdochc5610432016-08-08 18:44:38 +0100767 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000768 break;
769 }
770 }
771}
772
773
774void FullCodeGenerator::VisitFunctionDeclaration(
775 FunctionDeclaration* declaration) {
776 VariableProxy* proxy = declaration->proxy();
777 Variable* variable = proxy->var();
778 switch (variable->location()) {
779 case VariableLocation::GLOBAL:
780 case VariableLocation::UNALLOCATED: {
781 globals_->Add(variable->name(), zone());
782 Handle<SharedFunctionInfo> function =
783 Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
784 // Check for stack-overflow exception.
785 if (function.is_null()) return SetStackOverflow();
786 globals_->Add(function, zone());
787 break;
788 }
789
790 case VariableLocation::PARAMETER:
791 case VariableLocation::LOCAL: {
792 Comment cmnt(masm_, "[ FunctionDeclaration");
793 VisitForAccumulatorValue(declaration->fun());
794 __ movp(StackOperand(variable), result_register());
795 break;
796 }
797
798 case VariableLocation::CONTEXT: {
799 Comment cmnt(masm_, "[ FunctionDeclaration");
800 EmitDebugCheckDeclarationContext(variable);
801 VisitForAccumulatorValue(declaration->fun());
802 __ movp(ContextOperand(rsi, variable->index()), result_register());
803 int offset = Context::SlotOffset(variable->index());
804 // We know that we have written a function, which is not a smi.
805 __ RecordWriteContextSlot(rsi,
806 offset,
807 result_register(),
808 rcx,
809 kDontSaveFPRegs,
810 EMIT_REMEMBERED_SET,
811 OMIT_SMI_CHECK);
Ben Murdochc5610432016-08-08 18:44:38 +0100812 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000813 break;
814 }
815
816 case VariableLocation::LOOKUP: {
817 Comment cmnt(masm_, "[ FunctionDeclaration");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100818 PushOperand(variable->name());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819 VisitForStackValue(declaration->fun());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100820 CallRuntimeWithOperands(Runtime::kDeclareEvalFunction);
Ben Murdochc5610432016-08-08 18:44:38 +0100821 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000822 break;
823 }
824 }
825}
826
827
828void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
829 // Call the runtime to declare the globals.
830 __ Push(pairs);
831 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
832 __ CallRuntime(Runtime::kDeclareGlobals);
833 // Return value is ignored.
834}
835
836
837void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
838 // Call the runtime to declare the modules.
839 __ Push(descriptions);
840 __ CallRuntime(Runtime::kDeclareModules);
841 // Return value is ignored.
842}
843
844
845void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
846 Comment cmnt(masm_, "[ SwitchStatement");
847 Breakable nested_statement(this, stmt);
848 SetStatementPosition(stmt);
849
850 // Keep the switch value on the stack until a case matches.
851 VisitForStackValue(stmt->tag());
Ben Murdochc5610432016-08-08 18:44:38 +0100852 PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000853
854 ZoneList<CaseClause*>* clauses = stmt->cases();
855 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
856
857 Label next_test; // Recycled for each test.
858 // Compile all the tests with branches to their bodies.
859 for (int i = 0; i < clauses->length(); i++) {
860 CaseClause* clause = clauses->at(i);
861 clause->body_target()->Unuse();
862
863 // The default is not a test, but remember it as final fall through.
864 if (clause->is_default()) {
865 default_clause = clause;
866 continue;
867 }
868
869 Comment cmnt(masm_, "[ Case comparison");
870 __ bind(&next_test);
871 next_test.Unuse();
872
873 // Compile the label expression.
874 VisitForAccumulatorValue(clause->label());
875
876 // Perform the comparison as if via '==='.
877 __ movp(rdx, Operand(rsp, 0)); // Switch value.
878 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
879 JumpPatchSite patch_site(masm_);
880 if (inline_smi_code) {
881 Label slow_case;
882 __ movp(rcx, rdx);
883 __ orp(rcx, rax);
884 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
885
886 __ cmpp(rdx, rax);
887 __ j(not_equal, &next_test);
888 __ Drop(1); // Switch value is no longer needed.
889 __ jmp(clause->body_target());
890 __ bind(&slow_case);
891 }
892
893 // Record position before stub call for type feedback.
894 SetExpressionPosition(clause);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100895 Handle<Code> ic =
896 CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000897 CallIC(ic, clause->CompareId());
898 patch_site.EmitPatchInfo();
899
900 Label skip;
901 __ jmp(&skip, Label::kNear);
Ben Murdochc5610432016-08-08 18:44:38 +0100902 PrepareForBailout(clause, BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
904 __ j(not_equal, &next_test);
905 __ Drop(1);
906 __ jmp(clause->body_target());
907 __ bind(&skip);
908
909 __ testp(rax, rax);
910 __ j(not_equal, &next_test);
911 __ Drop(1); // Switch value is no longer needed.
912 __ jmp(clause->body_target());
913 }
914
915 // Discard the test value and jump to the default if present, otherwise to
916 // the end of the statement.
917 __ bind(&next_test);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100918 DropOperands(1); // Switch value is no longer needed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000919 if (default_clause == NULL) {
920 __ jmp(nested_statement.break_label());
921 } else {
922 __ jmp(default_clause->body_target());
923 }
924
925 // Compile all the case bodies.
926 for (int i = 0; i < clauses->length(); i++) {
927 Comment cmnt(masm_, "[ Case body");
928 CaseClause* clause = clauses->at(i);
929 __ bind(clause->body_target());
Ben Murdochc5610432016-08-08 18:44:38 +0100930 PrepareForBailoutForId(clause->EntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931 VisitStatements(clause->statements());
932 }
933
934 __ bind(nested_statement.break_label());
Ben Murdochc5610432016-08-08 18:44:38 +0100935 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936}
937
938
939void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
940 Comment cmnt(masm_, "[ ForInStatement");
941 SetStatementPosition(stmt, SKIP_BREAK);
942
943 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
944
Ben Murdoch097c5b22016-05-18 11:27:45 +0100945 // Get the object to enumerate over.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000946 SetExpressionAsStatementPosition(stmt->enumerable());
947 VisitForAccumulatorValue(stmt->enumerable());
Ben Murdochda12d292016-06-02 14:46:10 +0100948 OperandStackDepthIncrement(5);
949
950 Label loop, exit;
951 Iteration loop_statement(this, stmt);
952 increment_loop_depth();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000953
Ben Murdoch097c5b22016-05-18 11:27:45 +0100954 // If the object is null or undefined, skip over the loop, otherwise convert
955 // it to a JS receiver. See ECMA-262 version 5, section 12.6.4.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000956 Label convert, done_convert;
957 __ JumpIfSmi(rax, &convert, Label::kNear);
958 __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rcx);
959 __ j(above_equal, &done_convert, Label::kNear);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100960 __ CompareRoot(rax, Heap::kNullValueRootIndex);
961 __ j(equal, &exit);
962 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
963 __ j(equal, &exit);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000964 __ bind(&convert);
965 ToObjectStub stub(isolate());
966 __ CallStub(&stub);
967 __ bind(&done_convert);
Ben Murdochc5610432016-08-08 18:44:38 +0100968 PrepareForBailoutForId(stmt->ToObjectId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000969 __ Push(rax);
970
Ben Murdochc5610432016-08-08 18:44:38 +0100971 // Check cache validity in generated code. If we cannot guarantee cache
972 // validity, call the runtime system to check cache validity or get the
973 // property names in a fixed array. Note: Proxies never have an enum cache,
974 // so will always take the slow path.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100975 Label call_runtime;
976 __ CheckEnumCache(&call_runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000977
978 // The enum cache is valid. Load the map of the object being
979 // iterated over and use the cache for the iteration.
980 Label use_cache;
981 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset));
982 __ jmp(&use_cache, Label::kNear);
983
984 // Get the set of properties to enumerate.
985 __ bind(&call_runtime);
986 __ Push(rax); // Duplicate the enumerable object on the stack.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100987 __ CallRuntime(Runtime::kForInEnumerate);
Ben Murdochc5610432016-08-08 18:44:38 +0100988 PrepareForBailoutForId(stmt->EnumId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000989
990 // If we got a map from the runtime call, we can do a fast
991 // modification check. Otherwise, we got a fixed array, and we have
992 // to do a slow check.
993 Label fixed_array;
994 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
995 Heap::kMetaMapRootIndex);
996 __ j(not_equal, &fixed_array);
997
998 // We got a map in register rax. Get the enumeration cache from it.
999 __ bind(&use_cache);
1000
1001 Label no_descriptors;
1002
1003 __ EnumLength(rdx, rax);
1004 __ Cmp(rdx, Smi::FromInt(0));
1005 __ j(equal, &no_descriptors);
1006
1007 __ LoadInstanceDescriptors(rax, rcx);
1008 __ movp(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheOffset));
1009 __ movp(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1010
1011 // Set up the four remaining stack slots.
1012 __ Push(rax); // Map.
1013 __ Push(rcx); // Enumeration cache.
1014 __ Push(rdx); // Number of valid entries for the map in the enum cache.
1015 __ Push(Smi::FromInt(0)); // Initial index.
1016 __ jmp(&loop);
1017
1018 __ bind(&no_descriptors);
1019 __ addp(rsp, Immediate(kPointerSize));
1020 __ jmp(&exit);
1021
1022 // We got a fixed array in register rax. Iterate through that.
1023 __ bind(&fixed_array);
1024
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001025 __ movp(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
1026 __ Push(Smi::FromInt(1)); // Smi(1) indicates slow check
1027 __ Push(rax); // Array
1028 __ movp(rax, FieldOperand(rax, FixedArray::kLengthOffset));
1029 __ Push(rax); // Fixed array length (as smi).
Ben Murdochc5610432016-08-08 18:44:38 +01001030 PrepareForBailoutForId(stmt->PrepareId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001031 __ Push(Smi::FromInt(0)); // Initial index.
1032
1033 // Generate code for doing the condition check.
1034 __ bind(&loop);
1035 SetExpressionAsStatementPosition(stmt->each());
1036
1037 __ movp(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
1038 __ cmpp(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
1039 __ j(above_equal, loop_statement.break_label());
1040
1041 // Get the current entry of the array into register rbx.
1042 __ movp(rbx, Operand(rsp, 2 * kPointerSize));
1043 SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2);
1044 __ movp(rbx, FieldOperand(rbx,
1045 index.reg,
1046 index.scale,
1047 FixedArray::kHeaderSize));
1048
1049 // Get the expected map from the stack or a smi in the
1050 // permanent slow case into register rdx.
1051 __ movp(rdx, Operand(rsp, 3 * kPointerSize));
1052
1053 // Check if the expected map still matches that of the enumerable.
1054 // If not, we may have to filter the key.
1055 Label update_each;
1056 __ movp(rcx, Operand(rsp, 4 * kPointerSize));
1057 __ cmpp(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
1058 __ j(equal, &update_each, Label::kNear);
1059
Ben Murdochda12d292016-06-02 14:46:10 +01001060 // We need to filter the key, record slow-path here.
1061 int const vector_index = SmiFromSlot(slot)->value();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001062 __ EmitLoadTypeFeedbackVector(rdx);
1063 __ Move(FieldOperand(rdx, FixedArray::OffsetOfElementAt(vector_index)),
1064 TypeFeedbackVector::MegamorphicSentinel(isolate()));
1065
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001066 // Convert the entry to a string or null if it isn't a property
1067 // anymore. If the property has been removed while iterating, we
1068 // just skip it.
1069 __ Push(rcx); // Enumerable.
1070 __ Push(rbx); // Current entry.
1071 __ CallRuntime(Runtime::kForInFilter);
Ben Murdochc5610432016-08-08 18:44:38 +01001072 PrepareForBailoutForId(stmt->FilterId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001073 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
1074 __ j(equal, loop_statement.continue_label());
1075 __ movp(rbx, rax);
1076
1077 // Update the 'each' property or variable from the possibly filtered
1078 // entry in register rbx.
1079 __ bind(&update_each);
1080 __ movp(result_register(), rbx);
1081 // Perform the assignment as if via '='.
1082 { EffectContext context(this);
1083 EmitAssignment(stmt->each(), stmt->EachFeedbackSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01001084 PrepareForBailoutForId(stmt->AssignmentId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001085 }
1086
1087 // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body().
Ben Murdochc5610432016-08-08 18:44:38 +01001088 PrepareForBailoutForId(stmt->BodyId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001089 // Generate code for the body of the loop.
1090 Visit(stmt->body());
1091
1092 // Generate code for going to the next element by incrementing the
1093 // index (smi) stored on top of the stack.
1094 __ bind(loop_statement.continue_label());
1095 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
1096
1097 EmitBackEdgeBookkeeping(stmt, &loop);
1098 __ jmp(&loop);
1099
1100 // Remove the pointers stored on the stack.
1101 __ bind(loop_statement.break_label());
Ben Murdochda12d292016-06-02 14:46:10 +01001102 DropOperands(5);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001103
1104 // Exit and decrement the loop depth.
Ben Murdochc5610432016-08-08 18:44:38 +01001105 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001106 __ bind(&exit);
1107 decrement_loop_depth();
1108}
1109
1110
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001111void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset,
1112 FeedbackVectorSlot slot) {
1113 DCHECK(NeedsHomeObject(initializer));
1114 __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0));
1115 __ Move(StoreDescriptor::NameRegister(),
1116 isolate()->factory()->home_object_symbol());
1117 __ movp(StoreDescriptor::ValueRegister(),
1118 Operand(rsp, offset * kPointerSize));
1119 EmitLoadStoreICSlot(slot);
1120 CallStoreIC();
1121}
1122
1123
1124void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer,
1125 int offset,
1126 FeedbackVectorSlot slot) {
1127 DCHECK(NeedsHomeObject(initializer));
1128 __ movp(StoreDescriptor::ReceiverRegister(), rax);
1129 __ Move(StoreDescriptor::NameRegister(),
1130 isolate()->factory()->home_object_symbol());
1131 __ movp(StoreDescriptor::ValueRegister(),
1132 Operand(rsp, offset * kPointerSize));
1133 EmitLoadStoreICSlot(slot);
1134 CallStoreIC();
1135}
1136
1137
1138void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
1139 TypeofMode typeof_mode,
1140 Label* slow) {
1141 Register context = rsi;
1142 Register temp = rdx;
1143
1144 Scope* s = scope();
1145 while (s != NULL) {
1146 if (s->num_heap_slots() > 0) {
1147 if (s->calls_sloppy_eval()) {
1148 // Check that extension is "the hole".
1149 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1150 Heap::kTheHoleValueRootIndex, slow);
1151 }
1152 // Load next context in chain.
1153 __ movp(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1154 // Walk the rest of the chain without clobbering rsi.
1155 context = temp;
1156 }
1157 // If no outer scope calls eval, we do not need to check more
1158 // context extensions. If we have reached an eval scope, we check
1159 // all extensions from this point.
1160 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
1161 s = s->outer_scope();
1162 }
1163
1164 if (s != NULL && s->is_eval_scope()) {
1165 // Loop up the context chain. There is no frame effect so it is
1166 // safe to use raw labels here.
1167 Label next, fast;
1168 if (!context.is(temp)) {
1169 __ movp(temp, context);
1170 }
1171 // Load map for comparison into register, outside loop.
1172 __ LoadRoot(kScratchRegister, Heap::kNativeContextMapRootIndex);
1173 __ bind(&next);
1174 // Terminate at native context.
1175 __ cmpp(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset));
1176 __ j(equal, &fast, Label::kNear);
1177 // Check that extension is "the hole".
1178 __ JumpIfNotRoot(ContextOperand(temp, Context::EXTENSION_INDEX),
1179 Heap::kTheHoleValueRootIndex, slow);
1180 // Load next context in chain.
1181 __ movp(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
1182 __ jmp(&next);
1183 __ bind(&fast);
1184 }
1185
1186 // All extension objects were empty and it is safe to use a normal global
1187 // load machinery.
1188 EmitGlobalVariableLoad(proxy, typeof_mode);
1189}
1190
1191
1192MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1193 Label* slow) {
1194 DCHECK(var->IsContextSlot());
1195 Register context = rsi;
1196 Register temp = rbx;
1197
1198 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1199 if (s->num_heap_slots() > 0) {
1200 if (s->calls_sloppy_eval()) {
1201 // Check that extension is "the hole".
1202 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1203 Heap::kTheHoleValueRootIndex, slow);
1204 }
1205 __ movp(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1206 // Walk the rest of the chain without clobbering rsi.
1207 context = temp;
1208 }
1209 }
1210 // Check that last extension is "the hole".
1211 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1212 Heap::kTheHoleValueRootIndex, slow);
1213
1214 // This function is used only for loads, not stores, so it's safe to
1215 // return an rsi-based operand (the write barrier cannot be allowed to
1216 // destroy the rsi register).
1217 return ContextOperand(context, var->index());
1218}
1219
1220
1221void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
1222 TypeofMode typeof_mode,
1223 Label* slow, Label* done) {
1224 // Generate fast-case code for variables that might be shadowed by
1225 // eval-introduced variables. Eval is used a lot without
1226 // introducing variables. In those cases, we do not want to
1227 // perform a runtime call for all variables in the scope
1228 // containing the eval.
1229 Variable* var = proxy->var();
1230 if (var->mode() == DYNAMIC_GLOBAL) {
1231 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow);
1232 __ jmp(done);
1233 } else if (var->mode() == DYNAMIC_LOCAL) {
1234 Variable* local = var->local_if_not_shadowed();
1235 __ movp(rax, ContextSlotOperandCheckExtensions(local, slow));
Ben Murdochc5610432016-08-08 18:44:38 +01001236 if (local->mode() == LET || local->mode() == CONST) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001237 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1238 __ j(not_equal, done);
Ben Murdochc5610432016-08-08 18:44:38 +01001239 __ Push(var->name());
1240 __ CallRuntime(Runtime::kThrowReferenceError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001241 }
1242 __ jmp(done);
1243 }
1244}
1245
1246
1247void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
1248 TypeofMode typeof_mode) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001249#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001250 Variable* var = proxy->var();
1251 DCHECK(var->IsUnallocatedOrGlobalSlot() ||
1252 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001253#endif
1254 __ Move(LoadGlobalDescriptor::SlotRegister(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001255 SmiFromSlot(proxy->VariableFeedbackSlot()));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001256 CallLoadGlobalIC(typeof_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001257}
1258
1259
1260void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
1261 TypeofMode typeof_mode) {
1262 // Record position before possible IC call.
1263 SetExpressionPosition(proxy);
Ben Murdochc5610432016-08-08 18:44:38 +01001264 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001265 Variable* var = proxy->var();
1266
1267 // Three cases: global variables, lookup variables, and all other types of
1268 // variables.
1269 switch (var->location()) {
1270 case VariableLocation::GLOBAL:
1271 case VariableLocation::UNALLOCATED: {
1272 Comment cmnt(masm_, "[ Global variable");
1273 EmitGlobalVariableLoad(proxy, typeof_mode);
1274 context()->Plug(rax);
1275 break;
1276 }
1277
1278 case VariableLocation::PARAMETER:
1279 case VariableLocation::LOCAL:
1280 case VariableLocation::CONTEXT: {
1281 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
1282 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot"
1283 : "[ Stack slot");
1284 if (NeedsHoleCheckForLoad(proxy)) {
1285 // Let and const need a read barrier.
1286 Label done;
1287 GetVar(rax, var);
1288 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1289 __ j(not_equal, &done, Label::kNear);
1290 if (var->mode() == LET || var->mode() == CONST) {
1291 // Throw a reference error when using an uninitialized let/const
1292 // binding in harmony mode.
1293 __ Push(var->name());
1294 __ CallRuntime(Runtime::kThrowReferenceError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001295 }
1296 __ bind(&done);
1297 context()->Plug(rax);
1298 break;
1299 }
1300 context()->Plug(var);
1301 break;
1302 }
1303
1304 case VariableLocation::LOOKUP: {
1305 Comment cmnt(masm_, "[ Lookup slot");
1306 Label done, slow;
1307 // Generate code for loading from variables potentially shadowed
1308 // by eval-introduced variables.
1309 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done);
1310 __ bind(&slow);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001311 __ Push(var->name());
1312 Runtime::FunctionId function_id =
1313 typeof_mode == NOT_INSIDE_TYPEOF
1314 ? Runtime::kLoadLookupSlot
Ben Murdoch097c5b22016-05-18 11:27:45 +01001315 : Runtime::kLoadLookupSlotInsideTypeof;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001316 __ CallRuntime(function_id);
1317 __ bind(&done);
1318 context()->Plug(rax);
1319 break;
1320 }
1321 }
1322}
1323
1324
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001325void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) {
1326 Expression* expression = (property == NULL) ? NULL : property->value();
1327 if (expression == NULL) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001328 OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001329 __ PushRoot(Heap::kNullValueRootIndex);
1330 } else {
1331 VisitForStackValue(expression);
1332 if (NeedsHomeObject(expression)) {
1333 DCHECK(property->kind() == ObjectLiteral::Property::GETTER ||
1334 property->kind() == ObjectLiteral::Property::SETTER);
1335 int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3;
1336 EmitSetHomeObject(expression, offset, property->GetSlot());
1337 }
1338 }
1339}
1340
1341
1342void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1343 Comment cmnt(masm_, "[ ObjectLiteral");
1344
1345 Handle<FixedArray> constant_properties = expr->constant_properties();
1346 int flags = expr->ComputeFlags();
1347 if (MustCreateObjectLiteralWithRuntime(expr)) {
1348 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1349 __ Push(Smi::FromInt(expr->literal_index()));
1350 __ Push(constant_properties);
1351 __ Push(Smi::FromInt(flags));
1352 __ CallRuntime(Runtime::kCreateObjectLiteral);
1353 } else {
1354 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1355 __ Move(rbx, Smi::FromInt(expr->literal_index()));
1356 __ Move(rcx, constant_properties);
1357 __ Move(rdx, Smi::FromInt(flags));
1358 FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
1359 __ CallStub(&stub);
Ben Murdochc5610432016-08-08 18:44:38 +01001360 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001361 }
Ben Murdochc5610432016-08-08 18:44:38 +01001362 PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001363
1364 // If result_saved is true the result is on top of the stack. If
1365 // result_saved is false the result is in rax.
1366 bool result_saved = false;
1367
1368 AccessorTable accessor_table(zone());
1369 int property_index = 0;
1370 for (; property_index < expr->properties()->length(); property_index++) {
1371 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1372 if (property->is_computed_name()) break;
1373 if (property->IsCompileTimeValue()) continue;
1374
1375 Literal* key = property->key()->AsLiteral();
1376 Expression* value = property->value();
1377 if (!result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001378 PushOperand(rax); // Save result on the stack
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001379 result_saved = true;
1380 }
1381 switch (property->kind()) {
1382 case ObjectLiteral::Property::CONSTANT:
1383 UNREACHABLE();
1384 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1385 DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
1386 // Fall through.
1387 case ObjectLiteral::Property::COMPUTED:
1388 // It is safe to use [[Put]] here because the boilerplate already
1389 // contains computed properties with an uninitialized value.
1390 if (key->value()->IsInternalizedString()) {
1391 if (property->emit_store()) {
1392 VisitForAccumulatorValue(value);
1393 DCHECK(StoreDescriptor::ValueRegister().is(rax));
1394 __ Move(StoreDescriptor::NameRegister(), key->value());
1395 __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0));
1396 EmitLoadStoreICSlot(property->GetSlot(0));
1397 CallStoreIC();
Ben Murdochc5610432016-08-08 18:44:38 +01001398 PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001399
1400 if (NeedsHomeObject(value)) {
1401 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1));
1402 }
1403 } else {
1404 VisitForEffect(value);
1405 }
1406 break;
1407 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001408 PushOperand(Operand(rsp, 0)); // Duplicate receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001409 VisitForStackValue(key);
1410 VisitForStackValue(value);
1411 if (property->emit_store()) {
1412 if (NeedsHomeObject(value)) {
1413 EmitSetHomeObject(value, 2, property->GetSlot());
1414 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001415 PushOperand(Smi::FromInt(SLOPPY)); // Language mode
1416 CallRuntimeWithOperands(Runtime::kSetProperty);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001417 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001418 DropOperands(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001419 }
1420 break;
1421 case ObjectLiteral::Property::PROTOTYPE:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001422 PushOperand(Operand(rsp, 0)); // Duplicate receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 VisitForStackValue(value);
1424 DCHECK(property->emit_store());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001425 CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001426 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
Ben Murdochc5610432016-08-08 18:44:38 +01001427 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001428 break;
1429 case ObjectLiteral::Property::GETTER:
1430 if (property->emit_store()) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001431 AccessorTable::Iterator it = accessor_table.lookup(key);
1432 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1433 it->second->getter = property;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001434 }
1435 break;
1436 case ObjectLiteral::Property::SETTER:
1437 if (property->emit_store()) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001438 AccessorTable::Iterator it = accessor_table.lookup(key);
1439 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1440 it->second->setter = property;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001441 }
1442 break;
1443 }
1444 }
1445
1446 // Emit code to define accessors, using only a single call to the runtime for
1447 // each pair of corresponding getters and setters.
1448 for (AccessorTable::Iterator it = accessor_table.begin();
1449 it != accessor_table.end();
1450 ++it) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001451 PushOperand(Operand(rsp, 0)); // Duplicate receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001452 VisitForStackValue(it->first);
1453 EmitAccessor(it->second->getter);
1454 EmitAccessor(it->second->setter);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001455 PushOperand(Smi::FromInt(NONE));
1456 CallRuntimeWithOperands(Runtime::kDefineAccessorPropertyUnchecked);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001457 PrepareForBailoutForId(it->second->bailout_id, BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001458 }
1459
1460 // Object literals have two parts. The "static" part on the left contains no
1461 // computed property names, and so we can compute its map ahead of time; see
1462 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
1463 // starts with the first computed property name, and continues with all
1464 // properties to its right. All the code from above initializes the static
1465 // component of the object literal, and arranges for the map of the result to
1466 // reflect the static order in which the keys appear. For the dynamic
1467 // properties, we compile them into a series of "SetOwnProperty" runtime
1468 // calls. This will preserve insertion order.
1469 for (; property_index < expr->properties()->length(); property_index++) {
1470 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1471
1472 Expression* value = property->value();
1473 if (!result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001474 PushOperand(rax); // Save result on the stack
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001475 result_saved = true;
1476 }
1477
Ben Murdoch097c5b22016-05-18 11:27:45 +01001478 PushOperand(Operand(rsp, 0)); // Duplicate receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001479
1480 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1481 DCHECK(!property->is_computed_name());
1482 VisitForStackValue(value);
1483 DCHECK(property->emit_store());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001484 CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001485 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
Ben Murdochc5610432016-08-08 18:44:38 +01001486 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001487 } else {
1488 EmitPropertyKey(property, expr->GetIdForPropertyName(property_index));
1489 VisitForStackValue(value);
1490 if (NeedsHomeObject(value)) {
1491 EmitSetHomeObject(value, 2, property->GetSlot());
1492 }
1493
1494 switch (property->kind()) {
1495 case ObjectLiteral::Property::CONSTANT:
1496 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1497 case ObjectLiteral::Property::COMPUTED:
1498 if (property->emit_store()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001499 PushOperand(Smi::FromInt(NONE));
1500 PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
1501 CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001502 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1503 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001504 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001505 DropOperands(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 }
1507 break;
1508
1509 case ObjectLiteral::Property::PROTOTYPE:
1510 UNREACHABLE();
1511 break;
1512
1513 case ObjectLiteral::Property::GETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001514 PushOperand(Smi::FromInt(NONE));
1515 CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001516 break;
1517
1518 case ObjectLiteral::Property::SETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001519 PushOperand(Smi::FromInt(NONE));
1520 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521 break;
1522 }
1523 }
1524 }
1525
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 if (result_saved) {
1527 context()->PlugTOS();
1528 } else {
1529 context()->Plug(rax);
1530 }
1531}
1532
1533
1534void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1535 Comment cmnt(masm_, "[ ArrayLiteral");
1536
1537 Handle<FixedArray> constant_elements = expr->constant_elements();
1538 bool has_constant_fast_elements =
1539 IsFastObjectElementsKind(expr->constant_elements_kind());
1540
1541 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1542 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1543 // If the only customer of allocation sites is transitioning, then
1544 // we can turn it off if we don't have anywhere else to transition to.
1545 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1546 }
1547
1548 if (MustCreateArrayLiteralWithRuntime(expr)) {
1549 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1550 __ Push(Smi::FromInt(expr->literal_index()));
1551 __ Push(constant_elements);
1552 __ Push(Smi::FromInt(expr->ComputeFlags()));
1553 __ CallRuntime(Runtime::kCreateArrayLiteral);
1554 } else {
1555 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1556 __ Move(rbx, Smi::FromInt(expr->literal_index()));
1557 __ Move(rcx, constant_elements);
1558 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
1559 __ CallStub(&stub);
1560 }
Ben Murdochc5610432016-08-08 18:44:38 +01001561 PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001562
1563 bool result_saved = false; // Is the result saved to the stack?
1564 ZoneList<Expression*>* subexprs = expr->values();
1565 int length = subexprs->length();
1566
1567 // Emit code to evaluate all the non-constant subexpressions and to store
1568 // them into the newly cloned array.
1569 int array_index = 0;
1570 for (; array_index < length; array_index++) {
1571 Expression* subexpr = subexprs->at(array_index);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001572 DCHECK(!subexpr->IsSpread());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001573
1574 // If the subexpression is a literal or a simple materialized literal it
1575 // is already set in the cloned array.
1576 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1577
1578 if (!result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001579 PushOperand(rax); // array literal
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001580 result_saved = true;
1581 }
1582 VisitForAccumulatorValue(subexpr);
1583
1584 __ Move(StoreDescriptor::NameRegister(), Smi::FromInt(array_index));
1585 __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0));
1586 EmitLoadStoreICSlot(expr->LiteralFeedbackSlot());
1587 Handle<Code> ic =
1588 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
1589 CallIC(ic);
1590
Ben Murdochc5610432016-08-08 18:44:38 +01001591 PrepareForBailoutForId(expr->GetIdForElement(array_index),
1592 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001593 }
1594
1595 // In case the array literal contains spread expressions it has two parts. The
1596 // first part is the "static" array which has a literal index is handled
1597 // above. The second part is the part after the first spread expression
1598 // (inclusive) and these elements gets appended to the array. Note that the
1599 // number elements an iterable produces is unknown ahead of time.
1600 if (array_index < length && result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001601 PopOperand(rax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001602 result_saved = false;
1603 }
1604 for (; array_index < length; array_index++) {
1605 Expression* subexpr = subexprs->at(array_index);
1606
Ben Murdoch097c5b22016-05-18 11:27:45 +01001607 PushOperand(rax);
1608 DCHECK(!subexpr->IsSpread());
1609 VisitForStackValue(subexpr);
1610 CallRuntimeWithOperands(Runtime::kAppendElement);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001611
Ben Murdochc5610432016-08-08 18:44:38 +01001612 PrepareForBailoutForId(expr->GetIdForElement(array_index),
1613 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001614 }
1615
1616 if (result_saved) {
1617 context()->PlugTOS();
1618 } else {
1619 context()->Plug(rax);
1620 }
1621}
1622
1623
1624void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1625 DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
1626
1627 Comment cmnt(masm_, "[ Assignment");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001628
1629 Property* property = expr->target()->AsProperty();
1630 LhsKind assign_type = Property::GetAssignType(property);
1631
1632 // Evaluate LHS expression.
1633 switch (assign_type) {
1634 case VARIABLE:
1635 // Nothing to do here.
1636 break;
1637 case NAMED_PROPERTY:
1638 if (expr->is_compound()) {
1639 // We need the receiver both on the stack and in the register.
1640 VisitForStackValue(property->obj());
1641 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
1642 } else {
1643 VisitForStackValue(property->obj());
1644 }
1645 break;
1646 case NAMED_SUPER_PROPERTY:
1647 VisitForStackValue(
1648 property->obj()->AsSuperPropertyReference()->this_var());
1649 VisitForAccumulatorValue(
1650 property->obj()->AsSuperPropertyReference()->home_object());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001651 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001652 if (expr->is_compound()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001653 PushOperand(MemOperand(rsp, kPointerSize));
1654 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001655 }
1656 break;
1657 case KEYED_SUPER_PROPERTY:
1658 VisitForStackValue(
1659 property->obj()->AsSuperPropertyReference()->this_var());
1660 VisitForStackValue(
1661 property->obj()->AsSuperPropertyReference()->home_object());
1662 VisitForAccumulatorValue(property->key());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001663 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001664 if (expr->is_compound()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001665 PushOperand(MemOperand(rsp, 2 * kPointerSize));
1666 PushOperand(MemOperand(rsp, 2 * kPointerSize));
1667 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001668 }
1669 break;
1670 case KEYED_PROPERTY: {
1671 if (expr->is_compound()) {
1672 VisitForStackValue(property->obj());
1673 VisitForStackValue(property->key());
1674 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
1675 __ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
1676 } else {
1677 VisitForStackValue(property->obj());
1678 VisitForStackValue(property->key());
1679 }
1680 break;
1681 }
1682 }
1683
1684 // For compound assignments we need another deoptimization point after the
1685 // variable/property load.
1686 if (expr->is_compound()) {
1687 { AccumulatorValueContext context(this);
1688 switch (assign_type) {
1689 case VARIABLE:
1690 EmitVariableLoad(expr->target()->AsVariableProxy());
Ben Murdochc5610432016-08-08 18:44:38 +01001691 PrepareForBailout(expr->target(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001692 break;
1693 case NAMED_PROPERTY:
1694 EmitNamedPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001695 PrepareForBailoutForId(property->LoadId(),
1696 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001697 break;
1698 case NAMED_SUPER_PROPERTY:
1699 EmitNamedSuperPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001700 PrepareForBailoutForId(property->LoadId(),
1701 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001702 break;
1703 case KEYED_SUPER_PROPERTY:
1704 EmitKeyedSuperPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001705 PrepareForBailoutForId(property->LoadId(),
1706 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001707 break;
1708 case KEYED_PROPERTY:
1709 EmitKeyedPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001710 PrepareForBailoutForId(property->LoadId(),
1711 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001712 break;
1713 }
1714 }
1715
1716 Token::Value op = expr->binary_op();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001717 PushOperand(rax); // Left operand goes on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001718 VisitForAccumulatorValue(expr->value());
1719
1720 AccumulatorValueContext context(this);
1721 if (ShouldInlineSmiCase(op)) {
1722 EmitInlineSmiBinaryOp(expr->binary_operation(),
1723 op,
1724 expr->target(),
1725 expr->value());
1726 } else {
1727 EmitBinaryOp(expr->binary_operation(), op);
1728 }
1729 // Deoptimization point in case the binary operation may have side effects.
Ben Murdochc5610432016-08-08 18:44:38 +01001730 PrepareForBailout(expr->binary_operation(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001731 } else {
1732 VisitForAccumulatorValue(expr->value());
1733 }
1734
1735 SetExpressionPosition(expr);
1736
1737 // Store the value.
1738 switch (assign_type) {
1739 case VARIABLE:
1740 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1741 expr->op(), expr->AssignmentSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01001742 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001743 context()->Plug(rax);
1744 break;
1745 case NAMED_PROPERTY:
1746 EmitNamedPropertyAssignment(expr);
1747 break;
1748 case NAMED_SUPER_PROPERTY:
1749 EmitNamedSuperPropertyStore(property);
1750 context()->Plug(rax);
1751 break;
1752 case KEYED_SUPER_PROPERTY:
1753 EmitKeyedSuperPropertyStore(property);
1754 context()->Plug(rax);
1755 break;
1756 case KEYED_PROPERTY:
1757 EmitKeyedPropertyAssignment(expr);
1758 break;
1759 }
1760}
1761
1762
1763void FullCodeGenerator::VisitYield(Yield* expr) {
1764 Comment cmnt(masm_, "[ Yield");
1765 SetExpressionPosition(expr);
1766
1767 // Evaluate yielded value first; the initial iterator definition depends on
1768 // this. It stays on the stack while we update the iterator.
1769 VisitForStackValue(expr->expression());
1770
Ben Murdochc5610432016-08-08 18:44:38 +01001771 Label suspend, continuation, post_runtime, resume, exception;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001772
Ben Murdochda12d292016-06-02 14:46:10 +01001773 __ jmp(&suspend);
1774 __ bind(&continuation);
Ben Murdochc5610432016-08-08 18:44:38 +01001775 // When we arrive here, rax holds the generator object.
Ben Murdochda12d292016-06-02 14:46:10 +01001776 __ RecordGeneratorContinuation();
Ben Murdochc5610432016-08-08 18:44:38 +01001777 __ movp(rbx, FieldOperand(rax, JSGeneratorObject::kResumeModeOffset));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001778 __ movp(rax, FieldOperand(rax, JSGeneratorObject::kInputOrDebugPosOffset));
Ben Murdochc5610432016-08-08 18:44:38 +01001779 STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
1780 STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
1781 __ SmiCompare(rbx, Smi::FromInt(JSGeneratorObject::kReturn));
1782 __ j(less, &resume);
Ben Murdochda12d292016-06-02 14:46:10 +01001783 __ Push(result_register());
Ben Murdochc5610432016-08-08 18:44:38 +01001784 __ j(greater, &exception);
Ben Murdochda12d292016-06-02 14:46:10 +01001785 EmitCreateIteratorResult(true);
1786 EmitUnwindAndReturn();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001787
Ben Murdochc5610432016-08-08 18:44:38 +01001788 __ bind(&exception);
1789 __ CallRuntime(Runtime::kThrow);
1790
Ben Murdochda12d292016-06-02 14:46:10 +01001791 __ bind(&suspend);
1792 OperandStackDepthIncrement(1); // Not popped on this path.
1793 VisitForAccumulatorValue(expr->generator_object());
1794 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
1795 __ Move(FieldOperand(rax, JSGeneratorObject::kContinuationOffset),
1796 Smi::FromInt(continuation.pos()));
1797 __ movp(FieldOperand(rax, JSGeneratorObject::kContextOffset), rsi);
1798 __ movp(rcx, rsi);
1799 __ RecordWriteField(rax, JSGeneratorObject::kContextOffset, rcx, rdx,
1800 kDontSaveFPRegs);
1801 __ leap(rbx, Operand(rbp, StandardFrameConstants::kExpressionsOffset));
1802 __ cmpp(rsp, rbx);
1803 __ j(equal, &post_runtime);
1804 __ Push(rax); // generator object
1805 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
Ben Murdochc5610432016-08-08 18:44:38 +01001806 RestoreContext();
Ben Murdochda12d292016-06-02 14:46:10 +01001807 __ bind(&post_runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001808
Ben Murdochda12d292016-06-02 14:46:10 +01001809 PopOperand(result_register());
1810 EmitReturnSequence();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001811
Ben Murdochda12d292016-06-02 14:46:10 +01001812 __ bind(&resume);
1813 context()->Plug(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001814}
1815
Ben Murdoch097c5b22016-05-18 11:27:45 +01001816void FullCodeGenerator::PushOperand(MemOperand operand) {
1817 OperandStackDepthIncrement(1);
1818 __ Push(operand);
1819}
1820
1821void FullCodeGenerator::EmitOperandStackDepthCheck() {
1822 if (FLAG_debug_code) {
1823 int expected_diff = StandardFrameConstants::kFixedFrameSizeFromFp +
1824 operand_stack_depth_ * kPointerSize;
1825 __ movp(rax, rbp);
1826 __ subp(rax, rsp);
1827 __ cmpp(rax, Immediate(expected_diff));
1828 __ Assert(equal, kUnexpectedStackDepth);
1829 }
1830}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001831
1832void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
1833 Label allocate, done_allocate;
1834
Ben Murdochc5610432016-08-08 18:44:38 +01001835 __ Allocate(JSIteratorResult::kSize, rax, rcx, rdx, &allocate,
1836 NO_ALLOCATION_FLAGS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001837 __ jmp(&done_allocate, Label::kNear);
1838
1839 __ bind(&allocate);
1840 __ Push(Smi::FromInt(JSIteratorResult::kSize));
1841 __ CallRuntime(Runtime::kAllocateInNewSpace);
1842
1843 __ bind(&done_allocate);
1844 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, rbx);
1845 __ movp(FieldOperand(rax, HeapObject::kMapOffset), rbx);
1846 __ LoadRoot(rbx, Heap::kEmptyFixedArrayRootIndex);
1847 __ movp(FieldOperand(rax, JSObject::kPropertiesOffset), rbx);
1848 __ movp(FieldOperand(rax, JSObject::kElementsOffset), rbx);
1849 __ Pop(FieldOperand(rax, JSIteratorResult::kValueOffset));
1850 __ LoadRoot(FieldOperand(rax, JSIteratorResult::kDoneOffset),
1851 done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
1852 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
Ben Murdochda12d292016-06-02 14:46:10 +01001853 OperandStackDepthDecrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001854}
1855
1856
1857void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
1858 Token::Value op,
1859 Expression* left,
1860 Expression* right) {
1861 // Do combined smi check of the operands. Left operand is on the
1862 // stack (popped into rdx). Right operand is in rax but moved into
1863 // rcx to make the shifts easier.
1864 Label done, stub_call, smi_case;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001865 PopOperand(rdx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001866 __ movp(rcx, rax);
1867 __ orp(rax, rdx);
1868 JumpPatchSite patch_site(masm_);
1869 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear);
1870
1871 __ bind(&stub_call);
1872 __ movp(rax, rcx);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001873 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001874 CallIC(code, expr->BinaryOperationFeedbackId());
1875 patch_site.EmitPatchInfo();
1876 __ jmp(&done, Label::kNear);
1877
1878 __ bind(&smi_case);
1879 switch (op) {
1880 case Token::SAR:
1881 __ SmiShiftArithmeticRight(rax, rdx, rcx);
1882 break;
1883 case Token::SHL:
1884 __ SmiShiftLeft(rax, rdx, rcx, &stub_call);
1885 break;
1886 case Token::SHR:
1887 __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
1888 break;
1889 case Token::ADD:
1890 __ SmiAdd(rax, rdx, rcx, &stub_call);
1891 break;
1892 case Token::SUB:
1893 __ SmiSub(rax, rdx, rcx, &stub_call);
1894 break;
1895 case Token::MUL:
1896 __ SmiMul(rax, rdx, rcx, &stub_call);
1897 break;
1898 case Token::BIT_OR:
1899 __ SmiOr(rax, rdx, rcx);
1900 break;
1901 case Token::BIT_AND:
1902 __ SmiAnd(rax, rdx, rcx);
1903 break;
1904 case Token::BIT_XOR:
1905 __ SmiXor(rax, rdx, rcx);
1906 break;
1907 default:
1908 UNREACHABLE();
1909 break;
1910 }
1911
1912 __ bind(&done);
1913 context()->Plug(rax);
1914}
1915
1916
1917void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001918 for (int i = 0; i < lit->properties()->length(); i++) {
1919 ObjectLiteral::Property* property = lit->properties()->at(i);
1920 Expression* value = property->value();
1921
1922 if (property->is_static()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001923 PushOperand(Operand(rsp, kPointerSize)); // constructor
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001924 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001925 PushOperand(Operand(rsp, 0)); // prototype
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001926 }
1927 EmitPropertyKey(property, lit->GetIdForProperty(i));
1928
1929 // The static prototype property is read only. We handle the non computed
1930 // property name case in the parser. Since this is the only case where we
1931 // need to check for an own read only property we special case this so we do
1932 // not need to do this for every property.
1933 if (property->is_static() && property->is_computed_name()) {
1934 __ CallRuntime(Runtime::kThrowIfStaticPrototype);
1935 __ Push(rax);
1936 }
1937
1938 VisitForStackValue(value);
1939 if (NeedsHomeObject(value)) {
1940 EmitSetHomeObject(value, 2, property->GetSlot());
1941 }
1942
1943 switch (property->kind()) {
1944 case ObjectLiteral::Property::CONSTANT:
1945 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1946 case ObjectLiteral::Property::PROTOTYPE:
1947 UNREACHABLE();
1948 case ObjectLiteral::Property::COMPUTED:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001949 PushOperand(Smi::FromInt(DONT_ENUM));
1950 PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
1951 CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001952 break;
1953
1954 case ObjectLiteral::Property::GETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001955 PushOperand(Smi::FromInt(DONT_ENUM));
1956 CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001957 break;
1958
1959 case ObjectLiteral::Property::SETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001960 PushOperand(Smi::FromInt(DONT_ENUM));
1961 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001962 break;
1963
1964 default:
1965 UNREACHABLE();
1966 }
1967 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001968}
1969
1970
1971void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001972 PopOperand(rdx);
1973 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001974 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
1975 CallIC(code, expr->BinaryOperationFeedbackId());
1976 patch_site.EmitPatchInfo();
1977 context()->Plug(rax);
1978}
1979
1980
1981void FullCodeGenerator::EmitAssignment(Expression* expr,
1982 FeedbackVectorSlot slot) {
1983 DCHECK(expr->IsValidReferenceExpressionOrThis());
1984
1985 Property* prop = expr->AsProperty();
1986 LhsKind assign_type = Property::GetAssignType(prop);
1987
1988 switch (assign_type) {
1989 case VARIABLE: {
1990 Variable* var = expr->AsVariableProxy()->var();
1991 EffectContext context(this);
1992 EmitVariableAssignment(var, Token::ASSIGN, slot);
1993 break;
1994 }
1995 case NAMED_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001996 PushOperand(rax); // Preserve value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001997 VisitForAccumulatorValue(prop->obj());
1998 __ Move(StoreDescriptor::ReceiverRegister(), rax);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001999 PopOperand(StoreDescriptor::ValueRegister()); // Restore value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002000 __ Move(StoreDescriptor::NameRegister(),
2001 prop->key()->AsLiteral()->value());
2002 EmitLoadStoreICSlot(slot);
2003 CallStoreIC();
2004 break;
2005 }
2006 case NAMED_SUPER_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002007 PushOperand(rax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002008 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2009 VisitForAccumulatorValue(
2010 prop->obj()->AsSuperPropertyReference()->home_object());
2011 // stack: value, this; rax: home_object
2012 Register scratch = rcx;
2013 Register scratch2 = rdx;
2014 __ Move(scratch, result_register()); // home_object
2015 __ movp(rax, MemOperand(rsp, kPointerSize)); // value
2016 __ movp(scratch2, MemOperand(rsp, 0)); // this
2017 __ movp(MemOperand(rsp, kPointerSize), scratch2); // this
2018 __ movp(MemOperand(rsp, 0), scratch); // home_object
2019 // stack: this, home_object; rax: value
2020 EmitNamedSuperPropertyStore(prop);
2021 break;
2022 }
2023 case KEYED_SUPER_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002024 PushOperand(rax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002025 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2026 VisitForStackValue(
2027 prop->obj()->AsSuperPropertyReference()->home_object());
2028 VisitForAccumulatorValue(prop->key());
2029 Register scratch = rcx;
2030 Register scratch2 = rdx;
2031 __ movp(scratch2, MemOperand(rsp, 2 * kPointerSize)); // value
2032 // stack: value, this, home_object; rax: key, rdx: value
2033 __ movp(scratch, MemOperand(rsp, kPointerSize)); // this
2034 __ movp(MemOperand(rsp, 2 * kPointerSize), scratch);
2035 __ movp(scratch, MemOperand(rsp, 0)); // home_object
2036 __ movp(MemOperand(rsp, kPointerSize), scratch);
2037 __ movp(MemOperand(rsp, 0), rax);
2038 __ Move(rax, scratch2);
2039 // stack: this, home_object, key; rax: value.
2040 EmitKeyedSuperPropertyStore(prop);
2041 break;
2042 }
2043 case KEYED_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002044 PushOperand(rax); // Preserve value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002045 VisitForStackValue(prop->obj());
2046 VisitForAccumulatorValue(prop->key());
2047 __ Move(StoreDescriptor::NameRegister(), rax);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002048 PopOperand(StoreDescriptor::ReceiverRegister());
2049 PopOperand(StoreDescriptor::ValueRegister()); // Restore value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002050 EmitLoadStoreICSlot(slot);
2051 Handle<Code> ic =
2052 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2053 CallIC(ic);
2054 break;
2055 }
2056 }
2057 context()->Plug(rax);
2058}
2059
2060
2061void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2062 Variable* var, MemOperand location) {
2063 __ movp(location, rax);
2064 if (var->IsContextSlot()) {
2065 __ movp(rdx, rax);
2066 __ RecordWriteContextSlot(
2067 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
2068 }
2069}
2070
2071
2072void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
2073 FeedbackVectorSlot slot) {
2074 if (var->IsUnallocated()) {
2075 // Global var, const, or let.
2076 __ Move(StoreDescriptor::NameRegister(), var->name());
2077 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister());
2078 EmitLoadStoreICSlot(slot);
2079 CallStoreIC();
2080
2081 } else if (var->mode() == LET && op != Token::INIT) {
2082 // Non-initializing assignment to let variable needs a write barrier.
2083 DCHECK(!var->IsLookupSlot());
2084 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2085 Label assign;
2086 MemOperand location = VarOperand(var, rcx);
2087 __ movp(rdx, location);
2088 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2089 __ j(not_equal, &assign, Label::kNear);
2090 __ Push(var->name());
2091 __ CallRuntime(Runtime::kThrowReferenceError);
2092 __ bind(&assign);
2093 EmitStoreToStackLocalOrContextSlot(var, location);
2094
2095 } else if (var->mode() == CONST && op != Token::INIT) {
2096 // Assignment to const variable needs a write barrier.
2097 DCHECK(!var->IsLookupSlot());
2098 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2099 Label const_error;
2100 MemOperand location = VarOperand(var, rcx);
2101 __ movp(rdx, location);
2102 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2103 __ j(not_equal, &const_error, Label::kNear);
2104 __ Push(var->name());
2105 __ CallRuntime(Runtime::kThrowReferenceError);
2106 __ bind(&const_error);
2107 __ CallRuntime(Runtime::kThrowConstAssignError);
2108
2109 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
2110 // Initializing assignment to const {this} needs a write barrier.
2111 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2112 Label uninitialized_this;
2113 MemOperand location = VarOperand(var, rcx);
2114 __ movp(rdx, location);
2115 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2116 __ j(equal, &uninitialized_this);
2117 __ Push(var->name());
2118 __ CallRuntime(Runtime::kThrowReferenceError);
2119 __ bind(&uninitialized_this);
2120 EmitStoreToStackLocalOrContextSlot(var, location);
2121
Ben Murdochc5610432016-08-08 18:44:38 +01002122 } else if (!var->is_const_mode() || op == Token::INIT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002123 if (var->IsLookupSlot()) {
2124 // Assignment to var.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002125 __ Push(var->name());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002126 __ Push(rax);
2127 __ CallRuntime(is_strict(language_mode())
2128 ? Runtime::kStoreLookupSlot_Strict
2129 : Runtime::kStoreLookupSlot_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002130 } else {
2131 // Assignment to var or initializing assignment to let/const in harmony
2132 // mode.
2133 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2134 MemOperand location = VarOperand(var, rcx);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002135 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002136 // Check for an uninitialized let binding.
2137 __ movp(rdx, location);
2138 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2139 __ Check(equal, kLetBindingReInitialization);
2140 }
2141 EmitStoreToStackLocalOrContextSlot(var, location);
2142 }
2143
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002144 } else {
2145 DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
2146 if (is_strict(language_mode())) {
2147 __ CallRuntime(Runtime::kThrowConstAssignError);
2148 }
2149 // Silently ignore store in sloppy mode.
2150 }
2151}
2152
2153
2154void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2155 // Assignment to a property, using a named store IC.
2156 Property* prop = expr->target()->AsProperty();
2157 DCHECK(prop != NULL);
2158 DCHECK(prop->key()->IsLiteral());
2159
2160 __ Move(StoreDescriptor::NameRegister(), prop->key()->AsLiteral()->value());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002161 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002162 EmitLoadStoreICSlot(expr->AssignmentSlot());
2163 CallStoreIC();
2164
Ben Murdochc5610432016-08-08 18:44:38 +01002165 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002166 context()->Plug(rax);
2167}
2168
2169
2170void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2171 // Assignment to named property of super.
2172 // rax : value
2173 // stack : receiver ('this'), home_object
2174 DCHECK(prop != NULL);
2175 Literal* key = prop->key()->AsLiteral();
2176 DCHECK(key != NULL);
2177
Ben Murdoch097c5b22016-05-18 11:27:45 +01002178 PushOperand(key->value());
2179 PushOperand(rax);
2180 CallRuntimeWithOperands(is_strict(language_mode())
2181 ? Runtime::kStoreToSuper_Strict
2182 : Runtime::kStoreToSuper_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002183}
2184
2185
2186void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2187 // Assignment to named property of super.
2188 // rax : value
2189 // stack : receiver ('this'), home_object, key
2190 DCHECK(prop != NULL);
2191
Ben Murdoch097c5b22016-05-18 11:27:45 +01002192 PushOperand(rax);
2193 CallRuntimeWithOperands(is_strict(language_mode())
2194 ? Runtime::kStoreKeyedToSuper_Strict
2195 : Runtime::kStoreKeyedToSuper_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002196}
2197
2198
2199void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2200 // Assignment to a property, using a keyed store IC.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002201 PopOperand(StoreDescriptor::NameRegister()); // Key.
2202 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002203 DCHECK(StoreDescriptor::ValueRegister().is(rax));
2204 Handle<Code> ic =
2205 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2206 EmitLoadStoreICSlot(expr->AssignmentSlot());
2207 CallIC(ic);
2208
Ben Murdochc5610432016-08-08 18:44:38 +01002209 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002210 context()->Plug(rax);
2211}
2212
2213
2214void FullCodeGenerator::CallIC(Handle<Code> code,
2215 TypeFeedbackId ast_id) {
2216 ic_total_count_++;
2217 __ call(code, RelocInfo::CODE_TARGET, ast_id);
2218}
2219
2220
2221// Code common for calls using the IC.
2222void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2223 Expression* callee = expr->expression();
2224
2225 // Get the target function.
2226 ConvertReceiverMode convert_mode;
2227 if (callee->IsVariableProxy()) {
2228 { StackValueContext context(this);
2229 EmitVariableLoad(callee->AsVariableProxy());
Ben Murdochc5610432016-08-08 18:44:38 +01002230 PrepareForBailout(callee, BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002231 }
2232 // Push undefined as receiver. This is patched in the Call builtin if it
2233 // is a sloppy mode method.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002234 PushOperand(isolate()->factory()->undefined_value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002235 convert_mode = ConvertReceiverMode::kNullOrUndefined;
2236 } else {
2237 // Load the function from the receiver.
2238 DCHECK(callee->IsProperty());
2239 DCHECK(!callee->AsProperty()->IsSuperAccess());
2240 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
2241 EmitNamedPropertyLoad(callee->AsProperty());
Ben Murdochc5610432016-08-08 18:44:38 +01002242 PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2243 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002244 // Push the target function under the receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002245 PushOperand(Operand(rsp, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002246 __ movp(Operand(rsp, kPointerSize), rax);
2247 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
2248 }
2249
2250 EmitCall(expr, convert_mode);
2251}
2252
2253
2254void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2255 Expression* callee = expr->expression();
2256 DCHECK(callee->IsProperty());
2257 Property* prop = callee->AsProperty();
2258 DCHECK(prop->IsSuperAccess());
2259 SetExpressionPosition(prop);
2260
2261 Literal* key = prop->key()->AsLiteral();
2262 DCHECK(!key->value()->IsSmi());
2263 // Load the function from the receiver.
2264 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2265 VisitForStackValue(super_ref->home_object());
2266 VisitForAccumulatorValue(super_ref->this_var());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002267 PushOperand(rax);
2268 PushOperand(rax);
2269 PushOperand(Operand(rsp, kPointerSize * 2));
2270 PushOperand(key->value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002271
2272 // Stack here:
2273 // - home_object
2274 // - this (receiver)
2275 // - this (receiver) <-- LoadFromSuper will pop here and below.
2276 // - home_object
2277 // - key
Ben Murdoch097c5b22016-05-18 11:27:45 +01002278 CallRuntimeWithOperands(Runtime::kLoadFromSuper);
Ben Murdochc5610432016-08-08 18:44:38 +01002279 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002280
2281 // Replace home_object with target function.
2282 __ movp(Operand(rsp, kPointerSize), rax);
2283
2284 // Stack here:
2285 // - target function
2286 // - this (receiver)
2287 EmitCall(expr);
2288}
2289
2290
2291// Common code for calls using the IC.
2292void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2293 Expression* key) {
2294 // Load the key.
2295 VisitForAccumulatorValue(key);
2296
2297 Expression* callee = expr->expression();
2298
2299 // Load the function from the receiver.
2300 DCHECK(callee->IsProperty());
2301 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
2302 __ Move(LoadDescriptor::NameRegister(), rax);
2303 EmitKeyedPropertyLoad(callee->AsProperty());
Ben Murdochc5610432016-08-08 18:44:38 +01002304 PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2305 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002306
2307 // Push the target function under the receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002308 PushOperand(Operand(rsp, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002309 __ movp(Operand(rsp, kPointerSize), rax);
2310
2311 EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined);
2312}
2313
2314
2315void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2316 Expression* callee = expr->expression();
2317 DCHECK(callee->IsProperty());
2318 Property* prop = callee->AsProperty();
2319 DCHECK(prop->IsSuperAccess());
2320
2321 SetExpressionPosition(prop);
2322 // Load the function from the receiver.
2323 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2324 VisitForStackValue(super_ref->home_object());
2325 VisitForAccumulatorValue(super_ref->this_var());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002326 PushOperand(rax);
2327 PushOperand(rax);
2328 PushOperand(Operand(rsp, kPointerSize * 2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002329 VisitForStackValue(prop->key());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002330
2331 // Stack here:
2332 // - home_object
2333 // - this (receiver)
2334 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2335 // - home_object
2336 // - key
Ben Murdoch097c5b22016-05-18 11:27:45 +01002337 CallRuntimeWithOperands(Runtime::kLoadKeyedFromSuper);
Ben Murdochc5610432016-08-08 18:44:38 +01002338 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002339
2340 // Replace home_object with target function.
2341 __ movp(Operand(rsp, kPointerSize), rax);
2342
2343 // Stack here:
2344 // - target function
2345 // - this (receiver)
2346 EmitCall(expr);
2347}
2348
2349
2350void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
2351 // Load the arguments.
2352 ZoneList<Expression*>* args = expr->arguments();
2353 int arg_count = args->length();
2354 for (int i = 0; i < arg_count; i++) {
2355 VisitForStackValue(args->at(i));
2356 }
2357
Ben Murdochc5610432016-08-08 18:44:38 +01002358 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
Ben Murdochda12d292016-06-02 14:46:10 +01002359 SetCallPosition(expr, expr->tail_call_mode());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002360 if (expr->tail_call_mode() == TailCallMode::kAllow) {
2361 if (FLAG_trace) {
2362 __ CallRuntime(Runtime::kTraceTailCall);
2363 }
2364 // Update profiling counters before the tail call since we will
2365 // not return to this function.
2366 EmitProfilingCounterHandlingForReturnSequence(true);
2367 }
2368 Handle<Code> ic =
2369 CodeFactory::CallIC(isolate(), arg_count, mode, expr->tail_call_mode())
2370 .code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002371 __ Move(rdx, SmiFromSlot(expr->CallFeedbackICSlot()));
2372 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
2373 // Don't assign a type feedback id to the IC, since type feedback is provided
2374 // by the vector above.
2375 CallIC(ic);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002376 OperandStackDepthDecrement(arg_count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002377
2378 RecordJSReturnSite(expr);
Ben Murdochc5610432016-08-08 18:44:38 +01002379 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002380 // Discard the function left on TOS.
2381 context()->DropAndPlug(1, rax);
2382}
2383
Ben Murdochc5610432016-08-08 18:44:38 +01002384void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) {
2385 int arg_count = expr->arguments()->length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002386 // Push copy of the first argument or undefined if it doesn't exist.
2387 if (arg_count > 0) {
2388 __ Push(Operand(rsp, arg_count * kPointerSize));
2389 } else {
2390 __ PushRoot(Heap::kUndefinedValueRootIndex);
2391 }
2392
2393 // Push the enclosing function.
2394 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
2395
2396 // Push the language mode.
2397 __ Push(Smi::FromInt(language_mode()));
2398
2399 // Push the start position of the scope the calls resides in.
2400 __ Push(Smi::FromInt(scope()->start_position()));
2401
Ben Murdochc5610432016-08-08 18:44:38 +01002402 // Push the source position of the eval call.
2403 __ Push(Smi::FromInt(expr->position()));
2404
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002405 // Do the runtime call.
2406 __ CallRuntime(Runtime::kResolvePossiblyDirectEval);
2407}
2408
2409
2410// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
2411void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
2412 VariableProxy* callee = expr->expression()->AsVariableProxy();
2413 if (callee->var()->IsLookupSlot()) {
2414 Label slow, done;
2415 SetExpressionPosition(callee);
2416 // Generate code for loading from variables potentially shadowed by
2417 // eval-introduced variables.
2418 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
2419 __ bind(&slow);
2420 // Call the runtime to find the function to call (returned in rax) and
2421 // the object holding it (returned in rdx).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002422 __ Push(callee->name());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002423 __ CallRuntime(Runtime::kLoadLookupSlotForCall);
2424 PushOperand(rax); // Function.
2425 PushOperand(rdx); // Receiver.
Ben Murdochc5610432016-08-08 18:44:38 +01002426 PrepareForBailoutForId(expr->LookupId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002427
2428 // If fast case code has been generated, emit code to push the function
2429 // and receiver and have the slow path jump around this code.
2430 if (done.is_linked()) {
2431 Label call;
2432 __ jmp(&call, Label::kNear);
2433 __ bind(&done);
2434 // Push function.
2435 __ Push(rax);
2436 // Pass undefined as the receiver, which is the WithBaseObject of a
2437 // non-object environment record. If the callee is sloppy, it will patch
2438 // it up to be the global receiver.
2439 __ PushRoot(Heap::kUndefinedValueRootIndex);
2440 __ bind(&call);
2441 }
2442 } else {
2443 VisitForStackValue(callee);
2444 // refEnv.WithBaseObject()
Ben Murdoch097c5b22016-05-18 11:27:45 +01002445 OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002446 __ PushRoot(Heap::kUndefinedValueRootIndex);
2447 }
2448}
2449
2450
2451void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
Ben Murdochc5610432016-08-08 18:44:38 +01002452 // In a call to eval, we first call Runtime_ResolvePossiblyDirectEval
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002453 // to resolve the function we need to call. Then we call the resolved
2454 // function using the given arguments.
2455 ZoneList<Expression*>* args = expr->arguments();
2456 int arg_count = args->length();
2457 PushCalleeAndWithBaseObject(expr);
2458
2459 // Push the arguments.
2460 for (int i = 0; i < arg_count; i++) {
2461 VisitForStackValue(args->at(i));
2462 }
2463
2464 // Push a copy of the function (found below the arguments) and resolve
2465 // eval.
2466 __ Push(Operand(rsp, (arg_count + 1) * kPointerSize));
Ben Murdochc5610432016-08-08 18:44:38 +01002467 EmitResolvePossiblyDirectEval(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002468
2469 // Touch up the callee.
2470 __ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
2471
Ben Murdochc5610432016-08-08 18:44:38 +01002472 PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002473
2474 SetCallPosition(expr);
2475 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
2476 __ Set(rax, arg_count);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002477 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny,
2478 expr->tail_call_mode()),
2479 RelocInfo::CODE_TARGET);
2480 OperandStackDepthDecrement(arg_count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002481 RecordJSReturnSite(expr);
Ben Murdochc5610432016-08-08 18:44:38 +01002482 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002483 context()->DropAndPlug(1, rax);
2484}
2485
2486
2487void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2488 Comment cmnt(masm_, "[ CallNew");
2489 // According to ECMA-262, section 11.2.2, page 44, the function
2490 // expression in new calls must be evaluated before the
2491 // arguments.
2492
2493 // Push constructor on the stack. If it's not a function it's used as
2494 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2495 // ignored.
2496 DCHECK(!expr->expression()->IsSuperPropertyReference());
2497 VisitForStackValue(expr->expression());
2498
2499 // Push the arguments ("left-to-right") on the stack.
2500 ZoneList<Expression*>* args = expr->arguments();
2501 int arg_count = args->length();
2502 for (int i = 0; i < arg_count; i++) {
2503 VisitForStackValue(args->at(i));
2504 }
2505
2506 // Call the construct call builtin that handles allocation and
2507 // constructor invocation.
2508 SetConstructCallPosition(expr);
2509
2510 // Load function and argument count into rdi and rax.
2511 __ Set(rax, arg_count);
2512 __ movp(rdi, Operand(rsp, arg_count * kPointerSize));
2513
2514 // Record call targets in unoptimized code, but not in the snapshot.
2515 __ EmitLoadTypeFeedbackVector(rbx);
2516 __ Move(rdx, SmiFromSlot(expr->CallNewFeedbackSlot()));
2517
2518 CallConstructStub stub(isolate());
2519 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002520 OperandStackDepthDecrement(arg_count + 1);
Ben Murdochc5610432016-08-08 18:44:38 +01002521 PrepareForBailoutForId(expr->ReturnId(), BailoutState::TOS_REGISTER);
2522 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002523 context()->Plug(rax);
2524}
2525
2526
2527void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
2528 SuperCallReference* super_call_ref =
2529 expr->expression()->AsSuperCallReference();
2530 DCHECK_NOT_NULL(super_call_ref);
2531
2532 // Push the super constructor target on the stack (may be null,
2533 // but the Construct builtin can deal with that properly).
2534 VisitForAccumulatorValue(super_call_ref->this_function_var());
2535 __ AssertFunction(result_register());
2536 __ movp(result_register(),
2537 FieldOperand(result_register(), HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002538 PushOperand(FieldOperand(result_register(), Map::kPrototypeOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002539
2540 // Push the arguments ("left-to-right") on the stack.
2541 ZoneList<Expression*>* args = expr->arguments();
2542 int arg_count = args->length();
2543 for (int i = 0; i < arg_count; i++) {
2544 VisitForStackValue(args->at(i));
2545 }
2546
2547 // Call the construct call builtin that handles allocation and
2548 // constructor invocation.
2549 SetConstructCallPosition(expr);
2550
2551 // Load new target into rdx.
2552 VisitForAccumulatorValue(super_call_ref->new_target_var());
2553 __ movp(rdx, result_register());
2554
2555 // Load function and argument count into rdi and rax.
2556 __ Set(rax, arg_count);
2557 __ movp(rdi, Operand(rsp, arg_count * kPointerSize));
2558
2559 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002560 OperandStackDepthDecrement(arg_count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002561
2562 RecordJSReturnSite(expr);
Ben Murdochc5610432016-08-08 18:44:38 +01002563 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002564 context()->Plug(rax);
2565}
2566
2567
2568void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2569 ZoneList<Expression*>* args = expr->arguments();
2570 DCHECK(args->length() == 1);
2571
2572 VisitForAccumulatorValue(args->at(0));
2573
2574 Label materialize_true, materialize_false;
2575 Label* if_true = NULL;
2576 Label* if_false = NULL;
2577 Label* fall_through = NULL;
2578 context()->PrepareTest(&materialize_true, &materialize_false,
2579 &if_true, &if_false, &fall_through);
2580
2581 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2582 __ JumpIfSmi(rax, if_true);
2583 __ jmp(if_false);
2584
2585 context()->Plug(if_true, if_false);
2586}
2587
2588
2589void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) {
2590 ZoneList<Expression*>* args = expr->arguments();
2591 DCHECK(args->length() == 1);
2592
2593 VisitForAccumulatorValue(args->at(0));
2594
2595 Label materialize_true, materialize_false;
2596 Label* if_true = NULL;
2597 Label* if_false = NULL;
2598 Label* fall_through = NULL;
2599 context()->PrepareTest(&materialize_true, &materialize_false,
2600 &if_true, &if_false, &fall_through);
2601
2602 __ JumpIfSmi(rax, if_false);
2603 __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rbx);
2604 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2605 Split(above_equal, if_true, if_false, fall_through);
2606
2607 context()->Plug(if_true, if_false);
2608}
2609
2610
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002611void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2612 ZoneList<Expression*>* args = expr->arguments();
2613 DCHECK(args->length() == 1);
2614
2615 VisitForAccumulatorValue(args->at(0));
2616
2617 Label materialize_true, materialize_false;
2618 Label* if_true = NULL;
2619 Label* if_false = NULL;
2620 Label* fall_through = NULL;
2621 context()->PrepareTest(&materialize_true, &materialize_false,
2622 &if_true, &if_false, &fall_through);
2623
2624 __ JumpIfSmi(rax, if_false);
2625 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
2626 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2627 Split(equal, if_true, if_false, fall_through);
2628
2629 context()->Plug(if_true, if_false);
2630}
2631
2632
2633void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) {
2634 ZoneList<Expression*>* args = expr->arguments();
2635 DCHECK(args->length() == 1);
2636
2637 VisitForAccumulatorValue(args->at(0));
2638
2639 Label materialize_true, materialize_false;
2640 Label* if_true = NULL;
2641 Label* if_false = NULL;
2642 Label* fall_through = NULL;
2643 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2644 &if_false, &fall_through);
2645
2646 __ JumpIfSmi(rax, if_false);
2647 __ CmpObjectType(rax, JS_TYPED_ARRAY_TYPE, rbx);
2648 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2649 Split(equal, if_true, if_false, fall_through);
2650
2651 context()->Plug(if_true, if_false);
2652}
2653
2654
2655void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2656 ZoneList<Expression*>* args = expr->arguments();
2657 DCHECK(args->length() == 1);
2658
2659 VisitForAccumulatorValue(args->at(0));
2660
2661 Label materialize_true, materialize_false;
2662 Label* if_true = NULL;
2663 Label* if_false = NULL;
2664 Label* fall_through = NULL;
2665 context()->PrepareTest(&materialize_true, &materialize_false,
2666 &if_true, &if_false, &fall_through);
2667
2668 __ JumpIfSmi(rax, if_false);
2669 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
2670 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2671 Split(equal, if_true, if_false, fall_through);
2672
2673 context()->Plug(if_true, if_false);
2674}
2675
2676
2677void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
2678 ZoneList<Expression*>* args = expr->arguments();
2679 DCHECK(args->length() == 1);
2680
2681 VisitForAccumulatorValue(args->at(0));
2682
2683 Label materialize_true, materialize_false;
2684 Label* if_true = NULL;
2685 Label* if_false = NULL;
2686 Label* fall_through = NULL;
2687 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2688 &if_false, &fall_through);
2689
2690
2691 __ JumpIfSmi(rax, if_false);
2692 __ CmpObjectType(rax, JS_PROXY_TYPE, rbx);
2693 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2694 Split(equal, if_true, if_false, fall_through);
2695
2696 context()->Plug(if_true, if_false);
2697}
2698
2699
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002700void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2701 ZoneList<Expression*>* args = expr->arguments();
2702 DCHECK(args->length() == 1);
2703 Label done, null, function, non_function_constructor;
2704
2705 VisitForAccumulatorValue(args->at(0));
2706
2707 // If the object is not a JSReceiver, we return null.
2708 __ JumpIfSmi(rax, &null, Label::kNear);
2709 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2710 __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rax);
2711 __ j(below, &null, Label::kNear);
2712
Ben Murdochda12d292016-06-02 14:46:10 +01002713 // Return 'Function' for JSFunction and JSBoundFunction objects.
2714 __ CmpInstanceType(rax, FIRST_FUNCTION_TYPE);
2715 STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE);
2716 __ j(above_equal, &function, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002717
2718 // Check if the constructor in the map is a JS function.
2719 __ GetMapConstructor(rax, rax, rbx);
2720 __ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
2721 __ j(not_equal, &non_function_constructor, Label::kNear);
2722
2723 // rax now contains the constructor function. Grab the
2724 // instance class name from there.
2725 __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
2726 __ movp(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
2727 __ jmp(&done, Label::kNear);
2728
2729 // Non-JS objects have class null.
2730 __ bind(&null);
2731 __ LoadRoot(rax, Heap::kNullValueRootIndex);
2732 __ jmp(&done, Label::kNear);
2733
2734 // Functions have class 'Function'.
2735 __ bind(&function);
2736 __ LoadRoot(rax, Heap::kFunction_stringRootIndex);
2737 __ jmp(&done, Label::kNear);
2738
2739 // Objects with a non-function constructor have class 'Object'.
2740 __ bind(&non_function_constructor);
2741 __ LoadRoot(rax, Heap::kObject_stringRootIndex);
2742
2743 // All done.
2744 __ bind(&done);
2745
2746 context()->Plug(rax);
2747}
2748
2749
2750void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
2751 ZoneList<Expression*>* args = expr->arguments();
2752 DCHECK(args->length() == 1);
2753
2754 VisitForAccumulatorValue(args->at(0)); // Load the object.
2755
2756 Label done;
2757 // If the object is a smi return the object.
2758 __ JumpIfSmi(rax, &done);
2759 // If the object is not a value type, return the object.
2760 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
2761 __ j(not_equal, &done);
2762 __ movp(rax, FieldOperand(rax, JSValue::kValueOffset));
2763
2764 __ bind(&done);
2765 context()->Plug(rax);
2766}
2767
2768
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002769void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
2770 ZoneList<Expression*>* args = expr->arguments();
2771 DCHECK(args->length() == 1);
2772
2773 VisitForAccumulatorValue(args->at(0));
2774
2775 Label done;
2776 StringCharFromCodeGenerator generator(rax, rbx);
2777 generator.GenerateFast(masm_);
2778 __ jmp(&done);
2779
2780 NopRuntimeCallHelper call_helper;
2781 generator.GenerateSlow(masm_, call_helper);
2782
2783 __ bind(&done);
2784 context()->Plug(rbx);
2785}
2786
2787
2788void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
2789 ZoneList<Expression*>* args = expr->arguments();
2790 DCHECK(args->length() == 2);
2791
2792 VisitForStackValue(args->at(0));
2793 VisitForAccumulatorValue(args->at(1));
2794
2795 Register object = rbx;
2796 Register index = rax;
2797 Register result = rdx;
2798
Ben Murdoch097c5b22016-05-18 11:27:45 +01002799 PopOperand(object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002800
2801 Label need_conversion;
2802 Label index_out_of_range;
2803 Label done;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002804 StringCharCodeAtGenerator generator(object, index, result, &need_conversion,
2805 &need_conversion, &index_out_of_range);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002806 generator.GenerateFast(masm_);
2807 __ jmp(&done);
2808
2809 __ bind(&index_out_of_range);
2810 // When the index is out of range, the spec requires us to return
2811 // NaN.
2812 __ LoadRoot(result, Heap::kNanValueRootIndex);
2813 __ jmp(&done);
2814
2815 __ bind(&need_conversion);
2816 // Move the undefined value into the result register, which will
2817 // trigger conversion.
2818 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2819 __ jmp(&done);
2820
2821 NopRuntimeCallHelper call_helper;
2822 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
2823
2824 __ bind(&done);
2825 context()->Plug(result);
2826}
2827
2828
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002829void FullCodeGenerator::EmitCall(CallRuntime* expr) {
2830 ZoneList<Expression*>* args = expr->arguments();
2831 DCHECK_LE(2, args->length());
2832 // Push target, receiver and arguments onto the stack.
2833 for (Expression* const arg : *args) {
2834 VisitForStackValue(arg);
2835 }
Ben Murdochc5610432016-08-08 18:44:38 +01002836 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002837 // Move target to rdi.
2838 int const argc = args->length() - 2;
2839 __ movp(rdi, Operand(rsp, (argc + 1) * kPointerSize));
2840 // Call the target.
2841 __ Set(rax, argc);
2842 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002843 OperandStackDepthDecrement(argc + 1);
Ben Murdochc5610432016-08-08 18:44:38 +01002844 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002845 // Discard the function left on TOS.
2846 context()->DropAndPlug(1, rax);
2847}
2848
2849
2850void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
2851 ZoneList<Expression*>* args = expr->arguments();
2852 DCHECK(args->length() == 1);
2853
2854 VisitForAccumulatorValue(args->at(0));
2855
2856 Label materialize_true, materialize_false;
2857 Label* if_true = NULL;
2858 Label* if_false = NULL;
2859 Label* fall_through = NULL;
2860 context()->PrepareTest(&materialize_true, &materialize_false,
2861 &if_true, &if_false, &fall_through);
2862
2863 __ testl(FieldOperand(rax, String::kHashFieldOffset),
2864 Immediate(String::kContainsCachedArrayIndexMask));
2865 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2866 __ j(zero, if_true);
2867 __ jmp(if_false);
2868
2869 context()->Plug(if_true, if_false);
2870}
2871
2872
2873void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
2874 ZoneList<Expression*>* args = expr->arguments();
2875 DCHECK(args->length() == 1);
2876 VisitForAccumulatorValue(args->at(0));
2877
2878 __ AssertString(rax);
2879
2880 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
2881 DCHECK(String::kHashShift >= kSmiTagSize);
2882 __ IndexFromHash(rax, rax);
2883
2884 context()->Plug(rax);
2885}
2886
2887
2888void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) {
2889 ZoneList<Expression*>* args = expr->arguments();
2890 DCHECK_EQ(1, args->length());
2891 VisitForAccumulatorValue(args->at(0));
2892 __ AssertFunction(rax);
2893 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset));
2894 __ movp(rax, FieldOperand(rax, Map::kPrototypeOffset));
2895 context()->Plug(rax);
2896}
2897
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002898void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
2899 DCHECK(expr->arguments()->length() == 0);
2900 ExternalReference debug_is_active =
2901 ExternalReference::debug_is_active_address(isolate());
2902 __ Move(kScratchRegister, debug_is_active);
2903 __ movzxbp(rax, Operand(kScratchRegister, 0));
2904 __ Integer32ToSmi(rax, rax);
2905 context()->Plug(rax);
2906}
2907
2908
2909void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
2910 ZoneList<Expression*>* args = expr->arguments();
2911 DCHECK_EQ(2, args->length());
2912 VisitForStackValue(args->at(0));
2913 VisitForStackValue(args->at(1));
2914
2915 Label runtime, done;
2916
Ben Murdochc5610432016-08-08 18:44:38 +01002917 __ Allocate(JSIteratorResult::kSize, rax, rcx, rdx, &runtime,
2918 NO_ALLOCATION_FLAGS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002919 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, rbx);
2920 __ movp(FieldOperand(rax, HeapObject::kMapOffset), rbx);
2921 __ LoadRoot(rbx, Heap::kEmptyFixedArrayRootIndex);
2922 __ movp(FieldOperand(rax, JSObject::kPropertiesOffset), rbx);
2923 __ movp(FieldOperand(rax, JSObject::kElementsOffset), rbx);
2924 __ Pop(FieldOperand(rax, JSIteratorResult::kDoneOffset));
2925 __ Pop(FieldOperand(rax, JSIteratorResult::kValueOffset));
2926 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
2927 __ jmp(&done, Label::kNear);
2928
2929 __ bind(&runtime);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002930 CallRuntimeWithOperands(Runtime::kCreateIterResultObject);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002931
2932 __ bind(&done);
2933 context()->Plug(rax);
2934}
2935
2936
2937void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
Ben Murdochda12d292016-06-02 14:46:10 +01002938 // Push function.
2939 __ LoadNativeContextSlot(expr->context_index(), rax);
2940 PushOperand(rax);
2941
2942 // Push undefined as receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002943 OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002944 __ PushRoot(Heap::kUndefinedValueRootIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002945}
2946
2947
2948void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) {
2949 ZoneList<Expression*>* args = expr->arguments();
2950 int arg_count = args->length();
2951
2952 SetCallPosition(expr);
2953 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
2954 __ Set(rax, arg_count);
2955 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined),
2956 RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002957 OperandStackDepthDecrement(arg_count + 1);
Ben Murdochc5610432016-08-08 18:44:38 +01002958 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002959}
2960
2961
2962void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
2963 switch (expr->op()) {
2964 case Token::DELETE: {
2965 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2966 Property* property = expr->expression()->AsProperty();
2967 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2968
2969 if (property != NULL) {
2970 VisitForStackValue(property->obj());
2971 VisitForStackValue(property->key());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002972 CallRuntimeWithOperands(is_strict(language_mode())
2973 ? Runtime::kDeleteProperty_Strict
2974 : Runtime::kDeleteProperty_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002975 context()->Plug(rax);
2976 } else if (proxy != NULL) {
2977 Variable* var = proxy->var();
2978 // Delete of an unqualified identifier is disallowed in strict mode but
2979 // "delete this" is allowed.
2980 bool is_this = var->HasThisName(isolate());
2981 DCHECK(is_sloppy(language_mode()) || is_this);
2982 if (var->IsUnallocatedOrGlobalSlot()) {
2983 __ movp(rax, NativeContextOperand());
2984 __ Push(ContextOperand(rax, Context::EXTENSION_INDEX));
2985 __ Push(var->name());
2986 __ CallRuntime(Runtime::kDeleteProperty_Sloppy);
2987 context()->Plug(rax);
2988 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
2989 // Result of deleting non-global variables is false. 'this' is
2990 // not really a variable, though we implement it as one. The
2991 // subexpression does not have side effects.
2992 context()->Plug(is_this);
2993 } else {
2994 // Non-global variable. Call the runtime to try to delete from the
2995 // context where the variable was introduced.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002996 __ Push(var->name());
2997 __ CallRuntime(Runtime::kDeleteLookupSlot);
2998 context()->Plug(rax);
2999 }
3000 } else {
3001 // Result of deleting non-property, non-variable reference is true.
3002 // The subexpression may have side effects.
3003 VisitForEffect(expr->expression());
3004 context()->Plug(true);
3005 }
3006 break;
3007 }
3008
3009 case Token::VOID: {
3010 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3011 VisitForEffect(expr->expression());
3012 context()->Plug(Heap::kUndefinedValueRootIndex);
3013 break;
3014 }
3015
3016 case Token::NOT: {
3017 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
3018 if (context()->IsEffect()) {
3019 // Unary NOT has no side effects so it's only necessary to visit the
3020 // subexpression. Match the optimizing compiler by not branching.
3021 VisitForEffect(expr->expression());
3022 } else if (context()->IsTest()) {
3023 const TestContext* test = TestContext::cast(context());
3024 // The labels are swapped for the recursive call.
3025 VisitForControl(expr->expression(),
3026 test->false_label(),
3027 test->true_label(),
3028 test->fall_through());
3029 context()->Plug(test->true_label(), test->false_label());
3030 } else {
3031 // We handle value contexts explicitly rather than simply visiting
3032 // for control and plugging the control flow into the context,
3033 // because we need to prepare a pair of extra administrative AST ids
3034 // for the optimizing compiler.
3035 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
3036 Label materialize_true, materialize_false, done;
3037 VisitForControl(expr->expression(),
3038 &materialize_false,
3039 &materialize_true,
3040 &materialize_true);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003041 if (!context()->IsAccumulatorValue()) OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003042 __ bind(&materialize_true);
Ben Murdochc5610432016-08-08 18:44:38 +01003043 PrepareForBailoutForId(expr->MaterializeTrueId(),
3044 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003045 if (context()->IsAccumulatorValue()) {
3046 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
3047 } else {
3048 __ PushRoot(Heap::kTrueValueRootIndex);
3049 }
3050 __ jmp(&done, Label::kNear);
3051 __ bind(&materialize_false);
Ben Murdochc5610432016-08-08 18:44:38 +01003052 PrepareForBailoutForId(expr->MaterializeFalseId(),
3053 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003054 if (context()->IsAccumulatorValue()) {
3055 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
3056 } else {
3057 __ PushRoot(Heap::kFalseValueRootIndex);
3058 }
3059 __ bind(&done);
3060 }
3061 break;
3062 }
3063
3064 case Token::TYPEOF: {
3065 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
3066 {
3067 AccumulatorValueContext context(this);
3068 VisitForTypeofValue(expr->expression());
3069 }
3070 __ movp(rbx, rax);
3071 TypeofStub typeof_stub(isolate());
3072 __ CallStub(&typeof_stub);
3073 context()->Plug(rax);
3074 break;
3075 }
3076
3077 default:
3078 UNREACHABLE();
3079 }
3080}
3081
3082
3083void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3084 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
3085
3086 Comment cmnt(masm_, "[ CountOperation");
3087
3088 Property* prop = expr->expression()->AsProperty();
3089 LhsKind assign_type = Property::GetAssignType(prop);
3090
3091 // Evaluate expression and get value.
3092 if (assign_type == VARIABLE) {
3093 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
3094 AccumulatorValueContext context(this);
3095 EmitVariableLoad(expr->expression()->AsVariableProxy());
3096 } else {
3097 // Reserve space for result of postfix operation.
3098 if (expr->is_postfix() && !context()->IsEffect()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003099 PushOperand(Smi::FromInt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003100 }
3101 switch (assign_type) {
3102 case NAMED_PROPERTY: {
3103 VisitForStackValue(prop->obj());
3104 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
3105 EmitNamedPropertyLoad(prop);
3106 break;
3107 }
3108
3109 case NAMED_SUPER_PROPERTY: {
3110 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
3111 VisitForAccumulatorValue(
3112 prop->obj()->AsSuperPropertyReference()->home_object());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003113 PushOperand(result_register());
3114 PushOperand(MemOperand(rsp, kPointerSize));
3115 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003116 EmitNamedSuperPropertyLoad(prop);
3117 break;
3118 }
3119
3120 case KEYED_SUPER_PROPERTY: {
3121 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
3122 VisitForStackValue(
3123 prop->obj()->AsSuperPropertyReference()->home_object());
3124 VisitForAccumulatorValue(prop->key());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003125 PushOperand(result_register());
3126 PushOperand(MemOperand(rsp, 2 * kPointerSize));
3127 PushOperand(MemOperand(rsp, 2 * kPointerSize));
3128 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003129 EmitKeyedSuperPropertyLoad(prop);
3130 break;
3131 }
3132
3133 case KEYED_PROPERTY: {
3134 VisitForStackValue(prop->obj());
3135 VisitForStackValue(prop->key());
3136 // Leave receiver on stack
3137 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
3138 // Copy of key, needed for later store.
3139 __ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
3140 EmitKeyedPropertyLoad(prop);
3141 break;
3142 }
3143
3144 case VARIABLE:
3145 UNREACHABLE();
3146 }
3147 }
3148
3149 // We need a second deoptimization point after loading the value
3150 // in case evaluating the property load my have a side effect.
3151 if (assign_type == VARIABLE) {
Ben Murdochc5610432016-08-08 18:44:38 +01003152 PrepareForBailout(expr->expression(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003153 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01003154 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003155 }
3156
3157 // Inline smi case if we are in a loop.
3158 Label done, stub_call;
3159 JumpPatchSite patch_site(masm_);
3160 if (ShouldInlineSmiCase(expr->op())) {
3161 Label slow;
3162 patch_site.EmitJumpIfNotSmi(rax, &slow, Label::kNear);
3163
3164 // Save result for postfix expressions.
3165 if (expr->is_postfix()) {
3166 if (!context()->IsEffect()) {
3167 // Save the result on the stack. If we have a named or keyed property
3168 // we store the result under the receiver that is currently on top
3169 // of the stack.
3170 switch (assign_type) {
3171 case VARIABLE:
3172 __ Push(rax);
3173 break;
3174 case NAMED_PROPERTY:
3175 __ movp(Operand(rsp, kPointerSize), rax);
3176 break;
3177 case NAMED_SUPER_PROPERTY:
3178 __ movp(Operand(rsp, 2 * kPointerSize), rax);
3179 break;
3180 case KEYED_PROPERTY:
3181 __ movp(Operand(rsp, 2 * kPointerSize), rax);
3182 break;
3183 case KEYED_SUPER_PROPERTY:
3184 __ movp(Operand(rsp, 3 * kPointerSize), rax);
3185 break;
3186 }
3187 }
3188 }
3189
3190 SmiOperationConstraints constraints =
3191 SmiOperationConstraint::kPreserveSourceRegister |
3192 SmiOperationConstraint::kBailoutOnNoOverflow;
3193 if (expr->op() == Token::INC) {
3194 __ SmiAddConstant(rax, rax, Smi::FromInt(1), constraints, &done,
3195 Label::kNear);
3196 } else {
3197 __ SmiSubConstant(rax, rax, Smi::FromInt(1), constraints, &done,
3198 Label::kNear);
3199 }
3200 __ jmp(&stub_call, Label::kNear);
3201 __ bind(&slow);
3202 }
Ben Murdochda12d292016-06-02 14:46:10 +01003203
3204 // Convert old value into a number.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003205 __ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
Ben Murdochc5610432016-08-08 18:44:38 +01003206 PrepareForBailoutForId(expr->ToNumberId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003207
3208 // Save result for postfix expressions.
3209 if (expr->is_postfix()) {
3210 if (!context()->IsEffect()) {
3211 // Save the result on the stack. If we have a named or keyed property
3212 // we store the result under the receiver that is currently on top
3213 // of the stack.
3214 switch (assign_type) {
3215 case VARIABLE:
Ben Murdoch097c5b22016-05-18 11:27:45 +01003216 PushOperand(rax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003217 break;
3218 case NAMED_PROPERTY:
3219 __ movp(Operand(rsp, kPointerSize), rax);
3220 break;
3221 case NAMED_SUPER_PROPERTY:
3222 __ movp(Operand(rsp, 2 * kPointerSize), rax);
3223 break;
3224 case KEYED_PROPERTY:
3225 __ movp(Operand(rsp, 2 * kPointerSize), rax);
3226 break;
3227 case KEYED_SUPER_PROPERTY:
3228 __ movp(Operand(rsp, 3 * kPointerSize), rax);
3229 break;
3230 }
3231 }
3232 }
3233
3234 SetExpressionPosition(expr);
3235
3236 // Call stub for +1/-1.
3237 __ bind(&stub_call);
3238 __ movp(rdx, rax);
3239 __ Move(rax, Smi::FromInt(1));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003240 Handle<Code> code =
3241 CodeFactory::BinaryOpIC(isolate(), expr->binary_op()).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003242 CallIC(code, expr->CountBinOpFeedbackId());
3243 patch_site.EmitPatchInfo();
3244 __ bind(&done);
3245
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003246 // Store the value returned in rax.
3247 switch (assign_type) {
3248 case VARIABLE:
3249 if (expr->is_postfix()) {
3250 // Perform the assignment as if via '='.
3251 { EffectContext context(this);
3252 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3253 Token::ASSIGN, expr->CountSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01003254 PrepareForBailoutForId(expr->AssignmentId(),
3255 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003256 context.Plug(rax);
3257 }
3258 // For all contexts except kEffect: We have the result on
3259 // top of the stack.
3260 if (!context()->IsEffect()) {
3261 context()->PlugTOS();
3262 }
3263 } else {
3264 // Perform the assignment as if via '='.
3265 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3266 Token::ASSIGN, expr->CountSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01003267 PrepareForBailoutForId(expr->AssignmentId(),
3268 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003269 context()->Plug(rax);
3270 }
3271 break;
3272 case NAMED_PROPERTY: {
3273 __ Move(StoreDescriptor::NameRegister(),
3274 prop->key()->AsLiteral()->value());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003275 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003276 EmitLoadStoreICSlot(expr->CountSlot());
3277 CallStoreIC();
Ben Murdochc5610432016-08-08 18:44:38 +01003278 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003279 if (expr->is_postfix()) {
3280 if (!context()->IsEffect()) {
3281 context()->PlugTOS();
3282 }
3283 } else {
3284 context()->Plug(rax);
3285 }
3286 break;
3287 }
3288 case NAMED_SUPER_PROPERTY: {
3289 EmitNamedSuperPropertyStore(prop);
3290 if (expr->is_postfix()) {
3291 if (!context()->IsEffect()) {
3292 context()->PlugTOS();
3293 }
3294 } else {
3295 context()->Plug(rax);
3296 }
3297 break;
3298 }
3299 case KEYED_SUPER_PROPERTY: {
3300 EmitKeyedSuperPropertyStore(prop);
3301 if (expr->is_postfix()) {
3302 if (!context()->IsEffect()) {
3303 context()->PlugTOS();
3304 }
3305 } else {
3306 context()->Plug(rax);
3307 }
3308 break;
3309 }
3310 case KEYED_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003311 PopOperand(StoreDescriptor::NameRegister());
3312 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003313 Handle<Code> ic =
3314 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
3315 EmitLoadStoreICSlot(expr->CountSlot());
3316 CallIC(ic);
Ben Murdochc5610432016-08-08 18:44:38 +01003317 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003318 if (expr->is_postfix()) {
3319 if (!context()->IsEffect()) {
3320 context()->PlugTOS();
3321 }
3322 } else {
3323 context()->Plug(rax);
3324 }
3325 break;
3326 }
3327 }
3328}
3329
3330
3331void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3332 Expression* sub_expr,
3333 Handle<String> check) {
3334 Label materialize_true, materialize_false;
3335 Label* if_true = NULL;
3336 Label* if_false = NULL;
3337 Label* fall_through = NULL;
3338 context()->PrepareTest(&materialize_true, &materialize_false,
3339 &if_true, &if_false, &fall_through);
3340
3341 { AccumulatorValueContext context(this);
3342 VisitForTypeofValue(sub_expr);
3343 }
3344 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3345
3346 Factory* factory = isolate()->factory();
3347 if (String::Equals(check, factory->number_string())) {
3348 __ JumpIfSmi(rax, if_true);
3349 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset));
3350 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
3351 Split(equal, if_true, if_false, fall_through);
3352 } else if (String::Equals(check, factory->string_string())) {
3353 __ JumpIfSmi(rax, if_false);
3354 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
3355 Split(below, if_true, if_false, fall_through);
3356 } else if (String::Equals(check, factory->symbol_string())) {
3357 __ JumpIfSmi(rax, if_false);
3358 __ CmpObjectType(rax, SYMBOL_TYPE, rdx);
3359 Split(equal, if_true, if_false, fall_through);
3360 } else if (String::Equals(check, factory->boolean_string())) {
3361 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
3362 __ j(equal, if_true);
3363 __ CompareRoot(rax, Heap::kFalseValueRootIndex);
3364 Split(equal, if_true, if_false, fall_through);
3365 } else if (String::Equals(check, factory->undefined_string())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003366 __ CompareRoot(rax, Heap::kNullValueRootIndex);
3367 __ j(equal, if_false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003368 __ JumpIfSmi(rax, if_false);
3369 // Check for undetectable objects => true.
3370 __ movp(rdx, FieldOperand(rax, HeapObject::kMapOffset));
3371 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
3372 Immediate(1 << Map::kIsUndetectable));
3373 Split(not_zero, if_true, if_false, fall_through);
3374 } else if (String::Equals(check, factory->function_string())) {
3375 __ JumpIfSmi(rax, if_false);
3376 // Check for callable and not undetectable objects => true.
3377 __ movp(rdx, FieldOperand(rax, HeapObject::kMapOffset));
3378 __ movzxbl(rdx, FieldOperand(rdx, Map::kBitFieldOffset));
3379 __ andb(rdx,
3380 Immediate((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
3381 __ cmpb(rdx, Immediate(1 << Map::kIsCallable));
3382 Split(equal, if_true, if_false, fall_through);
3383 } else if (String::Equals(check, factory->object_string())) {
3384 __ JumpIfSmi(rax, if_false);
3385 __ CompareRoot(rax, Heap::kNullValueRootIndex);
3386 __ j(equal, if_true);
3387 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
3388 __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rdx);
3389 __ j(below, if_false);
3390 // Check for callable or undetectable objects => false.
3391 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
3392 Immediate((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
3393 Split(zero, if_true, if_false, fall_through);
3394// clang-format off
3395#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
3396 } else if (String::Equals(check, factory->type##_string())) { \
3397 __ JumpIfSmi(rax, if_false); \
3398 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset)); \
3399 __ CompareRoot(rax, Heap::k##Type##MapRootIndex); \
3400 Split(equal, if_true, if_false, fall_through);
3401 SIMD128_TYPES(SIMD128_TYPE)
3402#undef SIMD128_TYPE
3403 // clang-format on
3404 } else {
3405 if (if_false != fall_through) __ jmp(if_false);
3406 }
3407 context()->Plug(if_true, if_false);
3408}
3409
3410
3411void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3412 Comment cmnt(masm_, "[ CompareOperation");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003413
3414 // First we try a fast inlined version of the compare when one of
3415 // the operands is a literal.
3416 if (TryLiteralCompare(expr)) return;
3417
3418 // Always perform the comparison for its control flow. Pack the result
3419 // into the expression's context after the comparison is performed.
3420 Label materialize_true, materialize_false;
3421 Label* if_true = NULL;
3422 Label* if_false = NULL;
3423 Label* fall_through = NULL;
3424 context()->PrepareTest(&materialize_true, &materialize_false,
3425 &if_true, &if_false, &fall_through);
3426
3427 Token::Value op = expr->op();
3428 VisitForStackValue(expr->left());
3429 switch (op) {
3430 case Token::IN:
3431 VisitForStackValue(expr->right());
Ben Murdochc5610432016-08-08 18:44:38 +01003432 SetExpressionPosition(expr);
3433 EmitHasProperty();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003434 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3435 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
3436 Split(equal, if_true, if_false, fall_through);
3437 break;
3438
3439 case Token::INSTANCEOF: {
3440 VisitForAccumulatorValue(expr->right());
Ben Murdochc5610432016-08-08 18:44:38 +01003441 SetExpressionPosition(expr);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003442 PopOperand(rdx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003443 InstanceOfStub stub(isolate());
3444 __ CallStub(&stub);
3445 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3446 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
3447 Split(equal, if_true, if_false, fall_through);
3448 break;
3449 }
3450
3451 default: {
3452 VisitForAccumulatorValue(expr->right());
Ben Murdochc5610432016-08-08 18:44:38 +01003453 SetExpressionPosition(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003454 Condition cc = CompareIC::ComputeCondition(op);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003455 PopOperand(rdx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003456
3457 bool inline_smi_code = ShouldInlineSmiCase(op);
3458 JumpPatchSite patch_site(masm_);
3459 if (inline_smi_code) {
3460 Label slow_case;
3461 __ movp(rcx, rdx);
3462 __ orp(rcx, rax);
3463 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
3464 __ cmpp(rdx, rax);
3465 Split(cc, if_true, if_false, NULL);
3466 __ bind(&slow_case);
3467 }
3468
Ben Murdoch097c5b22016-05-18 11:27:45 +01003469 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003470 CallIC(ic, expr->CompareOperationFeedbackId());
3471 patch_site.EmitPatchInfo();
3472
3473 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3474 __ testp(rax, rax);
3475 Split(cc, if_true, if_false, fall_through);
3476 }
3477 }
3478
3479 // Convert the result of the comparison into one expected for this
3480 // expression's context.
3481 context()->Plug(if_true, if_false);
3482}
3483
3484
3485void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
3486 Expression* sub_expr,
3487 NilValue nil) {
3488 Label materialize_true, materialize_false;
3489 Label* if_true = NULL;
3490 Label* if_false = NULL;
3491 Label* fall_through = NULL;
3492 context()->PrepareTest(&materialize_true, &materialize_false,
3493 &if_true, &if_false, &fall_through);
3494
3495 VisitForAccumulatorValue(sub_expr);
3496 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3497 if (expr->op() == Token::EQ_STRICT) {
3498 Heap::RootListIndex nil_value = nil == kNullValue ?
3499 Heap::kNullValueRootIndex :
3500 Heap::kUndefinedValueRootIndex;
3501 __ CompareRoot(rax, nil_value);
3502 Split(equal, if_true, if_false, fall_through);
3503 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01003504 __ JumpIfSmi(rax, if_false);
3505 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset));
3506 __ testb(FieldOperand(rax, Map::kBitFieldOffset),
3507 Immediate(1 << Map::kIsUndetectable));
3508 Split(not_zero, if_true, if_false, fall_through);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003509 }
3510 context()->Plug(if_true, if_false);
3511}
3512
3513
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003514Register FullCodeGenerator::result_register() {
3515 return rax;
3516}
3517
3518
3519Register FullCodeGenerator::context_register() {
3520 return rsi;
3521}
3522
Ben Murdochda12d292016-06-02 14:46:10 +01003523void FullCodeGenerator::LoadFromFrameField(int frame_offset, Register value) {
3524 DCHECK(IsAligned(frame_offset, kPointerSize));
3525 __ movp(value, Operand(rbp, frame_offset));
3526}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003527
3528void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
3529 DCHECK(IsAligned(frame_offset, kPointerSize));
3530 __ movp(Operand(rbp, frame_offset), value);
3531}
3532
3533
3534void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
3535 __ movp(dst, ContextOperand(rsi, context_index));
3536}
3537
3538
3539void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
3540 Scope* closure_scope = scope()->ClosureScope();
3541 if (closure_scope->is_script_scope() ||
3542 closure_scope->is_module_scope()) {
3543 // Contexts nested in the native context have a canonical empty function
3544 // as their closure, not the anonymous closure containing the global
3545 // code.
3546 __ movp(rax, NativeContextOperand());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003547 PushOperand(ContextOperand(rax, Context::CLOSURE_INDEX));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003548 } else if (closure_scope->is_eval_scope()) {
3549 // Contexts created by a call to eval have the same closure as the
3550 // context calling eval, not the anonymous closure containing the eval
3551 // code. Fetch it from the context.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003552 PushOperand(ContextOperand(rsi, Context::CLOSURE_INDEX));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003553 } else {
3554 DCHECK(closure_scope->is_function_scope());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003555 PushOperand(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003556 }
3557}
3558
3559
3560// ----------------------------------------------------------------------------
3561// Non-local control flow support.
3562
3563
3564void FullCodeGenerator::EnterFinallyBlock() {
3565 DCHECK(!result_register().is(rdx));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003566
3567 // Store pending message while executing finally block.
3568 ExternalReference pending_message_obj =
3569 ExternalReference::address_of_pending_message_obj(isolate());
3570 __ Load(rdx, pending_message_obj);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003571 PushOperand(rdx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003572
3573 ClearPendingMessage();
3574}
3575
3576
3577void FullCodeGenerator::ExitFinallyBlock() {
3578 DCHECK(!result_register().is(rdx));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003579 // Restore pending message from stack.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003580 PopOperand(rdx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003581 ExternalReference pending_message_obj =
3582 ExternalReference::address_of_pending_message_obj(isolate());
3583 __ Store(pending_message_obj, rdx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003584}
3585
3586
3587void FullCodeGenerator::ClearPendingMessage() {
3588 DCHECK(!result_register().is(rdx));
3589 ExternalReference pending_message_obj =
3590 ExternalReference::address_of_pending_message_obj(isolate());
3591 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
3592 __ Store(pending_message_obj, rdx);
3593}
3594
3595
Ben Murdoch097c5b22016-05-18 11:27:45 +01003596void FullCodeGenerator::DeferredCommands::EmitCommands() {
3597 __ Pop(result_register()); // Restore the accumulator.
3598 __ Pop(rdx); // Get the token.
3599 for (DeferredCommand cmd : commands_) {
3600 Label skip;
3601 __ SmiCompare(rdx, Smi::FromInt(cmd.token));
3602 __ j(not_equal, &skip);
3603 switch (cmd.command) {
3604 case kReturn:
3605 codegen_->EmitUnwindAndReturn();
3606 break;
3607 case kThrow:
3608 __ Push(result_register());
3609 __ CallRuntime(Runtime::kReThrow);
3610 break;
3611 case kContinue:
3612 codegen_->EmitContinue(cmd.target);
3613 break;
3614 case kBreak:
3615 codegen_->EmitBreak(cmd.target);
3616 break;
3617 }
3618 __ bind(&skip);
3619 }
3620}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003621
3622#undef __
3623
3624
3625static const byte kJnsInstruction = 0x79;
3626static const byte kNopByteOne = 0x66;
3627static const byte kNopByteTwo = 0x90;
3628#ifdef DEBUG
3629static const byte kCallInstruction = 0xe8;
3630#endif
3631
3632
3633void BackEdgeTable::PatchAt(Code* unoptimized_code,
3634 Address pc,
3635 BackEdgeState target_state,
3636 Code* replacement_code) {
3637 Address call_target_address = pc - kIntSize;
3638 Address jns_instr_address = call_target_address - 3;
3639 Address jns_offset_address = call_target_address - 2;
3640
3641 switch (target_state) {
3642 case INTERRUPT:
3643 // sub <profiling_counter>, <delta> ;; Not changed
3644 // jns ok
3645 // call <interrupt stub>
3646 // ok:
3647 *jns_instr_address = kJnsInstruction;
3648 *jns_offset_address = kJnsOffset;
3649 break;
3650 case ON_STACK_REPLACEMENT:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003651 // sub <profiling_counter>, <delta> ;; Not changed
3652 // nop
3653 // nop
3654 // call <on-stack replacment>
3655 // ok:
3656 *jns_instr_address = kNopByteOne;
3657 *jns_offset_address = kNopByteTwo;
3658 break;
3659 }
3660
3661 Assembler::set_target_address_at(unoptimized_code->GetIsolate(),
3662 call_target_address, unoptimized_code,
3663 replacement_code->entry());
3664 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
3665 unoptimized_code, call_target_address, replacement_code);
3666}
3667
3668
3669BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
3670 Isolate* isolate,
3671 Code* unoptimized_code,
3672 Address pc) {
3673 Address call_target_address = pc - kIntSize;
3674 Address jns_instr_address = call_target_address - 3;
3675 DCHECK_EQ(kCallInstruction, *(call_target_address - 1));
3676
3677 if (*jns_instr_address == kJnsInstruction) {
3678 DCHECK_EQ(kJnsOffset, *(call_target_address - 2));
3679 DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(),
3680 Assembler::target_address_at(call_target_address,
3681 unoptimized_code));
3682 return INTERRUPT;
3683 }
3684
3685 DCHECK_EQ(kNopByteOne, *jns_instr_address);
3686 DCHECK_EQ(kNopByteTwo, *(call_target_address - 2));
3687
Ben Murdochda12d292016-06-02 14:46:10 +01003688 DCHECK_EQ(
3689 isolate->builtins()->OnStackReplacement()->entry(),
3690 Assembler::target_address_at(call_target_address, unoptimized_code));
3691 return ON_STACK_REPLACEMENT;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003692}
3693
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003694} // namespace internal
3695} // namespace v8
3696
3697#endif // V8_TARGET_ARCH_X64