blob: a58f17384fadc06ce0299c806c61b244fa7d40e6 [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_MIPS64
6
7// Note on Mips implementation:
8//
9// The result_register() for mips is the 'v0' register, which is defined
10// by the ABI to contain function return values. However, the first
11// parameter to a function is defined to be 'a0'. So there are many
12// places where we have to move a previous result in v0 to a0 for the
13// next call: mov(a0, v0). This is not needed on the other architectures.
14
15#include "src/ast/scopes.h"
16#include "src/code-factory.h"
17#include "src/code-stubs.h"
18#include "src/codegen.h"
19#include "src/debug/debug.h"
20#include "src/full-codegen/full-codegen.h"
21#include "src/ic/ic.h"
22#include "src/parsing/parser.h"
23
24#include "src/mips64/code-stubs-mips64.h"
25#include "src/mips64/macro-assembler-mips64.h"
26
27namespace v8 {
28namespace internal {
29
Ben Murdoch097c5b22016-05-18 11:27:45 +010030#define __ ACCESS_MASM(masm())
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031
32// A patch site is a location in the code which it is possible to patch. This
33// class has a number of methods to emit the code which is patchable and the
34// method EmitPatchInfo to record a marker back to the patchable code. This
35// marker is a andi zero_reg, rx, #yyyy instruction, and rx * 0x0000ffff + yyyy
36// (raw 16 bit immediate value is used) is the delta from the pc to the first
37// instruction of the patchable code.
38// The marker instruction is effectively a NOP (dest is zero_reg) and will
39// never be emitted by normal code.
40class JumpPatchSite BASE_EMBEDDED {
41 public:
42 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
43#ifdef DEBUG
44 info_emitted_ = false;
45#endif
46 }
47
48 ~JumpPatchSite() {
49 DCHECK(patch_site_.is_bound() == info_emitted_);
50 }
51
52 // When initially emitting this ensure that a jump is always generated to skip
53 // the inlined smi code.
54 void EmitJumpIfNotSmi(Register reg, Label* target) {
55 DCHECK(!patch_site_.is_bound() && !info_emitted_);
56 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
57 __ bind(&patch_site_);
58 __ andi(at, reg, 0);
59 // Always taken before patched.
60 __ BranchShort(target, eq, at, Operand(zero_reg));
61 }
62
63 // When initially emitting this ensure that a jump is never generated to skip
64 // the inlined smi code.
65 void EmitJumpIfSmi(Register reg, Label* target) {
66 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
67 DCHECK(!patch_site_.is_bound() && !info_emitted_);
68 __ bind(&patch_site_);
69 __ andi(at, reg, 0);
70 // Never taken before patched.
71 __ BranchShort(target, ne, at, Operand(zero_reg));
72 }
73
74 void EmitPatchInfo() {
75 if (patch_site_.is_bound()) {
76 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
77 Register reg = Register::from_code(delta_to_patch_site / kImm16Mask);
78 __ andi(zero_reg, reg, delta_to_patch_site % kImm16Mask);
79#ifdef DEBUG
80 info_emitted_ = true;
81#endif
82 } else {
83 __ nop(); // Signals no inlined code.
84 }
85 }
86
87 private:
Ben Murdoch097c5b22016-05-18 11:27:45 +010088 MacroAssembler* masm() { return masm_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 MacroAssembler* masm_;
90 Label patch_site_;
91#ifdef DEBUG
92 bool info_emitted_;
93#endif
94};
95
96
97// Generate code for a JS function. On entry to the function the receiver
98// and arguments have been pushed on the stack left to right. The actual
99// argument count matches the formal parameter count expected by the
100// function.
101//
102// The live registers are:
103// o a1: the JS function object being called (i.e. ourselves)
104// o a3: the new target value
105// o cp: our context
106// o fp: our caller's frame pointer
107// o sp: stack pointer
108// o ra: return address
109//
110// The function builds a JS frame. Please see JavaScriptFrameConstants in
111// frames-mips.h for its layout.
112void FullCodeGenerator::Generate() {
113 CompilationInfo* info = info_;
114 profiling_counter_ = isolate()->factory()->NewCell(
115 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
116 SetFunctionPosition(literal());
117 Comment cmnt(masm_, "[ function compiled by full code generator");
118
119 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
120
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000121 if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) {
122 int receiver_offset = info->scope()->num_parameters() * kPointerSize;
123 __ ld(a2, MemOperand(sp, receiver_offset));
124 __ AssertNotSmi(a2);
125 __ GetObjectType(a2, a2, a2);
126 __ Check(ge, kSloppyFunctionExpectsJSReceiverReceiver, a2,
127 Operand(FIRST_JS_RECEIVER_TYPE));
128 }
129
130 // Open a frame scope to indicate that there is a frame on the stack. The
131 // MANUAL indicates that the scope shouldn't actually generate code to set up
132 // the frame (that is done below).
133 FrameScope frame_scope(masm_, StackFrame::MANUAL);
134 info->set_prologue_offset(masm_->pc_offset());
135 __ Prologue(info->GeneratePreagedPrologue());
136
137 { Comment cmnt(masm_, "[ Allocate locals");
138 int locals_count = info->scope()->num_stack_slots();
139 // Generators allocate locals, if any, in context slots.
140 DCHECK(!IsGeneratorFunction(info->literal()->kind()) || locals_count == 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100141 OperandStackDepthIncrement(locals_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142 if (locals_count > 0) {
143 if (locals_count >= 128) {
144 Label ok;
145 __ Dsubu(t1, sp, Operand(locals_count * kPointerSize));
146 __ LoadRoot(a2, Heap::kRealStackLimitRootIndex);
147 __ Branch(&ok, hs, t1, Operand(a2));
148 __ CallRuntime(Runtime::kThrowStackOverflow);
149 __ bind(&ok);
150 }
151 __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
152 int kMaxPushes = FLAG_optimize_for_size ? 4 : 32;
153 if (locals_count >= kMaxPushes) {
154 int loop_iterations = locals_count / kMaxPushes;
155 __ li(a2, Operand(loop_iterations));
156 Label loop_header;
157 __ bind(&loop_header);
158 // Do pushes.
159 __ Dsubu(sp, sp, Operand(kMaxPushes * kPointerSize));
160 for (int i = 0; i < kMaxPushes; i++) {
161 __ sd(t1, MemOperand(sp, i * kPointerSize));
162 }
163 // Continue loop if not done.
164 __ Dsubu(a2, a2, Operand(1));
165 __ Branch(&loop_header, ne, a2, Operand(zero_reg));
166 }
167 int remaining = locals_count % kMaxPushes;
168 // Emit the remaining pushes.
169 __ Dsubu(sp, sp, Operand(remaining * kPointerSize));
170 for (int i = 0; i < remaining; i++) {
171 __ sd(t1, MemOperand(sp, i * kPointerSize));
172 }
173 }
174 }
175
176 bool function_in_register_a1 = true;
177
178 // Possibly allocate a local context.
179 if (info->scope()->num_heap_slots() > 0) {
180 Comment cmnt(masm_, "[ Allocate context");
181 // Argument to NewContext is the function, which is still in a1.
182 bool need_write_barrier = true;
183 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
184 if (info->scope()->is_script_scope()) {
185 __ push(a1);
186 __ Push(info->scope()->GetScopeInfo(info->isolate()));
187 __ CallRuntime(Runtime::kNewScriptContext);
Ben Murdochc5610432016-08-08 18:44:38 +0100188 PrepareForBailoutForId(BailoutId::ScriptContext(),
189 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 // The new target value is not used, clobbering is safe.
191 DCHECK_NULL(info->scope()->new_target_var());
192 } else {
193 if (info->scope()->new_target_var() != nullptr) {
194 __ push(a3); // Preserve new target.
195 }
196 if (slots <= FastNewContextStub::kMaximumSlots) {
197 FastNewContextStub stub(isolate(), slots);
198 __ CallStub(&stub);
199 // Result of FastNewContextStub is always in new space.
200 need_write_barrier = false;
201 } else {
202 __ push(a1);
203 __ CallRuntime(Runtime::kNewFunctionContext);
204 }
205 if (info->scope()->new_target_var() != nullptr) {
206 __ pop(a3); // Restore new target.
207 }
208 }
209 function_in_register_a1 = false;
210 // Context is returned in v0. It replaces the context passed to us.
211 // It's saved in the stack and kept live in cp.
212 __ mov(cp, v0);
213 __ sd(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
214 // Copy any necessary parameters into the context.
215 int num_parameters = info->scope()->num_parameters();
216 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
217 for (int i = first_parameter; i < num_parameters; i++) {
218 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
219 if (var->IsContextSlot()) {
220 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
221 (num_parameters - 1 - i) * kPointerSize;
222 // Load parameter from stack.
223 __ ld(a0, MemOperand(fp, parameter_offset));
224 // Store it in the context.
225 MemOperand target = ContextMemOperand(cp, var->index());
226 __ sd(a0, target);
227
228 // Update the write barrier.
229 if (need_write_barrier) {
230 __ RecordWriteContextSlot(cp, target.offset(), a0, a2,
231 kRAHasBeenSaved, kDontSaveFPRegs);
232 } else if (FLAG_debug_code) {
233 Label done;
234 __ JumpIfInNewSpace(cp, a0, &done);
235 __ Abort(kExpectedNewSpaceObject);
236 __ bind(&done);
237 }
238 }
239 }
240 }
241
242 // Register holding this function and new target are both trashed in case we
243 // bailout here. But since that can happen only when new target is not used
244 // and we allocate a context, the value of |function_in_register| is correct.
Ben Murdochc5610432016-08-08 18:44:38 +0100245 PrepareForBailoutForId(BailoutId::FunctionContext(),
246 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247
248 // Possibly set up a local binding to the this function which is used in
249 // derived constructors with super calls.
250 Variable* this_function_var = scope()->this_function_var();
251 if (this_function_var != nullptr) {
252 Comment cmnt(masm_, "[ This function");
253 if (!function_in_register_a1) {
254 __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
255 // The write barrier clobbers register again, keep it marked as such.
256 }
257 SetVar(this_function_var, a1, a0, a2);
258 }
259
260 Variable* new_target_var = scope()->new_target_var();
261 if (new_target_var != nullptr) {
262 Comment cmnt(masm_, "[ new.target");
263 SetVar(new_target_var, a3, a0, a2);
264 }
265
266 // Possibly allocate RestParameters
267 int rest_index;
268 Variable* rest_param = scope()->rest_parameter(&rest_index);
269 if (rest_param) {
270 Comment cmnt(masm_, "[ Allocate rest parameter array");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100271 if (!function_in_register_a1) {
272 __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
273 }
274 FastNewRestParameterStub stub(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000275 __ CallStub(&stub);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100276 function_in_register_a1 = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000277 SetVar(rest_param, v0, a1, a2);
278 }
279
280 Variable* arguments = scope()->arguments();
281 if (arguments != NULL) {
282 // Function uses arguments object.
283 Comment cmnt(masm_, "[ Allocate arguments object");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000284 if (!function_in_register_a1) {
285 // Load this again, if it's used by the local context below.
286 __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
287 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100288 if (is_strict(language_mode()) || !has_simple_parameters()) {
289 FastNewStrictArgumentsStub stub(isolate());
290 __ CallStub(&stub);
291 } else if (literal()->has_duplicate_parameters()) {
292 __ Push(a1);
293 __ CallRuntime(Runtime::kNewSloppyArguments_Generic);
294 } else {
295 FastNewSloppyArgumentsStub stub(isolate());
296 __ CallStub(&stub);
297 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298
299 SetVar(arguments, v0, a1, a2);
300 }
301
302 if (FLAG_trace) {
303 __ CallRuntime(Runtime::kTraceEnter);
304 }
305
Ben Murdochda12d292016-06-02 14:46:10 +0100306 // Visit the declarations and body.
Ben Murdochc5610432016-08-08 18:44:38 +0100307 PrepareForBailoutForId(BailoutId::FunctionEntry(),
308 BailoutState::NO_REGISTERS);
Ben Murdochda12d292016-06-02 14:46:10 +0100309 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310 Comment cmnt(masm_, "[ Declarations");
Ben Murdochda12d292016-06-02 14:46:10 +0100311 VisitDeclarations(scope()->declarations());
312 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313
Ben Murdochda12d292016-06-02 14:46:10 +0100314 // Assert that the declarations do not use ICs. Otherwise the debugger
315 // won't be able to redirect a PC at an IC to the correct IC in newly
316 // recompiled code.
317 DCHECK_EQ(0, ic_total_count_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318
Ben Murdochda12d292016-06-02 14:46:10 +0100319 {
320 Comment cmnt(masm_, "[ Stack check");
Ben Murdochc5610432016-08-08 18:44:38 +0100321 PrepareForBailoutForId(BailoutId::Declarations(),
322 BailoutState::NO_REGISTERS);
Ben Murdochda12d292016-06-02 14:46:10 +0100323 Label ok;
324 __ LoadRoot(at, Heap::kStackLimitRootIndex);
325 __ Branch(&ok, hs, sp, Operand(at));
326 Handle<Code> stack_check = isolate()->builtins()->StackCheck();
327 PredictableCodeSizeScope predictable(
328 masm_, masm_->CallSize(stack_check, RelocInfo::CODE_TARGET));
329 __ Call(stack_check, RelocInfo::CODE_TARGET);
330 __ bind(&ok);
331 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332
Ben Murdochda12d292016-06-02 14:46:10 +0100333 {
334 Comment cmnt(masm_, "[ Body");
335 DCHECK(loop_depth() == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336
Ben Murdochda12d292016-06-02 14:46:10 +0100337 VisitStatements(literal()->body());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338
Ben Murdochda12d292016-06-02 14:46:10 +0100339 DCHECK(loop_depth() == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000340 }
341
342 // Always emit a 'return undefined' in case control fell off the end of
343 // the body.
344 { Comment cmnt(masm_, "[ return <undefined>;");
345 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
346 }
347 EmitReturnSequence();
348}
349
350
351void FullCodeGenerator::ClearAccumulator() {
352 DCHECK(Smi::FromInt(0) == 0);
353 __ mov(v0, zero_reg);
354}
355
356
357void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
358 __ li(a2, Operand(profiling_counter_));
359 __ ld(a3, FieldMemOperand(a2, Cell::kValueOffset));
360 __ Dsubu(a3, a3, Operand(Smi::FromInt(delta)));
361 __ sd(a3, FieldMemOperand(a2, Cell::kValueOffset));
362}
363
364
365void FullCodeGenerator::EmitProfilingCounterReset() {
366 int reset_value = FLAG_interrupt_budget;
367 if (info_->is_debug()) {
368 // Detect debug break requests as soon as possible.
369 reset_value = FLAG_interrupt_budget >> 4;
370 }
371 __ li(a2, Operand(profiling_counter_));
372 __ li(a3, Operand(Smi::FromInt(reset_value)));
373 __ sd(a3, FieldMemOperand(a2, Cell::kValueOffset));
374}
375
376
377void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
378 Label* back_edge_target) {
379 // The generated code is used in Deoptimizer::PatchStackCheckCodeAt so we need
380 // to make sure it is constant. Branch may emit a skip-or-jump sequence
381 // instead of the normal Branch. It seems that the "skip" part of that
382 // sequence is about as long as this Branch would be so it is safe to ignore
383 // that.
384 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
385 Comment cmnt(masm_, "[ Back edge bookkeeping");
386 Label ok;
387 DCHECK(back_edge_target->is_bound());
388 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
389 int weight = Min(kMaxBackEdgeWeight,
390 Max(1, distance / kCodeSizeMultiplier));
391 EmitProfilingCounterDecrement(weight);
392 __ slt(at, a3, zero_reg);
393 __ beq(at, zero_reg, &ok);
394 // Call will emit a li t9 first, so it is safe to use the delay slot.
395 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
396 // Record a mapping of this PC offset to the OSR id. This is used to find
397 // the AST id from the unoptimized code in order to use it as a key into
398 // the deoptimization input data found in the optimized code.
399 RecordBackEdge(stmt->OsrEntryId());
400 EmitProfilingCounterReset();
401
402 __ bind(&ok);
Ben Murdochc5610432016-08-08 18:44:38 +0100403 PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000404 // Record a mapping of the OSR id to this PC. This is used if the OSR
405 // entry becomes the target of a bailout. We don't expect it to be, but
406 // we want it to work if it is.
Ben Murdochc5610432016-08-08 18:44:38 +0100407 PrepareForBailoutForId(stmt->OsrEntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000408}
409
Ben Murdoch097c5b22016-05-18 11:27:45 +0100410void FullCodeGenerator::EmitProfilingCounterHandlingForReturnSequence(
411 bool is_tail_call) {
412 // Pretend that the exit is a backwards jump to the entry.
413 int weight = 1;
414 if (info_->ShouldSelfOptimize()) {
415 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
416 } else {
417 int distance = masm_->pc_offset();
418 weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier));
419 }
420 EmitProfilingCounterDecrement(weight);
421 Label ok;
422 __ Branch(&ok, ge, a3, Operand(zero_reg));
423 // Don't need to save result register if we are going to do a tail call.
424 if (!is_tail_call) {
425 __ push(v0);
426 }
427 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
428 if (!is_tail_call) {
429 __ pop(v0);
430 }
431 EmitProfilingCounterReset();
432 __ bind(&ok);
433}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000434
435void FullCodeGenerator::EmitReturnSequence() {
436 Comment cmnt(masm_, "[ Return sequence");
437 if (return_label_.is_bound()) {
438 __ Branch(&return_label_);
439 } else {
440 __ bind(&return_label_);
441 if (FLAG_trace) {
442 // Push the return value on the stack as the parameter.
443 // Runtime::TraceExit returns its parameter in v0.
444 __ push(v0);
445 __ CallRuntime(Runtime::kTraceExit);
446 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100447 EmitProfilingCounterHandlingForReturnSequence(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448
449 // Make sure that the constant pool is not emitted inside of the return
450 // sequence.
451 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
452 // Here we use masm_-> instead of the __ macro to avoid the code coverage
453 // tool from instrumenting as we rely on the code size here.
454 int32_t arg_count = info_->scope()->num_parameters() + 1;
455 int32_t sp_delta = arg_count * kPointerSize;
456 SetReturnPosition(literal());
457 masm_->mov(sp, fp);
458 masm_->MultiPop(static_cast<RegList>(fp.bit() | ra.bit()));
459 masm_->Daddu(sp, sp, Operand(sp_delta));
460 masm_->Jump(ra);
461 }
462 }
463}
464
Ben Murdochc5610432016-08-08 18:44:38 +0100465void FullCodeGenerator::RestoreContext() {
466 __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
467}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000468
469void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
470 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
471 codegen()->GetVar(result_register(), var);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100472 codegen()->PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473}
474
475
476void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
477}
478
479
480void FullCodeGenerator::AccumulatorValueContext::Plug(
481 Heap::RootListIndex index) const {
482 __ LoadRoot(result_register(), index);
483}
484
485
486void FullCodeGenerator::StackValueContext::Plug(
487 Heap::RootListIndex index) const {
488 __ LoadRoot(result_register(), index);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100489 codegen()->PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490}
491
492
493void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
494 codegen()->PrepareForBailoutBeforeSplit(condition(),
495 true,
496 true_label_,
497 false_label_);
498 if (index == Heap::kUndefinedValueRootIndex ||
499 index == Heap::kNullValueRootIndex ||
500 index == Heap::kFalseValueRootIndex) {
501 if (false_label_ != fall_through_) __ Branch(false_label_);
502 } else if (index == Heap::kTrueValueRootIndex) {
503 if (true_label_ != fall_through_) __ Branch(true_label_);
504 } else {
505 __ LoadRoot(result_register(), index);
506 codegen()->DoTest(this);
507 }
508}
509
510
511void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
512}
513
514
515void FullCodeGenerator::AccumulatorValueContext::Plug(
516 Handle<Object> lit) const {
517 __ li(result_register(), Operand(lit));
518}
519
520
521void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
522 // Immediates cannot be pushed directly.
523 __ li(result_register(), Operand(lit));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100524 codegen()->PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525}
526
527
528void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
529 codegen()->PrepareForBailoutBeforeSplit(condition(),
530 true,
531 true_label_,
532 false_label_);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100533 DCHECK(lit->IsNull(isolate()) || lit->IsUndefined(isolate()) ||
534 !lit->IsUndetectable());
535 if (lit->IsUndefined(isolate()) || lit->IsNull(isolate()) ||
536 lit->IsFalse(isolate())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000537 if (false_label_ != fall_through_) __ Branch(false_label_);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100538 } else if (lit->IsTrue(isolate()) || lit->IsJSObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000539 if (true_label_ != fall_through_) __ Branch(true_label_);
540 } else if (lit->IsString()) {
541 if (String::cast(*lit)->length() == 0) {
542 if (false_label_ != fall_through_) __ Branch(false_label_);
543 } else {
544 if (true_label_ != fall_through_) __ Branch(true_label_);
545 }
546 } else if (lit->IsSmi()) {
547 if (Smi::cast(*lit)->value() == 0) {
548 if (false_label_ != fall_through_) __ Branch(false_label_);
549 } else {
550 if (true_label_ != fall_through_) __ Branch(true_label_);
551 }
552 } else {
553 // For simplicity we always test the accumulator register.
554 __ li(result_register(), Operand(lit));
555 codegen()->DoTest(this);
556 }
557}
558
559
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000560void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
561 Register reg) const {
562 DCHECK(count > 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100563 if (count > 1) codegen()->DropOperands(count - 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564 __ sd(reg, MemOperand(sp, 0));
565}
566
567
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000568void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
569 Label* materialize_false) const {
570 DCHECK(materialize_true == materialize_false);
571 __ bind(materialize_true);
572}
573
574
575void FullCodeGenerator::AccumulatorValueContext::Plug(
576 Label* materialize_true,
577 Label* materialize_false) const {
578 Label done;
579 __ bind(materialize_true);
580 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
581 __ Branch(&done);
582 __ bind(materialize_false);
583 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
584 __ bind(&done);
585}
586
587
588void FullCodeGenerator::StackValueContext::Plug(
589 Label* materialize_true,
590 Label* materialize_false) const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100591 codegen()->OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592 Label done;
593 __ bind(materialize_true);
594 __ LoadRoot(at, Heap::kTrueValueRootIndex);
595 // Push the value as the following branch can clobber at in long branch mode.
596 __ push(at);
597 __ Branch(&done);
598 __ bind(materialize_false);
599 __ LoadRoot(at, Heap::kFalseValueRootIndex);
600 __ push(at);
601 __ bind(&done);
602}
603
604
605void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
606 Label* materialize_false) const {
607 DCHECK(materialize_true == true_label_);
608 DCHECK(materialize_false == false_label_);
609}
610
611
612void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
613 Heap::RootListIndex value_root_index =
614 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
615 __ LoadRoot(result_register(), value_root_index);
616}
617
618
619void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
620 Heap::RootListIndex value_root_index =
621 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
622 __ LoadRoot(at, value_root_index);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100623 codegen()->PushOperand(at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000624}
625
626
627void FullCodeGenerator::TestContext::Plug(bool flag) const {
628 codegen()->PrepareForBailoutBeforeSplit(condition(),
629 true,
630 true_label_,
631 false_label_);
632 if (flag) {
633 if (true_label_ != fall_through_) __ Branch(true_label_);
634 } else {
635 if (false_label_ != fall_through_) __ Branch(false_label_);
636 }
637}
638
639
640void FullCodeGenerator::DoTest(Expression* condition,
641 Label* if_true,
642 Label* if_false,
643 Label* fall_through) {
644 __ mov(a0, result_register());
Ben Murdochda12d292016-06-02 14:46:10 +0100645 Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000646 CallIC(ic, condition->test_id());
647 __ LoadRoot(at, Heap::kTrueValueRootIndex);
648 Split(eq, result_register(), Operand(at), if_true, if_false, fall_through);
649}
650
651
652void FullCodeGenerator::Split(Condition cc,
653 Register lhs,
654 const Operand& rhs,
655 Label* if_true,
656 Label* if_false,
657 Label* fall_through) {
658 if (if_false == fall_through) {
659 __ Branch(if_true, cc, lhs, rhs);
660 } else if (if_true == fall_through) {
661 __ Branch(if_false, NegateCondition(cc), lhs, rhs);
662 } else {
663 __ Branch(if_true, cc, lhs, rhs);
664 __ Branch(if_false);
665 }
666}
667
668
669MemOperand FullCodeGenerator::StackOperand(Variable* var) {
670 DCHECK(var->IsStackAllocated());
671 // Offset is negative because higher indexes are at lower addresses.
672 int offset = -var->index() * kPointerSize;
673 // Adjust by a (parameter or local) base offset.
674 if (var->IsParameter()) {
675 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
676 } else {
677 offset += JavaScriptFrameConstants::kLocal0Offset;
678 }
679 return MemOperand(fp, offset);
680}
681
682
683MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
684 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
685 if (var->IsContextSlot()) {
686 int context_chain_length = scope()->ContextChainLength(var->scope());
687 __ LoadContext(scratch, context_chain_length);
688 return ContextMemOperand(scratch, var->index());
689 } else {
690 return StackOperand(var);
691 }
692}
693
694
695void FullCodeGenerator::GetVar(Register dest, Variable* var) {
696 // Use destination as scratch.
697 MemOperand location = VarOperand(var, dest);
698 __ ld(dest, location);
699}
700
701
702void FullCodeGenerator::SetVar(Variable* var,
703 Register src,
704 Register scratch0,
705 Register scratch1) {
706 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
707 DCHECK(!scratch0.is(src));
708 DCHECK(!scratch0.is(scratch1));
709 DCHECK(!scratch1.is(src));
710 MemOperand location = VarOperand(var, scratch0);
711 __ sd(src, location);
712 // Emit the write barrier code if the location is in the heap.
713 if (var->IsContextSlot()) {
714 __ RecordWriteContextSlot(scratch0,
715 location.offset(),
716 src,
717 scratch1,
718 kRAHasBeenSaved,
719 kDontSaveFPRegs);
720 }
721}
722
723
724void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
725 bool should_normalize,
726 Label* if_true,
727 Label* if_false) {
728 // Only prepare for bailouts before splits if we're in a test
729 // context. Otherwise, we let the Visit function deal with the
730 // preparation to avoid preparing with the same AST id twice.
731 if (!context()->IsTest()) return;
732
733 Label skip;
734 if (should_normalize) __ Branch(&skip);
Ben Murdochc5610432016-08-08 18:44:38 +0100735 PrepareForBailout(expr, BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000736 if (should_normalize) {
737 __ LoadRoot(a4, Heap::kTrueValueRootIndex);
738 Split(eq, a0, Operand(a4), if_true, if_false, NULL);
739 __ bind(&skip);
740 }
741}
742
743
744void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
745 // The variable in the declaration always resides in the current function
746 // context.
747 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100748 if (FLAG_debug_code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000749 // Check that we're not inside a with or catch context.
750 __ ld(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
751 __ LoadRoot(a4, Heap::kWithContextMapRootIndex);
752 __ Check(ne, kDeclarationInWithContext,
753 a1, Operand(a4));
754 __ LoadRoot(a4, Heap::kCatchContextMapRootIndex);
755 __ Check(ne, kDeclarationInCatchContext,
756 a1, Operand(a4));
757 }
758}
759
760
761void FullCodeGenerator::VisitVariableDeclaration(
762 VariableDeclaration* declaration) {
763 // If it was not possible to allocate the variable at compile time, we
764 // need to "declare" it at runtime to make sure it actually exists in the
765 // local context.
766 VariableProxy* proxy = declaration->proxy();
767 VariableMode mode = declaration->mode();
768 Variable* variable = proxy->var();
Ben Murdochc5610432016-08-08 18:44:38 +0100769 bool hole_init = mode == LET || mode == CONST;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770 switch (variable->location()) {
771 case VariableLocation::GLOBAL:
772 case VariableLocation::UNALLOCATED:
Ben Murdochc5610432016-08-08 18:44:38 +0100773 DCHECK(!variable->binding_needs_init());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000774 globals_->Add(variable->name(), zone());
Ben Murdochc5610432016-08-08 18:44:38 +0100775 globals_->Add(isolate()->factory()->undefined_value(), zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000776 break;
777
778 case VariableLocation::PARAMETER:
779 case VariableLocation::LOCAL:
780 if (hole_init) {
781 Comment cmnt(masm_, "[ VariableDeclaration");
782 __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
783 __ sd(a4, StackOperand(variable));
784 }
785 break;
786
787 case VariableLocation::CONTEXT:
788 if (hole_init) {
789 Comment cmnt(masm_, "[ VariableDeclaration");
790 EmitDebugCheckDeclarationContext(variable);
791 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
792 __ sd(at, ContextMemOperand(cp, variable->index()));
793 // No write barrier since the_hole_value is in old space.
Ben Murdochc5610432016-08-08 18:44:38 +0100794 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000795 }
796 break;
797
798 case VariableLocation::LOOKUP: {
799 Comment cmnt(masm_, "[ VariableDeclaration");
Ben Murdoch61f157c2016-09-16 13:49:30 +0100800 DCHECK_EQ(VAR, mode);
801 DCHECK(!hole_init);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000802 __ li(a2, Operand(variable->name()));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100803 __ Push(a2);
804 __ CallRuntime(Runtime::kDeclareEvalVar);
Ben Murdochc5610432016-08-08 18:44:38 +0100805 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000806 break;
807 }
808 }
809}
810
811
812void FullCodeGenerator::VisitFunctionDeclaration(
813 FunctionDeclaration* declaration) {
814 VariableProxy* proxy = declaration->proxy();
815 Variable* variable = proxy->var();
816 switch (variable->location()) {
817 case VariableLocation::GLOBAL:
818 case VariableLocation::UNALLOCATED: {
819 globals_->Add(variable->name(), zone());
820 Handle<SharedFunctionInfo> function =
821 Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
822 // Check for stack-overflow exception.
823 if (function.is_null()) return SetStackOverflow();
824 globals_->Add(function, zone());
825 break;
826 }
827
828 case VariableLocation::PARAMETER:
829 case VariableLocation::LOCAL: {
830 Comment cmnt(masm_, "[ FunctionDeclaration");
831 VisitForAccumulatorValue(declaration->fun());
832 __ sd(result_register(), StackOperand(variable));
833 break;
834 }
835
836 case VariableLocation::CONTEXT: {
837 Comment cmnt(masm_, "[ FunctionDeclaration");
838 EmitDebugCheckDeclarationContext(variable);
839 VisitForAccumulatorValue(declaration->fun());
840 __ sd(result_register(), ContextMemOperand(cp, variable->index()));
841 int offset = Context::SlotOffset(variable->index());
842 // We know that we have written a function, which is not a smi.
843 __ RecordWriteContextSlot(cp,
844 offset,
845 result_register(),
846 a2,
847 kRAHasBeenSaved,
848 kDontSaveFPRegs,
849 EMIT_REMEMBERED_SET,
850 OMIT_SMI_CHECK);
Ben Murdochc5610432016-08-08 18:44:38 +0100851 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000852 break;
853 }
854
855 case VariableLocation::LOOKUP: {
856 Comment cmnt(masm_, "[ FunctionDeclaration");
857 __ li(a2, Operand(variable->name()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100858 PushOperand(a2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000859 // Push initial value for function declaration.
860 VisitForStackValue(declaration->fun());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100861 CallRuntimeWithOperands(Runtime::kDeclareEvalFunction);
Ben Murdochc5610432016-08-08 18:44:38 +0100862 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000863 break;
864 }
865 }
866}
867
868
869void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
870 // Call the runtime to declare the globals.
871 __ li(a1, Operand(pairs));
872 __ li(a0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
873 __ Push(a1, a0);
874 __ CallRuntime(Runtime::kDeclareGlobals);
875 // Return value is ignored.
876}
877
878
879void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
880 // Call the runtime to declare the modules.
881 __ Push(descriptions);
882 __ CallRuntime(Runtime::kDeclareModules);
883 // Return value is ignored.
884}
885
886
887void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
888 Comment cmnt(masm_, "[ SwitchStatement");
889 Breakable nested_statement(this, stmt);
890 SetStatementPosition(stmt);
891
892 // Keep the switch value on the stack until a case matches.
893 VisitForStackValue(stmt->tag());
Ben Murdochc5610432016-08-08 18:44:38 +0100894 PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000895
896 ZoneList<CaseClause*>* clauses = stmt->cases();
897 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
898
899 Label next_test; // Recycled for each test.
900 // Compile all the tests with branches to their bodies.
901 for (int i = 0; i < clauses->length(); i++) {
902 CaseClause* clause = clauses->at(i);
903 clause->body_target()->Unuse();
904
905 // The default is not a test, but remember it as final fall through.
906 if (clause->is_default()) {
907 default_clause = clause;
908 continue;
909 }
910
911 Comment cmnt(masm_, "[ Case comparison");
912 __ bind(&next_test);
913 next_test.Unuse();
914
915 // Compile the label expression.
916 VisitForAccumulatorValue(clause->label());
917 __ mov(a0, result_register()); // CompareStub requires args in a0, a1.
918
919 // Perform the comparison as if via '==='.
920 __ ld(a1, MemOperand(sp, 0)); // Switch value.
921 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
922 JumpPatchSite patch_site(masm_);
923 if (inline_smi_code) {
924 Label slow_case;
925 __ or_(a2, a1, a0);
926 patch_site.EmitJumpIfNotSmi(a2, &slow_case);
927
928 __ Branch(&next_test, ne, a1, Operand(a0));
929 __ Drop(1); // Switch value is no longer needed.
930 __ Branch(clause->body_target());
931
932 __ bind(&slow_case);
933 }
934
935 // Record position before stub call for type feedback.
936 SetExpressionPosition(clause);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100937 Handle<Code> ic =
938 CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000939 CallIC(ic, clause->CompareId());
940 patch_site.EmitPatchInfo();
941
942 Label skip;
943 __ Branch(&skip);
Ben Murdochc5610432016-08-08 18:44:38 +0100944 PrepareForBailout(clause, BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000945 __ LoadRoot(at, Heap::kTrueValueRootIndex);
946 __ Branch(&next_test, ne, v0, Operand(at));
947 __ Drop(1);
948 __ Branch(clause->body_target());
949 __ bind(&skip);
950
951 __ Branch(&next_test, ne, v0, Operand(zero_reg));
952 __ Drop(1); // Switch value is no longer needed.
953 __ Branch(clause->body_target());
954 }
955
956 // Discard the test value and jump to the default if present, otherwise to
957 // the end of the statement.
958 __ bind(&next_test);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100959 DropOperands(1); // Switch value is no longer needed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000960 if (default_clause == NULL) {
961 __ Branch(nested_statement.break_label());
962 } else {
963 __ Branch(default_clause->body_target());
964 }
965
966 // Compile all the case bodies.
967 for (int i = 0; i < clauses->length(); i++) {
968 Comment cmnt(masm_, "[ Case body");
969 CaseClause* clause = clauses->at(i);
970 __ bind(clause->body_target());
Ben Murdochc5610432016-08-08 18:44:38 +0100971 PrepareForBailoutForId(clause->EntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000972 VisitStatements(clause->statements());
973 }
974
975 __ bind(nested_statement.break_label());
Ben Murdochc5610432016-08-08 18:44:38 +0100976 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000977}
978
979
980void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
981 Comment cmnt(masm_, "[ ForInStatement");
982 SetStatementPosition(stmt, SKIP_BREAK);
983
984 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
985
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000986 // Get the object to enumerate over. If the object is null or undefined, skip
987 // over the loop. See ECMA-262 version 5, section 12.6.4.
988 SetExpressionAsStatementPosition(stmt->enumerable());
989 VisitForAccumulatorValue(stmt->enumerable());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100990 __ mov(a0, result_register());
Ben Murdochda12d292016-06-02 14:46:10 +0100991 OperandStackDepthIncrement(5);
992
993 Label loop, exit;
994 Iteration loop_statement(this, stmt);
995 increment_loop_depth();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100996
997 // If the object is null or undefined, skip over the loop, otherwise convert
998 // it to a JS receiver. See ECMA-262 version 5, section 12.6.4.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000999 Label convert, done_convert;
1000 __ JumpIfSmi(a0, &convert);
1001 __ GetObjectType(a0, a1, a1);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001002 __ Branch(USE_DELAY_SLOT, &done_convert, ge, a1,
1003 Operand(FIRST_JS_RECEIVER_TYPE));
1004 __ LoadRoot(at, Heap::kNullValueRootIndex); // In delay slot.
1005 __ Branch(USE_DELAY_SLOT, &exit, eq, a0, Operand(at));
1006 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); // In delay slot.
1007 __ Branch(&exit, eq, a0, Operand(at));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001008 __ bind(&convert);
1009 ToObjectStub stub(isolate());
1010 __ CallStub(&stub);
1011 __ mov(a0, v0);
1012 __ bind(&done_convert);
Ben Murdochc5610432016-08-08 18:44:38 +01001013 PrepareForBailoutForId(stmt->ToObjectId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001014 __ push(a0);
1015
Ben Murdochc5610432016-08-08 18:44:38 +01001016 // Check cache validity in generated code. If we cannot guarantee cache
1017 // validity, call the runtime system to check cache validity or get the
1018 // property names in a fixed array. Note: Proxies never have an enum cache,
1019 // so will always take the slow path.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001020 Label call_runtime;
1021 __ CheckEnumCache(&call_runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001022
1023 // The enum cache is valid. Load the map of the object being
1024 // iterated over and use the cache for the iteration.
1025 Label use_cache;
1026 __ ld(v0, FieldMemOperand(a0, HeapObject::kMapOffset));
1027 __ Branch(&use_cache);
1028
1029 // Get the set of properties to enumerate.
1030 __ bind(&call_runtime);
1031 __ push(a0); // Duplicate the enumerable object on the stack.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001032 __ CallRuntime(Runtime::kForInEnumerate);
Ben Murdochc5610432016-08-08 18:44:38 +01001033 PrepareForBailoutForId(stmt->EnumId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001034
1035 // If we got a map from the runtime call, we can do a fast
1036 // modification check. Otherwise, we got a fixed array, and we have
1037 // to do a slow check.
1038 Label fixed_array;
1039 __ ld(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
1040 __ LoadRoot(at, Heap::kMetaMapRootIndex);
1041 __ Branch(&fixed_array, ne, a2, Operand(at));
1042
1043 // We got a map in register v0. Get the enumeration cache from it.
1044 Label no_descriptors;
1045 __ bind(&use_cache);
1046
1047 __ EnumLength(a1, v0);
1048 __ Branch(&no_descriptors, eq, a1, Operand(Smi::FromInt(0)));
1049
1050 __ LoadInstanceDescriptors(v0, a2);
1051 __ ld(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheOffset));
1052 __ ld(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheBridgeCacheOffset));
1053
1054 // Set up the four remaining stack slots.
1055 __ li(a0, Operand(Smi::FromInt(0)));
1056 // Push map, enumeration cache, enumeration cache length (as smi) and zero.
1057 __ Push(v0, a2, a1, a0);
1058 __ jmp(&loop);
1059
1060 __ bind(&no_descriptors);
1061 __ Drop(1);
1062 __ jmp(&exit);
1063
1064 // We got a fixed array in register v0. Iterate through that.
1065 __ bind(&fixed_array);
1066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067 __ li(a1, Operand(Smi::FromInt(1))); // Smi(1) indicates slow check
1068 __ Push(a1, v0); // Smi and array
1069 __ ld(a1, FieldMemOperand(v0, FixedArray::kLengthOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001070 __ Push(a1); // Fixed array length (as smi).
Ben Murdochc5610432016-08-08 18:44:38 +01001071 PrepareForBailoutForId(stmt->PrepareId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001072 __ li(a0, Operand(Smi::FromInt(0)));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001073 __ Push(a0); // Initial index.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074
1075 // Generate code for doing the condition check.
1076 __ bind(&loop);
1077 SetExpressionAsStatementPosition(stmt->each());
1078
1079 // Load the current count to a0, load the length to a1.
1080 __ ld(a0, MemOperand(sp, 0 * kPointerSize));
1081 __ ld(a1, MemOperand(sp, 1 * kPointerSize));
1082 __ Branch(loop_statement.break_label(), hs, a0, Operand(a1));
1083
1084 // Get the current entry of the array into register a3.
1085 __ ld(a2, MemOperand(sp, 2 * kPointerSize));
1086 __ Daddu(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1087 __ SmiScale(a4, a0, kPointerSizeLog2);
1088 __ daddu(a4, a2, a4); // Array base + scaled (smi) index.
1089 __ ld(a3, MemOperand(a4)); // Current entry.
1090
1091 // Get the expected map from the stack or a smi in the
1092 // permanent slow case into register a2.
1093 __ ld(a2, MemOperand(sp, 3 * kPointerSize));
1094
1095 // Check if the expected map still matches that of the enumerable.
1096 // If not, we may have to filter the key.
1097 Label update_each;
1098 __ ld(a1, MemOperand(sp, 4 * kPointerSize));
1099 __ ld(a4, FieldMemOperand(a1, HeapObject::kMapOffset));
1100 __ Branch(&update_each, eq, a4, Operand(a2));
1101
Ben Murdochda12d292016-06-02 14:46:10 +01001102 // We need to filter the key, record slow-path here.
1103 int const vector_index = SmiFromSlot(slot)->value();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001104 __ EmitLoadTypeFeedbackVector(a0);
1105 __ li(a2, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
1106 __ sd(a2, FieldMemOperand(a0, FixedArray::OffsetOfElementAt(vector_index)));
1107
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001108 // Convert the entry to a string or (smi) 0 if it isn't a property
1109 // any more. If the property has been removed while iterating, we
1110 // just skip it.
1111 __ Push(a1, a3); // Enumerable and current entry.
1112 __ CallRuntime(Runtime::kForInFilter);
Ben Murdochc5610432016-08-08 18:44:38 +01001113 PrepareForBailoutForId(stmt->FilterId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001114 __ mov(a3, result_register());
1115 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
1116 __ Branch(loop_statement.continue_label(), eq, a3, Operand(at));
1117
1118 // Update the 'each' property or variable from the possibly filtered
1119 // entry in register a3.
1120 __ bind(&update_each);
1121 __ mov(result_register(), a3);
1122 // Perform the assignment as if via '='.
1123 { EffectContext context(this);
1124 EmitAssignment(stmt->each(), stmt->EachFeedbackSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01001125 PrepareForBailoutForId(stmt->AssignmentId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001126 }
1127
1128 // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body().
Ben Murdochc5610432016-08-08 18:44:38 +01001129 PrepareForBailoutForId(stmt->BodyId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001130 // Generate code for the body of the loop.
1131 Visit(stmt->body());
1132
1133 // Generate code for the going to the next element by incrementing
1134 // the index (smi) stored on top of the stack.
1135 __ bind(loop_statement.continue_label());
1136 __ pop(a0);
1137 __ Daddu(a0, a0, Operand(Smi::FromInt(1)));
1138 __ push(a0);
1139
1140 EmitBackEdgeBookkeeping(stmt, &loop);
1141 __ Branch(&loop);
1142
1143 // Remove the pointers stored on the stack.
1144 __ bind(loop_statement.break_label());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001145 DropOperands(5);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001146
1147 // Exit and decrement the loop depth.
Ben Murdochc5610432016-08-08 18:44:38 +01001148 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001149 __ bind(&exit);
1150 decrement_loop_depth();
1151}
1152
1153
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001154void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset,
1155 FeedbackVectorSlot slot) {
1156 DCHECK(NeedsHomeObject(initializer));
1157 __ ld(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
1158 __ li(StoreDescriptor::NameRegister(),
1159 Operand(isolate()->factory()->home_object_symbol()));
1160 __ ld(StoreDescriptor::ValueRegister(),
1161 MemOperand(sp, offset * kPointerSize));
1162 EmitLoadStoreICSlot(slot);
1163 CallStoreIC();
1164}
1165
1166
1167void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer,
1168 int offset,
1169 FeedbackVectorSlot slot) {
1170 DCHECK(NeedsHomeObject(initializer));
1171 __ Move(StoreDescriptor::ReceiverRegister(), v0);
1172 __ li(StoreDescriptor::NameRegister(),
1173 Operand(isolate()->factory()->home_object_symbol()));
1174 __ ld(StoreDescriptor::ValueRegister(),
1175 MemOperand(sp, offset * kPointerSize));
1176 EmitLoadStoreICSlot(slot);
1177 CallStoreIC();
1178}
1179
1180
1181void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
1182 TypeofMode typeof_mode,
1183 Label* slow) {
1184 Register current = cp;
1185 Register next = a1;
1186 Register temp = a2;
1187
1188 Scope* s = scope();
1189 while (s != NULL) {
1190 if (s->num_heap_slots() > 0) {
1191 if (s->calls_sloppy_eval()) {
1192 // Check that extension is "the hole".
1193 __ ld(temp, ContextMemOperand(current, Context::EXTENSION_INDEX));
1194 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow);
1195 }
1196 // Load next context in chain.
1197 __ ld(next, ContextMemOperand(current, Context::PREVIOUS_INDEX));
1198 // Walk the rest of the chain without clobbering cp.
1199 current = next;
1200 }
1201 // If no outer scope calls eval, we do not need to check more
1202 // context extensions.
1203 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
1204 s = s->outer_scope();
1205 }
1206
1207 if (s->is_eval_scope()) {
1208 Label loop, fast;
1209 if (!current.is(next)) {
1210 __ Move(next, current);
1211 }
1212 __ bind(&loop);
1213 // Terminate at native context.
1214 __ ld(temp, FieldMemOperand(next, HeapObject::kMapOffset));
1215 __ LoadRoot(a4, Heap::kNativeContextMapRootIndex);
1216 __ Branch(&fast, eq, temp, Operand(a4));
1217 // Check that extension is "the hole".
1218 __ ld(temp, ContextMemOperand(next, Context::EXTENSION_INDEX));
1219 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow);
1220 // Load next context in chain.
1221 __ ld(next, ContextMemOperand(next, Context::PREVIOUS_INDEX));
1222 __ Branch(&loop);
1223 __ bind(&fast);
1224 }
1225
1226 // All extension objects were empty and it is safe to use a normal global
1227 // load machinery.
1228 EmitGlobalVariableLoad(proxy, typeof_mode);
1229}
1230
1231
1232MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1233 Label* slow) {
1234 DCHECK(var->IsContextSlot());
1235 Register context = cp;
1236 Register next = a3;
1237 Register temp = a4;
1238
1239 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1240 if (s->num_heap_slots() > 0) {
1241 if (s->calls_sloppy_eval()) {
1242 // Check that extension is "the hole".
1243 __ ld(temp, ContextMemOperand(context, Context::EXTENSION_INDEX));
1244 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow);
1245 }
1246 __ ld(next, ContextMemOperand(context, Context::PREVIOUS_INDEX));
1247 // Walk the rest of the chain without clobbering cp.
1248 context = next;
1249 }
1250 }
1251 // Check that last extension is "the hole".
1252 __ ld(temp, ContextMemOperand(context, Context::EXTENSION_INDEX));
1253 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow);
1254
1255 // This function is used only for loads, not stores, so it's safe to
1256 // return an cp-based operand (the write barrier cannot be allowed to
1257 // destroy the cp register).
1258 return ContextMemOperand(context, var->index());
1259}
1260
1261
1262void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
1263 TypeofMode typeof_mode,
1264 Label* slow, Label* done) {
1265 // Generate fast-case code for variables that might be shadowed by
1266 // eval-introduced variables. Eval is used a lot without
1267 // introducing variables. In those cases, we do not want to
1268 // perform a runtime call for all variables in the scope
1269 // containing the eval.
1270 Variable* var = proxy->var();
1271 if (var->mode() == DYNAMIC_GLOBAL) {
1272 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow);
1273 __ Branch(done);
1274 } else if (var->mode() == DYNAMIC_LOCAL) {
1275 Variable* local = var->local_if_not_shadowed();
1276 __ ld(v0, ContextSlotOperandCheckExtensions(local, slow));
Ben Murdochc5610432016-08-08 18:44:38 +01001277 if (local->mode() == LET || local->mode() == CONST) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001278 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
1279 __ dsubu(at, v0, at); // Sub as compare: at == 0 on eq.
Ben Murdochc5610432016-08-08 18:44:38 +01001280 __ Branch(done, ne, at, Operand(zero_reg));
1281 __ li(a0, Operand(var->name()));
1282 __ push(a0);
1283 __ CallRuntime(Runtime::kThrowReferenceError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001284 }
1285 __ Branch(done);
1286 }
1287}
1288
1289
1290void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
1291 TypeofMode typeof_mode) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001292#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001293 Variable* var = proxy->var();
1294 DCHECK(var->IsUnallocatedOrGlobalSlot() ||
1295 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001296#endif
1297 __ li(LoadGlobalDescriptor::SlotRegister(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001298 Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001299 CallLoadGlobalIC(typeof_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001300}
1301
1302
1303void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
1304 TypeofMode typeof_mode) {
1305 // Record position before possible IC call.
1306 SetExpressionPosition(proxy);
Ben Murdochc5610432016-08-08 18:44:38 +01001307 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001308 Variable* var = proxy->var();
1309
1310 // Three cases: global variables, lookup variables, and all other types of
1311 // variables.
1312 switch (var->location()) {
1313 case VariableLocation::GLOBAL:
1314 case VariableLocation::UNALLOCATED: {
1315 Comment cmnt(masm_, "[ Global variable");
1316 EmitGlobalVariableLoad(proxy, typeof_mode);
1317 context()->Plug(v0);
1318 break;
1319 }
1320
1321 case VariableLocation::PARAMETER:
1322 case VariableLocation::LOCAL:
1323 case VariableLocation::CONTEXT: {
1324 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
1325 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1326 : "[ Stack variable");
1327 if (NeedsHoleCheckForLoad(proxy)) {
1328 // Let and const need a read barrier.
1329 GetVar(v0, var);
1330 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
1331 __ dsubu(at, v0, at); // Sub as compare: at == 0 on eq.
1332 if (var->mode() == LET || var->mode() == CONST) {
1333 // Throw a reference error when using an uninitialized let/const
1334 // binding in harmony mode.
1335 Label done;
1336 __ Branch(&done, ne, at, Operand(zero_reg));
1337 __ li(a0, Operand(var->name()));
1338 __ push(a0);
1339 __ CallRuntime(Runtime::kThrowReferenceError);
1340 __ bind(&done);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001341 }
1342 context()->Plug(v0);
1343 break;
1344 }
1345 context()->Plug(var);
1346 break;
1347 }
1348
1349 case VariableLocation::LOOKUP: {
1350 Comment cmnt(masm_, "[ Lookup variable");
1351 Label done, slow;
1352 // Generate code for loading from variables potentially shadowed
1353 // by eval-introduced variables.
1354 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done);
1355 __ bind(&slow);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001356 __ Push(var->name());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001357 Runtime::FunctionId function_id =
1358 typeof_mode == NOT_INSIDE_TYPEOF
1359 ? Runtime::kLoadLookupSlot
Ben Murdoch097c5b22016-05-18 11:27:45 +01001360 : Runtime::kLoadLookupSlotInsideTypeof;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001361 __ CallRuntime(function_id);
1362 __ bind(&done);
1363 context()->Plug(v0);
1364 }
1365 }
1366}
1367
1368
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001369void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) {
1370 Expression* expression = (property == NULL) ? NULL : property->value();
1371 if (expression == NULL) {
1372 __ LoadRoot(a1, Heap::kNullValueRootIndex);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001373 PushOperand(a1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001374 } else {
1375 VisitForStackValue(expression);
1376 if (NeedsHomeObject(expression)) {
1377 DCHECK(property->kind() == ObjectLiteral::Property::GETTER ||
1378 property->kind() == ObjectLiteral::Property::SETTER);
1379 int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3;
1380 EmitSetHomeObject(expression, offset, property->GetSlot());
1381 }
1382 }
1383}
1384
1385
1386void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1387 Comment cmnt(masm_, "[ ObjectLiteral");
1388
1389 Handle<FixedArray> constant_properties = expr->constant_properties();
1390 __ ld(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1391 __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
1392 __ li(a1, Operand(constant_properties));
1393 __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags())));
1394 if (MustCreateObjectLiteralWithRuntime(expr)) {
1395 __ Push(a3, a2, a1, a0);
1396 __ CallRuntime(Runtime::kCreateObjectLiteral);
1397 } else {
1398 FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
1399 __ CallStub(&stub);
Ben Murdochc5610432016-08-08 18:44:38 +01001400 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001401 }
Ben Murdochc5610432016-08-08 18:44:38 +01001402 PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403
1404 // If result_saved is true the result is on top of the stack. If
1405 // result_saved is false the result is in v0.
1406 bool result_saved = false;
1407
1408 AccessorTable accessor_table(zone());
1409 int property_index = 0;
1410 for (; property_index < expr->properties()->length(); property_index++) {
1411 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1412 if (property->is_computed_name()) break;
1413 if (property->IsCompileTimeValue()) continue;
1414
1415 Literal* key = property->key()->AsLiteral();
1416 Expression* value = property->value();
1417 if (!result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001418 PushOperand(v0); // Save result on stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001419 result_saved = true;
1420 }
1421 switch (property->kind()) {
1422 case ObjectLiteral::Property::CONSTANT:
1423 UNREACHABLE();
1424 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1425 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
1426 // Fall through.
1427 case ObjectLiteral::Property::COMPUTED:
1428 // It is safe to use [[Put]] here because the boilerplate already
1429 // contains computed properties with an uninitialized value.
1430 if (key->value()->IsInternalizedString()) {
1431 if (property->emit_store()) {
1432 VisitForAccumulatorValue(value);
1433 __ mov(StoreDescriptor::ValueRegister(), result_register());
1434 DCHECK(StoreDescriptor::ValueRegister().is(a0));
1435 __ li(StoreDescriptor::NameRegister(), Operand(key->value()));
1436 __ ld(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
1437 EmitLoadStoreICSlot(property->GetSlot(0));
1438 CallStoreIC();
Ben Murdochc5610432016-08-08 18:44:38 +01001439 PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001440
1441 if (NeedsHomeObject(value)) {
1442 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1));
1443 }
1444 } else {
1445 VisitForEffect(value);
1446 }
1447 break;
1448 }
1449 // Duplicate receiver on stack.
1450 __ ld(a0, MemOperand(sp));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001451 PushOperand(a0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001452 VisitForStackValue(key);
1453 VisitForStackValue(value);
1454 if (property->emit_store()) {
1455 if (NeedsHomeObject(value)) {
1456 EmitSetHomeObject(value, 2, property->GetSlot());
1457 }
1458 __ li(a0, Operand(Smi::FromInt(SLOPPY))); // PropertyAttributes.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001459 PushOperand(a0);
1460 CallRuntimeWithOperands(Runtime::kSetProperty);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001461 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001462 DropOperands(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001463 }
1464 break;
1465 case ObjectLiteral::Property::PROTOTYPE:
1466 // Duplicate receiver on stack.
1467 __ ld(a0, MemOperand(sp));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001468 PushOperand(a0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001469 VisitForStackValue(value);
1470 DCHECK(property->emit_store());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001471 CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001472 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
Ben Murdochc5610432016-08-08 18:44:38 +01001473 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001474 break;
1475 case ObjectLiteral::Property::GETTER:
1476 if (property->emit_store()) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001477 AccessorTable::Iterator it = accessor_table.lookup(key);
1478 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1479 it->second->getter = property;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001480 }
1481 break;
1482 case ObjectLiteral::Property::SETTER:
1483 if (property->emit_store()) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001484 AccessorTable::Iterator it = accessor_table.lookup(key);
1485 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1486 it->second->setter = property;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001487 }
1488 break;
1489 }
1490 }
1491
1492 // Emit code to define accessors, using only a single call to the runtime for
1493 // each pair of corresponding getters and setters.
1494 for (AccessorTable::Iterator it = accessor_table.begin();
1495 it != accessor_table.end();
1496 ++it) {
1497 __ ld(a0, MemOperand(sp)); // Duplicate receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001498 PushOperand(a0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001499 VisitForStackValue(it->first);
1500 EmitAccessor(it->second->getter);
1501 EmitAccessor(it->second->setter);
1502 __ li(a0, Operand(Smi::FromInt(NONE)));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001503 PushOperand(a0);
1504 CallRuntimeWithOperands(Runtime::kDefineAccessorPropertyUnchecked);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001505 PrepareForBailoutForId(it->second->bailout_id, BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 }
1507
1508 // Object literals have two parts. The "static" part on the left contains no
1509 // computed property names, and so we can compute its map ahead of time; see
1510 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
1511 // starts with the first computed property name, and continues with all
1512 // properties to its right. All the code from above initializes the static
1513 // component of the object literal, and arranges for the map of the result to
1514 // reflect the static order in which the keys appear. For the dynamic
1515 // properties, we compile them into a series of "SetOwnProperty" runtime
1516 // calls. This will preserve insertion order.
1517 for (; property_index < expr->properties()->length(); property_index++) {
1518 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1519
1520 Expression* value = property->value();
1521 if (!result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001522 PushOperand(v0); // Save result on the stack
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001523 result_saved = true;
1524 }
1525
1526 __ ld(a0, MemOperand(sp)); // Duplicate receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001527 PushOperand(a0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001528
1529 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1530 DCHECK(!property->is_computed_name());
1531 VisitForStackValue(value);
1532 DCHECK(property->emit_store());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001533 CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001534 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
Ben Murdochc5610432016-08-08 18:44:38 +01001535 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 } else {
1537 EmitPropertyKey(property, expr->GetIdForPropertyName(property_index));
1538 VisitForStackValue(value);
1539 if (NeedsHomeObject(value)) {
1540 EmitSetHomeObject(value, 2, property->GetSlot());
1541 }
1542
1543 switch (property->kind()) {
1544 case ObjectLiteral::Property::CONSTANT:
1545 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1546 case ObjectLiteral::Property::COMPUTED:
1547 if (property->emit_store()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001548 PushOperand(Smi::FromInt(NONE));
1549 PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
1550 CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001551 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1552 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001553 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001554 DropOperands(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001555 }
1556 break;
1557
1558 case ObjectLiteral::Property::PROTOTYPE:
1559 UNREACHABLE();
1560 break;
1561
1562 case ObjectLiteral::Property::GETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001563 PushOperand(Smi::FromInt(NONE));
1564 CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001565 break;
1566
1567 case ObjectLiteral::Property::SETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001568 PushOperand(Smi::FromInt(NONE));
1569 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001570 break;
1571 }
1572 }
1573 }
1574
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001575 if (result_saved) {
1576 context()->PlugTOS();
1577 } else {
1578 context()->Plug(v0);
1579 }
1580}
1581
1582
1583void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1584 Comment cmnt(masm_, "[ ArrayLiteral");
1585
1586 Handle<FixedArray> constant_elements = expr->constant_elements();
1587 bool has_fast_elements =
1588 IsFastObjectElementsKind(expr->constant_elements_kind());
1589
1590 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1591 if (has_fast_elements && !FLAG_allocation_site_pretenuring) {
1592 // If the only customer of allocation sites is transitioning, then
1593 // we can turn it off if we don't have anywhere else to transition to.
1594 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1595 }
1596
1597 __ mov(a0, result_register());
1598 __ ld(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1599 __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
1600 __ li(a1, Operand(constant_elements));
1601 if (MustCreateArrayLiteralWithRuntime(expr)) {
1602 __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags())));
1603 __ Push(a3, a2, a1, a0);
1604 __ CallRuntime(Runtime::kCreateArrayLiteral);
1605 } else {
1606 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
1607 __ CallStub(&stub);
1608 }
Ben Murdochc5610432016-08-08 18:44:38 +01001609 PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001610
1611 bool result_saved = false; // Is the result saved to the stack?
1612 ZoneList<Expression*>* subexprs = expr->values();
1613 int length = subexprs->length();
1614
1615 // Emit code to evaluate all the non-constant subexpressions and to store
1616 // them into the newly cloned array.
1617 int array_index = 0;
1618 for (; array_index < length; array_index++) {
1619 Expression* subexpr = subexprs->at(array_index);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001620 DCHECK(!subexpr->IsSpread());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001621
1622 // If the subexpression is a literal or a simple materialized literal it
1623 // is already set in the cloned array.
1624 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1625
1626 if (!result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001627 PushOperand(v0); // array literal
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001628 result_saved = true;
1629 }
1630
1631 VisitForAccumulatorValue(subexpr);
1632
1633 __ li(StoreDescriptor::NameRegister(), Operand(Smi::FromInt(array_index)));
1634 __ ld(StoreDescriptor::ReceiverRegister(), MemOperand(sp, 0));
1635 __ mov(StoreDescriptor::ValueRegister(), result_register());
1636 EmitLoadStoreICSlot(expr->LiteralFeedbackSlot());
1637 Handle<Code> ic =
1638 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
1639 CallIC(ic);
1640
Ben Murdochc5610432016-08-08 18:44:38 +01001641 PrepareForBailoutForId(expr->GetIdForElement(array_index),
1642 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001643 }
1644
1645 // In case the array literal contains spread expressions it has two parts. The
1646 // first part is the "static" array which has a literal index is handled
1647 // above. The second part is the part after the first spread expression
1648 // (inclusive) and these elements gets appended to the array. Note that the
1649 // number elements an iterable produces is unknown ahead of time.
1650 if (array_index < length && result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001651 PopOperand(v0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001652 result_saved = false;
1653 }
1654 for (; array_index < length; array_index++) {
1655 Expression* subexpr = subexprs->at(array_index);
1656
Ben Murdoch097c5b22016-05-18 11:27:45 +01001657 PushOperand(v0);
1658 DCHECK(!subexpr->IsSpread());
1659 VisitForStackValue(subexpr);
1660 CallRuntimeWithOperands(Runtime::kAppendElement);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001661
Ben Murdochc5610432016-08-08 18:44:38 +01001662 PrepareForBailoutForId(expr->GetIdForElement(array_index),
1663 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001664 }
1665
1666 if (result_saved) {
1667 context()->PlugTOS();
1668 } else {
1669 context()->Plug(v0);
1670 }
1671}
1672
1673
1674void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1675 DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
1676
1677 Comment cmnt(masm_, "[ Assignment");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001678
1679 Property* property = expr->target()->AsProperty();
1680 LhsKind assign_type = Property::GetAssignType(property);
1681
1682 // Evaluate LHS expression.
1683 switch (assign_type) {
1684 case VARIABLE:
1685 // Nothing to do here.
1686 break;
1687 case NAMED_PROPERTY:
1688 if (expr->is_compound()) {
1689 // We need the receiver both on the stack and in the register.
1690 VisitForStackValue(property->obj());
1691 __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
1692 } else {
1693 VisitForStackValue(property->obj());
1694 }
1695 break;
1696 case NAMED_SUPER_PROPERTY:
1697 VisitForStackValue(
1698 property->obj()->AsSuperPropertyReference()->this_var());
1699 VisitForAccumulatorValue(
1700 property->obj()->AsSuperPropertyReference()->home_object());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001701 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001702 if (expr->is_compound()) {
1703 const Register scratch = a1;
1704 __ ld(scratch, MemOperand(sp, kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001705 PushOperands(scratch, result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001706 }
1707 break;
1708 case KEYED_SUPER_PROPERTY: {
1709 const Register scratch = a1;
1710 VisitForStackValue(
1711 property->obj()->AsSuperPropertyReference()->this_var());
1712 VisitForAccumulatorValue(
1713 property->obj()->AsSuperPropertyReference()->home_object());
1714 __ Move(scratch, result_register());
1715 VisitForAccumulatorValue(property->key());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001716 PushOperands(scratch, result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001717 if (expr->is_compound()) {
1718 const Register scratch1 = a4;
1719 __ ld(scratch1, MemOperand(sp, 2 * kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001720 PushOperands(scratch1, scratch, result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001721 }
1722 break;
1723 }
1724 case KEYED_PROPERTY:
1725 // We need the key and receiver on both the stack and in v0 and a1.
1726 if (expr->is_compound()) {
1727 VisitForStackValue(property->obj());
1728 VisitForStackValue(property->key());
1729 __ ld(LoadDescriptor::ReceiverRegister(),
1730 MemOperand(sp, 1 * kPointerSize));
1731 __ ld(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
1732 } else {
1733 VisitForStackValue(property->obj());
1734 VisitForStackValue(property->key());
1735 }
1736 break;
1737 }
1738
1739 // For compound assignments we need another deoptimization point after the
1740 // variable/property load.
1741 if (expr->is_compound()) {
1742 { AccumulatorValueContext context(this);
1743 switch (assign_type) {
1744 case VARIABLE:
1745 EmitVariableLoad(expr->target()->AsVariableProxy());
Ben Murdochc5610432016-08-08 18:44:38 +01001746 PrepareForBailout(expr->target(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001747 break;
1748 case NAMED_PROPERTY:
1749 EmitNamedPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001750 PrepareForBailoutForId(property->LoadId(),
1751 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001752 break;
1753 case NAMED_SUPER_PROPERTY:
1754 EmitNamedSuperPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001755 PrepareForBailoutForId(property->LoadId(),
1756 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001757 break;
1758 case KEYED_SUPER_PROPERTY:
1759 EmitKeyedSuperPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001760 PrepareForBailoutForId(property->LoadId(),
1761 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001762 break;
1763 case KEYED_PROPERTY:
1764 EmitKeyedPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001765 PrepareForBailoutForId(property->LoadId(),
1766 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001767 break;
1768 }
1769 }
1770
1771 Token::Value op = expr->binary_op();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001772 PushOperand(v0); // Left operand goes on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001773 VisitForAccumulatorValue(expr->value());
1774
1775 AccumulatorValueContext context(this);
1776 if (ShouldInlineSmiCase(op)) {
1777 EmitInlineSmiBinaryOp(expr->binary_operation(),
1778 op,
1779 expr->target(),
1780 expr->value());
1781 } else {
1782 EmitBinaryOp(expr->binary_operation(), op);
1783 }
1784
1785 // Deoptimization point in case the binary operation may have side effects.
Ben Murdochc5610432016-08-08 18:44:38 +01001786 PrepareForBailout(expr->binary_operation(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001787 } else {
1788 VisitForAccumulatorValue(expr->value());
1789 }
1790
1791 SetExpressionPosition(expr);
1792
1793 // Store the value.
1794 switch (assign_type) {
1795 case VARIABLE:
1796 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1797 expr->op(), expr->AssignmentSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01001798 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001799 context()->Plug(v0);
1800 break;
1801 case NAMED_PROPERTY:
1802 EmitNamedPropertyAssignment(expr);
1803 break;
1804 case NAMED_SUPER_PROPERTY:
1805 EmitNamedSuperPropertyStore(property);
1806 context()->Plug(v0);
1807 break;
1808 case KEYED_SUPER_PROPERTY:
1809 EmitKeyedSuperPropertyStore(property);
1810 context()->Plug(v0);
1811 break;
1812 case KEYED_PROPERTY:
1813 EmitKeyedPropertyAssignment(expr);
1814 break;
1815 }
1816}
1817
1818
1819void FullCodeGenerator::VisitYield(Yield* expr) {
1820 Comment cmnt(masm_, "[ Yield");
1821 SetExpressionPosition(expr);
1822
1823 // Evaluate yielded value first; the initial iterator definition depends on
1824 // this. It stays on the stack while we update the iterator.
1825 VisitForStackValue(expr->expression());
1826
Ben Murdochc5610432016-08-08 18:44:38 +01001827 Label suspend, continuation, post_runtime, resume, exception;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001828
Ben Murdochda12d292016-06-02 14:46:10 +01001829 __ jmp(&suspend);
1830 __ bind(&continuation);
Ben Murdochc5610432016-08-08 18:44:38 +01001831 // When we arrive here, v0 holds the generator object.
Ben Murdochda12d292016-06-02 14:46:10 +01001832 __ RecordGeneratorContinuation();
Ben Murdochc5610432016-08-08 18:44:38 +01001833 __ ld(a1, FieldMemOperand(v0, JSGeneratorObject::kResumeModeOffset));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001834 __ ld(v0, FieldMemOperand(v0, JSGeneratorObject::kInputOrDebugPosOffset));
Ben Murdochc5610432016-08-08 18:44:38 +01001835 __ Branch(&resume, eq, a1, Operand(Smi::FromInt(JSGeneratorObject::kNext)));
1836 __ Push(result_register());
1837 __ Branch(&exception, eq, a1,
1838 Operand(Smi::FromInt(JSGeneratorObject::kThrow)));
Ben Murdochda12d292016-06-02 14:46:10 +01001839 EmitCreateIteratorResult(true);
1840 EmitUnwindAndReturn();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001841
Ben Murdochc5610432016-08-08 18:44:38 +01001842 __ bind(&exception);
1843 __ CallRuntime(Runtime::kThrow);
1844
Ben Murdochda12d292016-06-02 14:46:10 +01001845 __ bind(&suspend);
1846 OperandStackDepthIncrement(1); // Not popped on this path.
1847 VisitForAccumulatorValue(expr->generator_object());
1848 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
1849 __ li(a1, Operand(Smi::FromInt(continuation.pos())));
1850 __ sd(a1, FieldMemOperand(v0, JSGeneratorObject::kContinuationOffset));
1851 __ sd(cp, FieldMemOperand(v0, JSGeneratorObject::kContextOffset));
1852 __ mov(a1, cp);
1853 __ RecordWriteField(v0, JSGeneratorObject::kContextOffset, a1, a2,
1854 kRAHasBeenSaved, kDontSaveFPRegs);
1855 __ Daddu(a1, fp, Operand(StandardFrameConstants::kExpressionsOffset));
1856 __ Branch(&post_runtime, eq, sp, Operand(a1));
1857 __ push(v0); // generator object
1858 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
Ben Murdochc5610432016-08-08 18:44:38 +01001859 RestoreContext();
Ben Murdochda12d292016-06-02 14:46:10 +01001860 __ bind(&post_runtime);
1861 PopOperand(result_register());
1862 EmitReturnSequence();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001863
Ben Murdochda12d292016-06-02 14:46:10 +01001864 __ bind(&resume);
1865 context()->Plug(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001866}
1867
Ben Murdoch097c5b22016-05-18 11:27:45 +01001868void FullCodeGenerator::PushOperands(Register reg1, Register reg2) {
1869 OperandStackDepthIncrement(2);
1870 __ Push(reg1, reg2);
1871}
1872
1873void FullCodeGenerator::PushOperands(Register reg1, Register reg2,
1874 Register reg3) {
1875 OperandStackDepthIncrement(3);
1876 __ Push(reg1, reg2, reg3);
1877}
1878
1879void FullCodeGenerator::PushOperands(Register reg1, Register reg2,
1880 Register reg3, Register reg4) {
1881 OperandStackDepthIncrement(4);
1882 __ Push(reg1, reg2, reg3, reg4);
1883}
1884
1885void FullCodeGenerator::PopOperands(Register reg1, Register reg2) {
1886 OperandStackDepthDecrement(2);
1887 __ Pop(reg1, reg2);
1888}
1889
1890void FullCodeGenerator::EmitOperandStackDepthCheck() {
1891 if (FLAG_debug_code) {
1892 int expected_diff = StandardFrameConstants::kFixedFrameSizeFromFp +
1893 operand_stack_depth_ * kPointerSize;
1894 __ Dsubu(v0, fp, sp);
1895 __ Assert(eq, kUnexpectedStackDepth, v0, Operand(expected_diff));
1896 }
1897}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001898
1899void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
1900 Label allocate, done_allocate;
1901
Ben Murdochc5610432016-08-08 18:44:38 +01001902 __ Allocate(JSIteratorResult::kSize, v0, a2, a3, &allocate,
1903 NO_ALLOCATION_FLAGS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001904 __ jmp(&done_allocate);
1905
1906 __ bind(&allocate);
1907 __ Push(Smi::FromInt(JSIteratorResult::kSize));
1908 __ CallRuntime(Runtime::kAllocateInNewSpace);
1909
1910 __ bind(&done_allocate);
1911 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, a1);
Ben Murdochda12d292016-06-02 14:46:10 +01001912 PopOperand(a2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001913 __ LoadRoot(a3,
1914 done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
1915 __ LoadRoot(a4, Heap::kEmptyFixedArrayRootIndex);
1916 __ sd(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
1917 __ sd(a4, FieldMemOperand(v0, JSObject::kPropertiesOffset));
1918 __ sd(a4, FieldMemOperand(v0, JSObject::kElementsOffset));
1919 __ sd(a2, FieldMemOperand(v0, JSIteratorResult::kValueOffset));
1920 __ sd(a3, FieldMemOperand(v0, JSIteratorResult::kDoneOffset));
1921 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
1922}
1923
1924
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001925void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
1926 Token::Value op,
1927 Expression* left_expr,
1928 Expression* right_expr) {
1929 Label done, smi_case, stub_call;
1930
1931 Register scratch1 = a2;
1932 Register scratch2 = a3;
1933
1934 // Get the arguments.
1935 Register left = a1;
1936 Register right = a0;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001937 PopOperand(left);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001938 __ mov(a0, result_register());
1939
1940 // Perform combined smi check on both operands.
1941 __ Or(scratch1, left, Operand(right));
1942 STATIC_ASSERT(kSmiTag == 0);
1943 JumpPatchSite patch_site(masm_);
1944 patch_site.EmitJumpIfSmi(scratch1, &smi_case);
1945
1946 __ bind(&stub_call);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001947 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001948 CallIC(code, expr->BinaryOperationFeedbackId());
1949 patch_site.EmitPatchInfo();
1950 __ jmp(&done);
1951
1952 __ bind(&smi_case);
1953 // Smi case. This code works the same way as the smi-smi case in the type
1954 // recording binary operation stub, see
1955 switch (op) {
1956 case Token::SAR:
1957 __ GetLeastBitsFromSmi(scratch1, right, 5);
1958 __ dsrav(right, left, scratch1);
1959 __ And(v0, right, Operand(0xffffffff00000000L));
1960 break;
1961 case Token::SHL: {
1962 __ SmiUntag(scratch1, left);
1963 __ GetLeastBitsFromSmi(scratch2, right, 5);
1964 __ dsllv(scratch1, scratch1, scratch2);
1965 __ SmiTag(v0, scratch1);
1966 break;
1967 }
1968 case Token::SHR: {
1969 __ SmiUntag(scratch1, left);
1970 __ GetLeastBitsFromSmi(scratch2, right, 5);
1971 __ dsrlv(scratch1, scratch1, scratch2);
1972 __ And(scratch2, scratch1, 0x80000000);
1973 __ Branch(&stub_call, ne, scratch2, Operand(zero_reg));
1974 __ SmiTag(v0, scratch1);
1975 break;
1976 }
1977 case Token::ADD:
Ben Murdochda12d292016-06-02 14:46:10 +01001978 __ DaddBranchOvf(v0, left, Operand(right), &stub_call);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001979 break;
1980 case Token::SUB:
Ben Murdochda12d292016-06-02 14:46:10 +01001981 __ DsubBranchOvf(v0, left, Operand(right), &stub_call);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001982 break;
1983 case Token::MUL: {
1984 __ Dmulh(v0, left, right);
1985 __ dsra32(scratch2, v0, 0);
1986 __ sra(scratch1, v0, 31);
1987 __ Branch(USE_DELAY_SLOT, &stub_call, ne, scratch2, Operand(scratch1));
1988 __ SmiTag(v0);
1989 __ Branch(USE_DELAY_SLOT, &done, ne, v0, Operand(zero_reg));
1990 __ Daddu(scratch2, right, left);
1991 __ Branch(&stub_call, lt, scratch2, Operand(zero_reg));
1992 DCHECK(Smi::FromInt(0) == 0);
1993 __ mov(v0, zero_reg);
1994 break;
1995 }
1996 case Token::BIT_OR:
1997 __ Or(v0, left, Operand(right));
1998 break;
1999 case Token::BIT_AND:
2000 __ And(v0, left, Operand(right));
2001 break;
2002 case Token::BIT_XOR:
2003 __ Xor(v0, left, Operand(right));
2004 break;
2005 default:
2006 UNREACHABLE();
2007 }
2008
2009 __ bind(&done);
2010 context()->Plug(v0);
2011}
2012
2013
2014void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002015 for (int i = 0; i < lit->properties()->length(); i++) {
2016 ObjectLiteral::Property* property = lit->properties()->at(i);
2017 Expression* value = property->value();
2018
Ben Murdoch097c5b22016-05-18 11:27:45 +01002019 Register scratch = a1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002020 if (property->is_static()) {
2021 __ ld(scratch, MemOperand(sp, kPointerSize)); // constructor
2022 } else {
2023 __ ld(scratch, MemOperand(sp, 0)); // prototype
2024 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002025 PushOperand(scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002026 EmitPropertyKey(property, lit->GetIdForProperty(i));
2027
2028 // The static prototype property is read only. We handle the non computed
2029 // property name case in the parser. Since this is the only case where we
2030 // need to check for an own read only property we special case this so we do
2031 // not need to do this for every property.
2032 if (property->is_static() && property->is_computed_name()) {
2033 __ CallRuntime(Runtime::kThrowIfStaticPrototype);
2034 __ push(v0);
2035 }
2036
2037 VisitForStackValue(value);
2038 if (NeedsHomeObject(value)) {
2039 EmitSetHomeObject(value, 2, property->GetSlot());
2040 }
2041
2042 switch (property->kind()) {
2043 case ObjectLiteral::Property::CONSTANT:
2044 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2045 case ObjectLiteral::Property::PROTOTYPE:
2046 UNREACHABLE();
2047 case ObjectLiteral::Property::COMPUTED:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002048 PushOperand(Smi::FromInt(DONT_ENUM));
2049 PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
2050 CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002051 break;
2052
2053 case ObjectLiteral::Property::GETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002054 PushOperand(Smi::FromInt(DONT_ENUM));
2055 CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002056 break;
2057
2058 case ObjectLiteral::Property::SETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002059 PushOperand(Smi::FromInt(DONT_ENUM));
2060 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002061 break;
2062
2063 default:
2064 UNREACHABLE();
2065 }
2066 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002067}
2068
2069
2070void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
2071 __ mov(a0, result_register());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002072 PopOperand(a1);
2073 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002074 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
2075 CallIC(code, expr->BinaryOperationFeedbackId());
2076 patch_site.EmitPatchInfo();
2077 context()->Plug(v0);
2078}
2079
2080
2081void FullCodeGenerator::EmitAssignment(Expression* expr,
2082 FeedbackVectorSlot slot) {
2083 DCHECK(expr->IsValidReferenceExpressionOrThis());
2084
2085 Property* prop = expr->AsProperty();
2086 LhsKind assign_type = Property::GetAssignType(prop);
2087
2088 switch (assign_type) {
2089 case VARIABLE: {
2090 Variable* var = expr->AsVariableProxy()->var();
2091 EffectContext context(this);
2092 EmitVariableAssignment(var, Token::ASSIGN, slot);
2093 break;
2094 }
2095 case NAMED_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002096 PushOperand(result_register()); // Preserve value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002097 VisitForAccumulatorValue(prop->obj());
2098 __ mov(StoreDescriptor::ReceiverRegister(), result_register());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002099 PopOperand(StoreDescriptor::ValueRegister()); // Restore value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002100 __ li(StoreDescriptor::NameRegister(),
2101 Operand(prop->key()->AsLiteral()->value()));
2102 EmitLoadStoreICSlot(slot);
2103 CallStoreIC();
2104 break;
2105 }
2106 case NAMED_SUPER_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002107 PushOperand(v0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002108 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2109 VisitForAccumulatorValue(
2110 prop->obj()->AsSuperPropertyReference()->home_object());
2111 // stack: value, this; v0: home_object
2112 Register scratch = a2;
2113 Register scratch2 = a3;
2114 __ mov(scratch, result_register()); // home_object
2115 __ ld(v0, MemOperand(sp, kPointerSize)); // value
2116 __ ld(scratch2, MemOperand(sp, 0)); // this
2117 __ sd(scratch2, MemOperand(sp, kPointerSize)); // this
2118 __ sd(scratch, MemOperand(sp, 0)); // home_object
2119 // stack: this, home_object; v0: value
2120 EmitNamedSuperPropertyStore(prop);
2121 break;
2122 }
2123 case KEYED_SUPER_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002124 PushOperand(v0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002125 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2126 VisitForStackValue(
2127 prop->obj()->AsSuperPropertyReference()->home_object());
2128 VisitForAccumulatorValue(prop->key());
2129 Register scratch = a2;
2130 Register scratch2 = a3;
2131 __ ld(scratch2, MemOperand(sp, 2 * kPointerSize)); // value
2132 // stack: value, this, home_object; v0: key, a3: value
2133 __ ld(scratch, MemOperand(sp, kPointerSize)); // this
2134 __ sd(scratch, MemOperand(sp, 2 * kPointerSize));
2135 __ ld(scratch, MemOperand(sp, 0)); // home_object
2136 __ sd(scratch, MemOperand(sp, kPointerSize));
2137 __ sd(v0, MemOperand(sp, 0));
2138 __ Move(v0, scratch2);
2139 // stack: this, home_object, key; v0: value.
2140 EmitKeyedSuperPropertyStore(prop);
2141 break;
2142 }
2143 case KEYED_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002144 PushOperand(result_register()); // Preserve value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002145 VisitForStackValue(prop->obj());
2146 VisitForAccumulatorValue(prop->key());
2147 __ Move(StoreDescriptor::NameRegister(), result_register());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002148 PopOperands(StoreDescriptor::ValueRegister(),
2149 StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002150 EmitLoadStoreICSlot(slot);
2151 Handle<Code> ic =
2152 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2153 CallIC(ic);
2154 break;
2155 }
2156 }
2157 context()->Plug(v0);
2158}
2159
2160
2161void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2162 Variable* var, MemOperand location) {
2163 __ sd(result_register(), location);
2164 if (var->IsContextSlot()) {
2165 // RecordWrite may destroy all its register arguments.
2166 __ Move(a3, result_register());
2167 int offset = Context::SlotOffset(var->index());
2168 __ RecordWriteContextSlot(
2169 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs);
2170 }
2171}
2172
2173
2174void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
2175 FeedbackVectorSlot slot) {
2176 if (var->IsUnallocated()) {
2177 // Global var, const, or let.
2178 __ mov(StoreDescriptor::ValueRegister(), result_register());
2179 __ li(StoreDescriptor::NameRegister(), Operand(var->name()));
2180 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister());
2181 EmitLoadStoreICSlot(slot);
2182 CallStoreIC();
2183
2184 } else if (var->mode() == LET && op != Token::INIT) {
2185 // Non-initializing assignment to let variable needs a write barrier.
2186 DCHECK(!var->IsLookupSlot());
2187 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2188 Label assign;
2189 MemOperand location = VarOperand(var, a1);
2190 __ ld(a3, location);
2191 __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
2192 __ Branch(&assign, ne, a3, Operand(a4));
2193 __ li(a3, Operand(var->name()));
2194 __ push(a3);
2195 __ CallRuntime(Runtime::kThrowReferenceError);
2196 // Perform the assignment.
2197 __ bind(&assign);
2198 EmitStoreToStackLocalOrContextSlot(var, location);
2199
2200 } else if (var->mode() == CONST && op != Token::INIT) {
2201 // Assignment to const variable needs a write barrier.
2202 DCHECK(!var->IsLookupSlot());
2203 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2204 Label const_error;
2205 MemOperand location = VarOperand(var, a1);
2206 __ ld(a3, location);
2207 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2208 __ Branch(&const_error, ne, a3, Operand(at));
2209 __ li(a3, Operand(var->name()));
2210 __ push(a3);
2211 __ CallRuntime(Runtime::kThrowReferenceError);
2212 __ bind(&const_error);
2213 __ CallRuntime(Runtime::kThrowConstAssignError);
2214
2215 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
2216 // Initializing assignment to const {this} needs a write barrier.
2217 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2218 Label uninitialized_this;
2219 MemOperand location = VarOperand(var, a1);
2220 __ ld(a3, location);
2221 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2222 __ Branch(&uninitialized_this, eq, a3, Operand(at));
2223 __ li(a0, Operand(var->name()));
2224 __ Push(a0);
2225 __ CallRuntime(Runtime::kThrowReferenceError);
2226 __ bind(&uninitialized_this);
2227 EmitStoreToStackLocalOrContextSlot(var, location);
2228
Ben Murdochc5610432016-08-08 18:44:38 +01002229 } else if (!var->is_const_mode() || op == Token::INIT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002230 if (var->IsLookupSlot()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002231 __ Push(var->name());
2232 __ Push(v0);
2233 __ CallRuntime(is_strict(language_mode())
2234 ? Runtime::kStoreLookupSlot_Strict
2235 : Runtime::kStoreLookupSlot_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002236 } else {
2237 // Assignment to var or initializing assignment to let/const in harmony
2238 // mode.
2239 DCHECK((var->IsStackAllocated() || var->IsContextSlot()));
2240 MemOperand location = VarOperand(var, a1);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002241 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002242 // Check for an uninitialized let binding.
2243 __ ld(a2, location);
2244 __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
2245 __ Check(eq, kLetBindingReInitialization, a2, Operand(a4));
2246 }
2247 EmitStoreToStackLocalOrContextSlot(var, location);
2248 }
2249
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002250 } else {
2251 DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
2252 if (is_strict(language_mode())) {
2253 __ CallRuntime(Runtime::kThrowConstAssignError);
2254 }
2255 // Silently ignore store in sloppy mode.
2256 }
2257}
2258
2259
2260void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2261 // Assignment to a property, using a named store IC.
2262 Property* prop = expr->target()->AsProperty();
2263 DCHECK(prop != NULL);
2264 DCHECK(prop->key()->IsLiteral());
2265
2266 __ mov(StoreDescriptor::ValueRegister(), result_register());
2267 __ li(StoreDescriptor::NameRegister(),
2268 Operand(prop->key()->AsLiteral()->value()));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002269 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002270 EmitLoadStoreICSlot(expr->AssignmentSlot());
2271 CallStoreIC();
2272
Ben Murdochc5610432016-08-08 18:44:38 +01002273 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002274 context()->Plug(v0);
2275}
2276
2277
2278void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2279 // Assignment to named property of super.
2280 // v0 : value
2281 // stack : receiver ('this'), home_object
2282 DCHECK(prop != NULL);
2283 Literal* key = prop->key()->AsLiteral();
2284 DCHECK(key != NULL);
2285
Ben Murdoch097c5b22016-05-18 11:27:45 +01002286 PushOperand(key->value());
2287 PushOperand(v0);
2288 CallRuntimeWithOperands(is_strict(language_mode())
2289 ? Runtime::kStoreToSuper_Strict
2290 : Runtime::kStoreToSuper_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002291}
2292
2293
2294void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2295 // Assignment to named property of super.
2296 // v0 : value
2297 // stack : receiver ('this'), home_object, key
2298 DCHECK(prop != NULL);
2299
Ben Murdoch097c5b22016-05-18 11:27:45 +01002300 PushOperand(v0);
2301 CallRuntimeWithOperands(is_strict(language_mode())
2302 ? Runtime::kStoreKeyedToSuper_Strict
2303 : Runtime::kStoreKeyedToSuper_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002304}
2305
2306
2307void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2308 // Assignment to a property, using a keyed store IC.
2309 // Call keyed store IC.
2310 // The arguments are:
2311 // - a0 is the value,
2312 // - a1 is the key,
2313 // - a2 is the receiver.
2314 __ mov(StoreDescriptor::ValueRegister(), result_register());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002315 PopOperands(StoreDescriptor::ReceiverRegister(),
2316 StoreDescriptor::NameRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002317 DCHECK(StoreDescriptor::ValueRegister().is(a0));
2318
2319 Handle<Code> ic =
2320 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2321 EmitLoadStoreICSlot(expr->AssignmentSlot());
2322 CallIC(ic);
2323
Ben Murdochc5610432016-08-08 18:44:38 +01002324 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002325 context()->Plug(v0);
2326}
2327
2328
2329void FullCodeGenerator::CallIC(Handle<Code> code,
2330 TypeFeedbackId id) {
2331 ic_total_count_++;
2332 __ Call(code, RelocInfo::CODE_TARGET, id);
2333}
2334
2335
2336// Code common for calls using the IC.
2337void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2338 Expression* callee = expr->expression();
2339
2340 // Get the target function.
2341 ConvertReceiverMode convert_mode;
2342 if (callee->IsVariableProxy()) {
2343 { StackValueContext context(this);
2344 EmitVariableLoad(callee->AsVariableProxy());
Ben Murdochc5610432016-08-08 18:44:38 +01002345 PrepareForBailout(callee, BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002346 }
2347 // Push undefined as receiver. This is patched in the method prologue if it
2348 // is a sloppy mode method.
2349 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002350 PushOperand(at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002351 convert_mode = ConvertReceiverMode::kNullOrUndefined;
2352 } else {
2353 // Load the function from the receiver.
2354 DCHECK(callee->IsProperty());
2355 DCHECK(!callee->AsProperty()->IsSuperAccess());
2356 __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
2357 EmitNamedPropertyLoad(callee->AsProperty());
Ben Murdochc5610432016-08-08 18:44:38 +01002358 PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2359 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002360 // Push the target function under the receiver.
2361 __ ld(at, MemOperand(sp, 0));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002362 PushOperand(at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002363 __ sd(v0, MemOperand(sp, kPointerSize));
2364 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
2365 }
2366
2367 EmitCall(expr, convert_mode);
2368}
2369
2370
2371void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2372 SetExpressionPosition(expr);
2373 Expression* callee = expr->expression();
2374 DCHECK(callee->IsProperty());
2375 Property* prop = callee->AsProperty();
2376 DCHECK(prop->IsSuperAccess());
2377
2378 Literal* key = prop->key()->AsLiteral();
2379 DCHECK(!key->value()->IsSmi());
2380 // Load the function from the receiver.
2381 const Register scratch = a1;
2382 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2383 VisitForAccumulatorValue(super_ref->home_object());
2384 __ mov(scratch, v0);
2385 VisitForAccumulatorValue(super_ref->this_var());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002386 PushOperands(scratch, v0, v0, scratch);
2387 PushOperand(key->value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002388
2389 // Stack here:
2390 // - home_object
2391 // - this (receiver)
2392 // - this (receiver) <-- LoadFromSuper will pop here and below.
2393 // - home_object
2394 // - key
Ben Murdoch097c5b22016-05-18 11:27:45 +01002395 CallRuntimeWithOperands(Runtime::kLoadFromSuper);
Ben Murdochc5610432016-08-08 18:44:38 +01002396 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002397
2398 // Replace home_object with target function.
2399 __ sd(v0, MemOperand(sp, kPointerSize));
2400
2401 // Stack here:
2402 // - target function
2403 // - this (receiver)
2404 EmitCall(expr);
2405}
2406
2407
2408// Code common for calls using the IC.
2409void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2410 Expression* key) {
2411 // Load the key.
2412 VisitForAccumulatorValue(key);
2413
2414 Expression* callee = expr->expression();
2415
2416 // Load the function from the receiver.
2417 DCHECK(callee->IsProperty());
2418 __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
2419 __ Move(LoadDescriptor::NameRegister(), v0);
2420 EmitKeyedPropertyLoad(callee->AsProperty());
Ben Murdochc5610432016-08-08 18:44:38 +01002421 PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2422 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002423
2424 // Push the target function under the receiver.
2425 __ ld(at, MemOperand(sp, 0));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002426 PushOperand(at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002427 __ sd(v0, MemOperand(sp, kPointerSize));
2428
2429 EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined);
2430}
2431
2432
2433void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2434 Expression* callee = expr->expression();
2435 DCHECK(callee->IsProperty());
2436 Property* prop = callee->AsProperty();
2437 DCHECK(prop->IsSuperAccess());
2438
2439 SetExpressionPosition(prop);
2440 // Load the function from the receiver.
2441 const Register scratch = a1;
2442 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2443 VisitForAccumulatorValue(super_ref->home_object());
2444 __ Move(scratch, v0);
2445 VisitForAccumulatorValue(super_ref->this_var());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002446 PushOperands(scratch, v0, v0, scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002447 VisitForStackValue(prop->key());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002448
2449 // Stack here:
2450 // - home_object
2451 // - this (receiver)
2452 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2453 // - home_object
2454 // - key
Ben Murdoch097c5b22016-05-18 11:27:45 +01002455 CallRuntimeWithOperands(Runtime::kLoadKeyedFromSuper);
Ben Murdochc5610432016-08-08 18:44:38 +01002456 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002457
2458 // Replace home_object with target function.
2459 __ sd(v0, MemOperand(sp, kPointerSize));
2460
2461 // Stack here:
2462 // - target function
2463 // - this (receiver)
2464 EmitCall(expr);
2465}
2466
2467
2468void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
2469 // Load the arguments.
2470 ZoneList<Expression*>* args = expr->arguments();
2471 int arg_count = args->length();
2472 for (int i = 0; i < arg_count; i++) {
2473 VisitForStackValue(args->at(i));
2474 }
2475
Ben Murdochc5610432016-08-08 18:44:38 +01002476 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002477 // Record source position of the IC call.
Ben Murdochda12d292016-06-02 14:46:10 +01002478 SetCallPosition(expr, expr->tail_call_mode());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002479 if (expr->tail_call_mode() == TailCallMode::kAllow) {
2480 if (FLAG_trace) {
2481 __ CallRuntime(Runtime::kTraceTailCall);
2482 }
2483 // Update profiling counters before the tail call since we will
2484 // not return to this function.
2485 EmitProfilingCounterHandlingForReturnSequence(true);
2486 }
2487 Handle<Code> ic =
2488 CodeFactory::CallIC(isolate(), arg_count, mode, expr->tail_call_mode())
2489 .code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002490 __ li(a3, Operand(SmiFromSlot(expr->CallFeedbackICSlot())));
2491 __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2492 // Don't assign a type feedback id to the IC, since type feedback is provided
2493 // by the vector above.
2494 CallIC(ic);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002495 OperandStackDepthDecrement(arg_count + 1);
2496
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002497 RecordJSReturnSite(expr);
Ben Murdochc5610432016-08-08 18:44:38 +01002498 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002499 context()->DropAndPlug(1, v0);
2500}
2501
Ben Murdochc5610432016-08-08 18:44:38 +01002502void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) {
2503 int arg_count = expr->arguments()->length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002504 // a6: copy of the first argument or undefined if it doesn't exist.
2505 if (arg_count > 0) {
2506 __ ld(a6, MemOperand(sp, arg_count * kPointerSize));
2507 } else {
2508 __ LoadRoot(a6, Heap::kUndefinedValueRootIndex);
2509 }
2510
2511 // a5: the receiver of the enclosing function.
2512 __ ld(a5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
2513
2514 // a4: the language mode.
2515 __ li(a4, Operand(Smi::FromInt(language_mode())));
2516
2517 // a1: the start position of the scope the calls resides in.
2518 __ li(a1, Operand(Smi::FromInt(scope()->start_position())));
2519
Ben Murdochc5610432016-08-08 18:44:38 +01002520 // a0: the source position of the eval call.
2521 __ li(a0, Operand(Smi::FromInt(expr->position())));
2522
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002523 // Do the runtime call.
Ben Murdochc5610432016-08-08 18:44:38 +01002524 __ Push(a6, a5, a4, a1, a0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002525 __ CallRuntime(Runtime::kResolvePossiblyDirectEval);
2526}
2527
2528
2529// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
2530void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
2531 VariableProxy* callee = expr->expression()->AsVariableProxy();
2532 if (callee->var()->IsLookupSlot()) {
2533 Label slow, done;
2534
2535 SetExpressionPosition(callee);
2536 // Generate code for loading from variables potentially shadowed by
2537 // eval-introduced variables.
2538 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
2539
2540 __ bind(&slow);
2541 // Call the runtime to find the function to call (returned in v0)
2542 // and the object holding it (returned in v1).
Ben Murdoch097c5b22016-05-18 11:27:45 +01002543 __ Push(callee->name());
2544 __ CallRuntime(Runtime::kLoadLookupSlotForCall);
2545 PushOperands(v0, v1); // Function, receiver.
Ben Murdochc5610432016-08-08 18:44:38 +01002546 PrepareForBailoutForId(expr->LookupId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002547
2548 // If fast case code has been generated, emit code to push the
2549 // function and receiver and have the slow path jump around this
2550 // code.
2551 if (done.is_linked()) {
2552 Label call;
2553 __ Branch(&call);
2554 __ bind(&done);
2555 // Push function.
2556 __ push(v0);
2557 // The receiver is implicitly the global receiver. Indicate this
2558 // by passing the hole to the call function stub.
2559 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
2560 __ push(a1);
2561 __ bind(&call);
2562 }
2563 } else {
2564 VisitForStackValue(callee);
2565 // refEnv.WithBaseObject()
2566 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002567 PushOperand(a2); // Reserved receiver slot.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002568 }
2569}
2570
2571
2572void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
Ben Murdochc5610432016-08-08 18:44:38 +01002573 // In a call to eval, we first call Runtime_ResolvePossiblyDirectEval
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002574 // to resolve the function we need to call. Then we call the resolved
2575 // function using the given arguments.
2576 ZoneList<Expression*>* args = expr->arguments();
2577 int arg_count = args->length();
2578 PushCalleeAndWithBaseObject(expr);
2579
2580 // Push the arguments.
2581 for (int i = 0; i < arg_count; i++) {
2582 VisitForStackValue(args->at(i));
2583 }
2584
2585 // Push a copy of the function (found below the arguments) and
2586 // resolve eval.
2587 __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2588 __ push(a1);
Ben Murdochc5610432016-08-08 18:44:38 +01002589 EmitResolvePossiblyDirectEval(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002590
2591 // Touch up the stack with the resolved function.
2592 __ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
2593
Ben Murdochc5610432016-08-08 18:44:38 +01002594 PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002595 // Record source position for debugger.
2596 SetCallPosition(expr);
2597 __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2598 __ li(a0, Operand(arg_count));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002599 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny,
2600 expr->tail_call_mode()),
2601 RelocInfo::CODE_TARGET);
2602 OperandStackDepthDecrement(arg_count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002603 RecordJSReturnSite(expr);
Ben Murdochc5610432016-08-08 18:44:38 +01002604 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002605 context()->DropAndPlug(1, v0);
2606}
2607
2608
2609void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2610 Comment cmnt(masm_, "[ CallNew");
2611 // According to ECMA-262, section 11.2.2, page 44, the function
2612 // expression in new calls must be evaluated before the
2613 // arguments.
2614
2615 // Push constructor on the stack. If it's not a function it's used as
2616 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2617 // ignored.
2618 DCHECK(!expr->expression()->IsSuperPropertyReference());
2619 VisitForStackValue(expr->expression());
2620
2621 // Push the arguments ("left-to-right") on the stack.
2622 ZoneList<Expression*>* args = expr->arguments();
2623 int arg_count = args->length();
2624 for (int i = 0; i < arg_count; i++) {
2625 VisitForStackValue(args->at(i));
2626 }
2627
2628 // Call the construct call builtin that handles allocation and
2629 // constructor invocation.
2630 SetConstructCallPosition(expr);
2631
2632 // Load function and argument count into a1 and a0.
2633 __ li(a0, Operand(arg_count));
2634 __ ld(a1, MemOperand(sp, arg_count * kPointerSize));
2635
2636 // Record call targets in unoptimized code.
2637 __ EmitLoadTypeFeedbackVector(a2);
2638 __ li(a3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot())));
2639
2640 CallConstructStub stub(isolate());
2641 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002642 OperandStackDepthDecrement(arg_count + 1);
Ben Murdochc5610432016-08-08 18:44:38 +01002643 PrepareForBailoutForId(expr->ReturnId(), BailoutState::TOS_REGISTER);
2644 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002645 context()->Plug(v0);
2646}
2647
2648
2649void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
2650 SuperCallReference* super_call_ref =
2651 expr->expression()->AsSuperCallReference();
2652 DCHECK_NOT_NULL(super_call_ref);
2653
2654 // Push the super constructor target on the stack (may be null,
2655 // but the Construct builtin can deal with that properly).
2656 VisitForAccumulatorValue(super_call_ref->this_function_var());
2657 __ AssertFunction(result_register());
2658 __ ld(result_register(),
2659 FieldMemOperand(result_register(), HeapObject::kMapOffset));
2660 __ ld(result_register(),
2661 FieldMemOperand(result_register(), Map::kPrototypeOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002662 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002663
2664 // Push the arguments ("left-to-right") on the stack.
2665 ZoneList<Expression*>* args = expr->arguments();
2666 int arg_count = args->length();
2667 for (int i = 0; i < arg_count; i++) {
2668 VisitForStackValue(args->at(i));
2669 }
2670
2671 // Call the construct call builtin that handles allocation and
2672 // constructor invocation.
2673 SetConstructCallPosition(expr);
2674
2675 // Load new target into a3.
2676 VisitForAccumulatorValue(super_call_ref->new_target_var());
2677 __ mov(a3, result_register());
2678
2679 // Load function and argument count into a1 and a0.
2680 __ li(a0, Operand(arg_count));
2681 __ ld(a1, MemOperand(sp, arg_count * kPointerSize));
2682
2683 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002684 OperandStackDepthDecrement(arg_count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002685
2686 RecordJSReturnSite(expr);
Ben Murdochc5610432016-08-08 18:44:38 +01002687 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002688 context()->Plug(v0);
2689}
2690
2691
2692void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2693 ZoneList<Expression*>* args = expr->arguments();
2694 DCHECK(args->length() == 1);
2695
2696 VisitForAccumulatorValue(args->at(0));
2697
2698 Label materialize_true, materialize_false;
2699 Label* if_true = NULL;
2700 Label* if_false = NULL;
2701 Label* fall_through = NULL;
2702 context()->PrepareTest(&materialize_true, &materialize_false,
2703 &if_true, &if_false, &fall_through);
2704
2705 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2706 __ SmiTst(v0, a4);
2707 Split(eq, a4, Operand(zero_reg), if_true, if_false, fall_through);
2708
2709 context()->Plug(if_true, if_false);
2710}
2711
2712
2713void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) {
2714 ZoneList<Expression*>* args = expr->arguments();
2715 DCHECK(args->length() == 1);
2716
2717 VisitForAccumulatorValue(args->at(0));
2718
2719 Label materialize_true, materialize_false;
2720 Label* if_true = NULL;
2721 Label* if_false = NULL;
2722 Label* fall_through = NULL;
2723 context()->PrepareTest(&materialize_true, &materialize_false,
2724 &if_true, &if_false, &fall_through);
2725
2726 __ JumpIfSmi(v0, if_false);
2727 __ GetObjectType(v0, a1, a1);
2728 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2729 Split(ge, a1, Operand(FIRST_JS_RECEIVER_TYPE),
2730 if_true, if_false, fall_through);
2731
2732 context()->Plug(if_true, if_false);
2733}
2734
2735
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002736void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2737 ZoneList<Expression*>* args = expr->arguments();
2738 DCHECK(args->length() == 1);
2739
2740 VisitForAccumulatorValue(args->at(0));
2741
2742 Label materialize_true, materialize_false;
2743 Label* if_true = NULL;
2744 Label* if_false = NULL;
2745 Label* fall_through = NULL;
2746 context()->PrepareTest(&materialize_true, &materialize_false,
2747 &if_true, &if_false, &fall_through);
2748
2749 __ JumpIfSmi(v0, if_false);
2750 __ GetObjectType(v0, a1, a1);
2751 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2752 Split(eq, a1, Operand(JS_ARRAY_TYPE),
2753 if_true, if_false, fall_through);
2754
2755 context()->Plug(if_true, if_false);
2756}
2757
2758
2759void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) {
2760 ZoneList<Expression*>* args = expr->arguments();
2761 DCHECK(args->length() == 1);
2762
2763 VisitForAccumulatorValue(args->at(0));
2764
2765 Label materialize_true, materialize_false;
2766 Label* if_true = NULL;
2767 Label* if_false = NULL;
2768 Label* fall_through = NULL;
2769 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2770 &if_false, &fall_through);
2771
2772 __ JumpIfSmi(v0, if_false);
2773 __ GetObjectType(v0, a1, a1);
2774 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2775 Split(eq, a1, Operand(JS_TYPED_ARRAY_TYPE), if_true, if_false, fall_through);
2776
2777 context()->Plug(if_true, if_false);
2778}
2779
2780
2781void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2782 ZoneList<Expression*>* args = expr->arguments();
2783 DCHECK(args->length() == 1);
2784
2785 VisitForAccumulatorValue(args->at(0));
2786
2787 Label materialize_true, materialize_false;
2788 Label* if_true = NULL;
2789 Label* if_false = NULL;
2790 Label* fall_through = NULL;
2791 context()->PrepareTest(&materialize_true, &materialize_false,
2792 &if_true, &if_false, &fall_through);
2793
2794 __ JumpIfSmi(v0, if_false);
2795 __ GetObjectType(v0, a1, a1);
2796 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2797 Split(eq, a1, Operand(JS_REGEXP_TYPE), if_true, if_false, fall_through);
2798
2799 context()->Plug(if_true, if_false);
2800}
2801
2802
2803void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
2804 ZoneList<Expression*>* args = expr->arguments();
2805 DCHECK(args->length() == 1);
2806
2807 VisitForAccumulatorValue(args->at(0));
2808
2809 Label materialize_true, materialize_false;
2810 Label* if_true = NULL;
2811 Label* if_false = NULL;
2812 Label* fall_through = NULL;
2813 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2814 &if_false, &fall_through);
2815
2816 __ JumpIfSmi(v0, if_false);
2817 __ GetObjectType(v0, a1, a1);
2818 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2819 Split(eq, a1, Operand(JS_PROXY_TYPE), if_true, if_false, fall_through);
2820
2821 context()->Plug(if_true, if_false);
2822}
2823
2824
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002825void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2826 ZoneList<Expression*>* args = expr->arguments();
2827 DCHECK(args->length() == 1);
2828 Label done, null, function, non_function_constructor;
2829
2830 VisitForAccumulatorValue(args->at(0));
2831
2832 // If the object is not a JSReceiver, we return null.
2833 __ JumpIfSmi(v0, &null);
2834 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2835 __ GetObjectType(v0, v0, a1); // Map is now in v0.
2836 __ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
2837
Ben Murdochda12d292016-06-02 14:46:10 +01002838 // Return 'Function' for JSFunction and JSBoundFunction objects.
2839 STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE);
2840 __ Branch(&function, hs, a1, Operand(FIRST_FUNCTION_TYPE));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002841
2842 // Check if the constructor in the map is a JS function.
2843 Register instance_type = a2;
2844 __ GetMapConstructor(v0, v0, a1, instance_type);
2845 __ Branch(&non_function_constructor, ne, instance_type,
2846 Operand(JS_FUNCTION_TYPE));
2847
2848 // v0 now contains the constructor function. Grab the
2849 // instance class name from there.
2850 __ ld(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset));
2851 __ ld(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset));
2852 __ Branch(&done);
2853
2854 // Functions have class 'Function'.
2855 __ bind(&function);
2856 __ LoadRoot(v0, Heap::kFunction_stringRootIndex);
2857 __ jmp(&done);
2858
2859 // Objects with a non-function constructor have class 'Object'.
2860 __ bind(&non_function_constructor);
2861 __ LoadRoot(v0, Heap::kObject_stringRootIndex);
2862 __ jmp(&done);
2863
2864 // Non-JS objects have class null.
2865 __ bind(&null);
2866 __ LoadRoot(v0, Heap::kNullValueRootIndex);
2867
2868 // All done.
2869 __ bind(&done);
2870
2871 context()->Plug(v0);
2872}
2873
2874
2875void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
2876 ZoneList<Expression*>* args = expr->arguments();
2877 DCHECK(args->length() == 1);
2878
2879 VisitForAccumulatorValue(args->at(0)); // Load the object.
2880
2881 Label done;
2882 // If the object is a smi return the object.
2883 __ JumpIfSmi(v0, &done);
2884 // If the object is not a value type, return the object.
2885 __ GetObjectType(v0, a1, a1);
2886 __ Branch(&done, ne, a1, Operand(JS_VALUE_TYPE));
2887
2888 __ ld(v0, FieldMemOperand(v0, JSValue::kValueOffset));
2889
2890 __ bind(&done);
2891 context()->Plug(v0);
2892}
2893
2894
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002895void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
2896 ZoneList<Expression*>* args = expr->arguments();
2897 DCHECK(args->length() == 1);
2898
2899 VisitForAccumulatorValue(args->at(0));
2900
2901 Label done;
2902 StringCharFromCodeGenerator generator(v0, a1);
2903 generator.GenerateFast(masm_);
2904 __ jmp(&done);
2905
2906 NopRuntimeCallHelper call_helper;
2907 generator.GenerateSlow(masm_, call_helper);
2908
2909 __ bind(&done);
2910 context()->Plug(a1);
2911}
2912
2913
2914void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
2915 ZoneList<Expression*>* args = expr->arguments();
2916 DCHECK(args->length() == 2);
2917
2918 VisitForStackValue(args->at(0));
2919 VisitForAccumulatorValue(args->at(1));
2920 __ mov(a0, result_register());
2921
2922 Register object = a1;
2923 Register index = a0;
2924 Register result = v0;
2925
Ben Murdoch097c5b22016-05-18 11:27:45 +01002926 PopOperand(object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002927
2928 Label need_conversion;
2929 Label index_out_of_range;
2930 Label done;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002931 StringCharCodeAtGenerator generator(object, index, result, &need_conversion,
2932 &need_conversion, &index_out_of_range);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002933 generator.GenerateFast(masm_);
2934 __ jmp(&done);
2935
2936 __ bind(&index_out_of_range);
2937 // When the index is out of range, the spec requires us to return
2938 // NaN.
2939 __ LoadRoot(result, Heap::kNanValueRootIndex);
2940 __ jmp(&done);
2941
2942 __ bind(&need_conversion);
2943 // Load the undefined value into the result register, which will
2944 // trigger conversion.
2945 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2946 __ jmp(&done);
2947
2948 NopRuntimeCallHelper call_helper;
2949 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
2950
2951 __ bind(&done);
2952 context()->Plug(result);
2953}
2954
2955
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002956void FullCodeGenerator::EmitCall(CallRuntime* expr) {
2957 ZoneList<Expression*>* args = expr->arguments();
2958 DCHECK_LE(2, args->length());
2959 // Push target, receiver and arguments onto the stack.
2960 for (Expression* const arg : *args) {
2961 VisitForStackValue(arg);
2962 }
Ben Murdochc5610432016-08-08 18:44:38 +01002963 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002964 // Move target to a1.
2965 int const argc = args->length() - 2;
2966 __ ld(a1, MemOperand(sp, (argc + 1) * kPointerSize));
2967 // Call the target.
2968 __ li(a0, Operand(argc));
2969 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002970 OperandStackDepthDecrement(argc + 1);
Ben Murdochc5610432016-08-08 18:44:38 +01002971 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002972 // Discard the function left on TOS.
2973 context()->DropAndPlug(1, v0);
2974}
2975
2976
2977void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
2978 ZoneList<Expression*>* args = expr->arguments();
2979 VisitForAccumulatorValue(args->at(0));
2980
2981 Label materialize_true, materialize_false;
2982 Label* if_true = NULL;
2983 Label* if_false = NULL;
2984 Label* fall_through = NULL;
2985 context()->PrepareTest(&materialize_true, &materialize_false,
2986 &if_true, &if_false, &fall_through);
2987
2988 __ lwu(a0, FieldMemOperand(v0, String::kHashFieldOffset));
2989 __ And(a0, a0, Operand(String::kContainsCachedArrayIndexMask));
2990
2991 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2992 Split(eq, a0, Operand(zero_reg), if_true, if_false, fall_through);
2993
2994 context()->Plug(if_true, if_false);
2995}
2996
2997
2998void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
2999 ZoneList<Expression*>* args = expr->arguments();
3000 DCHECK(args->length() == 1);
3001 VisitForAccumulatorValue(args->at(0));
3002
3003 __ AssertString(v0);
3004
3005 __ lwu(v0, FieldMemOperand(v0, String::kHashFieldOffset));
3006 __ IndexFromHash(v0, v0);
3007
3008 context()->Plug(v0);
3009}
3010
3011
3012void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) {
3013 ZoneList<Expression*>* args = expr->arguments();
3014 DCHECK_EQ(1, args->length());
3015 VisitForAccumulatorValue(args->at(0));
3016 __ AssertFunction(v0);
3017 __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3018 __ ld(v0, FieldMemOperand(v0, Map::kPrototypeOffset));
3019 context()->Plug(v0);
3020}
3021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003022void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
3023 DCHECK(expr->arguments()->length() == 0);
3024 ExternalReference debug_is_active =
3025 ExternalReference::debug_is_active_address(isolate());
3026 __ li(at, Operand(debug_is_active));
3027 __ lbu(v0, MemOperand(at));
3028 __ SmiTag(v0);
3029 context()->Plug(v0);
3030}
3031
3032
3033void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
3034 ZoneList<Expression*>* args = expr->arguments();
3035 DCHECK_EQ(2, args->length());
3036 VisitForStackValue(args->at(0));
3037 VisitForStackValue(args->at(1));
3038
3039 Label runtime, done;
3040
Ben Murdochc5610432016-08-08 18:44:38 +01003041 __ Allocate(JSIteratorResult::kSize, v0, a2, a3, &runtime,
3042 NO_ALLOCATION_FLAGS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003043 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, a1);
3044 __ Pop(a2, a3);
3045 __ LoadRoot(a4, Heap::kEmptyFixedArrayRootIndex);
3046 __ sd(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
3047 __ sd(a4, FieldMemOperand(v0, JSObject::kPropertiesOffset));
3048 __ sd(a4, FieldMemOperand(v0, JSObject::kElementsOffset));
3049 __ sd(a2, FieldMemOperand(v0, JSIteratorResult::kValueOffset));
3050 __ sd(a3, FieldMemOperand(v0, JSIteratorResult::kDoneOffset));
3051 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
3052 __ jmp(&done);
3053
3054 __ bind(&runtime);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003055 CallRuntimeWithOperands(Runtime::kCreateIterResultObject);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003056
3057 __ bind(&done);
3058 context()->Plug(v0);
3059}
3060
3061
3062void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
Ben Murdochda12d292016-06-02 14:46:10 +01003063 // Push function.
3064 __ LoadNativeContextSlot(expr->context_index(), v0);
3065 PushOperand(v0);
3066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003067 // Push undefined as the receiver.
3068 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003069 PushOperand(v0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003070}
3071
3072
3073void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) {
3074 ZoneList<Expression*>* args = expr->arguments();
3075 int arg_count = args->length();
3076
3077 SetCallPosition(expr);
3078 __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
3079 __ li(a0, Operand(arg_count));
3080 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined),
3081 RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003082 OperandStackDepthDecrement(arg_count + 1);
Ben Murdochc5610432016-08-08 18:44:38 +01003083 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003084}
3085
3086
3087void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3088 switch (expr->op()) {
3089 case Token::DELETE: {
3090 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3091 Property* property = expr->expression()->AsProperty();
3092 VariableProxy* proxy = expr->expression()->AsVariableProxy();
3093
3094 if (property != NULL) {
3095 VisitForStackValue(property->obj());
3096 VisitForStackValue(property->key());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003097 CallRuntimeWithOperands(is_strict(language_mode())
3098 ? Runtime::kDeleteProperty_Strict
3099 : Runtime::kDeleteProperty_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003100 context()->Plug(v0);
3101 } else if (proxy != NULL) {
3102 Variable* var = proxy->var();
3103 // Delete of an unqualified identifier is disallowed in strict mode but
3104 // "delete this" is allowed.
3105 bool is_this = var->HasThisName(isolate());
3106 DCHECK(is_sloppy(language_mode()) || is_this);
3107 if (var->IsUnallocatedOrGlobalSlot()) {
3108 __ LoadGlobalObject(a2);
3109 __ li(a1, Operand(var->name()));
3110 __ Push(a2, a1);
3111 __ CallRuntime(Runtime::kDeleteProperty_Sloppy);
3112 context()->Plug(v0);
3113 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
3114 // Result of deleting non-global, non-dynamic variables is false.
3115 // The subexpression does not have side effects.
3116 context()->Plug(is_this);
3117 } else {
3118 // Non-global variable. Call the runtime to try to delete from the
3119 // context where the variable was introduced.
3120 DCHECK(!context_register().is(a2));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003121 __ Push(var->name());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003122 __ CallRuntime(Runtime::kDeleteLookupSlot);
3123 context()->Plug(v0);
3124 }
3125 } else {
3126 // Result of deleting non-property, non-variable reference is true.
3127 // The subexpression may have side effects.
3128 VisitForEffect(expr->expression());
3129 context()->Plug(true);
3130 }
3131 break;
3132 }
3133
3134 case Token::VOID: {
3135 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3136 VisitForEffect(expr->expression());
3137 context()->Plug(Heap::kUndefinedValueRootIndex);
3138 break;
3139 }
3140
3141 case Token::NOT: {
3142 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
3143 if (context()->IsEffect()) {
3144 // Unary NOT has no side effects so it's only necessary to visit the
3145 // subexpression. Match the optimizing compiler by not branching.
3146 VisitForEffect(expr->expression());
3147 } else if (context()->IsTest()) {
3148 const TestContext* test = TestContext::cast(context());
3149 // The labels are swapped for the recursive call.
3150 VisitForControl(expr->expression(),
3151 test->false_label(),
3152 test->true_label(),
3153 test->fall_through());
3154 context()->Plug(test->true_label(), test->false_label());
3155 } else {
3156 // We handle value contexts explicitly rather than simply visiting
3157 // for control and plugging the control flow into the context,
3158 // because we need to prepare a pair of extra administrative AST ids
3159 // for the optimizing compiler.
3160 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
3161 Label materialize_true, materialize_false, done;
3162 VisitForControl(expr->expression(),
3163 &materialize_false,
3164 &materialize_true,
3165 &materialize_true);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003166 if (!context()->IsAccumulatorValue()) OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003167 __ bind(&materialize_true);
Ben Murdochc5610432016-08-08 18:44:38 +01003168 PrepareForBailoutForId(expr->MaterializeTrueId(),
3169 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003170 __ LoadRoot(v0, Heap::kTrueValueRootIndex);
3171 if (context()->IsStackValue()) __ push(v0);
3172 __ jmp(&done);
3173 __ bind(&materialize_false);
Ben Murdochc5610432016-08-08 18:44:38 +01003174 PrepareForBailoutForId(expr->MaterializeFalseId(),
3175 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003176 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
3177 if (context()->IsStackValue()) __ push(v0);
3178 __ bind(&done);
3179 }
3180 break;
3181 }
3182
3183 case Token::TYPEOF: {
3184 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
3185 {
3186 AccumulatorValueContext context(this);
3187 VisitForTypeofValue(expr->expression());
3188 }
3189 __ mov(a3, v0);
3190 TypeofStub typeof_stub(isolate());
3191 __ CallStub(&typeof_stub);
3192 context()->Plug(v0);
3193 break;
3194 }
3195
3196 default:
3197 UNREACHABLE();
3198 }
3199}
3200
3201
3202void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3203 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
3204
3205 Comment cmnt(masm_, "[ CountOperation");
3206
3207 Property* prop = expr->expression()->AsProperty();
3208 LhsKind assign_type = Property::GetAssignType(prop);
3209
3210 // Evaluate expression and get value.
3211 if (assign_type == VARIABLE) {
3212 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
3213 AccumulatorValueContext context(this);
3214 EmitVariableLoad(expr->expression()->AsVariableProxy());
3215 } else {
3216 // Reserve space for result of postfix operation.
3217 if (expr->is_postfix() && !context()->IsEffect()) {
3218 __ li(at, Operand(Smi::FromInt(0)));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003219 PushOperand(at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003220 }
3221 switch (assign_type) {
3222 case NAMED_PROPERTY: {
3223 // Put the object both on the stack and in the register.
3224 VisitForStackValue(prop->obj());
3225 __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
3226 EmitNamedPropertyLoad(prop);
3227 break;
3228 }
3229
3230 case NAMED_SUPER_PROPERTY: {
3231 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
3232 VisitForAccumulatorValue(
3233 prop->obj()->AsSuperPropertyReference()->home_object());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003234 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003235 const Register scratch = a1;
3236 __ ld(scratch, MemOperand(sp, kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003237 PushOperands(scratch, result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003238 EmitNamedSuperPropertyLoad(prop);
3239 break;
3240 }
3241
3242 case KEYED_SUPER_PROPERTY: {
3243 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
3244 VisitForAccumulatorValue(
3245 prop->obj()->AsSuperPropertyReference()->home_object());
3246 const Register scratch = a1;
3247 const Register scratch1 = a4;
3248 __ Move(scratch, result_register());
3249 VisitForAccumulatorValue(prop->key());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003250 PushOperands(scratch, result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003251 __ ld(scratch1, MemOperand(sp, 2 * kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003252 PushOperands(scratch1, scratch, result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003253 EmitKeyedSuperPropertyLoad(prop);
3254 break;
3255 }
3256
3257 case KEYED_PROPERTY: {
3258 VisitForStackValue(prop->obj());
3259 VisitForStackValue(prop->key());
3260 __ ld(LoadDescriptor::ReceiverRegister(),
3261 MemOperand(sp, 1 * kPointerSize));
3262 __ ld(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
3263 EmitKeyedPropertyLoad(prop);
3264 break;
3265 }
3266
3267 case VARIABLE:
3268 UNREACHABLE();
3269 }
3270 }
3271
3272 // We need a second deoptimization point after loading the value
3273 // in case evaluating the property load my have a side effect.
3274 if (assign_type == VARIABLE) {
Ben Murdochc5610432016-08-08 18:44:38 +01003275 PrepareForBailout(expr->expression(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003276 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01003277 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003278 }
3279
3280 // Inline smi case if we are in a loop.
3281 Label stub_call, done;
3282 JumpPatchSite patch_site(masm_);
3283
3284 int count_value = expr->op() == Token::INC ? 1 : -1;
3285 __ mov(a0, v0);
3286 if (ShouldInlineSmiCase(expr->op())) {
3287 Label slow;
3288 patch_site.EmitJumpIfNotSmi(v0, &slow);
3289
3290 // Save result for postfix expressions.
3291 if (expr->is_postfix()) {
3292 if (!context()->IsEffect()) {
3293 // Save the result on the stack. If we have a named or keyed property
3294 // we store the result under the receiver that is currently on top
3295 // of the stack.
3296 switch (assign_type) {
3297 case VARIABLE:
3298 __ push(v0);
3299 break;
3300 case NAMED_PROPERTY:
3301 __ sd(v0, MemOperand(sp, kPointerSize));
3302 break;
3303 case NAMED_SUPER_PROPERTY:
3304 __ sd(v0, MemOperand(sp, 2 * kPointerSize));
3305 break;
3306 case KEYED_PROPERTY:
3307 __ sd(v0, MemOperand(sp, 2 * kPointerSize));
3308 break;
3309 case KEYED_SUPER_PROPERTY:
3310 __ sd(v0, MemOperand(sp, 3 * kPointerSize));
3311 break;
3312 }
3313 }
3314 }
3315
3316 Register scratch1 = a1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003317 __ li(scratch1, Operand(Smi::FromInt(count_value)));
Ben Murdochda12d292016-06-02 14:46:10 +01003318 __ DaddBranchNoOvf(v0, v0, Operand(scratch1), &done);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003319 // Call stub. Undo operation first.
3320 __ Move(v0, a0);
3321 __ jmp(&stub_call);
3322 __ bind(&slow);
3323 }
Ben Murdochda12d292016-06-02 14:46:10 +01003324
3325 // Convert old value into a number.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003326 __ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
Ben Murdochc5610432016-08-08 18:44:38 +01003327 PrepareForBailoutForId(expr->ToNumberId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003328
3329 // Save result for postfix expressions.
3330 if (expr->is_postfix()) {
3331 if (!context()->IsEffect()) {
3332 // Save the result on the stack. If we have a named or keyed property
3333 // we store the result under the receiver that is currently on top
3334 // of the stack.
3335 switch (assign_type) {
3336 case VARIABLE:
Ben Murdoch097c5b22016-05-18 11:27:45 +01003337 PushOperand(v0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003338 break;
3339 case NAMED_PROPERTY:
3340 __ sd(v0, MemOperand(sp, kPointerSize));
3341 break;
3342 case NAMED_SUPER_PROPERTY:
3343 __ sd(v0, MemOperand(sp, 2 * kPointerSize));
3344 break;
3345 case KEYED_PROPERTY:
3346 __ sd(v0, MemOperand(sp, 2 * kPointerSize));
3347 break;
3348 case KEYED_SUPER_PROPERTY:
3349 __ sd(v0, MemOperand(sp, 3 * kPointerSize));
3350 break;
3351 }
3352 }
3353 }
3354
3355 __ bind(&stub_call);
3356 __ mov(a1, v0);
3357 __ li(a0, Operand(Smi::FromInt(count_value)));
3358
3359 SetExpressionPosition(expr);
3360
Ben Murdoch097c5b22016-05-18 11:27:45 +01003361 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003362 CallIC(code, expr->CountBinOpFeedbackId());
3363 patch_site.EmitPatchInfo();
3364 __ bind(&done);
3365
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003366 // Store the value returned in v0.
3367 switch (assign_type) {
3368 case VARIABLE:
3369 if (expr->is_postfix()) {
3370 { EffectContext context(this);
3371 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3372 Token::ASSIGN, expr->CountSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01003373 PrepareForBailoutForId(expr->AssignmentId(),
3374 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003375 context.Plug(v0);
3376 }
3377 // For all contexts except EffectConstant we have the result on
3378 // top of the stack.
3379 if (!context()->IsEffect()) {
3380 context()->PlugTOS();
3381 }
3382 } else {
3383 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3384 Token::ASSIGN, expr->CountSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01003385 PrepareForBailoutForId(expr->AssignmentId(),
3386 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003387 context()->Plug(v0);
3388 }
3389 break;
3390 case NAMED_PROPERTY: {
3391 __ mov(StoreDescriptor::ValueRegister(), result_register());
3392 __ li(StoreDescriptor::NameRegister(),
3393 Operand(prop->key()->AsLiteral()->value()));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003394 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003395 EmitLoadStoreICSlot(expr->CountSlot());
3396 CallStoreIC();
Ben Murdochc5610432016-08-08 18:44:38 +01003397 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003398 if (expr->is_postfix()) {
3399 if (!context()->IsEffect()) {
3400 context()->PlugTOS();
3401 }
3402 } else {
3403 context()->Plug(v0);
3404 }
3405 break;
3406 }
3407 case NAMED_SUPER_PROPERTY: {
3408 EmitNamedSuperPropertyStore(prop);
3409 if (expr->is_postfix()) {
3410 if (!context()->IsEffect()) {
3411 context()->PlugTOS();
3412 }
3413 } else {
3414 context()->Plug(v0);
3415 }
3416 break;
3417 }
3418 case KEYED_SUPER_PROPERTY: {
3419 EmitKeyedSuperPropertyStore(prop);
3420 if (expr->is_postfix()) {
3421 if (!context()->IsEffect()) {
3422 context()->PlugTOS();
3423 }
3424 } else {
3425 context()->Plug(v0);
3426 }
3427 break;
3428 }
3429 case KEYED_PROPERTY: {
3430 __ mov(StoreDescriptor::ValueRegister(), result_register());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003431 PopOperands(StoreDescriptor::ReceiverRegister(),
3432 StoreDescriptor::NameRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003433 Handle<Code> ic =
3434 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
3435 EmitLoadStoreICSlot(expr->CountSlot());
3436 CallIC(ic);
Ben Murdochc5610432016-08-08 18:44:38 +01003437 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003438 if (expr->is_postfix()) {
3439 if (!context()->IsEffect()) {
3440 context()->PlugTOS();
3441 }
3442 } else {
3443 context()->Plug(v0);
3444 }
3445 break;
3446 }
3447 }
3448}
3449
3450
3451void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3452 Expression* sub_expr,
3453 Handle<String> check) {
3454 Label materialize_true, materialize_false;
3455 Label* if_true = NULL;
3456 Label* if_false = NULL;
3457 Label* fall_through = NULL;
3458 context()->PrepareTest(&materialize_true, &materialize_false,
3459 &if_true, &if_false, &fall_through);
3460
3461 { AccumulatorValueContext context(this);
3462 VisitForTypeofValue(sub_expr);
3463 }
3464 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3465
3466 Factory* factory = isolate()->factory();
3467 if (String::Equals(check, factory->number_string())) {
3468 __ JumpIfSmi(v0, if_true);
3469 __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3470 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3471 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
3472 } else if (String::Equals(check, factory->string_string())) {
3473 __ JumpIfSmi(v0, if_false);
3474 __ GetObjectType(v0, v0, a1);
3475 Split(lt, a1, Operand(FIRST_NONSTRING_TYPE), if_true, if_false,
3476 fall_through);
3477 } else if (String::Equals(check, factory->symbol_string())) {
3478 __ JumpIfSmi(v0, if_false);
3479 __ GetObjectType(v0, v0, a1);
3480 Split(eq, a1, Operand(SYMBOL_TYPE), if_true, if_false, fall_through);
3481 } else if (String::Equals(check, factory->boolean_string())) {
3482 __ LoadRoot(at, Heap::kTrueValueRootIndex);
3483 __ Branch(if_true, eq, v0, Operand(at));
3484 __ LoadRoot(at, Heap::kFalseValueRootIndex);
3485 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
3486 } else if (String::Equals(check, factory->undefined_string())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003487 __ LoadRoot(at, Heap::kNullValueRootIndex);
3488 __ Branch(if_false, eq, v0, Operand(at));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003489 __ JumpIfSmi(v0, if_false);
3490 // Check for undetectable objects => true.
3491 __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3492 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3493 __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
3494 Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through);
3495 } else if (String::Equals(check, factory->function_string())) {
3496 __ JumpIfSmi(v0, if_false);
3497 __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3498 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3499 __ And(a1, a1,
3500 Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
3501 Split(eq, a1, Operand(1 << Map::kIsCallable), if_true, if_false,
3502 fall_through);
3503 } else if (String::Equals(check, factory->object_string())) {
3504 __ JumpIfSmi(v0, if_false);
3505 __ LoadRoot(at, Heap::kNullValueRootIndex);
3506 __ Branch(if_true, eq, v0, Operand(at));
3507 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
3508 __ GetObjectType(v0, v0, a1);
3509 __ Branch(if_false, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
3510 // Check for callable or undetectable objects => false.
3511 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3512 __ And(a1, a1,
3513 Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
3514 Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through);
3515// clang-format off
3516#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
3517 } else if (String::Equals(check, factory->type##_string())) { \
3518 __ JumpIfSmi(v0, if_false); \
3519 __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); \
3520 __ LoadRoot(at, Heap::k##Type##MapRootIndex); \
3521 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
3522 SIMD128_TYPES(SIMD128_TYPE)
3523#undef SIMD128_TYPE
3524 // clang-format on
3525 } else {
3526 if (if_false != fall_through) __ jmp(if_false);
3527 }
3528 context()->Plug(if_true, if_false);
3529}
3530
3531
3532void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3533 Comment cmnt(masm_, "[ CompareOperation");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003534
3535 // First we try a fast inlined version of the compare when one of
3536 // the operands is a literal.
3537 if (TryLiteralCompare(expr)) return;
3538
3539 // Always perform the comparison for its control flow. Pack the result
3540 // into the expression's context after the comparison is performed.
3541 Label materialize_true, materialize_false;
3542 Label* if_true = NULL;
3543 Label* if_false = NULL;
3544 Label* fall_through = NULL;
3545 context()->PrepareTest(&materialize_true, &materialize_false,
3546 &if_true, &if_false, &fall_through);
3547
3548 Token::Value op = expr->op();
3549 VisitForStackValue(expr->left());
3550 switch (op) {
3551 case Token::IN:
3552 VisitForStackValue(expr->right());
Ben Murdochc5610432016-08-08 18:44:38 +01003553 SetExpressionPosition(expr);
3554 EmitHasProperty();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003555 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3556 __ LoadRoot(a4, Heap::kTrueValueRootIndex);
3557 Split(eq, v0, Operand(a4), if_true, if_false, fall_through);
3558 break;
3559
3560 case Token::INSTANCEOF: {
3561 VisitForAccumulatorValue(expr->right());
Ben Murdochc5610432016-08-08 18:44:38 +01003562 SetExpressionPosition(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003563 __ mov(a0, result_register());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003564 PopOperand(a1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003565 InstanceOfStub stub(isolate());
3566 __ CallStub(&stub);
3567 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3568 __ LoadRoot(a4, Heap::kTrueValueRootIndex);
3569 Split(eq, v0, Operand(a4), if_true, if_false, fall_through);
3570 break;
3571 }
3572
3573 default: {
3574 VisitForAccumulatorValue(expr->right());
Ben Murdochc5610432016-08-08 18:44:38 +01003575 SetExpressionPosition(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003576 Condition cc = CompareIC::ComputeCondition(op);
3577 __ mov(a0, result_register());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003578 PopOperand(a1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003579
3580 bool inline_smi_code = ShouldInlineSmiCase(op);
3581 JumpPatchSite patch_site(masm_);
3582 if (inline_smi_code) {
3583 Label slow_case;
3584 __ Or(a2, a0, Operand(a1));
3585 patch_site.EmitJumpIfNotSmi(a2, &slow_case);
3586 Split(cc, a1, Operand(a0), if_true, if_false, NULL);
3587 __ bind(&slow_case);
3588 }
3589
Ben Murdoch097c5b22016-05-18 11:27:45 +01003590 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003591 CallIC(ic, expr->CompareOperationFeedbackId());
3592 patch_site.EmitPatchInfo();
3593 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3594 Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through);
3595 }
3596 }
3597
3598 // Convert the result of the comparison into one expected for this
3599 // expression's context.
3600 context()->Plug(if_true, if_false);
3601}
3602
3603
3604void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
3605 Expression* sub_expr,
3606 NilValue nil) {
3607 Label materialize_true, materialize_false;
3608 Label* if_true = NULL;
3609 Label* if_false = NULL;
3610 Label* fall_through = NULL;
3611 context()->PrepareTest(&materialize_true, &materialize_false,
3612 &if_true, &if_false, &fall_through);
3613
3614 VisitForAccumulatorValue(sub_expr);
3615 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003616 if (expr->op() == Token::EQ_STRICT) {
3617 Heap::RootListIndex nil_value = nil == kNullValue ?
3618 Heap::kNullValueRootIndex :
3619 Heap::kUndefinedValueRootIndex;
3620 __ LoadRoot(a1, nil_value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003621 Split(eq, v0, Operand(a1), if_true, if_false, fall_through);
Ben Murdochda12d292016-06-02 14:46:10 +01003622 } else {
3623 __ JumpIfSmi(v0, if_false);
3624 __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3625 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3626 __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
3627 Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003628 }
3629 context()->Plug(if_true, if_false);
3630}
3631
3632
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003633Register FullCodeGenerator::result_register() {
3634 return v0;
3635}
3636
3637
3638Register FullCodeGenerator::context_register() {
3639 return cp;
3640}
3641
Ben Murdochda12d292016-06-02 14:46:10 +01003642void FullCodeGenerator::LoadFromFrameField(int frame_offset, Register value) {
3643 // DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3644 DCHECK(IsAligned(frame_offset, kPointerSize));
3645 // __ sw(value, MemOperand(fp, frame_offset));
3646 __ ld(value, MemOperand(fp, frame_offset));
3647}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003648
3649void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
3650 // DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3651 DCHECK(IsAligned(frame_offset, kPointerSize));
3652 // __ sw(value, MemOperand(fp, frame_offset));
3653 __ sd(value, MemOperand(fp, frame_offset));
3654}
3655
3656
3657void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
3658 __ ld(dst, ContextMemOperand(cp, context_index));
3659}
3660
3661
3662void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
3663 Scope* closure_scope = scope()->ClosureScope();
3664 if (closure_scope->is_script_scope() ||
3665 closure_scope->is_module_scope()) {
3666 // Contexts nested in the native context have a canonical empty function
3667 // as their closure, not the anonymous closure containing the global
3668 // code.
3669 __ LoadNativeContextSlot(Context::CLOSURE_INDEX, at);
3670 } else if (closure_scope->is_eval_scope()) {
3671 // Contexts created by a call to eval have the same closure as the
3672 // context calling eval, not the anonymous closure containing the eval
3673 // code. Fetch it from the context.
3674 __ ld(at, ContextMemOperand(cp, Context::CLOSURE_INDEX));
3675 } else {
3676 DCHECK(closure_scope->is_function_scope());
3677 __ ld(at, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
3678 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01003679 PushOperand(at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003680}
3681
3682
3683// ----------------------------------------------------------------------------
3684// Non-local control flow support.
3685
3686void FullCodeGenerator::EnterFinallyBlock() {
3687 DCHECK(!result_register().is(a1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003688 // Store pending message while executing finally block.
3689 ExternalReference pending_message_obj =
3690 ExternalReference::address_of_pending_message_obj(isolate());
3691 __ li(at, Operand(pending_message_obj));
3692 __ ld(a1, MemOperand(at));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003693 PushOperand(a1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003694
3695 ClearPendingMessage();
3696}
3697
3698
3699void FullCodeGenerator::ExitFinallyBlock() {
3700 DCHECK(!result_register().is(a1));
3701 // Restore pending message from stack.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003702 PopOperand(a1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003703 ExternalReference pending_message_obj =
3704 ExternalReference::address_of_pending_message_obj(isolate());
3705 __ li(at, Operand(pending_message_obj));
3706 __ sd(a1, MemOperand(at));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003707}
3708
3709
3710void FullCodeGenerator::ClearPendingMessage() {
3711 DCHECK(!result_register().is(a1));
3712 ExternalReference pending_message_obj =
3713 ExternalReference::address_of_pending_message_obj(isolate());
3714 __ LoadRoot(a1, Heap::kTheHoleValueRootIndex);
3715 __ li(at, Operand(pending_message_obj));
3716 __ sd(a1, MemOperand(at));
3717}
3718
3719
Ben Murdoch097c5b22016-05-18 11:27:45 +01003720void FullCodeGenerator::DeferredCommands::EmitCommands() {
3721 __ Pop(result_register()); // Restore the accumulator.
3722 __ Pop(a1); // Get the token.
3723 for (DeferredCommand cmd : commands_) {
3724 Label skip;
3725 __ li(at, Operand(Smi::FromInt(cmd.token)));
3726 __ Branch(&skip, ne, a1, Operand(at));
3727 switch (cmd.command) {
3728 case kReturn:
3729 codegen_->EmitUnwindAndReturn();
3730 break;
3731 case kThrow:
3732 __ Push(result_register());
3733 __ CallRuntime(Runtime::kReThrow);
3734 break;
3735 case kContinue:
3736 codegen_->EmitContinue(cmd.target);
3737 break;
3738 case kBreak:
3739 codegen_->EmitBreak(cmd.target);
3740 break;
3741 }
3742 __ bind(&skip);
3743 }
3744}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003745
3746#undef __
3747
3748
3749void BackEdgeTable::PatchAt(Code* unoptimized_code,
3750 Address pc,
3751 BackEdgeState target_state,
3752 Code* replacement_code) {
3753 static const int kInstrSize = Assembler::kInstrSize;
Ben Murdochda12d292016-06-02 14:46:10 +01003754 Address pc_immediate_load_address =
3755 Assembler::target_address_from_return_address(pc);
3756 Address branch_address = pc_immediate_load_address - 2 * kInstrSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003757 Isolate* isolate = unoptimized_code->GetIsolate();
3758 CodePatcher patcher(isolate, branch_address, 1);
3759
3760 switch (target_state) {
3761 case INTERRUPT:
3762 // slt at, a3, zero_reg (in case of count based interrupts)
3763 // beq at, zero_reg, ok
3764 // lui t9, <interrupt stub address> upper
3765 // ori t9, <interrupt stub address> u-middle
3766 // dsll t9, t9, 16
3767 // ori t9, <interrupt stub address> lower
3768 // jalr t9
3769 // nop
3770 // ok-label ----- pc_after points here
3771 patcher.masm()->slt(at, a3, zero_reg);
3772 break;
3773 case ON_STACK_REPLACEMENT:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003774 // addiu at, zero_reg, 1
3775 // beq at, zero_reg, ok ;; Not changed
3776 // lui t9, <on-stack replacement address> upper
3777 // ori t9, <on-stack replacement address> middle
3778 // dsll t9, t9, 16
3779 // ori t9, <on-stack replacement address> lower
3780 // jalr t9 ;; Not changed
3781 // nop ;; Not changed
3782 // ok-label ----- pc_after points here
3783 patcher.masm()->daddiu(at, zero_reg, 1);
3784 break;
3785 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003786 // Replace the stack check address in the load-immediate (6-instr sequence)
3787 // with the entry address of the replacement code.
3788 Assembler::set_target_address_at(isolate, pc_immediate_load_address,
3789 replacement_code->entry());
3790
3791 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
3792 unoptimized_code, pc_immediate_load_address, replacement_code);
3793}
3794
3795
3796BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
3797 Isolate* isolate,
3798 Code* unoptimized_code,
3799 Address pc) {
3800 static const int kInstrSize = Assembler::kInstrSize;
Ben Murdochda12d292016-06-02 14:46:10 +01003801 Address pc_immediate_load_address =
3802 Assembler::target_address_from_return_address(pc);
3803 Address branch_address = pc_immediate_load_address - 2 * kInstrSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003804
Ben Murdochda12d292016-06-02 14:46:10 +01003805 DCHECK(Assembler::IsBeq(Assembler::instr_at(branch_address + kInstrSize)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003806 if (!Assembler::IsAddImmediate(Assembler::instr_at(branch_address))) {
3807 DCHECK(reinterpret_cast<uint64_t>(
3808 Assembler::target_address_at(pc_immediate_load_address)) ==
3809 reinterpret_cast<uint64_t>(
3810 isolate->builtins()->InterruptCheck()->entry()));
3811 return INTERRUPT;
3812 }
3813
3814 DCHECK(Assembler::IsAddImmediate(Assembler::instr_at(branch_address)));
3815
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003816 DCHECK(reinterpret_cast<uint64_t>(
Ben Murdochda12d292016-06-02 14:46:10 +01003817 Assembler::target_address_at(pc_immediate_load_address)) ==
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003818 reinterpret_cast<uint64_t>(
Ben Murdochda12d292016-06-02 14:46:10 +01003819 isolate->builtins()->OnStackReplacement()->entry()));
3820 return ON_STACK_REPLACEMENT;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003821}
3822
3823
3824} // namespace internal
3825} // namespace v8
3826
3827#endif // V8_TARGET_ARCH_MIPS64