blob: 24747ee9e85b11d7e3fed1b50e70db0d2073e9b2 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Block3ce2e202009-11-05 08:53:23 +00004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/v8.h"
Steve Block3ce2e202009-11-05 08:53:23 +00006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#if V8_TARGET_ARCH_X64
Leon Clarkef7060e22010-06-03 12:02:55 +01008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/code-factory.h"
10#include "src/code-stubs.h"
11#include "src/codegen.h"
12#include "src/compiler.h"
13#include "src/debug.h"
14#include "src/full-codegen.h"
15#include "src/ic/ic.h"
16#include "src/isolate-inl.h"
17#include "src/parser.h"
18#include "src/scopes.h"
Steve Block3ce2e202009-11-05 08:53:23 +000019
20namespace v8 {
21namespace internal {
22
23#define __ ACCESS_MASM(masm_)
24
Steve Block1e0659c2011-05-24 12:43:12 +010025
26class JumpPatchSite BASE_EMBEDDED {
27 public:
Ben Murdoch589d6972011-11-30 16:04:58 +000028 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
Steve Block1e0659c2011-05-24 12:43:12 +010029#ifdef DEBUG
30 info_emitted_ = false;
31#endif
32 }
33
34 ~JumpPatchSite() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035 DCHECK(patch_site_.is_bound() == info_emitted_);
Steve Block1e0659c2011-05-24 12:43:12 +010036 }
37
Ben Murdoch257744e2011-11-30 15:57:28 +000038 void EmitJumpIfNotSmi(Register reg,
39 Label* target,
40 Label::Distance near_jump = Label::kFar) {
Steve Block1e0659c2011-05-24 12:43:12 +010041 __ testb(reg, Immediate(kSmiTagMask));
Ben Murdoch257744e2011-11-30 15:57:28 +000042 EmitJump(not_carry, target, near_jump); // Always taken before patched.
Steve Block1e0659c2011-05-24 12:43:12 +010043 }
44
Ben Murdoch257744e2011-11-30 15:57:28 +000045 void EmitJumpIfSmi(Register reg,
46 Label* target,
47 Label::Distance near_jump = Label::kFar) {
Steve Block1e0659c2011-05-24 12:43:12 +010048 __ testb(reg, Immediate(kSmiTagMask));
Ben Murdoch257744e2011-11-30 15:57:28 +000049 EmitJump(carry, target, near_jump); // Never taken before patched.
Steve Block1e0659c2011-05-24 12:43:12 +010050 }
51
52 void EmitPatchInfo() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000053 if (patch_site_.is_bound()) {
54 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055 DCHECK(is_uint8(delta_to_patch_site));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000056 __ testl(rax, Immediate(delta_to_patch_site));
Steve Block1e0659c2011-05-24 12:43:12 +010057#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000058 info_emitted_ = true;
Steve Block1e0659c2011-05-24 12:43:12 +010059#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000060 } else {
61 __ nop(); // Signals no inlined code.
62 }
Steve Block1e0659c2011-05-24 12:43:12 +010063 }
64
Steve Block1e0659c2011-05-24 12:43:12 +010065 private:
66 // jc will be patched with jz, jnc will become jnz.
Ben Murdoch257744e2011-11-30 15:57:28 +000067 void EmitJump(Condition cc, Label* target, Label::Distance near_jump) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068 DCHECK(!patch_site_.is_bound() && !info_emitted_);
69 DCHECK(cc == carry || cc == not_carry);
Steve Block1e0659c2011-05-24 12:43:12 +010070 __ bind(&patch_site_);
Ben Murdoch257744e2011-11-30 15:57:28 +000071 __ j(cc, target, near_jump);
Steve Block1e0659c2011-05-24 12:43:12 +010072 }
73
74 MacroAssembler* masm_;
75 Label patch_site_;
76#ifdef DEBUG
77 bool info_emitted_;
78#endif
79};
80
81
Steve Block3ce2e202009-11-05 08:53:23 +000082// Generate code for a JS function. On entry to the function the receiver
83// and arguments have been pushed on the stack left to right, with the
84// return address on top of them. The actual argument count matches the
85// formal parameter count expected by the function.
86//
87// The live registers are:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010088// o rdi: the JS function object being called (i.e. ourselves)
Steve Block3ce2e202009-11-05 08:53:23 +000089// o rsi: our context
90// o rbp: our caller's frame pointer
91// o rsp: stack pointer (pointing to return address)
92//
93// The function builds a JS frame. Please see JavaScriptFrameConstants in
94// frames-x64.h for its layout.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010095void FullCodeGenerator::Generate() {
96 CompilationInfo* info = info_;
97 handler_table_ =
98 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000099
100 profiling_counter_ = isolate()->factory()->NewCell(
101 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
Andrei Popescu31002712010-02-23 13:46:05 +0000102 SetFunctionPosition(function());
Steve Block6ded16b2010-05-10 14:33:55 +0100103 Comment cmnt(masm_, "[ function compiled by full code generator");
Steve Block3ce2e202009-11-05 08:53:23 +0000104
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100106
Ben Murdochf87a2032010-10-22 12:50:53 +0100107#ifdef DEBUG
108 if (strlen(FLAG_stop_at) > 0 &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100110 __ int3();
111 }
112#endif
Ben Murdoch257744e2011-11-30 15:57:28 +0000113
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 // Sloppy mode functions and builtins need to replace the receiver with the
115 // global proxy when called as functions (without an explicit receiver
116 // object).
117 if (info->strict_mode() == SLOPPY && !info->is_native()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000118 Label ok;
Ben Murdoch257744e2011-11-30 15:57:28 +0000119 // +1 for return address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 StackArgumentsAccessor args(rsp, info->scope()->num_parameters());
121 __ movp(rcx, args.GetReceiverOperand());
122
123 __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
124 __ j(not_equal, &ok, Label::kNear);
125
126 __ movp(rcx, GlobalObjectOperand());
127 __ movp(rcx, FieldOperand(rcx, GlobalObject::kGlobalProxyOffset));
128
129 __ movp(args.GetReceiverOperand(), rcx);
130
Ben Murdoch257744e2011-11-30 15:57:28 +0000131 __ bind(&ok);
132 }
133
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100134 // Open a frame scope to indicate that there is a frame on the stack. The
135 // MANUAL indicates that the scope shouldn't actually generate code to set up
136 // the frame (that is done below).
137 FrameScope frame_scope(masm_, StackFrame::MANUAL);
138
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 info->set_prologue_offset(masm_->pc_offset());
140 __ Prologue(info->IsCodePreAgingActive());
141 info->AddNoFrameRange(0, masm_->pc_offset());
Steve Block3ce2e202009-11-05 08:53:23 +0000142
Iain Merrick75681382010-08-19 15:07:18 +0100143 { Comment cmnt(masm_, "[ Allocate locals");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000144 int locals_count = info->scope()->num_stack_slots();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 // Generators allocate locals, if any, in context slots.
146 DCHECK(!info->function()->is_generator() || locals_count == 0);
Iain Merrick75681382010-08-19 15:07:18 +0100147 if (locals_count == 1) {
148 __ PushRoot(Heap::kUndefinedValueRootIndex);
149 } else if (locals_count > 1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 if (locals_count >= 128) {
151 Label ok;
152 __ movp(rcx, rsp);
153 __ subp(rcx, Immediate(locals_count * kPointerSize));
154 __ CompareRoot(rcx, Heap::kRealStackLimitRootIndex);
155 __ j(above_equal, &ok, Label::kNear);
156 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
157 __ bind(&ok);
158 }
Iain Merrick75681382010-08-19 15:07:18 +0100159 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160 const int kMaxPushes = 32;
161 if (locals_count >= kMaxPushes) {
162 int loop_iterations = locals_count / kMaxPushes;
163 __ movp(rcx, Immediate(loop_iterations));
164 Label loop_header;
165 __ bind(&loop_header);
166 // Do pushes.
167 for (int i = 0; i < kMaxPushes; i++) {
168 __ Push(rdx);
169 }
170 // Continue loop if not done.
171 __ decp(rcx);
172 __ j(not_zero, &loop_header, Label::kNear);
173 }
174 int remaining = locals_count % kMaxPushes;
175 // Emit the remaining pushes.
176 for (int i = 0; i < remaining; i++) {
177 __ Push(rdx);
Steve Blockd0582a62009-12-15 09:54:21 +0000178 }
Steve Block3ce2e202009-11-05 08:53:23 +0000179 }
Iain Merrick75681382010-08-19 15:07:18 +0100180 }
Steve Block3ce2e202009-11-05 08:53:23 +0000181
Iain Merrick75681382010-08-19 15:07:18 +0100182 bool function_in_register = true;
Steve Blockd0582a62009-12-15 09:54:21 +0000183
Iain Merrick75681382010-08-19 15:07:18 +0100184 // Possibly allocate a local context.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000185 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
Iain Merrick75681382010-08-19 15:07:18 +0100186 if (heap_slots > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187 Comment cmnt(masm_, "[ Allocate context");
188 bool need_write_barrier = true;
Iain Merrick75681382010-08-19 15:07:18 +0100189 // Argument to NewContext is the function, which is still in rdi.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400190 if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000191 __ Push(rdi);
192 __ Push(info->scope()->GetScopeInfo());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400193 __ CallRuntime(Runtime::kNewScriptContext, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000194 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
195 FastNewContextStub stub(isolate(), heap_slots);
Leon Clarke4515c472010-02-03 11:58:03 +0000196 __ CallStub(&stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197 // Result of FastNewContextStub is always in new space.
198 need_write_barrier = false;
Iain Merrick75681382010-08-19 15:07:18 +0100199 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 __ Push(rdi);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000201 __ CallRuntime(Runtime::kNewFunctionContext, 1);
Leon Clarke4515c472010-02-03 11:58:03 +0000202 }
Iain Merrick75681382010-08-19 15:07:18 +0100203 function_in_register = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 // Context is returned in rax. It replaces the context passed to us.
205 // It's saved in the stack and kept live in rsi.
206 __ movp(rsi, rax);
207 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rax);
Iain Merrick75681382010-08-19 15:07:18 +0100208
209 // Copy any necessary parameters into the context.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000210 int num_parameters = info->scope()->num_parameters();
Iain Merrick75681382010-08-19 15:07:18 +0100211 for (int i = 0; i < num_parameters; i++) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000212 Variable* var = scope()->parameter(i);
213 if (var->IsContextSlot()) {
Iain Merrick75681382010-08-19 15:07:18 +0100214 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
215 (num_parameters - 1 - i) * kPointerSize;
216 // Load parameter from stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217 __ movp(rax, Operand(rbp, parameter_offset));
Iain Merrick75681382010-08-19 15:07:18 +0100218 // Store it in the context.
Ben Murdoch589d6972011-11-30 16:04:58 +0000219 int context_offset = Context::SlotOffset(var->index());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 __ movp(Operand(rsi, context_offset), rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100221 // Update the write barrier. This clobbers rax and rbx.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222 if (need_write_barrier) {
223 __ RecordWriteContextSlot(
224 rsi, context_offset, rax, rbx, kDontSaveFPRegs);
225 } else if (FLAG_debug_code) {
226 Label done;
227 __ JumpIfInNewSpace(rsi, rax, &done, Label::kNear);
228 __ Abort(kExpectedNewSpaceObject);
229 __ bind(&done);
230 }
Iain Merrick75681382010-08-19 15:07:18 +0100231 }
232 }
233 }
234
235 // Possibly allocate an arguments object.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100236 Variable* arguments = scope()->arguments();
Iain Merrick75681382010-08-19 15:07:18 +0100237 if (arguments != NULL) {
238 // Arguments object must be allocated after the context object, in
239 // case the "arguments" or ".arguments" variables are in the context.
240 Comment cmnt(masm_, "[ Allocate arguments object");
241 if (function_in_register) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 __ Push(rdi);
Iain Merrick75681382010-08-19 15:07:18 +0100243 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Iain Merrick75681382010-08-19 15:07:18 +0100245 }
246 // The receiver is just before the parameters on the caller's stack.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000247 int num_parameters = info->scope()->num_parameters();
248 int offset = num_parameters * kPointerSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 __ leap(rdx,
Iain Merrick75681382010-08-19 15:07:18 +0100250 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251 __ Push(rdx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000252 __ Push(Smi::FromInt(num_parameters));
Iain Merrick75681382010-08-19 15:07:18 +0100253 // Arguments to ArgumentsAccessStub:
254 // function, receiver address, parameter count.
255 // The stub will rewrite receiver and parameter count if the previous
256 // stack frame was an arguments adapter frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100257 ArgumentsAccessStub::Type type;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000258 if (strict_mode() == STRICT) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100259 type = ArgumentsAccessStub::NEW_STRICT;
260 } else if (function()->has_duplicate_parameters()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000261 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100262 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263 type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100264 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265 ArgumentsAccessStub stub(isolate(), type);
Iain Merrick75681382010-08-19 15:07:18 +0100266 __ CallStub(&stub);
Steve Block44f0eee2011-05-26 01:26:41 +0100267
Ben Murdoch589d6972011-11-30 16:04:58 +0000268 SetVar(arguments, rax, rbx, rdx);
Steve Blockd0582a62009-12-15 09:54:21 +0000269 }
270
Ben Murdochb0fe1622011-05-05 13:52:32 +0100271 if (FLAG_trace) {
272 __ CallRuntime(Runtime::kTraceEnter, 0);
273 }
274
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100275 // Visit the declarations and body unless there is an illegal
276 // redeclaration.
277 if (scope()->HasIllegalRedeclaration()) {
278 Comment cmnt(masm_, "[ Declarations");
279 scope()->VisitIllegalRedeclaration(this);
Ben Murdoch589d6972011-11-30 16:04:58 +0000280
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100281 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100283 { Comment cmnt(masm_, "[ Declarations");
284 // For named function expressions, declare the function name as a
285 // constant.
286 if (scope()->is_function_scope() && scope()->function() != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 VariableDeclaration* function = scope()->function();
288 DCHECK(function->proxy()->var()->mode() == CONST ||
289 function->proxy()->var()->mode() == CONST_LEGACY);
290 DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
291 VisitVariableDeclaration(function);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100292 }
293 VisitDeclarations(scope()->declarations());
294 }
295
296 { Comment cmnt(masm_, "[ Stack check");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
298 Label ok;
299 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
300 __ j(above_equal, &ok, Label::kNear);
301 __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
302 __ bind(&ok);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100303 }
304
305 { Comment cmnt(masm_, "[ Body");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 DCHECK(loop_depth() == 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100307 VisitStatements(function()->body());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000308 DCHECK(loop_depth() == 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100309 }
Steve Block3ce2e202009-11-05 08:53:23 +0000310 }
311
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100312 // Always emit a 'return undefined' in case control fell off the end of
313 // the body.
Steve Block3ce2e202009-11-05 08:53:23 +0000314 { Comment cmnt(masm_, "[ return <undefined>;");
Steve Block3ce2e202009-11-05 08:53:23 +0000315 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100316 EmitReturnSequence();
Steve Blockd0582a62009-12-15 09:54:21 +0000317 }
318}
319
320
Ben Murdochdb5a90a2011-01-06 18:27:03 +0000321void FullCodeGenerator::ClearAccumulator() {
Steve Block9fac8402011-05-12 15:51:54 +0100322 __ Set(rax, 0);
Ben Murdochdb5a90a2011-01-06 18:27:03 +0000323}
324
325
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
327 __ Move(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
328 __ SmiAddConstant(FieldOperand(rbx, Cell::kValueOffset),
329 Smi::FromInt(-delta));
330}
331
332
333void FullCodeGenerator::EmitProfilingCounterReset() {
334 int reset_value = FLAG_interrupt_budget;
335 __ Move(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
336 __ Move(kScratchRegister, Smi::FromInt(reset_value));
337 __ movp(FieldOperand(rbx, Cell::kValueOffset), kScratchRegister);
338}
339
340
341static const byte kJnsOffset = kPointerSize == kInt64Size ? 0x1d : 0x14;
342
343
344void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
345 Label* back_edge_target) {
346 Comment cmnt(masm_, "[ Back edge bookkeeping");
Ben Murdoch257744e2011-11-30 15:57:28 +0000347 Label ok;
Ben Murdoch086aeea2011-05-13 15:57:08 +0100348
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000349 DCHECK(back_edge_target->is_bound());
350 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
351 int weight = Min(kMaxBackEdgeWeight,
352 Max(1, distance / kCodeSizeMultiplier));
353 EmitProfilingCounterDecrement(weight);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100354
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000355 __ j(positive, &ok, Label::kNear);
356 {
357 PredictableCodeSizeScope predictible_code_size_scope(masm_, kJnsOffset);
358 DontEmitDebugCodeScope dont_emit_debug_code_scope(masm_);
359 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
360
361 // Record a mapping of this PC offset to the OSR id. This is used to find
362 // the AST id from the unoptimized code in order to use it as a key into
363 // the deoptimization input data found in the optimized code.
364 RecordBackEdge(stmt->OsrEntryId());
365
366 EmitProfilingCounterReset();
367 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100368 __ bind(&ok);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369
Ben Murdochb0fe1622011-05-05 13:52:32 +0100370 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100371 // Record a mapping of the OSR id to this PC. This is used if the OSR
372 // entry becomes the target of a bailout. We don't expect it to be, but
373 // we want it to work if it is.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100374 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100375}
376
377
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100378void FullCodeGenerator::EmitReturnSequence() {
Steve Blockd0582a62009-12-15 09:54:21 +0000379 Comment cmnt(masm_, "[ Return sequence");
380 if (return_label_.is_bound()) {
381 __ jmp(&return_label_);
382 } else {
383 __ bind(&return_label_);
Steve Block3ce2e202009-11-05 08:53:23 +0000384 if (FLAG_trace) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 __ Push(rax);
Steve Block3ce2e202009-11-05 08:53:23 +0000386 __ CallRuntime(Runtime::kTraceExit, 1);
387 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000388 // Pretend that the exit is a backwards jump to the entry.
389 int weight = 1;
390 if (info_->ShouldSelfOptimize()) {
391 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
392 } else {
393 int distance = masm_->pc_offset();
394 weight = Min(kMaxBackEdgeWeight,
395 Max(1, distance / kCodeSizeMultiplier));
396 }
397 EmitProfilingCounterDecrement(weight);
398 Label ok;
399 __ j(positive, &ok, Label::kNear);
400 __ Push(rax);
401 __ call(isolate()->builtins()->InterruptCheck(),
402 RelocInfo::CODE_TARGET);
403 __ Pop(rax);
404 EmitProfilingCounterReset();
405 __ bind(&ok);
Steve Blockd0582a62009-12-15 09:54:21 +0000406#ifdef DEBUG
407 // Add a label for checking the size of the code used for returning.
408 Label check_exit_codesize;
409 masm_->bind(&check_exit_codesize);
410#endif
Ben Murdochbb769b22010-08-11 14:56:33 +0100411 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
Steve Block3ce2e202009-11-05 08:53:23 +0000412 __ RecordJSReturn();
Steve Block3ce2e202009-11-05 08:53:23 +0000413 // Do not use the leave instruction here because it is too short to
414 // patch with the code required by the debugger.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415 __ movp(rsp, rbp);
416 __ popq(rbp);
417 int no_frame_start = masm_->pc_offset();
Steve Block1e0659c2011-05-24 12:43:12 +0100418
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000419 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
Steve Block1e0659c2011-05-24 12:43:12 +0100420 __ Ret(arguments_bytes, rcx);
421
Steve Block3ce2e202009-11-05 08:53:23 +0000422 // Add padding that will be overwritten by a debugger breakpoint. We
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000423 // have just generated at least 7 bytes: "movp rsp, rbp; pop rbp; ret k"
424 // (3 + 1 + 3) for x64 and at least 6 (2 + 1 + 3) bytes for x32.
425 const int kPadding = Assembler::kJSReturnSequenceLength -
426 kPointerSize == kInt64Size ? 7 : 6;
Steve Block3ce2e202009-11-05 08:53:23 +0000427 for (int i = 0; i < kPadding; ++i) {
428 masm_->int3();
429 }
Steve Block1e0659c2011-05-24 12:43:12 +0100430 // Check that the size of the code used for returning is large enough
431 // for the debugger's requirements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000432 DCHECK(Assembler::kJSReturnSequenceLength <=
Steve Block1e0659c2011-05-24 12:43:12 +0100433 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434
435 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
Steve Block3ce2e202009-11-05 08:53:23 +0000436 }
437}
438
439
Ben Murdoch589d6972011-11-30 16:04:58 +0000440void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100442}
Leon Clarkee46be812010-01-19 14:06:41 +0000443
Leon Clarkee46be812010-01-19 14:06:41 +0000444
Ben Murdoch589d6972011-11-30 16:04:58 +0000445void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Ben Murdoch589d6972011-11-30 16:04:58 +0000447 codegen()->GetVar(result_register(), var);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100448}
Leon Clarkee46be812010-01-19 14:06:41 +0000449
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100450
Ben Murdoch589d6972011-11-30 16:04:58 +0000451void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Ben Murdoch589d6972011-11-30 16:04:58 +0000453 MemOperand operand = codegen()->VarOperand(var, result_register());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000454 __ Push(operand);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100455}
456
457
Ben Murdoch589d6972011-11-30 16:04:58 +0000458void FullCodeGenerator::TestContext::Plug(Variable* var) const {
459 codegen()->GetVar(result_register(), var);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100460 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000461 codegen()->DoTest(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100462}
463
464
465void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
466}
467
468
469void FullCodeGenerator::AccumulatorValueContext::Plug(
470 Heap::RootListIndex index) const {
471 __ LoadRoot(result_register(), index);
472}
473
474
475void FullCodeGenerator::StackValueContext::Plug(
476 Heap::RootListIndex index) const {
477 __ PushRoot(index);
478}
479
480
481void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100482 codegen()->PrepareForBailoutBeforeSplit(condition(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100483 true,
484 true_label_,
485 false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100486 if (index == Heap::kUndefinedValueRootIndex ||
487 index == Heap::kNullValueRootIndex ||
488 index == Heap::kFalseValueRootIndex) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100489 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100490 } else if (index == Heap::kTrueValueRootIndex) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100491 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100492 } else {
493 __ LoadRoot(result_register(), index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000494 codegen()->DoTest(this);
Steve Blockd0582a62009-12-15 09:54:21 +0000495 }
496}
497
498
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100499void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
500}
501
502
503void FullCodeGenerator::AccumulatorValueContext::Plug(
504 Handle<Object> lit) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000505 if (lit->IsSmi()) {
506 __ SafeMove(result_register(), Smi::cast(*lit));
507 } else {
508 __ Move(result_register(), lit);
509 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100510}
511
512
513void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 if (lit->IsSmi()) {
515 __ SafePush(Smi::cast(*lit));
516 } else {
517 __ Push(lit);
518 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100519}
520
521
522void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100523 codegen()->PrepareForBailoutBeforeSplit(condition(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100524 true,
525 true_label_,
526 false_label_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527 DCHECK(!lit->IsUndetectableObject()); // There are no undetectable literals.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100528 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100529 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100530 } else if (lit->IsTrue() || lit->IsJSObject()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100531 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100532 } else if (lit->IsString()) {
533 if (String::cast(*lit)->length() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100534 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100535 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100536 if (true_label_ != fall_through_) __ jmp(true_label_);
Steve Blockd0582a62009-12-15 09:54:21 +0000537 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100538 } else if (lit->IsSmi()) {
539 if (Smi::cast(*lit)->value() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100540 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100541 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100542 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100543 }
544 } else {
545 // For simplicity we always test the accumulator register.
546 __ Move(result_register(), lit);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000547 codegen()->DoTest(this);
Steve Blockd0582a62009-12-15 09:54:21 +0000548 }
549}
550
551
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100552void FullCodeGenerator::EffectContext::DropAndPlug(int count,
553 Register reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000554 DCHECK(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100555 __ Drop(count);
Leon Clarkef7060e22010-06-03 12:02:55 +0100556}
557
558
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100559void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
560 int count,
561 Register reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562 DCHECK(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100563 __ Drop(count);
564 __ Move(result_register(), reg);
Leon Clarkee46be812010-01-19 14:06:41 +0000565}
566
567
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100568void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
569 Register reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570 DCHECK(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100571 if (count > 1) __ Drop(count - 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000572 __ movp(Operand(rsp, 0), reg);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100573}
574
575
576void FullCodeGenerator::TestContext::DropAndPlug(int count,
577 Register reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000578 DCHECK(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100579 // For simplicity we always test the accumulator register.
580 __ Drop(count);
581 __ Move(result_register(), reg);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100582 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000583 codegen()->DoTest(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100584}
585
586
587void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
588 Label* materialize_false) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 DCHECK(materialize_true == materialize_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100590 __ bind(materialize_true);
591}
592
593
594void FullCodeGenerator::AccumulatorValueContext::Plug(
595 Label* materialize_true,
596 Label* materialize_false) const {
Ben Murdoch257744e2011-11-30 15:57:28 +0000597 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100598 __ bind(materialize_true);
Steve Block44f0eee2011-05-26 01:26:41 +0100599 __ Move(result_register(), isolate()->factory()->true_value());
Ben Murdoch257744e2011-11-30 15:57:28 +0000600 __ jmp(&done, Label::kNear);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100601 __ bind(materialize_false);
Steve Block44f0eee2011-05-26 01:26:41 +0100602 __ Move(result_register(), isolate()->factory()->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100603 __ bind(&done);
604}
605
606
607void FullCodeGenerator::StackValueContext::Plug(
608 Label* materialize_true,
609 Label* materialize_false) const {
Ben Murdoch257744e2011-11-30 15:57:28 +0000610 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100611 __ bind(materialize_true);
Steve Block44f0eee2011-05-26 01:26:41 +0100612 __ Push(isolate()->factory()->true_value());
Ben Murdoch257744e2011-11-30 15:57:28 +0000613 __ jmp(&done, Label::kNear);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100614 __ bind(materialize_false);
Steve Block44f0eee2011-05-26 01:26:41 +0100615 __ Push(isolate()->factory()->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100616 __ bind(&done);
617}
618
619
620void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
621 Label* materialize_false) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000622 DCHECK(materialize_true == true_label_);
623 DCHECK(materialize_false == false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100624}
625
626
627void FullCodeGenerator::EffectContext::Plug(bool flag) const {
628}
629
630
631void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
632 Heap::RootListIndex value_root_index =
633 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
634 __ LoadRoot(result_register(), value_root_index);
635}
636
637
638void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
639 Heap::RootListIndex value_root_index =
640 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
641 __ PushRoot(value_root_index);
642}
643
644
645void FullCodeGenerator::TestContext::Plug(bool flag) const {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100646 codegen()->PrepareForBailoutBeforeSplit(condition(),
Ben Murdoch086aeea2011-05-13 15:57:08 +0100647 true,
648 true_label_,
649 false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100650 if (flag) {
651 if (true_label_ != fall_through_) __ jmp(true_label_);
652 } else {
653 if (false_label_ != fall_through_) __ jmp(false_label_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100654 }
655}
656
657
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000658void FullCodeGenerator::DoTest(Expression* condition,
659 Label* if_true,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100660 Label* if_false,
661 Label* fall_through) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000662 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
663 CallIC(ic, condition->test_id());
664 __ testp(result_register(), result_register());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100665 // The stub returns nonzero for true.
666 Split(not_zero, if_true, if_false, fall_through);
667}
Leon Clarkee46be812010-01-19 14:06:41 +0000668
Leon Clarkee46be812010-01-19 14:06:41 +0000669
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100670void FullCodeGenerator::Split(Condition cc,
671 Label* if_true,
672 Label* if_false,
673 Label* fall_through) {
674 if (if_false == fall_through) {
675 __ j(cc, if_true);
676 } else if (if_true == fall_through) {
677 __ j(NegateCondition(cc), if_false);
678 } else {
679 __ j(cc, if_true);
680 __ jmp(if_false);
Leon Clarkee46be812010-01-19 14:06:41 +0000681 }
682}
683
684
Ben Murdoch589d6972011-11-30 16:04:58 +0000685MemOperand FullCodeGenerator::StackOperand(Variable* var) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000686 DCHECK(var->IsStackAllocated());
Ben Murdoch589d6972011-11-30 16:04:58 +0000687 // Offset is negative because higher indexes are at lower addresses.
688 int offset = -var->index() * kPointerSize;
689 // Adjust by a (parameter or local) base offset.
690 if (var->IsParameter()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000691 offset += kFPOnStackSize + kPCOnStackSize +
692 (info_->scope()->num_parameters() - 1) * kPointerSize;
Ben Murdoch589d6972011-11-30 16:04:58 +0000693 } else {
694 offset += JavaScriptFrameConstants::kLocal0Offset;
Leon Clarkee46be812010-01-19 14:06:41 +0000695 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000696 return Operand(rbp, offset);
Leon Clarkee46be812010-01-19 14:06:41 +0000697}
698
699
Ben Murdoch589d6972011-11-30 16:04:58 +0000700MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
Ben Murdoch589d6972011-11-30 16:04:58 +0000702 if (var->IsContextSlot()) {
703 int context_chain_length = scope()->ContextChainLength(var->scope());
704 __ LoadContext(scratch, context_chain_length);
705 return ContextOperand(scratch, var->index());
706 } else {
707 return StackOperand(var);
708 }
Leon Clarkee46be812010-01-19 14:06:41 +0000709}
710
711
Ben Murdoch589d6972011-11-30 16:04:58 +0000712void FullCodeGenerator::GetVar(Register dest, Variable* var) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
Ben Murdoch589d6972011-11-30 16:04:58 +0000714 MemOperand location = VarOperand(var, dest);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000715 __ movp(dest, location);
Ben Murdoch589d6972011-11-30 16:04:58 +0000716}
717
718
719void FullCodeGenerator::SetVar(Variable* var,
720 Register src,
721 Register scratch0,
722 Register scratch1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
724 DCHECK(!scratch0.is(src));
725 DCHECK(!scratch0.is(scratch1));
726 DCHECK(!scratch1.is(src));
Ben Murdoch589d6972011-11-30 16:04:58 +0000727 MemOperand location = VarOperand(var, scratch0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000728 __ movp(location, src);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100729
Leon Clarkee46be812010-01-19 14:06:41 +0000730 // Emit the write barrier code if the location is in the heap.
Ben Murdoch589d6972011-11-30 16:04:58 +0000731 if (var->IsContextSlot()) {
732 int offset = Context::SlotOffset(var->index());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100733 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
Steve Blockd0582a62009-12-15 09:54:21 +0000734 }
735}
736
737
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100738void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100739 bool should_normalize,
740 Label* if_true,
741 Label* if_false) {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100742 // Only prepare for bailouts before splits if we're in a test
743 // context. Otherwise, we let the Visit function deal with the
744 // preparation to avoid preparing with the same AST id twice.
745 if (!context()->IsTest() || !info_->IsOptimizable()) return;
746
Ben Murdoch257744e2011-11-30 15:57:28 +0000747 Label skip;
748 if (should_normalize) __ jmp(&skip, Label::kNear);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100749 PrepareForBailout(expr, TOS_REG);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100750 if (should_normalize) {
751 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
752 Split(equal, if_true, if_false, NULL);
753 __ bind(&skip);
754 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100755}
756
757
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000758void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
759 // The variable in the declaration always resides in the current context.
760 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
761 if (generate_debug_code_) {
762 // Check that we're not inside a with or catch context.
763 __ movp(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
764 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
765 __ Check(not_equal, kDeclarationInWithContext);
766 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
767 __ Check(not_equal, kDeclarationInCatchContext);
768 }
769}
770
771
772void FullCodeGenerator::VisitVariableDeclaration(
773 VariableDeclaration* declaration) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000774 // If it was not possible to allocate the variable at compile time, we
775 // need to "declare" it at runtime to make sure it actually exists in the
776 // local context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777 VariableProxy* proxy = declaration->proxy();
778 VariableMode mode = declaration->mode();
Ben Murdoch589d6972011-11-30 16:04:58 +0000779 Variable* variable = proxy->var();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000780 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
Ben Murdoch589d6972011-11-30 16:04:58 +0000781 switch (variable->location()) {
782 case Variable::UNALLOCATED:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783 globals_->Add(variable->name(), zone());
784 globals_->Add(variable->binding_needs_init()
785 ? isolate()->factory()->the_hole_value()
786 : isolate()->factory()->undefined_value(),
787 zone());
Ben Murdoch589d6972011-11-30 16:04:58 +0000788 break;
789
790 case Variable::PARAMETER:
791 case Variable::LOCAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000792 if (hole_init) {
793 Comment cmnt(masm_, "[ VariableDeclaration");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000794 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000795 __ movp(StackOperand(variable), kScratchRegister);
Steve Blockd0582a62009-12-15 09:54:21 +0000796 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000797 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000798
Ben Murdoch589d6972011-11-30 16:04:58 +0000799 case Variable::CONTEXT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000800 if (hole_init) {
801 Comment cmnt(masm_, "[ VariableDeclaration");
802 EmitDebugCheckDeclarationContext(variable);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000803 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000804 __ movp(ContextOperand(rsi, variable->index()), kScratchRegister);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000805 // No write barrier since the hole value is in old space.
Ben Murdoch589d6972011-11-30 16:04:58 +0000806 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000807 }
808 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000809
Ben Murdoch589d6972011-11-30 16:04:58 +0000810 case Variable::LOOKUP: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000811 Comment cmnt(masm_, "[ VariableDeclaration");
812 __ Push(rsi);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000813 __ Push(variable->name());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100814 // Declaration nodes are always introduced in one of four modes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000815 DCHECK(IsDeclaredVariableMode(mode));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100816 PropertyAttributes attr =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000817 IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000818 __ Push(Smi::FromInt(attr));
819 // Push initial value, if any.
820 // Note: For variables we must not push an initial value (such as
821 // 'undefined') because we may have a (legal) redeclaration and we
822 // must not destroy the current value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000823 if (hole_init) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000824 __ PushRoot(Heap::kTheHoleValueRootIndex);
825 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000826 __ Push(Smi::FromInt(0)); // Indicates no initial value.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000827 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000828 __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000829 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000830 }
831 }
832}
833
834
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000835void FullCodeGenerator::VisitFunctionDeclaration(
836 FunctionDeclaration* declaration) {
837 VariableProxy* proxy = declaration->proxy();
838 Variable* variable = proxy->var();
839 switch (variable->location()) {
840 case Variable::UNALLOCATED: {
841 globals_->Add(variable->name(), zone());
842 Handle<SharedFunctionInfo> function =
843 Compiler::BuildFunctionInfo(declaration->fun(), script(), info_);
844 // Check for stack-overflow exception.
845 if (function.is_null()) return SetStackOverflow();
846 globals_->Add(function, zone());
847 break;
848 }
849
850 case Variable::PARAMETER:
851 case Variable::LOCAL: {
852 Comment cmnt(masm_, "[ FunctionDeclaration");
853 VisitForAccumulatorValue(declaration->fun());
854 __ movp(StackOperand(variable), result_register());
855 break;
856 }
857
858 case Variable::CONTEXT: {
859 Comment cmnt(masm_, "[ FunctionDeclaration");
860 EmitDebugCheckDeclarationContext(variable);
861 VisitForAccumulatorValue(declaration->fun());
862 __ movp(ContextOperand(rsi, variable->index()), result_register());
863 int offset = Context::SlotOffset(variable->index());
864 // We know that we have written a function, which is not a smi.
865 __ RecordWriteContextSlot(rsi,
866 offset,
867 result_register(),
868 rcx,
869 kDontSaveFPRegs,
870 EMIT_REMEMBERED_SET,
871 OMIT_SMI_CHECK);
872 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
873 break;
874 }
875
876 case Variable::LOOKUP: {
877 Comment cmnt(masm_, "[ FunctionDeclaration");
878 __ Push(rsi);
879 __ Push(variable->name());
880 __ Push(Smi::FromInt(NONE));
881 VisitForStackValue(declaration->fun());
882 __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
883 break;
884 }
885 }
886}
887
888
889void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
890 Variable* variable = declaration->proxy()->var();
891 DCHECK(variable->location() == Variable::CONTEXT);
892 DCHECK(variable->interface()->IsFrozen());
893
894 Comment cmnt(masm_, "[ ModuleDeclaration");
895 EmitDebugCheckDeclarationContext(variable);
896
897 // Load instance object.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400898 __ LoadContext(rax, scope_->ContextChainLength(scope_->ScriptScope()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000899 __ movp(rax, ContextOperand(rax, variable->interface()->Index()));
900 __ movp(rax, ContextOperand(rax, Context::EXTENSION_INDEX));
901
902 // Assign it.
903 __ movp(ContextOperand(rsi, variable->index()), rax);
904 // We know that we have written a module, which is not a smi.
905 __ RecordWriteContextSlot(rsi,
906 Context::SlotOffset(variable->index()),
907 rax,
908 rcx,
909 kDontSaveFPRegs,
910 EMIT_REMEMBERED_SET,
911 OMIT_SMI_CHECK);
912 PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
913
914 // Traverse into body.
915 Visit(declaration->module());
916}
917
918
919void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
920 VariableProxy* proxy = declaration->proxy();
921 Variable* variable = proxy->var();
922 switch (variable->location()) {
923 case Variable::UNALLOCATED:
924 // TODO(rossberg)
925 break;
926
927 case Variable::CONTEXT: {
928 Comment cmnt(masm_, "[ ImportDeclaration");
929 EmitDebugCheckDeclarationContext(variable);
930 // TODO(rossberg)
931 break;
932 }
933
934 case Variable::PARAMETER:
935 case Variable::LOCAL:
936 case Variable::LOOKUP:
937 UNREACHABLE();
938 }
939}
940
941
942void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
943 // TODO(rossberg)
944}
945
946
Leon Clarked91b9f72010-01-27 17:25:45 +0000947void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
Steve Block3ce2e202009-11-05 08:53:23 +0000948 // Call the runtime to declare the globals.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000949 __ Push(rsi); // The context is the first argument.
Steve Block3ce2e202009-11-05 08:53:23 +0000950 __ Push(pairs);
Ben Murdoch589d6972011-11-30 16:04:58 +0000951 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
952 __ CallRuntime(Runtime::kDeclareGlobals, 3);
Steve Block3ce2e202009-11-05 08:53:23 +0000953 // Return value is ignored.
954}
955
956
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000957void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
958 // Call the runtime to declare the modules.
959 __ Push(descriptions);
960 __ CallRuntime(Runtime::kDeclareModules, 1);
961 // Return value is ignored.
962}
963
964
Leon Clarkef7060e22010-06-03 12:02:55 +0100965void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
966 Comment cmnt(masm_, "[ SwitchStatement");
967 Breakable nested_statement(this, stmt);
968 SetStatementPosition(stmt);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100969
Leon Clarkef7060e22010-06-03 12:02:55 +0100970 // Keep the switch value on the stack until a case matches.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100971 VisitForStackValue(stmt->tag());
Ben Murdoch086aeea2011-05-13 15:57:08 +0100972 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +0000973
Leon Clarkef7060e22010-06-03 12:02:55 +0100974 ZoneList<CaseClause*>* clauses = stmt->cases();
975 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
Steve Block3ce2e202009-11-05 08:53:23 +0000976
Leon Clarkef7060e22010-06-03 12:02:55 +0100977 Label next_test; // Recycled for each test.
978 // Compile all the tests with branches to their bodies.
979 for (int i = 0; i < clauses->length(); i++) {
980 CaseClause* clause = clauses->at(i);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100981 clause->body_target()->Unuse();
Steve Block1e0659c2011-05-24 12:43:12 +0100982
Leon Clarkef7060e22010-06-03 12:02:55 +0100983 // The default is not a test, but remember it as final fall through.
984 if (clause->is_default()) {
985 default_clause = clause;
986 continue;
987 }
988
989 Comment cmnt(masm_, "[ Case comparison");
990 __ bind(&next_test);
991 next_test.Unuse();
992
993 // Compile the label expression.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100994 VisitForAccumulatorValue(clause->label());
Leon Clarkef7060e22010-06-03 12:02:55 +0100995
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100996 // Perform the comparison as if via '==='.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000997 __ movp(rdx, Operand(rsp, 0)); // Switch value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100998 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
Steve Block1e0659c2011-05-24 12:43:12 +0100999 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001000 if (inline_smi_code) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001001 Label slow_case;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001002 __ movp(rcx, rdx);
1003 __ orp(rcx, rax);
Ben Murdoch257744e2011-11-30 15:57:28 +00001004 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +01001005
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001006 __ cmpp(rdx, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001007 __ j(not_equal, &next_test);
1008 __ Drop(1); // Switch value is no longer needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001009 __ jmp(clause->body_target());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001010 __ bind(&slow_case);
1011 }
Leon Clarkef7060e22010-06-03 12:02:55 +01001012
Steve Block1e0659c2011-05-24 12:43:12 +01001013 // Record position before stub call for type feedback.
1014 SetSourcePosition(clause->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001015 Handle<Code> ic =
1016 CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
1017 CallIC(ic, clause->CompareId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001018 patch_site.EmitPatchInfo();
Steve Block1e0659c2011-05-24 12:43:12 +01001019
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001020 Label skip;
1021 __ jmp(&skip, Label::kNear);
1022 PrepareForBailout(clause, TOS_REG);
1023 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
1024 __ j(not_equal, &next_test);
1025 __ Drop(1);
1026 __ jmp(clause->body_target());
1027 __ bind(&skip);
1028
1029 __ testp(rax, rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001030 __ j(not_equal, &next_test);
1031 __ Drop(1); // Switch value is no longer needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001032 __ jmp(clause->body_target());
Leon Clarkef7060e22010-06-03 12:02:55 +01001033 }
1034
1035 // Discard the test value and jump to the default if present, otherwise to
1036 // the end of the statement.
1037 __ bind(&next_test);
1038 __ Drop(1); // Switch value is no longer needed.
1039 if (default_clause == NULL) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001040 __ jmp(nested_statement.break_label());
Leon Clarkef7060e22010-06-03 12:02:55 +01001041 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001042 __ jmp(default_clause->body_target());
Leon Clarkef7060e22010-06-03 12:02:55 +01001043 }
1044
1045 // Compile all the case bodies.
1046 for (int i = 0; i < clauses->length(); i++) {
1047 Comment cmnt(masm_, "[ Case body");
1048 CaseClause* clause = clauses->at(i);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001049 __ bind(clause->body_target());
Steve Block44f0eee2011-05-26 01:26:41 +01001050 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001051 VisitStatements(clause->statements());
1052 }
1053
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001054 __ bind(nested_statement.break_label());
Ben Murdoch086aeea2011-05-13 15:57:08 +01001055 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001056}
1057
1058
1059void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1060 Comment cmnt(masm_, "[ ForInStatement");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001061 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
Leon Clarkef7060e22010-06-03 12:02:55 +01001062 SetStatementPosition(stmt);
1063
1064 Label loop, exit;
1065 ForIn loop_statement(this, stmt);
1066 increment_loop_depth();
1067
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001068 // Get the object to enumerate over. If the object is null or undefined, skip
1069 // over the loop. See ECMA-262 version 5, section 12.6.4.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001070 SetExpressionPosition(stmt->enumerable());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001071 VisitForAccumulatorValue(stmt->enumerable());
Leon Clarkef7060e22010-06-03 12:02:55 +01001072 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
1073 __ j(equal, &exit);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001074 Register null_value = rdi;
1075 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001076 __ cmpp(rax, null_value);
Leon Clarkef7060e22010-06-03 12:02:55 +01001077 __ j(equal, &exit);
1078
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001079 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1080
Leon Clarkef7060e22010-06-03 12:02:55 +01001081 // Convert the object to a JS object.
1082 Label convert, done_convert;
1083 __ JumpIfSmi(rax, &convert);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001084 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
Leon Clarkef7060e22010-06-03 12:02:55 +01001085 __ j(above_equal, &done_convert);
1086 __ bind(&convert);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001087 __ Push(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001088 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1089 __ bind(&done_convert);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001090 PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001091 __ Push(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001092
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001093 // Check for proxies.
1094 Label call_runtime;
1095 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1096 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
1097 __ j(below_equal, &call_runtime);
1098
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001099 // Check cache validity in generated code. This is a fast case for
1100 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1101 // guarantee cache validity, call the runtime system to check cache
1102 // validity or get the property names in a fixed array.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001103 __ CheckEnumCache(null_value, &call_runtime);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001104
1105 // The enum cache is valid. Load the map of the object being
1106 // iterated over and use the cache for the iteration.
Ben Murdoch257744e2011-11-30 15:57:28 +00001107 Label use_cache;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001108 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001109 __ jmp(&use_cache, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01001110
1111 // Get the set of properties to enumerate.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001112 __ bind(&call_runtime);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001113 __ Push(rax); // Duplicate the enumerable object on the stack.
Leon Clarkef7060e22010-06-03 12:02:55 +01001114 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001115 PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
Leon Clarkef7060e22010-06-03 12:02:55 +01001116
1117 // If we got a map from the runtime call, we can do a fast
1118 // modification check. Otherwise, we got a fixed array, and we have
1119 // to do a slow check.
Ben Murdoch257744e2011-11-30 15:57:28 +00001120 Label fixed_array;
Leon Clarkef7060e22010-06-03 12:02:55 +01001121 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1122 Heap::kMetaMapRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001123 __ j(not_equal, &fixed_array);
Leon Clarkef7060e22010-06-03 12:02:55 +01001124
1125 // We got a map in register rax. Get the enumeration cache from it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001126 __ bind(&use_cache);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001127
1128 Label no_descriptors;
1129
1130 __ EnumLength(rdx, rax);
1131 __ Cmp(rdx, Smi::FromInt(0));
1132 __ j(equal, &no_descriptors);
1133
Ben Murdoch257744e2011-11-30 15:57:28 +00001134 __ LoadInstanceDescriptors(rax, rcx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001135 __ movp(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheOffset));
1136 __ movp(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01001137
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001138 // Set up the four remaining stack slots.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001139 __ Push(rax); // Map.
1140 __ Push(rcx); // Enumeration cache.
1141 __ Push(rdx); // Number of valid entries for the map in the enum cache.
Leon Clarkef7060e22010-06-03 12:02:55 +01001142 __ Push(Smi::FromInt(0)); // Initial index.
1143 __ jmp(&loop);
1144
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001145 __ bind(&no_descriptors);
1146 __ addp(rsp, Immediate(kPointerSize));
1147 __ jmp(&exit);
1148
Leon Clarkef7060e22010-06-03 12:02:55 +01001149 // We got a fixed array in register rax. Iterate through that.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001150 Label non_proxy;
Leon Clarkef7060e22010-06-03 12:02:55 +01001151 __ bind(&fixed_array);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001152
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001153 // No need for a write barrier, we are storing a Smi in the feedback vector.
1154 __ Move(rbx, FeedbackVector());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001155 int vector_index = FeedbackVector()->GetIndex(slot);
1156 __ Move(FieldOperand(rbx, FixedArray::OffsetOfElementAt(vector_index)),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001157 TypeFeedbackVector::MegamorphicSentinel(isolate()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001158 __ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001159 __ movp(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001160 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1161 __ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx);
1162 __ j(above, &non_proxy);
1163 __ Move(rbx, Smi::FromInt(0)); // Zero indicates proxy
1164 __ bind(&non_proxy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001165 __ Push(rbx); // Smi
1166 __ Push(rax); // Array
1167 __ movp(rax, FieldOperand(rax, FixedArray::kLengthOffset));
1168 __ Push(rax); // Fixed array length (as smi).
Leon Clarkef7060e22010-06-03 12:02:55 +01001169 __ Push(Smi::FromInt(0)); // Initial index.
1170
1171 // Generate code for doing the condition check.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001172 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001173 __ bind(&loop);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001174 SetExpressionPosition(stmt->each());
1175
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001176 __ movp(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
1177 __ cmpp(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001178 __ j(above_equal, loop_statement.break_label());
Leon Clarkef7060e22010-06-03 12:02:55 +01001179
1180 // Get the current entry of the array into register rbx.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001181 __ movp(rbx, Operand(rsp, 2 * kPointerSize));
Ben Murdochf87a2032010-10-22 12:50:53 +01001182 SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001183 __ movp(rbx, FieldOperand(rbx,
Leon Clarkef7060e22010-06-03 12:02:55 +01001184 index.reg,
1185 index.scale,
1186 FixedArray::kHeaderSize));
1187
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001188 // Get the expected map from the stack or a smi in the
Leon Clarkef7060e22010-06-03 12:02:55 +01001189 // permanent slow case into register rdx.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001190 __ movp(rdx, Operand(rsp, 3 * kPointerSize));
Leon Clarkef7060e22010-06-03 12:02:55 +01001191
1192 // Check if the expected map still matches that of the enumerable.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001193 // If not, we may have to filter the key.
Ben Murdoch257744e2011-11-30 15:57:28 +00001194 Label update_each;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001195 __ movp(rcx, Operand(rsp, 4 * kPointerSize));
1196 __ cmpp(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001197 __ j(equal, &update_each, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01001198
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001199 // For proxies, no filtering is done.
1200 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1201 __ Cmp(rdx, Smi::FromInt(0));
1202 __ j(equal, &update_each, Label::kNear);
1203
Leon Clarkef7060e22010-06-03 12:02:55 +01001204 // Convert the entry to a string or null if it isn't a property
1205 // anymore. If the property has been removed while iterating, we
1206 // just skip it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001207 __ Push(rcx); // Enumerable.
1208 __ Push(rbx); // Current entry.
Leon Clarkef7060e22010-06-03 12:02:55 +01001209 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
Steve Block44f0eee2011-05-26 01:26:41 +01001210 __ Cmp(rax, Smi::FromInt(0));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001211 __ j(equal, loop_statement.continue_label());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001212 __ movp(rbx, rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001213
1214 // Update the 'each' property or variable from the possibly filtered
1215 // entry in register rbx.
1216 __ bind(&update_each);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001217 __ movp(result_register(), rbx);
Leon Clarkef7060e22010-06-03 12:02:55 +01001218 // Perform the assignment as if via '='.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001219 { EffectContext context(this);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001220 EmitAssignment(stmt->each());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001221 }
Leon Clarkef7060e22010-06-03 12:02:55 +01001222
1223 // Generate code for the body of the loop.
Leon Clarkef7060e22010-06-03 12:02:55 +01001224 Visit(stmt->body());
1225
Leon Clarkef7060e22010-06-03 12:02:55 +01001226 // Generate code for going to the next element by incrementing the
1227 // index (smi) stored on top of the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001228 __ bind(loop_statement.continue_label());
Leon Clarkef7060e22010-06-03 12:02:55 +01001229 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01001230
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001231 EmitBackEdgeBookkeeping(stmt, &loop);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001232 __ jmp(&loop);
Leon Clarkef7060e22010-06-03 12:02:55 +01001233
1234 // Remove the pointers stored on the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001235 __ bind(loop_statement.break_label());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001236 __ addp(rsp, Immediate(5 * kPointerSize));
Leon Clarkef7060e22010-06-03 12:02:55 +01001237
1238 // Exit and decrement the loop depth.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001239 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001240 __ bind(&exit);
1241 decrement_loop_depth();
1242}
1243
1244
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001245void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1246 bool pretenure) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001247 // Use the fast case closure allocation code that allocates in new
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001248 // space for nested functions that don't need literals cloning. If
1249 // we're running with the --always-opt or the --prepare-always-opt
1250 // flag, we need to use the runtime function so that the new function
1251 // we are creating here gets a chance to have its code optimized and
1252 // doesn't just get a copy of the existing unoptimized code.
1253 if (!FLAG_always_opt &&
1254 !FLAG_prepare_always_opt &&
Steve Block44f0eee2011-05-26 01:26:41 +01001255 !pretenure &&
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001256 scope()->is_function_scope() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001257 info->num_literals() == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001258 FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind());
1259 __ Move(rbx, info);
Leon Clarkef7060e22010-06-03 12:02:55 +01001260 __ CallStub(&stub);
1261 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001262 __ Push(rsi);
Leon Clarkef7060e22010-06-03 12:02:55 +01001263 __ Push(info);
Steve Block44f0eee2011-05-26 01:26:41 +01001264 __ Push(pretenure
1265 ? isolate()->factory()->true_value()
1266 : isolate()->factory()->false_value());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001267 __ CallRuntime(Runtime::kNewClosure, 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01001268 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001269 context()->Plug(rax);
Steve Block3ce2e202009-11-05 08:53:23 +00001270}
1271
1272
Leon Clarked91b9f72010-01-27 17:25:45 +00001273void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001274 Comment cmnt(masm_, "[ VariableProxy");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001275 EmitVariableLoad(expr);
Leon Clarkee46be812010-01-19 14:06:41 +00001276}
1277
1278
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001279void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
1280 Comment cnmt(masm_, "[ SuperReference ");
1281
1282 __ movp(LoadDescriptor::ReceiverRegister(),
1283 Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1284
1285 Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
1286 __ Move(LoadDescriptor::NameRegister(), home_object_symbol);
1287
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001288 if (FLAG_vector_ics) {
1289 __ Move(VectorLoadICDescriptor::SlotRegister(),
1290 SmiFromSlot(expr->HomeObjectFeedbackSlot()));
1291 CallLoadIC(NOT_CONTEXTUAL);
1292 } else {
1293 CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
1294 }
1295
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001296
1297 __ Cmp(rax, isolate()->factory()->undefined_value());
1298 Label done;
1299 __ j(not_equal, &done);
1300 __ CallRuntime(Runtime::kThrowNonMethodError, 0);
1301 __ bind(&done);
1302}
1303
1304
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001305void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
1306 int offset) {
1307 if (NeedsHomeObject(initializer)) {
1308 __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0));
1309 __ Move(StoreDescriptor::NameRegister(),
1310 isolate()->factory()->home_object_symbol());
1311 __ movp(StoreDescriptor::ValueRegister(),
1312 Operand(rsp, offset * kPointerSize));
1313 CallStoreIC();
1314 }
1315}
1316
1317
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001318void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
Ben Murdoch589d6972011-11-30 16:04:58 +00001319 TypeofState typeof_state,
1320 Label* slow) {
Steve Block59151502010-09-22 15:07:15 +01001321 Register context = rsi;
1322 Register temp = rdx;
1323
1324 Scope* s = scope();
1325 while (s != NULL) {
1326 if (s->num_heap_slots() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001327 if (s->calls_sloppy_eval()) {
Steve Block59151502010-09-22 15:07:15 +01001328 // Check that extension is NULL.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001329 __ cmpp(ContextOperand(context, Context::EXTENSION_INDEX),
Steve Block59151502010-09-22 15:07:15 +01001330 Immediate(0));
1331 __ j(not_equal, slow);
1332 }
1333 // Load next context in chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001334 __ movp(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001335 // Walk the rest of the chain without clobbering rsi.
1336 context = temp;
1337 }
1338 // If no outer scope calls eval, we do not need to check more
1339 // context extensions. If we have reached an eval scope, we check
1340 // all extensions from this point.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001341 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
Steve Block59151502010-09-22 15:07:15 +01001342 s = s->outer_scope();
1343 }
1344
1345 if (s != NULL && s->is_eval_scope()) {
1346 // Loop up the context chain. There is no frame effect so it is
1347 // safe to use raw labels here.
Ben Murdoch257744e2011-11-30 15:57:28 +00001348 Label next, fast;
Steve Block59151502010-09-22 15:07:15 +01001349 if (!context.is(temp)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001350 __ movp(temp, context);
Steve Block59151502010-09-22 15:07:15 +01001351 }
1352 // Load map for comparison into register, outside loop.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001353 __ LoadRoot(kScratchRegister, Heap::kNativeContextMapRootIndex);
Steve Block59151502010-09-22 15:07:15 +01001354 __ bind(&next);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001355 // Terminate at native context.
1356 __ cmpp(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001357 __ j(equal, &fast, Label::kNear);
Steve Block59151502010-09-22 15:07:15 +01001358 // Check that extension is NULL.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001359 __ cmpp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
Steve Block59151502010-09-22 15:07:15 +01001360 __ j(not_equal, slow);
1361 // Load next context in chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001362 __ movp(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001363 __ jmp(&next);
1364 __ bind(&fast);
1365 }
1366
1367 // All extension objects were empty and it is safe to use a global
1368 // load IC call.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001369 __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
1370 __ Move(LoadDescriptor::NameRegister(), proxy->var()->name());
1371 if (FLAG_vector_ics) {
1372 __ Move(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001373 SmiFromSlot(proxy->VariableFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001374 }
1375
1376 ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
1377 ? NOT_CONTEXTUAL
1378 : CONTEXTUAL;
1379 CallLoadIC(mode);
Steve Block59151502010-09-22 15:07:15 +01001380}
1381
1382
Ben Murdoch589d6972011-11-30 16:04:58 +00001383MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1384 Label* slow) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001385 DCHECK(var->IsContextSlot());
Steve Block59151502010-09-22 15:07:15 +01001386 Register context = rsi;
1387 Register temp = rbx;
1388
Ben Murdoch589d6972011-11-30 16:04:58 +00001389 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
Steve Block59151502010-09-22 15:07:15 +01001390 if (s->num_heap_slots() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001391 if (s->calls_sloppy_eval()) {
Steve Block59151502010-09-22 15:07:15 +01001392 // Check that extension is NULL.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001393 __ cmpp(ContextOperand(context, Context::EXTENSION_INDEX),
Steve Block59151502010-09-22 15:07:15 +01001394 Immediate(0));
1395 __ j(not_equal, slow);
1396 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001397 __ movp(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001398 // Walk the rest of the chain without clobbering rsi.
1399 context = temp;
1400 }
1401 }
1402 // Check that last extension is NULL.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001403 __ cmpp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
Steve Block59151502010-09-22 15:07:15 +01001404 __ j(not_equal, slow);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001405
1406 // This function is used only for loads, not stores, so it's safe to
1407 // return an rsi-based operand (the write barrier cannot be allowed to
1408 // destroy the rsi register).
Ben Murdoch589d6972011-11-30 16:04:58 +00001409 return ContextOperand(context, var->index());
Steve Block59151502010-09-22 15:07:15 +01001410}
1411
1412
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
Ben Murdoch589d6972011-11-30 16:04:58 +00001414 TypeofState typeof_state,
1415 Label* slow,
1416 Label* done) {
Steve Block59151502010-09-22 15:07:15 +01001417 // Generate fast-case code for variables that might be shadowed by
1418 // eval-introduced variables. Eval is used a lot without
1419 // introducing variables. In those cases, we do not want to
1420 // perform a runtime call for all variables in the scope
1421 // containing the eval.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001422 Variable* var = proxy->var();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001423 if (var->mode() == DYNAMIC_GLOBAL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001424 EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow);
Steve Block59151502010-09-22 15:07:15 +01001425 __ jmp(done);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001426 } else if (var->mode() == DYNAMIC_LOCAL) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001427 Variable* local = var->local_if_not_shadowed();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001428 __ movp(rax, ContextSlotOperandCheckExtensions(local, slow));
1429 if (local->mode() == LET || local->mode() == CONST ||
1430 local->mode() == CONST_LEGACY) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001431 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1432 __ j(not_equal, done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001433 if (local->mode() == CONST_LEGACY) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001434 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001435 } else { // LET || CONST
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001436 __ Push(var->name());
1437 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1438 }
Steve Block59151502010-09-22 15:07:15 +01001439 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001440 __ jmp(done);
Steve Block59151502010-09-22 15:07:15 +01001441 }
1442}
1443
1444
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001445void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1446 // Record position before possible IC call.
1447 SetSourcePosition(proxy->position());
1448 Variable* var = proxy->var();
Leon Clarked91b9f72010-01-27 17:25:45 +00001449
Ben Murdoch589d6972011-11-30 16:04:58 +00001450 // Three cases: global variables, lookup variables, and all other types of
1451 // variables.
1452 switch (var->location()) {
1453 case Variable::UNALLOCATED: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001454 Comment cmnt(masm_, "[ Global variable");
1455 __ Move(LoadDescriptor::NameRegister(), var->name());
1456 __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
1457 if (FLAG_vector_ics) {
1458 __ Move(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001459 SmiFromSlot(proxy->VariableFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001460 }
1461 CallLoadIC(CONTEXTUAL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001462 context()->Plug(rax);
Ben Murdoch589d6972011-11-30 16:04:58 +00001463 break;
1464 }
1465
1466 case Variable::PARAMETER:
1467 case Variable::LOCAL:
1468 case Variable::CONTEXT: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001469 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot"
1470 : "[ Stack slot");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001471 if (var->binding_needs_init()) {
1472 // var->scope() may be NULL when the proxy is located in eval code and
1473 // refers to a potential outside binding. Currently those bindings are
1474 // always looked up dynamically, i.e. in that case
1475 // var->location() == LOOKUP.
1476 // always holds.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001477 DCHECK(var->scope() != NULL);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001478
1479 // Check if the binding really needs an initialization check. The check
1480 // can be skipped in the following situation: we have a LET or CONST
1481 // binding in harmony mode, both the Variable and the VariableProxy have
1482 // the same declaration scope (i.e. they are both in global code, in the
1483 // same function or in the same eval code) and the VariableProxy is in
1484 // the source physically located after the initializer of the variable.
1485 //
1486 // We cannot skip any initialization checks for CONST in non-harmony
1487 // mode because const variables may be declared but never initialized:
1488 // if (false) { const x; }; var y = x;
1489 //
1490 // The condition on the declaration scopes is a conservative check for
1491 // nested functions that access a binding and are called before the
1492 // binding is initialized:
1493 // function() { f(); let x = 1; function f() { x = 2; } }
1494 //
1495 bool skip_init_check;
1496 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1497 skip_init_check = false;
1498 } else {
1499 // Check that we always have valid source position.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001500 DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
1501 DCHECK(proxy->position() != RelocInfo::kNoPosition);
1502 skip_init_check = var->mode() != CONST_LEGACY &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001503 var->initializer_position() < proxy->position();
Ben Murdoch589d6972011-11-30 16:04:58 +00001504 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001505
1506 if (!skip_init_check) {
1507 // Let and const need a read barrier.
1508 Label done;
1509 GetVar(rax, var);
1510 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1511 __ j(not_equal, &done, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001512 if (var->mode() == LET || var->mode() == CONST) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001513 // Throw a reference error when using an uninitialized let/const
1514 // binding in harmony mode.
1515 __ Push(var->name());
1516 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1517 } else {
1518 // Uninitalized const bindings outside of harmony mode are unholed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001519 DCHECK(var->mode() == CONST_LEGACY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001520 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1521 }
1522 __ bind(&done);
1523 context()->Plug(rax);
1524 break;
1525 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001526 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001527 context()->Plug(var);
Ben Murdoch589d6972011-11-30 16:04:58 +00001528 break;
1529 }
1530
1531 case Variable::LOOKUP: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001532 Comment cmnt(masm_, "[ Lookup slot");
Ben Murdoch589d6972011-11-30 16:04:58 +00001533 Label done, slow;
1534 // Generate code for loading from variables potentially shadowed
1535 // by eval-introduced variables.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001536 EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
Ben Murdoch589d6972011-11-30 16:04:58 +00001537 __ bind(&slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001538 __ Push(rsi); // Context.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001539 __ Push(var->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001540 __ CallRuntime(Runtime::kLoadLookupSlot, 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001541 __ bind(&done);
1542 context()->Plug(rax);
Ben Murdoch589d6972011-11-30 16:04:58 +00001543 break;
Leon Clarkef7060e22010-06-03 12:02:55 +01001544 }
Steve Block3ce2e202009-11-05 08:53:23 +00001545 }
1546}
1547
1548
Leon Clarked91b9f72010-01-27 17:25:45 +00001549void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001550 Comment cmnt(masm_, "[ RegExpLiteral");
Ben Murdochbb769b22010-08-11 14:56:33 +01001551 Label materialized;
Steve Block3ce2e202009-11-05 08:53:23 +00001552 // Registers will be used as follows:
1553 // rdi = JS function.
Ben Murdochbb769b22010-08-11 14:56:33 +01001554 // rcx = literals array.
1555 // rbx = regexp literal.
1556 // rax = regexp literal clone.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001557 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1558 __ movp(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001559 int literal_offset =
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001560 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001561 __ movp(rbx, FieldOperand(rcx, literal_offset));
Ben Murdochbb769b22010-08-11 14:56:33 +01001562 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
Ben Murdoch589d6972011-11-30 16:04:58 +00001563 __ j(not_equal, &materialized, Label::kNear);
Ben Murdochbb769b22010-08-11 14:56:33 +01001564
Steve Block3ce2e202009-11-05 08:53:23 +00001565 // Create regexp literal using runtime function
1566 // Result will be in rax.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001567 __ Push(rcx);
Steve Block3ce2e202009-11-05 08:53:23 +00001568 __ Push(Smi::FromInt(expr->literal_index()));
1569 __ Push(expr->pattern());
1570 __ Push(expr->flags());
1571 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001572 __ movp(rbx, rax);
Ben Murdochbb769b22010-08-11 14:56:33 +01001573
1574 __ bind(&materialized);
1575 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1576 Label allocated, runtime_allocate;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001577 __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
Ben Murdochbb769b22010-08-11 14:56:33 +01001578 __ jmp(&allocated);
1579
1580 __ bind(&runtime_allocate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001581 __ Push(rbx);
Ben Murdochbb769b22010-08-11 14:56:33 +01001582 __ Push(Smi::FromInt(size));
1583 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 __ Pop(rbx);
Ben Murdochbb769b22010-08-11 14:56:33 +01001585
1586 __ bind(&allocated);
1587 // Copy the content into the newly allocated memory.
1588 // (Unroll copy loop once for better throughput).
1589 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001590 __ movp(rdx, FieldOperand(rbx, i));
1591 __ movp(rcx, FieldOperand(rbx, i + kPointerSize));
1592 __ movp(FieldOperand(rax, i), rdx);
1593 __ movp(FieldOperand(rax, i + kPointerSize), rcx);
Ben Murdochbb769b22010-08-11 14:56:33 +01001594 }
1595 if ((size % (2 * kPointerSize)) != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001596 __ movp(rdx, FieldOperand(rbx, size - kPointerSize));
1597 __ movp(FieldOperand(rax, size - kPointerSize), rdx);
Ben Murdochbb769b22010-08-11 14:56:33 +01001598 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001599 context()->Plug(rax);
Steve Blockd0582a62009-12-15 09:54:21 +00001600}
1601
1602
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001603void FullCodeGenerator::EmitAccessor(Expression* expression) {
1604 if (expression == NULL) {
1605 __ PushRoot(Heap::kNullValueRootIndex);
1606 } else {
1607 VisitForStackValue(expression);
1608 }
1609}
1610
1611
Leon Clarked91b9f72010-01-27 17:25:45 +00001612void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001613 Comment cmnt(masm_, "[ ObjectLiteral");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001614
1615 expr->BuildConstantProperties(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001616 Handle<FixedArray> constant_properties = expr->constant_properties();
Steve Block44f0eee2011-05-26 01:26:41 +01001617 int flags = expr->fast_elements()
1618 ? ObjectLiteral::kFastElements
1619 : ObjectLiteral::kNoFlags;
1620 flags |= expr->has_function()
1621 ? ObjectLiteral::kHasFunction
1622 : ObjectLiteral::kNoFlags;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001623 int properties_count = constant_properties->length() / 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001624 if (expr->may_store_doubles() || expr->depth() > 1 ||
1625 masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001626 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001627 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1628 __ Push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
1629 __ Push(Smi::FromInt(expr->literal_index()));
1630 __ Push(constant_properties);
1631 __ Push(Smi::FromInt(flags));
1632 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001633 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001634 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1635 __ movp(rax, FieldOperand(rdi, JSFunction::kLiteralsOffset));
1636 __ Move(rbx, Smi::FromInt(expr->literal_index()));
1637 __ Move(rcx, constant_properties);
1638 __ Move(rdx, Smi::FromInt(flags));
1639 FastCloneShallowObjectStub stub(isolate(), properties_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001640 __ CallStub(&stub);
Steve Blockd0582a62009-12-15 09:54:21 +00001641 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001642 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
Steve Blockd0582a62009-12-15 09:54:21 +00001643
Leon Clarkee46be812010-01-19 14:06:41 +00001644 // If result_saved is true the result is on top of the stack. If
1645 // result_saved is false the result is in rax.
Steve Blockd0582a62009-12-15 09:54:21 +00001646 bool result_saved = false;
1647
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001648 // Mark all computed expressions that are bound to a key that
1649 // is shadowed by a later occurrence of the same key. For the
1650 // marked expressions, no store code is emitted.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001651 expr->CalculateEmitStore(zone());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001652
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001653 AccessorTable accessor_table(zone());
Steve Blockd0582a62009-12-15 09:54:21 +00001654 for (int i = 0; i < expr->properties()->length(); i++) {
1655 ObjectLiteral::Property* property = expr->properties()->at(i);
1656 if (property->IsCompileTimeValue()) continue;
1657
1658 Literal* key = property->key();
1659 Expression* value = property->value();
1660 if (!result_saved) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001661 __ Push(rax); // Save result on the stack
Steve Blockd0582a62009-12-15 09:54:21 +00001662 result_saved = true;
1663 }
1664 switch (property->kind()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001665 case ObjectLiteral::Property::CONSTANT:
1666 UNREACHABLE();
1667 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001668 DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
Leon Clarkee46be812010-01-19 14:06:41 +00001669 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001670 case ObjectLiteral::Property::COMPUTED:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001671 // It is safe to use [[Put]] here because the boilerplate already
1672 // contains computed properties with an uninitialized value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001673 if (key->value()->IsInternalizedString()) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001674 if (property->emit_store()) {
Steve Block053d10c2011-06-13 19:13:29 +01001675 VisitForAccumulatorValue(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001676 DCHECK(StoreDescriptor::ValueRegister().is(rax));
1677 __ Move(StoreDescriptor::NameRegister(), key->value());
1678 __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0));
1679 CallStoreIC(key->LiteralFeedbackId());
Ben Murdoch086aeea2011-05-13 15:57:08 +01001680 PrepareForBailoutForId(key->id(), NO_REGISTERS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001681
1682 if (NeedsHomeObject(value)) {
1683 __ movp(StoreDescriptor::ReceiverRegister(), rax);
1684 __ Move(StoreDescriptor::NameRegister(),
1685 isolate()->factory()->home_object_symbol());
1686 __ movp(StoreDescriptor::ValueRegister(), Operand(rsp, 0));
1687 CallStoreIC();
1688 }
Steve Block053d10c2011-06-13 19:13:29 +01001689 } else {
1690 VisitForEffect(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001691 }
Steve Blockd0582a62009-12-15 09:54:21 +00001692 break;
1693 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001694 __ Push(Operand(rsp, 0)); // Duplicate receiver.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001695 VisitForStackValue(key);
1696 VisitForStackValue(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001697 if (property->emit_store()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001698 EmitSetHomeObjectIfNeeded(value, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001699 __ Push(Smi::FromInt(SLOPPY)); // Strict mode
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001700 __ CallRuntime(Runtime::kSetProperty, 4);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001701 } else {
1702 __ Drop(3);
1703 }
Steve Blockd0582a62009-12-15 09:54:21 +00001704 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001705 case ObjectLiteral::Property::PROTOTYPE:
1706 __ Push(Operand(rsp, 0)); // Duplicate receiver.
1707 VisitForStackValue(value);
1708 if (property->emit_store()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001709 __ CallRuntime(Runtime::kInternalSetPrototype, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001710 } else {
1711 __ Drop(2);
1712 }
1713 break;
Ben Murdoch85b71792012-04-11 18:30:58 +01001714 case ObjectLiteral::Property::GETTER:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001715 accessor_table.lookup(key)->second->getter = value;
1716 break;
1717 case ObjectLiteral::Property::SETTER:
1718 accessor_table.lookup(key)->second->setter = value;
Steve Blockd0582a62009-12-15 09:54:21 +00001719 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001720 }
1721 }
Leon Clarkee46be812010-01-19 14:06:41 +00001722
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001723 // Emit code to define accessors, using only a single call to the runtime for
1724 // each pair of corresponding getters and setters.
1725 for (AccessorTable::Iterator it = accessor_table.begin();
1726 it != accessor_table.end();
1727 ++it) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001728 __ Push(Operand(rsp, 0)); // Duplicate receiver.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001729 VisitForStackValue(it->first);
1730 EmitAccessor(it->second->getter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001731 EmitSetHomeObjectIfNeeded(it->second->getter, 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001732 EmitAccessor(it->second->setter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001733 EmitSetHomeObjectIfNeeded(it->second->setter, 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001734 __ Push(Smi::FromInt(NONE));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001735 __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001736 }
1737
Steve Block44f0eee2011-05-26 01:26:41 +01001738 if (expr->has_function()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001739 DCHECK(result_saved);
1740 __ Push(Operand(rsp, 0));
Steve Block44f0eee2011-05-26 01:26:41 +01001741 __ CallRuntime(Runtime::kToFastProperties, 1);
1742 }
1743
Leon Clarkee46be812010-01-19 14:06:41 +00001744 if (result_saved) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001745 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001746 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001747 context()->Plug(rax);
Steve Block3ce2e202009-11-05 08:53:23 +00001748 }
1749}
1750
1751
Leon Clarked91b9f72010-01-27 17:25:45 +00001752void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001753 Comment cmnt(masm_, "[ ArrayLiteral");
Leon Clarkef7060e22010-06-03 12:02:55 +01001754
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001755 expr->BuildConstantElements(isolate());
1756 int flags = expr->depth() == 1
1757 ? ArrayLiteral::kShallowElements
1758 : ArrayLiteral::kNoFlags;
1759
Leon Clarkef7060e22010-06-03 12:02:55 +01001760 ZoneList<Expression*>* subexprs = expr->values();
1761 int length = subexprs->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001762 Handle<FixedArray> constant_elements = expr->constant_elements();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001763 DCHECK_EQ(2, constant_elements->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001764 ElementsKind constant_elements_kind =
1765 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001766 bool has_constant_fast_elements =
1767 IsFastObjectElementsKind(constant_elements_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001768 Handle<FixedArrayBase> constant_elements_values(
1769 FixedArrayBase::cast(constant_elements->get(1)));
Leon Clarkef7060e22010-06-03 12:02:55 +01001770
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001771 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1772 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1773 // If the only customer of allocation sites is transitioning, then
1774 // we can turn it off if we don't have anywhere else to transition to.
1775 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1776 }
1777
1778 if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) {
1779 __ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1780 __ Push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1781 __ Push(Smi::FromInt(expr->literal_index()));
1782 __ Push(constant_elements);
1783 __ Push(Smi::FromInt(flags));
1784 __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
Leon Clarkef7060e22010-06-03 12:02:55 +01001785 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001786 __ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1787 __ movp(rax, FieldOperand(rbx, JSFunction::kLiteralsOffset));
1788 __ Move(rbx, Smi::FromInt(expr->literal_index()));
1789 __ Move(rcx, constant_elements);
1790 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
Leon Clarkef7060e22010-06-03 12:02:55 +01001791 __ CallStub(&stub);
Steve Block3ce2e202009-11-05 08:53:23 +00001792 }
1793
1794 bool result_saved = false; // Is the result saved to the stack?
1795
1796 // Emit code to evaluate all the non-constant subexpressions and to store
1797 // them into the newly cloned array.
Leon Clarkef7060e22010-06-03 12:02:55 +01001798 for (int i = 0; i < length; i++) {
Steve Block3ce2e202009-11-05 08:53:23 +00001799 Expression* subexpr = subexprs->at(i);
1800 // If the subexpression is a literal or a simple materialized literal it
1801 // is already set in the cloned array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001802 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
Steve Block3ce2e202009-11-05 08:53:23 +00001803
1804 if (!result_saved) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001805 __ Push(rax); // array literal
1806 __ Push(Smi::FromInt(expr->literal_index()));
Steve Block3ce2e202009-11-05 08:53:23 +00001807 result_saved = true;
1808 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001809 VisitForAccumulatorValue(subexpr);
Steve Block3ce2e202009-11-05 08:53:23 +00001810
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001811 if (IsFastObjectElementsKind(constant_elements_kind)) {
1812 // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
1813 // cannot transition and don't need to call the runtime stub.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001814 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001815 __ movp(rbx, Operand(rsp, kPointerSize)); // Copy of array literal.
1816 __ movp(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001817 // Store the subexpression value in the array's elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001818 __ movp(FieldOperand(rbx, offset), result_register());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001819 // Update the write barrier for the array store.
1820 __ RecordWriteField(rbx, offset, result_register(), rcx,
1821 kDontSaveFPRegs,
1822 EMIT_REMEMBERED_SET,
1823 INLINE_SMI_CHECK);
1824 } else {
1825 // Store the subexpression value in the array's elements.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001826 __ Move(rcx, Smi::FromInt(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001827 StoreArrayLiteralElementStub stub(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001828 __ CallStub(&stub);
1829 }
Ben Murdoch086aeea2011-05-13 15:57:08 +01001830
1831 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +00001832 }
1833
Leon Clarkee46be812010-01-19 14:06:41 +00001834 if (result_saved) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001835 __ addp(rsp, Immediate(kPointerSize)); // literal index
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001836 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001837 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001838 context()->Plug(rax);
Steve Block3ce2e202009-11-05 08:53:23 +00001839 }
1840}
1841
1842
Andrei Popescu402d9372010-02-26 13:31:12 +00001843void FullCodeGenerator::VisitAssignment(Assignment* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001844 DCHECK(expr->target()->IsValidReferenceExpression());
1845
Andrei Popescu402d9372010-02-26 13:31:12 +00001846 Comment cmnt(masm_, "[ Assignment");
Leon Clarkef7060e22010-06-03 12:02:55 +01001847
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001848 Property* property = expr->target()->AsProperty();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001849 LhsKind assign_type = GetAssignType(property);
Andrei Popescu402d9372010-02-26 13:31:12 +00001850
1851 // Evaluate LHS expression.
1852 switch (assign_type) {
1853 case VARIABLE:
1854 // Nothing to do here.
1855 break;
1856 case NAMED_PROPERTY:
1857 if (expr->is_compound()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001858 // We need the receiver both on the stack and in the register.
1859 VisitForStackValue(property->obj());
1860 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
Andrei Popescu402d9372010-02-26 13:31:12 +00001861 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001862 VisitForStackValue(property->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00001863 }
1864 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001865 case NAMED_SUPER_PROPERTY:
1866 VisitForStackValue(property->obj()->AsSuperReference()->this_var());
1867 EmitLoadHomeObject(property->obj()->AsSuperReference());
1868 __ Push(result_register());
1869 if (expr->is_compound()) {
1870 __ Push(MemOperand(rsp, kPointerSize));
1871 __ Push(result_register());
1872 }
1873 break;
1874 case KEYED_SUPER_PROPERTY:
1875 VisitForStackValue(property->obj()->AsSuperReference()->this_var());
1876 EmitLoadHomeObject(property->obj()->AsSuperReference());
1877 __ Push(result_register());
1878 VisitForAccumulatorValue(property->key());
1879 __ Push(result_register());
1880 if (expr->is_compound()) {
1881 __ Push(MemOperand(rsp, 2 * kPointerSize));
1882 __ Push(MemOperand(rsp, 2 * kPointerSize));
1883 __ Push(result_register());
1884 }
1885 break;
Ben Murdoch086aeea2011-05-13 15:57:08 +01001886 case KEYED_PROPERTY: {
Leon Clarkef7060e22010-06-03 12:02:55 +01001887 if (expr->is_compound()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001888 VisitForStackValue(property->obj());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889 VisitForStackValue(property->key());
1890 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
1891 __ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
Leon Clarkef7060e22010-06-03 12:02:55 +01001892 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001893 VisitForStackValue(property->obj());
1894 VisitForStackValue(property->key());
Leon Clarkef7060e22010-06-03 12:02:55 +01001895 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001896 break;
Ben Murdoch086aeea2011-05-13 15:57:08 +01001897 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001898 }
1899
Ben Murdoch8b112d22011-06-08 16:22:53 +01001900 // For compound assignments we need another deoptimization point after the
1901 // variable/property load.
Andrei Popescu402d9372010-02-26 13:31:12 +00001902 if (expr->is_compound()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001903 { AccumulatorValueContext context(this);
1904 switch (assign_type) {
1905 case VARIABLE:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001906 EmitVariableLoad(expr->target()->AsVariableProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001907 PrepareForBailout(expr->target(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001908 break;
1909 case NAMED_PROPERTY:
1910 EmitNamedPropertyLoad(property);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001911 PrepareForBailoutForId(property->LoadId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001912 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001913 case NAMED_SUPER_PROPERTY:
1914 EmitNamedSuperPropertyLoad(property);
1915 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1916 break;
1917 case KEYED_SUPER_PROPERTY:
1918 EmitKeyedSuperPropertyLoad(property);
1919 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1920 break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001921 case KEYED_PROPERTY:
1922 EmitKeyedPropertyLoad(property);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001923 PrepareForBailoutForId(property->LoadId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001924 break;
1925 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001926 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001927
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001928 Token::Value op = expr->binary_op();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001929 __ Push(rax); // Left operand goes on the stack.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001930 VisitForAccumulatorValue(expr->value());
Andrei Popescu402d9372010-02-26 13:31:12 +00001931
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001932 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1933 ? OVERWRITE_RIGHT
1934 : NO_OVERWRITE;
1935 SetSourcePosition(expr->position() + 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001936 AccumulatorValueContext context(this);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001937 if (ShouldInlineSmiCase(op)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001938 EmitInlineSmiBinaryOp(expr->binary_operation(),
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001939 op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001940 mode,
1941 expr->target(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001942 expr->value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001943 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00001944 EmitBinaryOp(expr->binary_operation(), op, mode);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001945 }
Ben Murdoch086aeea2011-05-13 15:57:08 +01001946 // Deoptimization point in case the binary operation may have side effects.
1947 PrepareForBailout(expr->binary_operation(), TOS_REG);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001948 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001949 VisitForAccumulatorValue(expr->value());
Andrei Popescu402d9372010-02-26 13:31:12 +00001950 }
1951
1952 // Record source position before possible IC call.
1953 SetSourcePosition(expr->position());
1954
1955 // Store the value.
1956 switch (assign_type) {
1957 case VARIABLE:
1958 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001959 expr->op());
Ben Murdoch086aeea2011-05-13 15:57:08 +01001960 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001961 context()->Plug(rax);
Andrei Popescu402d9372010-02-26 13:31:12 +00001962 break;
1963 case NAMED_PROPERTY:
1964 EmitNamedPropertyAssignment(expr);
1965 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001966 case NAMED_SUPER_PROPERTY:
1967 EmitNamedSuperPropertyStore(property);
1968 context()->Plug(rax);
1969 break;
1970 case KEYED_SUPER_PROPERTY:
1971 EmitKeyedSuperPropertyStore(property);
1972 context()->Plug(rax);
1973 break;
Andrei Popescu402d9372010-02-26 13:31:12 +00001974 case KEYED_PROPERTY:
1975 EmitKeyedPropertyAssignment(expr);
1976 break;
1977 }
1978}
1979
1980
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001981void FullCodeGenerator::VisitYield(Yield* expr) {
1982 Comment cmnt(masm_, "[ Yield");
1983 // Evaluate yielded value first; the initial iterator definition depends on
1984 // this. It stays on the stack while we update the iterator.
1985 VisitForStackValue(expr->expression());
1986
1987 switch (expr->yield_kind()) {
1988 case Yield::kSuspend:
1989 // Pop value from top-of-stack slot; box result into result register.
1990 EmitCreateIteratorResult(false);
1991 __ Push(result_register());
1992 // Fall through.
1993 case Yield::kInitial: {
1994 Label suspend, continuation, post_runtime, resume;
1995
1996 __ jmp(&suspend);
1997
1998 __ bind(&continuation);
1999 __ jmp(&resume);
2000
2001 __ bind(&suspend);
2002 VisitForAccumulatorValue(expr->generator_object());
2003 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
2004 __ Move(FieldOperand(rax, JSGeneratorObject::kContinuationOffset),
2005 Smi::FromInt(continuation.pos()));
2006 __ movp(FieldOperand(rax, JSGeneratorObject::kContextOffset), rsi);
2007 __ movp(rcx, rsi);
2008 __ RecordWriteField(rax, JSGeneratorObject::kContextOffset, rcx, rdx,
2009 kDontSaveFPRegs);
2010 __ leap(rbx, Operand(rbp, StandardFrameConstants::kExpressionsOffset));
2011 __ cmpp(rsp, rbx);
2012 __ j(equal, &post_runtime);
2013 __ Push(rax); // generator object
2014 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
2015 __ movp(context_register(),
2016 Operand(rbp, StandardFrameConstants::kContextOffset));
2017 __ bind(&post_runtime);
2018
2019 __ Pop(result_register());
2020 EmitReturnSequence();
2021
2022 __ bind(&resume);
2023 context()->Plug(result_register());
2024 break;
2025 }
2026
2027 case Yield::kFinal: {
2028 VisitForAccumulatorValue(expr->generator_object());
2029 __ Move(FieldOperand(result_register(),
2030 JSGeneratorObject::kContinuationOffset),
2031 Smi::FromInt(JSGeneratorObject::kGeneratorClosed));
2032 // Pop value from top-of-stack slot, box result into result register.
2033 EmitCreateIteratorResult(true);
2034 EmitUnwindBeforeReturn();
2035 EmitReturnSequence();
2036 break;
2037 }
2038
2039 case Yield::kDelegating: {
2040 VisitForStackValue(expr->generator_object());
2041
2042 // Initial stack layout is as follows:
2043 // [sp + 1 * kPointerSize] iter
2044 // [sp + 0 * kPointerSize] g
2045
2046 Label l_catch, l_try, l_suspend, l_continuation, l_resume;
2047 Label l_next, l_call, l_loop;
2048 Register load_receiver = LoadDescriptor::ReceiverRegister();
2049 Register load_name = LoadDescriptor::NameRegister();
2050
2051 // Initial send value is undefined.
2052 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2053 __ jmp(&l_next);
2054
2055 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
2056 __ bind(&l_catch);
2057 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
2058 __ LoadRoot(load_name, Heap::kthrow_stringRootIndex); // "throw"
2059 __ Push(load_name);
2060 __ Push(Operand(rsp, 2 * kPointerSize)); // iter
2061 __ Push(rax); // exception
2062 __ jmp(&l_call);
2063
2064 // try { received = %yield result }
2065 // Shuffle the received result above a try handler and yield it without
2066 // re-boxing.
2067 __ bind(&l_try);
2068 __ Pop(rax); // result
2069 __ PushTryHandler(StackHandler::CATCH, expr->index());
2070 const int handler_size = StackHandlerConstants::kSize;
2071 __ Push(rax); // result
2072 __ jmp(&l_suspend);
2073 __ bind(&l_continuation);
2074 __ jmp(&l_resume);
2075 __ bind(&l_suspend);
2076 const int generator_object_depth = kPointerSize + handler_size;
2077 __ movp(rax, Operand(rsp, generator_object_depth));
2078 __ Push(rax); // g
2079 DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
2080 __ Move(FieldOperand(rax, JSGeneratorObject::kContinuationOffset),
2081 Smi::FromInt(l_continuation.pos()));
2082 __ movp(FieldOperand(rax, JSGeneratorObject::kContextOffset), rsi);
2083 __ movp(rcx, rsi);
2084 __ RecordWriteField(rax, JSGeneratorObject::kContextOffset, rcx, rdx,
2085 kDontSaveFPRegs);
2086 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
2087 __ movp(context_register(),
2088 Operand(rbp, StandardFrameConstants::kContextOffset));
2089 __ Pop(rax); // result
2090 EmitReturnSequence();
2091 __ bind(&l_resume); // received in rax
2092 __ PopTryHandler();
2093
2094 // receiver = iter; f = 'next'; arg = received;
2095 __ bind(&l_next);
2096
2097 __ LoadRoot(load_name, Heap::knext_stringRootIndex);
2098 __ Push(load_name); // "next"
2099 __ Push(Operand(rsp, 2 * kPointerSize)); // iter
2100 __ Push(rax); // received
2101
2102 // result = receiver[f](arg);
2103 __ bind(&l_call);
2104 __ movp(load_receiver, Operand(rsp, kPointerSize));
2105 if (FLAG_vector_ics) {
2106 __ Move(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002107 SmiFromSlot(expr->KeyedLoadFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002108 }
2109 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
2110 CallIC(ic, TypeFeedbackId::None());
2111 __ movp(rdi, rax);
2112 __ movp(Operand(rsp, 2 * kPointerSize), rdi);
2113 CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
2114 __ CallStub(&stub);
2115
2116 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2117 __ Drop(1); // The function is still on the stack; drop it.
2118
2119 // if (!result.done) goto l_try;
2120 __ bind(&l_loop);
2121 __ Move(load_receiver, rax);
2122 __ Push(load_receiver); // save result
2123 __ LoadRoot(load_name, Heap::kdone_stringRootIndex); // "done"
2124 if (FLAG_vector_ics) {
2125 __ Move(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002126 SmiFromSlot(expr->DoneFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002127 }
2128 CallLoadIC(NOT_CONTEXTUAL); // rax=result.done
2129 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
2130 CallIC(bool_ic);
2131 __ testp(result_register(), result_register());
2132 __ j(zero, &l_try);
2133
2134 // result.value
2135 __ Pop(load_receiver); // result
2136 __ LoadRoot(load_name, Heap::kvalue_stringRootIndex); // "value"
2137 if (FLAG_vector_ics) {
2138 __ Move(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002139 SmiFromSlot(expr->ValueFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002140 }
2141 CallLoadIC(NOT_CONTEXTUAL); // result.value in rax
2142 context()->DropAndPlug(2, rax); // drop iter and g
2143 break;
2144 }
2145 }
2146}
2147
2148
2149void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
2150 Expression *value,
2151 JSGeneratorObject::ResumeMode resume_mode) {
2152 // The value stays in rax, and is ultimately read by the resumed generator, as
2153 // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
2154 // is read to throw the value when the resumed generator is already closed.
2155 // rbx will hold the generator object until the activation has been resumed.
2156 VisitForStackValue(generator);
2157 VisitForAccumulatorValue(value);
2158 __ Pop(rbx);
2159
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002160 // Load suspended function and context.
2161 __ movp(rsi, FieldOperand(rbx, JSGeneratorObject::kContextOffset));
2162 __ movp(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset));
2163
2164 // Push receiver.
2165 __ Push(FieldOperand(rbx, JSGeneratorObject::kReceiverOffset));
2166
2167 // Push holes for arguments to generator function.
2168 __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
2169 __ LoadSharedFunctionInfoSpecialField(rdx, rdx,
2170 SharedFunctionInfo::kFormalParameterCountOffset);
2171 __ LoadRoot(rcx, Heap::kTheHoleValueRootIndex);
2172 Label push_argument_holes, push_frame;
2173 __ bind(&push_argument_holes);
2174 __ subp(rdx, Immediate(1));
2175 __ j(carry, &push_frame);
2176 __ Push(rcx);
2177 __ jmp(&push_argument_holes);
2178
2179 // Enter a new JavaScript frame, and initialize its slots as they were when
2180 // the generator was suspended.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002181 Label resume_frame, done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002182 __ bind(&push_frame);
2183 __ call(&resume_frame);
2184 __ jmp(&done);
2185 __ bind(&resume_frame);
2186 __ pushq(rbp); // Caller's frame pointer.
2187 __ movp(rbp, rsp);
2188 __ Push(rsi); // Callee's context.
2189 __ Push(rdi); // Callee's JS Function.
2190
2191 // Load the operand stack size.
2192 __ movp(rdx, FieldOperand(rbx, JSGeneratorObject::kOperandStackOffset));
2193 __ movp(rdx, FieldOperand(rdx, FixedArray::kLengthOffset));
2194 __ SmiToInteger32(rdx, rdx);
2195
2196 // If we are sending a value and there is no operand stack, we can jump back
2197 // in directly.
2198 if (resume_mode == JSGeneratorObject::NEXT) {
2199 Label slow_resume;
2200 __ cmpp(rdx, Immediate(0));
2201 __ j(not_zero, &slow_resume);
2202 __ movp(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2203 __ SmiToInteger64(rcx,
2204 FieldOperand(rbx, JSGeneratorObject::kContinuationOffset));
2205 __ addp(rdx, rcx);
2206 __ Move(FieldOperand(rbx, JSGeneratorObject::kContinuationOffset),
2207 Smi::FromInt(JSGeneratorObject::kGeneratorExecuting));
2208 __ jmp(rdx);
2209 __ bind(&slow_resume);
2210 }
2211
2212 // Otherwise, we push holes for the operand stack and call the runtime to fix
2213 // up the stack and the handlers.
2214 Label push_operand_holes, call_resume;
2215 __ bind(&push_operand_holes);
2216 __ subp(rdx, Immediate(1));
2217 __ j(carry, &call_resume);
2218 __ Push(rcx);
2219 __ jmp(&push_operand_holes);
2220 __ bind(&call_resume);
2221 __ Push(rbx);
2222 __ Push(result_register());
2223 __ Push(Smi::FromInt(resume_mode));
2224 __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
2225 // Not reached: the runtime call returns elsewhere.
2226 __ Abort(kGeneratorFailedToResume);
2227
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002228 __ bind(&done);
2229 context()->Plug(result_register());
2230}
2231
2232
2233void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
2234 Label gc_required;
2235 Label allocated;
2236
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002237 const int instance_size = 5 * kPointerSize;
2238 DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
2239 instance_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002240
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002241 __ Allocate(instance_size, rax, rcx, rdx, &gc_required, TAG_OBJECT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002242 __ jmp(&allocated);
2243
2244 __ bind(&gc_required);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002245 __ Push(Smi::FromInt(instance_size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002246 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
2247 __ movp(context_register(),
2248 Operand(rbp, StandardFrameConstants::kContextOffset));
2249
2250 __ bind(&allocated);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002251 __ movp(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2252 __ movp(rbx, FieldOperand(rbx, GlobalObject::kNativeContextOffset));
2253 __ movp(rbx, ContextOperand(rbx, Context::ITERATOR_RESULT_MAP_INDEX));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002254 __ Pop(rcx);
2255 __ Move(rdx, isolate()->factory()->ToBoolean(done));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002256 __ movp(FieldOperand(rax, HeapObject::kMapOffset), rbx);
2257 __ Move(FieldOperand(rax, JSObject::kPropertiesOffset),
2258 isolate()->factory()->empty_fixed_array());
2259 __ Move(FieldOperand(rax, JSObject::kElementsOffset),
2260 isolate()->factory()->empty_fixed_array());
2261 __ movp(FieldOperand(rax, JSGeneratorObject::kResultValuePropertyOffset),
2262 rcx);
2263 __ movp(FieldOperand(rax, JSGeneratorObject::kResultDonePropertyOffset),
2264 rdx);
2265
2266 // Only the value field needs a write barrier, as the other values are in the
2267 // root set.
2268 __ RecordWriteField(rax, JSGeneratorObject::kResultValuePropertyOffset,
2269 rcx, rdx, kDontSaveFPRegs);
2270}
2271
2272
Leon Clarked91b9f72010-01-27 17:25:45 +00002273void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00002274 SetSourcePosition(prop->position());
2275 Literal* key = prop->key()->AsLiteral();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002276 DCHECK(!prop->IsSuperAccess());
2277
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002278 __ Move(LoadDescriptor::NameRegister(), key->value());
2279 if (FLAG_vector_ics) {
2280 __ Move(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002281 SmiFromSlot(prop->PropertyFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002282 CallLoadIC(NOT_CONTEXTUAL);
2283 } else {
2284 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
2285 }
2286}
2287
2288
2289void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002290 // Stack: receiver, home_object
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002291 SetSourcePosition(prop->position());
2292 Literal* key = prop->key()->AsLiteral();
2293 DCHECK(!key->value()->IsSmi());
2294 DCHECK(prop->IsSuperAccess());
2295
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002296 __ Push(key->value());
2297 __ CallRuntime(Runtime::kLoadFromSuper, 3);
Leon Clarkee46be812010-01-19 14:06:41 +00002298}
2299
2300
Leon Clarked91b9f72010-01-27 17:25:45 +00002301void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00002302 SetSourcePosition(prop->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002303 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
2304 if (FLAG_vector_ics) {
2305 __ Move(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002306 SmiFromSlot(prop->PropertyFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002307 CallIC(ic);
2308 } else {
2309 CallIC(ic, prop->PropertyFeedbackId());
2310 }
Leon Clarkee46be812010-01-19 14:06:41 +00002311}
2312
2313
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002314void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
2315 // Stack: receiver, home_object, key.
2316 SetSourcePosition(prop->position());
2317
2318 __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
2319}
2320
2321
Ben Murdoch257744e2011-11-30 15:57:28 +00002322void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002323 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002324 OverwriteMode mode,
2325 Expression* left,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002326 Expression* right) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002327 // Do combined smi check of the operands. Left operand is on the
2328 // stack (popped into rdx). Right operand is in rax but moved into
2329 // rcx to make the shifts easier.
Ben Murdoch257744e2011-11-30 15:57:28 +00002330 Label done, stub_call, smi_case;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002331 __ Pop(rdx);
2332 __ movp(rcx, rax);
2333 __ orp(rax, rdx);
Steve Block1e0659c2011-05-24 12:43:12 +01002334 JumpPatchSite patch_site(masm_);
Ben Murdoch257744e2011-11-30 15:57:28 +00002335 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002336
2337 __ bind(&stub_call);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002338 __ movp(rax, rcx);
2339 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op, mode).code();
2340 CallIC(code, expr->BinaryOperationFeedbackId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002341 patch_site.EmitPatchInfo();
Ben Murdoch257744e2011-11-30 15:57:28 +00002342 __ jmp(&done, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002343
2344 __ bind(&smi_case);
2345 switch (op) {
2346 case Token::SAR:
2347 __ SmiShiftArithmeticRight(rax, rdx, rcx);
2348 break;
2349 case Token::SHL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002350 __ SmiShiftLeft(rax, rdx, rcx, &stub_call);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002351 break;
2352 case Token::SHR:
2353 __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
2354 break;
2355 case Token::ADD:
2356 __ SmiAdd(rax, rdx, rcx, &stub_call);
2357 break;
2358 case Token::SUB:
2359 __ SmiSub(rax, rdx, rcx, &stub_call);
2360 break;
2361 case Token::MUL:
2362 __ SmiMul(rax, rdx, rcx, &stub_call);
2363 break;
2364 case Token::BIT_OR:
2365 __ SmiOr(rax, rdx, rcx);
2366 break;
2367 case Token::BIT_AND:
2368 __ SmiAnd(rax, rdx, rcx);
2369 break;
2370 case Token::BIT_XOR:
2371 __ SmiXor(rax, rdx, rcx);
2372 break;
2373 default:
2374 UNREACHABLE();
2375 break;
2376 }
2377
2378 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002379 context()->Plug(rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002380}
2381
2382
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002383void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
2384 // Constructor is in rax.
2385 DCHECK(lit != NULL);
2386 __ Push(rax);
2387
2388 // No access check is needed here since the constructor is created by the
2389 // class literal.
2390 Register scratch = rbx;
2391 __ movp(scratch, FieldOperand(rax, JSFunction::kPrototypeOrInitialMapOffset));
2392 __ Push(scratch);
2393
2394 for (int i = 0; i < lit->properties()->length(); i++) {
2395 ObjectLiteral::Property* property = lit->properties()->at(i);
2396 Literal* key = property->key()->AsLiteral();
2397 Expression* value = property->value();
2398 DCHECK(key != NULL);
2399
2400 if (property->is_static()) {
2401 __ Push(Operand(rsp, kPointerSize)); // constructor
2402 } else {
2403 __ Push(Operand(rsp, 0)); // prototype
2404 }
2405 VisitForStackValue(key);
2406 VisitForStackValue(value);
2407 EmitSetHomeObjectIfNeeded(value, 2);
2408
2409 switch (property->kind()) {
2410 case ObjectLiteral::Property::CONSTANT:
2411 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2412 case ObjectLiteral::Property::COMPUTED:
2413 case ObjectLiteral::Property::PROTOTYPE:
2414 __ CallRuntime(Runtime::kDefineClassMethod, 3);
2415 break;
2416
2417 case ObjectLiteral::Property::GETTER:
2418 __ CallRuntime(Runtime::kDefineClassGetter, 3);
2419 break;
2420
2421 case ObjectLiteral::Property::SETTER:
2422 __ CallRuntime(Runtime::kDefineClassSetter, 3);
2423 break;
2424
2425 default:
2426 UNREACHABLE();
2427 }
2428 }
2429
2430 // prototype
2431 __ CallRuntime(Runtime::kToFastProperties, 1);
2432
2433 // constructor
2434 __ CallRuntime(Runtime::kToFastProperties, 1);
2435}
2436
2437
Ben Murdoch257744e2011-11-30 15:57:28 +00002438void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
2439 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002440 OverwriteMode mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002441 __ Pop(rdx);
2442 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op, mode).code();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002443 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002444 CallIC(code, expr->BinaryOperationFeedbackId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002445 patch_site.EmitPatchInfo();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002446 context()->Plug(rax);
Leon Clarkee46be812010-01-19 14:06:41 +00002447}
2448
2449
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002450void FullCodeGenerator::EmitAssignment(Expression* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002451 DCHECK(expr->IsValidReferenceExpression());
Leon Clarkef7060e22010-06-03 12:02:55 +01002452
Leon Clarkef7060e22010-06-03 12:02:55 +01002453 Property* prop = expr->AsProperty();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002454 LhsKind assign_type = GetAssignType(prop);
Leon Clarkef7060e22010-06-03 12:02:55 +01002455
2456 switch (assign_type) {
2457 case VARIABLE: {
2458 Variable* var = expr->AsVariableProxy()->var();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002459 EffectContext context(this);
2460 EmitVariableAssignment(var, Token::ASSIGN);
Leon Clarkef7060e22010-06-03 12:02:55 +01002461 break;
2462 }
2463 case NAMED_PROPERTY: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002464 __ Push(rax); // Preserve value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002465 VisitForAccumulatorValue(prop->obj());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002466 __ Move(StoreDescriptor::ReceiverRegister(), rax);
2467 __ Pop(StoreDescriptor::ValueRegister()); // Restore value.
2468 __ Move(StoreDescriptor::NameRegister(),
2469 prop->key()->AsLiteral()->value());
2470 CallStoreIC();
Leon Clarkef7060e22010-06-03 12:02:55 +01002471 break;
2472 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002473 case NAMED_SUPER_PROPERTY: {
2474 __ Push(rax);
2475 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
2476 EmitLoadHomeObject(prop->obj()->AsSuperReference());
2477 // stack: value, this; rax: home_object
2478 Register scratch = rcx;
2479 Register scratch2 = rdx;
2480 __ Move(scratch, result_register()); // home_object
2481 __ movp(rax, MemOperand(rsp, kPointerSize)); // value
2482 __ movp(scratch2, MemOperand(rsp, 0)); // this
2483 __ movp(MemOperand(rsp, kPointerSize), scratch2); // this
2484 __ movp(MemOperand(rsp, 0), scratch); // home_object
2485 // stack: this, home_object; rax: value
2486 EmitNamedSuperPropertyStore(prop);
2487 break;
2488 }
2489 case KEYED_SUPER_PROPERTY: {
2490 __ Push(rax);
2491 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
2492 EmitLoadHomeObject(prop->obj()->AsSuperReference());
2493 __ Push(result_register());
2494 VisitForAccumulatorValue(prop->key());
2495 Register scratch = rcx;
2496 Register scratch2 = rdx;
2497 __ movp(scratch2, MemOperand(rsp, 2 * kPointerSize)); // value
2498 // stack: value, this, home_object; rax: key, rdx: value
2499 __ movp(scratch, MemOperand(rsp, kPointerSize)); // this
2500 __ movp(MemOperand(rsp, 2 * kPointerSize), scratch);
2501 __ movp(scratch, MemOperand(rsp, 0)); // home_object
2502 __ movp(MemOperand(rsp, kPointerSize), scratch);
2503 __ movp(MemOperand(rsp, 0), rax);
2504 __ Move(rax, scratch2);
2505 // stack: this, home_object, key; rax: value.
2506 EmitKeyedSuperPropertyStore(prop);
2507 break;
2508 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002509 case KEYED_PROPERTY: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002510 __ Push(rax); // Preserve value.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002511 VisitForStackValue(prop->obj());
2512 VisitForAccumulatorValue(prop->key());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002513 __ Move(StoreDescriptor::NameRegister(), rax);
2514 __ Pop(StoreDescriptor::ReceiverRegister());
2515 __ Pop(StoreDescriptor::ValueRegister()); // Restore value.
2516 Handle<Code> ic =
2517 CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
2518 CallIC(ic);
Leon Clarkef7060e22010-06-03 12:02:55 +01002519 break;
2520 }
2521 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002522 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002523}
2524
2525
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002526void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2527 Variable* var, MemOperand location) {
2528 __ movp(location, rax);
2529 if (var->IsContextSlot()) {
2530 __ movp(rdx, rax);
2531 __ RecordWriteContextSlot(
2532 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
2533 }
2534}
2535
2536
Leon Clarked91b9f72010-01-27 17:25:45 +00002537void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002538 Token::Value op) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002539 if (var->IsUnallocated()) {
2540 // Global var, const, or let.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002541 __ Move(StoreDescriptor::NameRegister(), var->name());
2542 __ movp(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
2543 CallStoreIC();
2544
2545 } else if (op == Token::INIT_CONST_LEGACY) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002546 // Const initializers need a write barrier.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002547 DCHECK(!var->IsParameter()); // No const parameters.
2548 if (var->IsLookupSlot()) {
2549 __ Push(rax);
2550 __ Push(rsi);
2551 __ Push(var->name());
2552 __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
2553 } else {
2554 DCHECK(var->IsStackLocal() || var->IsContextSlot());
Ben Murdoch589d6972011-11-30 16:04:58 +00002555 Label skip;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002556 MemOperand location = VarOperand(var, rcx);
2557 __ movp(rdx, location);
Ben Murdoch589d6972011-11-30 16:04:58 +00002558 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2559 __ j(not_equal, &skip);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002560 EmitStoreToStackLocalOrContextSlot(var, location);
Ben Murdoch589d6972011-11-30 16:04:58 +00002561 __ bind(&skip);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002562 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002563
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002564 } else if (var->mode() == LET && op != Token::INIT_LET) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002565 // Non-initializing assignment to let variable needs a write barrier.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002566 DCHECK(!var->IsLookupSlot());
2567 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2568 Label assign;
2569 MemOperand location = VarOperand(var, rcx);
2570 __ movp(rdx, location);
2571 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2572 __ j(not_equal, &assign, Label::kNear);
2573 __ Push(var->name());
2574 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2575 __ bind(&assign);
2576 EmitStoreToStackLocalOrContextSlot(var, location);
Ben Murdoch589d6972011-11-30 16:04:58 +00002577
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002578 } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
2579 if (var->IsLookupSlot()) {
2580 // Assignment to var.
2581 __ Push(rax); // Value.
2582 __ Push(rsi); // Context.
Ben Murdoch589d6972011-11-30 16:04:58 +00002583 __ Push(var->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002584 __ Push(Smi::FromInt(strict_mode()));
2585 __ CallRuntime(Runtime::kStoreLookupSlot, 4);
2586 } else {
2587 // Assignment to var or initializing assignment to let/const in harmony
2588 // mode.
2589 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2590 MemOperand location = VarOperand(var, rcx);
2591 if (generate_debug_code_ && op == Token::INIT_LET) {
2592 // Check for an uninitialized let binding.
2593 __ movp(rdx, location);
2594 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2595 __ Check(equal, kLetBindingReInitialization);
2596 }
2597 EmitStoreToStackLocalOrContextSlot(var, location);
Steve Block3ce2e202009-11-05 08:53:23 +00002598 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002599 } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) {
2600 __ CallRuntime(Runtime::kThrowConstAssignError, 0);
Steve Block3ce2e202009-11-05 08:53:23 +00002601 }
2602}
2603
2604
Leon Clarked91b9f72010-01-27 17:25:45 +00002605void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002606 // Assignment to a property, using a named store IC.
2607 Property* prop = expr->target()->AsProperty();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002608 DCHECK(prop != NULL);
2609 DCHECK(prop->key()->IsLiteral());
Steve Blockd0582a62009-12-15 09:54:21 +00002610
Leon Clarkee46be812010-01-19 14:06:41 +00002611 // Record source code position before IC call.
2612 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002613 __ Move(StoreDescriptor::NameRegister(), prop->key()->AsLiteral()->value());
2614 __ Pop(StoreDescriptor::ReceiverRegister());
2615 CallStoreIC(expr->AssignmentFeedbackId());
Steve Blockd0582a62009-12-15 09:54:21 +00002616
Ben Murdoch086aeea2011-05-13 15:57:08 +01002617 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002618 context()->Plug(rax);
Steve Blockd0582a62009-12-15 09:54:21 +00002619}
2620
2621
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002622void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2623 // Assignment to named property of super.
2624 // rax : value
2625 // stack : receiver ('this'), home_object
2626 DCHECK(prop != NULL);
2627 Literal* key = prop->key()->AsLiteral();
2628 DCHECK(key != NULL);
2629
2630 __ Push(key->value());
2631 __ Push(rax);
2632 __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
2633 : Runtime::kStoreToSuper_Sloppy),
2634 4);
2635}
2636
2637
2638void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2639 // Assignment to named property of super.
2640 // rax : value
2641 // stack : receiver ('this'), home_object, key
2642 DCHECK(prop != NULL);
2643
2644 __ Push(rax);
2645 __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
2646 : Runtime::kStoreKeyedToSuper_Sloppy),
2647 4);
2648}
2649
2650
Leon Clarked91b9f72010-01-27 17:25:45 +00002651void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002652 // Assignment to a property, using a keyed store IC.
2653
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002654 __ Pop(StoreDescriptor::NameRegister()); // Key.
2655 __ Pop(StoreDescriptor::ReceiverRegister());
2656 DCHECK(StoreDescriptor::ValueRegister().is(rax));
Leon Clarkee46be812010-01-19 14:06:41 +00002657 // Record source code position before IC call.
2658 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002659 Handle<Code> ic = CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
2660 CallIC(ic, expr->AssignmentFeedbackId());
Steve Blockd0582a62009-12-15 09:54:21 +00002661
Ben Murdoch086aeea2011-05-13 15:57:08 +01002662 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002663 context()->Plug(rax);
Steve Blockd0582a62009-12-15 09:54:21 +00002664}
2665
2666
Leon Clarked91b9f72010-01-27 17:25:45 +00002667void FullCodeGenerator::VisitProperty(Property* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002668 Comment cmnt(masm_, "[ Property");
2669 Expression* key = expr->key();
Steve Blockd0582a62009-12-15 09:54:21 +00002670
Leon Clarkee46be812010-01-19 14:06:41 +00002671 if (key->IsPropertyName()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002672 if (!expr->IsSuperAccess()) {
2673 VisitForAccumulatorValue(expr->obj());
2674 DCHECK(!rax.is(LoadDescriptor::ReceiverRegister()));
2675 __ movp(LoadDescriptor::ReceiverRegister(), rax);
2676 EmitNamedPropertyLoad(expr);
2677 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002678 VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
2679 EmitLoadHomeObject(expr->obj()->AsSuperReference());
2680 __ Push(result_register());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002681 EmitNamedSuperPropertyLoad(expr);
2682 }
2683 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002684 context()->Plug(rax);
Steve Blockd0582a62009-12-15 09:54:21 +00002685 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002686 if (!expr->IsSuperAccess()) {
2687 VisitForStackValue(expr->obj());
2688 VisitForAccumulatorValue(expr->key());
2689 __ Move(LoadDescriptor::NameRegister(), rax);
2690 __ Pop(LoadDescriptor::ReceiverRegister());
2691 EmitKeyedPropertyLoad(expr);
2692 } else {
2693 VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
2694 EmitLoadHomeObject(expr->obj()->AsSuperReference());
2695 __ Push(result_register());
2696 VisitForStackValue(expr->key());
2697 EmitKeyedSuperPropertyLoad(expr);
2698 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002699 context()->Plug(rax);
Steve Blockd0582a62009-12-15 09:54:21 +00002700 }
Steve Blockd0582a62009-12-15 09:54:21 +00002701}
2702
2703
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002704void FullCodeGenerator::CallIC(Handle<Code> code,
2705 TypeFeedbackId ast_id) {
2706 ic_total_count_++;
2707 __ call(code, RelocInfo::CODE_TARGET, ast_id);
Steve Blockd0582a62009-12-15 09:54:21 +00002708}
2709
2710
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002711// Code common for calls using the IC.
2712void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2713 Expression* callee = expr->expression();
2714
2715 CallICState::CallType call_type =
2716 callee->IsVariableProxy() ? CallICState::FUNCTION : CallICState::METHOD;
2717 // Get the target function.
2718 if (call_type == CallICState::FUNCTION) {
2719 { StackValueContext context(this);
2720 EmitVariableLoad(callee->AsVariableProxy());
2721 PrepareForBailout(callee, NO_REGISTERS);
2722 }
2723 // Push undefined as receiver. This is patched in the method prologue if it
2724 // is a sloppy mode method.
2725 __ Push(isolate()->factory()->undefined_value());
2726 } else {
2727 // Load the function from the receiver.
2728 DCHECK(callee->IsProperty());
2729 DCHECK(!callee->AsProperty()->IsSuperAccess());
2730 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
2731 EmitNamedPropertyLoad(callee->AsProperty());
2732 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2733 // Push the target function under the receiver.
2734 __ Push(Operand(rsp, 0));
2735 __ movp(Operand(rsp, kPointerSize), rax);
2736 }
2737
2738 EmitCall(expr, call_type);
2739}
2740
2741
2742void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2743 Expression* callee = expr->expression();
2744 DCHECK(callee->IsProperty());
2745 Property* prop = callee->AsProperty();
2746 DCHECK(prop->IsSuperAccess());
2747
2748 SetSourcePosition(prop->position());
2749 Literal* key = prop->key()->AsLiteral();
2750 DCHECK(!key->value()->IsSmi());
2751 // Load the function from the receiver.
2752 SuperReference* super_ref = prop->obj()->AsSuperReference();
2753 EmitLoadHomeObject(super_ref);
2754 __ Push(rax);
2755 VisitForAccumulatorValue(super_ref->this_var());
2756 __ Push(rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002757 __ Push(rax);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002758 __ Push(Operand(rsp, kPointerSize * 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002759 __ Push(key->value());
2760
2761 // Stack here:
2762 // - home_object
2763 // - this (receiver)
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002764 // - this (receiver) <-- LoadFromSuper will pop here and below.
2765 // - home_object
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002766 // - key
2767 __ CallRuntime(Runtime::kLoadFromSuper, 3);
2768
2769 // Replace home_object with target function.
2770 __ movp(Operand(rsp, kPointerSize), rax);
2771
2772 // Stack here:
2773 // - target function
2774 // - this (receiver)
2775 EmitCall(expr, CallICState::METHOD);
2776}
2777
2778
2779// Common code for calls using the IC.
2780void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2781 Expression* key) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002782 // Load the key.
2783 VisitForAccumulatorValue(key);
2784
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002785 Expression* callee = expr->expression();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002786
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002787 // Load the function from the receiver.
2788 DCHECK(callee->IsProperty());
2789 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
2790 __ Move(LoadDescriptor::NameRegister(), rax);
2791 EmitKeyedPropertyLoad(callee->AsProperty());
2792 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2793
2794 // Push the target function under the receiver.
2795 __ Push(Operand(rsp, 0));
2796 __ movp(Operand(rsp, kPointerSize), rax);
2797
2798 EmitCall(expr, CallICState::METHOD);
2799}
2800
2801
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002802void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2803 Expression* callee = expr->expression();
2804 DCHECK(callee->IsProperty());
2805 Property* prop = callee->AsProperty();
2806 DCHECK(prop->IsSuperAccess());
2807
2808 SetSourcePosition(prop->position());
2809 // Load the function from the receiver.
2810 SuperReference* super_ref = prop->obj()->AsSuperReference();
2811 EmitLoadHomeObject(super_ref);
2812 __ Push(rax);
2813 VisitForAccumulatorValue(super_ref->this_var());
2814 __ Push(rax);
2815 __ Push(rax);
2816 __ Push(Operand(rsp, kPointerSize * 2));
2817 VisitForStackValue(prop->key());
2818
2819 // Stack here:
2820 // - home_object
2821 // - this (receiver)
2822 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2823 // - home_object
2824 // - key
2825 __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
2826
2827 // Replace home_object with target function.
2828 __ movp(Operand(rsp, kPointerSize), rax);
2829
2830 // Stack here:
2831 // - target function
2832 // - this (receiver)
2833 EmitCall(expr, CallICState::METHOD);
2834}
2835
2836
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002837void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002838 // Load the arguments.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002839 ZoneList<Expression*>* args = expr->arguments();
2840 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002841 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002842 for (int i = 0; i < arg_count; i++) {
2843 VisitForStackValue(args->at(i));
2844 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002845 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002846
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002847 // Record source position of the IC call.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002848 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002849 Handle<Code> ic = CallIC::initialize_stub(
2850 isolate(), arg_count, call_type);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002851 __ Move(rdx, SmiFromSlot(expr->CallFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002852 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
2853 // Don't assign a type feedback id to the IC, since type feedback is provided
2854 // by the vector above.
2855 CallIC(ic);
2856
Ben Murdoch086aeea2011-05-13 15:57:08 +01002857 RecordJSReturnSite(expr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002858
Steve Blockd0582a62009-12-15 09:54:21 +00002859 // Restore context register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002860 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
Steve Blockd0582a62009-12-15 09:54:21 +00002861 // Discard the function left on TOS.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002862 context()->DropAndPlug(1, rax);
Steve Blockd0582a62009-12-15 09:54:21 +00002863}
2864
2865
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002866void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002867 // Push copy of the first argument or undefined if it doesn't exist.
2868 if (arg_count > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002869 __ Push(Operand(rsp, arg_count * kPointerSize));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002870 } else {
2871 __ PushRoot(Heap::kUndefinedValueRootIndex);
2872 }
2873
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002874 // Push the enclosing function.
2875 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
2876
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002877 // Push the receiver of the enclosing function and do runtime call.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002878 StackArgumentsAccessor args(rbp, info_->scope()->num_parameters());
2879 __ Push(args.GetReceiverOperand());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002880
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002881 // Push the language mode.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002882 __ Push(Smi::FromInt(strict_mode()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002883
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002884 // Push the start position of the scope the calls resides in.
2885 __ Push(Smi::FromInt(scope()->start_position()));
2886
2887 // Do the runtime call.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002888 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002889}
2890
2891
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002892void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
2893 DCHECK(super_ref != NULL);
2894 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
2895 __ CallRuntime(Runtime::kGetPrototype, 1);
2896}
2897
2898
Leon Clarked91b9f72010-01-27 17:25:45 +00002899void FullCodeGenerator::VisitCall(Call* expr) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002900#ifdef DEBUG
2901 // We want to verify that RecordJSReturnSite gets called on all paths
2902 // through this function. Avoid early returns.
2903 expr->return_is_recorded_ = false;
2904#endif
2905
Steve Blockd0582a62009-12-15 09:54:21 +00002906 Comment cmnt(masm_, "[ Call");
Ben Murdoch589d6972011-11-30 16:04:58 +00002907 Expression* callee = expr->expression();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002908 Call::CallType call_type = expr->GetCallType(isolate());
Steve Blockd0582a62009-12-15 09:54:21 +00002909
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002910 if (call_type == Call::POSSIBLY_EVAL_CALL) {
2911 // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
2912 // to resolve the function we need to call and the receiver of the call.
Ben Murdoch589d6972011-11-30 16:04:58 +00002913 // Then we call the resolved function using the given arguments.
Leon Clarkef7060e22010-06-03 12:02:55 +01002914 ZoneList<Expression*>* args = expr->arguments();
2915 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002916 { PreservePositionScope pos_scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002917 VisitForStackValue(callee);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002918 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
Leon Clarkef7060e22010-06-03 12:02:55 +01002919
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002920 // Push the arguments.
2921 for (int i = 0; i < arg_count; i++) {
2922 VisitForStackValue(args->at(i));
2923 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002924
Ben Murdoch589d6972011-11-30 16:04:58 +00002925 // Push a copy of the function (found below the arguments) and resolve
2926 // eval.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002927 __ Push(Operand(rsp, (arg_count + 1) * kPointerSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002928 EmitResolvePossiblyDirectEval(arg_count);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002929
2930 // The runtime call returns a pair of values in rax (function) and
2931 // rdx (receiver). Touch up the stack with the right values.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002932 __ movp(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
2933 __ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002934
2935 PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01002936 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002937 // Record source position for debugger.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002938 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002939 CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
2940 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
Leon Clarkef7060e22010-06-03 12:02:55 +01002941 __ CallStub(&stub);
Ben Murdoch086aeea2011-05-13 15:57:08 +01002942 RecordJSReturnSite(expr);
Leon Clarkef7060e22010-06-03 12:02:55 +01002943 // Restore context register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002944 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002945 context()->DropAndPlug(1, rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002946 } else if (call_type == Call::GLOBAL_CALL) {
2947 EmitCallWithLoadIC(expr);
2948
2949 } else if (call_type == Call::LOOKUP_SLOT_CALL) {
Steve Block59151502010-09-22 15:07:15 +01002950 // Call to a lookup slot (dynamically introduced variable).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002951 VariableProxy* proxy = callee->AsVariableProxy();
Steve Block59151502010-09-22 15:07:15 +01002952 Label slow, done;
2953
Ben Murdochb0fe1622011-05-05 13:52:32 +01002954 { PreservePositionScope scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002955 // Generate code for loading from variables potentially shadowed by
2956 // eval-introduced variables.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002957 EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
Ben Murdoch086aeea2011-05-13 15:57:08 +01002958 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002959 __ bind(&slow);
2960 // Call the runtime to find the function to call (returned in rax) and
2961 // the object holding it (returned in rdx).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002962 __ Push(context_register());
Ben Murdoch589d6972011-11-30 16:04:58 +00002963 __ Push(proxy->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002964 __ CallRuntime(Runtime::kLoadLookupSlot, 2);
2965 __ Push(rax); // Function.
2966 __ Push(rdx); // Receiver.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002967 PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
Steve Block59151502010-09-22 15:07:15 +01002968
Ben Murdoch589d6972011-11-30 16:04:58 +00002969 // If fast case code has been generated, emit code to push the function
2970 // and receiver and have the slow path jump around this code.
Ben Murdoch086aeea2011-05-13 15:57:08 +01002971 if (done.is_linked()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002972 Label call;
2973 __ jmp(&call, Label::kNear);
Ben Murdoch086aeea2011-05-13 15:57:08 +01002974 __ bind(&done);
2975 // Push function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002976 __ Push(rax);
Ben Murdoch589d6972011-11-30 16:04:58 +00002977 // The receiver is implicitly the global receiver. Indicate this by
2978 // passing the hole to the call function stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002979 __ PushRoot(Heap::kUndefinedValueRootIndex);
Ben Murdoch257744e2011-11-30 15:57:28 +00002980 __ bind(&call);
Steve Block59151502010-09-22 15:07:15 +01002981 }
2982
Ben Murdoch589d6972011-11-30 16:04:58 +00002983 // The receiver is either the global receiver or an object found by
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002984 // LoadContextSlot.
2985 EmitCall(expr);
2986 } else if (call_type == Call::PROPERTY_CALL) {
2987 Property* property = callee->AsProperty();
2988 bool is_named_call = property->key()->IsPropertyName();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002989 if (property->IsSuperAccess()) {
2990 if (is_named_call) {
2991 EmitSuperCallWithLoadIC(expr);
2992 } else {
2993 EmitKeyedSuperCallWithLoadIC(expr);
2994 }
Steve Blockd0582a62009-12-15 09:54:21 +00002995 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002996 {
2997 PreservePositionScope scope(masm()->positions_recorder());
2998 VisitForStackValue(property->obj());
2999 }
3000 if (is_named_call) {
3001 EmitCallWithLoadIC(expr);
3002 } else {
3003 EmitKeyedCallWithLoadIC(expr, property->key());
3004 }
Steve Blockd0582a62009-12-15 09:54:21 +00003005 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003006 } else if (call_type == Call::SUPER_CALL) {
3007 SuperReference* super_ref = callee->AsSuperReference();
3008 EmitLoadSuperConstructor(super_ref);
3009 __ Push(result_register());
3010 VisitForStackValue(super_ref->this_var());
3011 EmitCall(expr, CallICState::METHOD);
Steve Blockd0582a62009-12-15 09:54:21 +00003012 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003013 DCHECK(call_type == Call::OTHER_CALL);
Ben Murdoch589d6972011-11-30 16:04:58 +00003014 // Call to an arbitrary expression not handled specially above.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003015 { PreservePositionScope scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00003016 VisitForStackValue(callee);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08003017 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003018 __ PushRoot(Heap::kUndefinedValueRootIndex);
Steve Blockd0582a62009-12-15 09:54:21 +00003019 // Emit function call.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003020 EmitCall(expr);
Steve Blockd0582a62009-12-15 09:54:21 +00003021 }
Ben Murdoch086aeea2011-05-13 15:57:08 +01003022
3023#ifdef DEBUG
3024 // RecordJSReturnSite should have been called.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003025 DCHECK(expr->return_is_recorded_);
Ben Murdoch086aeea2011-05-13 15:57:08 +01003026#endif
Steve Blockd0582a62009-12-15 09:54:21 +00003027}
3028
3029
Leon Clarked91b9f72010-01-27 17:25:45 +00003030void FullCodeGenerator::VisitCallNew(CallNew* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003031 Comment cmnt(masm_, "[ CallNew");
3032 // According to ECMA-262, section 11.2.2, page 44, the function
3033 // expression in new calls must be evaluated before the
3034 // arguments.
Steve Blockd0582a62009-12-15 09:54:21 +00003035
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003036 // Push constructor on the stack. If it's not a function it's used as
3037 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
3038 // ignored.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003039 if (expr->expression()->IsSuperReference()) {
3040 EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
3041 __ Push(result_register());
3042 } else {
3043 VisitForStackValue(expr->expression());
3044 }
Steve Blockd0582a62009-12-15 09:54:21 +00003045
3046 // Push the arguments ("left-to-right") on the stack.
3047 ZoneList<Expression*>* args = expr->arguments();
3048 int arg_count = args->length();
3049 for (int i = 0; i < arg_count; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003050 VisitForStackValue(args->at(i));
Steve Blockd0582a62009-12-15 09:54:21 +00003051 }
3052
3053 // Call the construct call builtin that handles allocation and
3054 // constructor invocation.
3055 SetSourcePosition(expr->position());
3056
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003057 // Load function and argument count into rdi and rax.
Steve Blockd0582a62009-12-15 09:54:21 +00003058 __ Set(rax, arg_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003059 __ movp(rdi, Operand(rsp, arg_count * kPointerSize));
Steve Blockd0582a62009-12-15 09:54:21 +00003060
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003061 // Record call targets in unoptimized code, but not in the snapshot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003062 if (FLAG_pretenuring_call_new) {
3063 EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003064 DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
3065 expr->CallNewFeedbackSlot().ToInt() + 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003066 }
3067
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003068 __ Move(rbx, FeedbackVector());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003069 __ Move(rdx, SmiFromSlot(expr->CallNewFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003070
3071 CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003072 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
3073 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003074 context()->Plug(rax);
Steve Block3ce2e202009-11-05 08:53:23 +00003075}
3076
3077
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003078void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
3079 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003080 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003081
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003082 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003083
3084 Label materialize_true, materialize_false;
3085 Label* if_true = NULL;
3086 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003087 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003088 context()->PrepareTest(&materialize_true, &materialize_false,
3089 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003090
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003091 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003092 __ JumpIfSmi(rax, if_true);
3093 __ jmp(if_false);
3094
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003095 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003096}
3097
3098
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003099void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
3100 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003101 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003102
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003103 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003104
3105 Label materialize_true, materialize_false;
3106 Label* if_true = NULL;
3107 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003108 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003109 context()->PrepareTest(&materialize_true, &materialize_false,
3110 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003111
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003112 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Ben Murdochf87a2032010-10-22 12:50:53 +01003113 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
3114 Split(non_negative_smi, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003115
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003116 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003117}
3118
3119
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003120void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
3121 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003122 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003123
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003124 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003125
3126 Label materialize_true, materialize_false;
3127 Label* if_true = NULL;
3128 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003129 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003130 context()->PrepareTest(&materialize_true, &materialize_false,
3131 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003132
3133 __ JumpIfSmi(rax, if_false);
3134 __ CompareRoot(rax, Heap::kNullValueRootIndex);
3135 __ j(equal, if_true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003136 __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01003137 // Undetectable objects behave like undefined when tested with typeof.
3138 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
3139 Immediate(1 << Map::kIsUndetectable));
3140 __ j(not_zero, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003141 __ movzxbp(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
3142 __ cmpp(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
Leon Clarkef7060e22010-06-03 12:02:55 +01003143 __ j(below, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003144 __ cmpp(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003145 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003146 Split(below_equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003147
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003148 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003149}
3150
3151
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003152void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
3153 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003154 DCHECK(args->length() == 1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003155
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003156 VisitForAccumulatorValue(args->at(0));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003157
3158 Label materialize_true, materialize_false;
3159 Label* if_true = NULL;
3160 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003161 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003162 context()->PrepareTest(&materialize_true, &materialize_false,
3163 &if_true, &if_false, &fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003164
3165 __ JumpIfSmi(rax, if_false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003166 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003167 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003168 Split(above_equal, if_true, if_false, fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003169
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003170 context()->Plug(if_true, if_false);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003171}
3172
3173
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003174void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
3175 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003176 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003177
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003178 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003179
3180 Label materialize_true, materialize_false;
3181 Label* if_true = NULL;
3182 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003183 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003184 context()->PrepareTest(&materialize_true, &materialize_false,
3185 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003186
3187 __ JumpIfSmi(rax, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003188 __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01003189 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
3190 Immediate(1 << Map::kIsUndetectable));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003191 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003192 Split(not_zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003193
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003194 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003195}
3196
3197
Iain Merrick75681382010-08-19 15:07:18 +01003198void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003199 CallRuntime* expr) {
3200 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003201 DCHECK(args->length() == 1);
Iain Merrick75681382010-08-19 15:07:18 +01003202
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003203 VisitForAccumulatorValue(args->at(0));
Iain Merrick75681382010-08-19 15:07:18 +01003204
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003205 Label materialize_true, materialize_false, skip_lookup;
Iain Merrick75681382010-08-19 15:07:18 +01003206 Label* if_true = NULL;
3207 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003208 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003209 context()->PrepareTest(&materialize_true, &materialize_false,
3210 &if_true, &if_false, &fall_through);
Iain Merrick75681382010-08-19 15:07:18 +01003211
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003212 __ AssertNotSmi(rax);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003213
3214 // Check whether this map has already been checked to be safe for default
3215 // valueOf.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003216 __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003217 __ testb(FieldOperand(rbx, Map::kBitField2Offset),
3218 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003219 __ j(not_zero, &skip_lookup);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003220
3221 // Check for fast case object. Generate false result for slow case object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003222 __ movp(rcx, FieldOperand(rax, JSObject::kPropertiesOffset));
3223 __ movp(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003224 __ CompareRoot(rcx, Heap::kHashTableMapRootIndex);
3225 __ j(equal, if_false);
3226
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003227 // Look for valueOf string in the descriptor array, and indicate false if
3228 // found. Since we omit an enumeration index check, if it is added via a
3229 // transition that shares its descriptor array, this is a false positive.
3230 Label entry, loop, done;
3231
3232 // Skip loop if no descriptors are valid.
3233 __ NumberOfOwnDescriptors(rcx, rbx);
3234 __ cmpp(rcx, Immediate(0));
3235 __ j(equal, &done);
3236
3237 __ LoadInstanceDescriptors(rbx, r8);
3238 // rbx: descriptor array.
3239 // rcx: valid entries in the descriptor array.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003240 // Calculate the end of the descriptor array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003241 __ imulp(rcx, rcx, Immediate(DescriptorArray::kDescriptorSize));
3242 __ leap(rcx,
3243 Operand(r8, rcx, times_pointer_size, DescriptorArray::kFirstOffset));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003244 // Calculate location of the first key name.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003245 __ addp(r8, Immediate(DescriptorArray::kFirstOffset));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003246 // Loop through all the keys in the descriptor array. If one of these is the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003247 // internalized string "valueOf" the result is false.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003248 __ jmp(&entry);
3249 __ bind(&loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003250 __ movp(rdx, FieldOperand(r8, 0));
3251 __ Cmp(rdx, isolate()->factory()->value_of_string());
Ben Murdoch8b112d22011-06-08 16:22:53 +01003252 __ j(equal, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003253 __ addp(r8, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003254 __ bind(&entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003255 __ cmpp(r8, rcx);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003256 __ j(not_equal, &loop);
3257
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003258 __ bind(&done);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003259
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003260 // Set the bit in the map to indicate that there is no local valueOf field.
3261 __ orp(FieldOperand(rbx, Map::kBitField2Offset),
Ben Murdoch8b112d22011-06-08 16:22:53 +01003262 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003263
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003264 __ bind(&skip_lookup);
3265
3266 // If a valueOf property is not found on the object check that its
3267 // prototype is the un-modified String prototype. If not result is false.
3268 __ movp(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
3269 __ testp(rcx, Immediate(kSmiTagMask));
3270 __ j(zero, if_false);
3271 __ movp(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
3272 __ movp(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
3273 __ movp(rdx, FieldOperand(rdx, GlobalObject::kNativeContextOffset));
3274 __ cmpp(rcx,
3275 ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003276 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003277 Split(equal, if_true, if_false, fall_through);
3278
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003279 context()->Plug(if_true, if_false);
Iain Merrick75681382010-08-19 15:07:18 +01003280}
3281
3282
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003283void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
3284 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003285 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003286
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003287 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003288
3289 Label materialize_true, materialize_false;
3290 Label* if_true = NULL;
3291 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003292 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003293 context()->PrepareTest(&materialize_true, &materialize_false,
3294 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003295
3296 __ JumpIfSmi(rax, if_false);
3297 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003298 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003299 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003300
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003301 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003302}
3303
3304
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003305void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
3306 ZoneList<Expression*>* args = expr->arguments();
3307 DCHECK(args->length() == 1);
3308
3309 VisitForAccumulatorValue(args->at(0));
3310
3311 Label materialize_true, materialize_false;
3312 Label* if_true = NULL;
3313 Label* if_false = NULL;
3314 Label* fall_through = NULL;
3315 context()->PrepareTest(&materialize_true, &materialize_false,
3316 &if_true, &if_false, &fall_through);
3317
3318 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
3319 __ CheckMap(rax, map, if_false, DO_SMI_CHECK);
3320 __ cmpl(FieldOperand(rax, HeapNumber::kExponentOffset),
3321 Immediate(0x1));
3322 __ j(no_overflow, if_false);
3323 __ cmpl(FieldOperand(rax, HeapNumber::kMantissaOffset),
3324 Immediate(0x00000000));
3325 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3326 Split(equal, if_true, if_false, fall_through);
3327
3328 context()->Plug(if_true, if_false);
3329}
3330
3331
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003332void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
3333 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003334 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003335
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003336 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003337
3338 Label materialize_true, materialize_false;
3339 Label* if_true = NULL;
3340 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003341 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003342 context()->PrepareTest(&materialize_true, &materialize_false,
3343 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003344
3345 __ JumpIfSmi(rax, if_false);
3346 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003347 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003348 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003349
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003350 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003351}
3352
3353
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003354void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
3355 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003356 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003357
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003358 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003359
3360 Label materialize_true, materialize_false;
3361 Label* if_true = NULL;
3362 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003363 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003364 context()->PrepareTest(&materialize_true, &materialize_false,
3365 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003366
3367 __ JumpIfSmi(rax, if_false);
3368 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003369 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003370 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003371
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003372 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003373}
3374
3375
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003376void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
3377 ZoneList<Expression*>* args = expr->arguments();
3378 DCHECK(args->length() == 1);
3379
3380 VisitForAccumulatorValue(args->at(0));
3381
3382 Label materialize_true, materialize_false;
3383 Label* if_true = NULL;
3384 Label* if_false = NULL;
3385 Label* fall_through = NULL;
3386 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3387 &if_false, &fall_through);
3388
3389 __ JumpIfSmi(rax, if_false);
3390 Register map = rbx;
3391 __ movp(map, FieldOperand(rax, HeapObject::kMapOffset));
3392 __ CmpInstanceType(map, FIRST_JS_PROXY_TYPE);
3393 __ j(less, if_false);
3394 __ CmpInstanceType(map, LAST_JS_PROXY_TYPE);
3395 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3396 Split(less_equal, if_true, if_false, fall_through);
3397
3398 context()->Plug(if_true, if_false);
3399}
3400
Leon Clarkef7060e22010-06-03 12:02:55 +01003401
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003402void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003403 DCHECK(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01003404
3405 Label materialize_true, materialize_false;
3406 Label* if_true = NULL;
3407 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003408 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003409 context()->PrepareTest(&materialize_true, &materialize_false,
3410 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003411
3412 // Get the frame pointer for the calling frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003413 __ movp(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01003414
3415 // Skip the arguments adaptor frame if it exists.
3416 Label check_frame_marker;
Steve Block44f0eee2011-05-26 01:26:41 +01003417 __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset),
3418 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
Leon Clarkef7060e22010-06-03 12:02:55 +01003419 __ j(not_equal, &check_frame_marker);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003420 __ movp(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01003421
3422 // Check the marker in the calling frame.
3423 __ bind(&check_frame_marker);
Steve Block44f0eee2011-05-26 01:26:41 +01003424 __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
3425 Smi::FromInt(StackFrame::CONSTRUCT));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003426 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003427 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003428
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003429 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003430}
3431
3432
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003433void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
3434 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003435 DCHECK(args->length() == 2);
Leon Clarkef7060e22010-06-03 12:02:55 +01003436
3437 // Load the two objects into registers and perform the comparison.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003438 VisitForStackValue(args->at(0));
3439 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003440
3441 Label materialize_true, materialize_false;
3442 Label* if_true = NULL;
3443 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003444 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003445 context()->PrepareTest(&materialize_true, &materialize_false,
3446 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003447
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003448 __ Pop(rbx);
3449 __ cmpp(rax, rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003450 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003451 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003452
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003453 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003454}
3455
3456
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003457void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3458 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003459 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003460
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003461 // ArgumentsAccessStub expects the key in rdx and the formal
3462 // parameter count in rax.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003463 VisitForAccumulatorValue(args->at(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003464 __ movp(rdx, rax);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003465 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003466 ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
Leon Clarkef7060e22010-06-03 12:02:55 +01003467 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003468 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003469}
3470
3471
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003472void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003473 DCHECK(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01003474
Ben Murdoch257744e2011-11-30 15:57:28 +00003475 Label exit;
Leon Clarkef7060e22010-06-03 12:02:55 +01003476 // Get the number of formal parameters.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003477 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
Leon Clarkef7060e22010-06-03 12:02:55 +01003478
3479 // Check if the calling frame is an arguments adaptor frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003480 __ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01003481 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
3482 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
Ben Murdoch257744e2011-11-30 15:57:28 +00003483 __ j(not_equal, &exit, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01003484
3485 // Arguments adaptor case: Read the arguments length from the
3486 // adaptor frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003487 __ movp(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01003488
3489 __ bind(&exit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003490 __ AssertSmi(rax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003491 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003492}
3493
3494
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003495void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3496 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003497 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003498 Label done, null, function, non_function_constructor;
3499
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003500 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003501
3502 // If the object is a smi, we return null.
3503 __ JumpIfSmi(rax, &null);
3504
3505 // Check that the object is a JS object but take special care of JS
3506 // functions to make sure they have 'Function' as their class.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003507 // Assume that there are only two callable types, and one of them is at
3508 // either end of the type range for JS object types. Saves extra comparisons.
3509 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003510 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
3511 // Map is now in rax.
Leon Clarkef7060e22010-06-03 12:02:55 +01003512 __ j(below, &null);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003513 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3514 FIRST_SPEC_OBJECT_TYPE + 1);
3515 __ j(equal, &function);
Leon Clarkef7060e22010-06-03 12:02:55 +01003516
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003517 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
3518 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3519 LAST_SPEC_OBJECT_TYPE - 1);
3520 __ j(equal, &function);
3521 // Assume that there is no larger type.
3522 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003523
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003524 // Check if the constructor in the map is a JS function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003525 __ movp(rax, FieldOperand(rax, Map::kConstructorOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01003526 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
3527 __ j(not_equal, &non_function_constructor);
3528
3529 // rax now contains the constructor function. Grab the
3530 // instance class name from there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003531 __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
3532 __ movp(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01003533 __ jmp(&done);
3534
3535 // Functions have class 'Function'.
3536 __ bind(&function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003537 __ Move(rax, isolate()->factory()->Function_string());
Leon Clarkef7060e22010-06-03 12:02:55 +01003538 __ jmp(&done);
3539
3540 // Objects with a non-function constructor have class 'Object'.
3541 __ bind(&non_function_constructor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003542 __ Move(rax, isolate()->factory()->Object_string());
Leon Clarkef7060e22010-06-03 12:02:55 +01003543 __ jmp(&done);
3544
3545 // Non-JS objects have class null.
3546 __ bind(&null);
3547 __ LoadRoot(rax, Heap::kNullValueRootIndex);
3548
3549 // All done.
3550 __ bind(&done);
3551
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003552 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003553}
3554
3555
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003556void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003557 // Load the arguments on the stack and call the stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003558 SubStringStub stub(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003559 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003560 DCHECK(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003561 VisitForStackValue(args->at(0));
3562 VisitForStackValue(args->at(1));
3563 VisitForStackValue(args->at(2));
Leon Clarkef7060e22010-06-03 12:02:55 +01003564 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003565 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003566}
3567
3568
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003569void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003570 // Load the arguments on the stack and call the stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003571 RegExpExecStub stub(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003572 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003573 DCHECK(args->length() == 4);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003574 VisitForStackValue(args->at(0));
3575 VisitForStackValue(args->at(1));
3576 VisitForStackValue(args->at(2));
3577 VisitForStackValue(args->at(3));
Leon Clarkef7060e22010-06-03 12:02:55 +01003578 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003579 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003580}
3581
3582
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003583void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3584 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003585 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003586
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003587 VisitForAccumulatorValue(args->at(0)); // Load the object.
Leon Clarkef7060e22010-06-03 12:02:55 +01003588
3589 Label done;
3590 // If the object is a smi return the object.
3591 __ JumpIfSmi(rax, &done);
3592 // If the object is not a value type, return the object.
3593 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
3594 __ j(not_equal, &done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003595 __ movp(rax, FieldOperand(rax, JSValue::kValueOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01003596
3597 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003598 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003599}
3600
3601
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003602void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3603 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003604 DCHECK(args->length() == 2);
3605 DCHECK_NE(NULL, args->at(1)->AsLiteral());
3606 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003607
3608 VisitForAccumulatorValue(args->at(0)); // Load the object.
3609
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003610 Label runtime, done, not_date_object;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003611 Register object = rax;
3612 Register result = rax;
3613 Register scratch = rcx;
3614
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003615 __ JumpIfSmi(object, &not_date_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003616 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003617 __ j(not_equal, &not_date_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003618
3619 if (index->value() == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003620 __ movp(result, FieldOperand(object, JSDate::kValueOffset));
3621 __ jmp(&done);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003622 } else {
3623 if (index->value() < JSDate::kFirstUncachedField) {
3624 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003625 Operand stamp_operand = __ ExternalOperand(stamp);
3626 __ movp(scratch, stamp_operand);
3627 __ cmpp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003628 __ j(not_equal, &runtime, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003629 __ movp(result, FieldOperand(object, JSDate::kValueOffset +
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003630 kPointerSize * index->value()));
3631 __ jmp(&done);
3632 }
3633 __ bind(&runtime);
3634 __ PrepareCallCFunction(2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003635 __ movp(arg_reg_1, object);
3636 __ Move(arg_reg_2, index, Assembler::RelocInfoNone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003637 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003638 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3639 __ jmp(&done);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003640 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003641
3642 __ bind(&not_date_object);
3643 __ CallRuntime(Runtime::kThrowNotDateError, 0);
3644 __ bind(&done);
3645 context()->Plug(rax);
3646}
3647
3648
3649void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3650 ZoneList<Expression*>* args = expr->arguments();
3651 DCHECK_EQ(3, args->length());
3652
3653 Register string = rax;
3654 Register index = rbx;
3655 Register value = rcx;
3656
3657 VisitForStackValue(args->at(0)); // index
3658 VisitForStackValue(args->at(1)); // value
3659 VisitForAccumulatorValue(args->at(2)); // string
3660 __ Pop(value);
3661 __ Pop(index);
3662
3663 if (FLAG_debug_code) {
3664 __ Check(__ CheckSmi(value), kNonSmiValue);
3665 __ Check(__ CheckSmi(index), kNonSmiValue);
3666 }
3667
3668 __ SmiToInteger32(value, value);
3669 __ SmiToInteger32(index, index);
3670
3671 if (FLAG_debug_code) {
3672 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
3673 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
3674 }
3675
3676 __ movb(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
3677 value);
3678 context()->Plug(string);
3679}
3680
3681
3682void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3683 ZoneList<Expression*>* args = expr->arguments();
3684 DCHECK_EQ(3, args->length());
3685
3686 Register string = rax;
3687 Register index = rbx;
3688 Register value = rcx;
3689
3690 VisitForStackValue(args->at(0)); // index
3691 VisitForStackValue(args->at(1)); // value
3692 VisitForAccumulatorValue(args->at(2)); // string
3693 __ Pop(value);
3694 __ Pop(index);
3695
3696 if (FLAG_debug_code) {
3697 __ Check(__ CheckSmi(value), kNonSmiValue);
3698 __ Check(__ CheckSmi(index), kNonSmiValue);
3699 }
3700
3701 __ SmiToInteger32(value, value);
3702 __ SmiToInteger32(index, index);
3703
3704 if (FLAG_debug_code) {
3705 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
3706 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
3707 }
3708
3709 __ movw(FieldOperand(string, index, times_2, SeqTwoByteString::kHeaderSize),
3710 value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003711 context()->Plug(rax);
3712}
3713
3714
3715void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003716 // Load the arguments on the stack and call the runtime function.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003717 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003718 DCHECK(args->length() == 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003719 VisitForStackValue(args->at(0));
3720 VisitForStackValue(args->at(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003721 MathPowStub stub(isolate(), MathPowStub::ON_STACK);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003722 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003723 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003724}
3725
3726
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003727void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3728 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003729 DCHECK(args->length() == 2);
Leon Clarkef7060e22010-06-03 12:02:55 +01003730
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003731 VisitForStackValue(args->at(0)); // Load the object.
3732 VisitForAccumulatorValue(args->at(1)); // Load the value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003733 __ Pop(rbx); // rax = value. rbx = object.
Leon Clarkef7060e22010-06-03 12:02:55 +01003734
3735 Label done;
3736 // If the object is a smi, return the value.
3737 __ JumpIfSmi(rbx, &done);
3738
3739 // If the object is not a value type, return the value.
3740 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
3741 __ j(not_equal, &done);
3742
3743 // Store the value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003744 __ movp(FieldOperand(rbx, JSValue::kValueOffset), rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003745 // Update the write barrier. Save the value as it will be
3746 // overwritten by the write barrier code and is needed afterward.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003747 __ movp(rdx, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003748 __ RecordWriteField(rbx, JSValue::kValueOffset, rdx, rcx, kDontSaveFPRegs);
Leon Clarkef7060e22010-06-03 12:02:55 +01003749
3750 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003751 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003752}
3753
3754
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003755void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3756 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003757 DCHECK_EQ(args->length(), 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003758
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003759 // Load the argument into rax and call the stub.
3760 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003761
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003762 NumberToStringStub stub(isolate());
Leon Clarkef7060e22010-06-03 12:02:55 +01003763 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003764 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003765}
3766
3767
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003768void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3769 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003770 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003771
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003772 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003773
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003774 Label done;
3775 StringCharFromCodeGenerator generator(rax, rbx);
3776 generator.GenerateFast(masm_);
Leon Clarkef7060e22010-06-03 12:02:55 +01003777 __ jmp(&done);
3778
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003779 NopRuntimeCallHelper call_helper;
3780 generator.GenerateSlow(masm_, call_helper);
Leon Clarkef7060e22010-06-03 12:02:55 +01003781
3782 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003783 context()->Plug(rbx);
Leon Clarkef7060e22010-06-03 12:02:55 +01003784}
3785
3786
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003787void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3788 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003789 DCHECK(args->length() == 2);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003790
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003791 VisitForStackValue(args->at(0));
3792 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003793
3794 Register object = rbx;
3795 Register index = rax;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003796 Register result = rdx;
3797
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003798 __ Pop(object);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003799
3800 Label need_conversion;
3801 Label index_out_of_range;
3802 Label done;
3803 StringCharCodeAtGenerator generator(object,
3804 index,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003805 result,
3806 &need_conversion,
3807 &need_conversion,
3808 &index_out_of_range,
3809 STRING_INDEX_IS_NUMBER);
3810 generator.GenerateFast(masm_);
3811 __ jmp(&done);
3812
3813 __ bind(&index_out_of_range);
3814 // When the index is out of range, the spec requires us to return
3815 // NaN.
3816 __ LoadRoot(result, Heap::kNanValueRootIndex);
3817 __ jmp(&done);
3818
3819 __ bind(&need_conversion);
Leon Clarkef7060e22010-06-03 12:02:55 +01003820 // Move the undefined value into the result register, which will
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003821 // trigger conversion.
3822 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
3823 __ jmp(&done);
3824
3825 NopRuntimeCallHelper call_helper;
3826 generator.GenerateSlow(masm_, call_helper);
3827
3828 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003829 context()->Plug(result);
Leon Clarkef7060e22010-06-03 12:02:55 +01003830}
3831
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003832
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003833void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3834 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003835 DCHECK(args->length() == 2);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003836
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003837 VisitForStackValue(args->at(0));
3838 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003839
3840 Register object = rbx;
3841 Register index = rax;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003842 Register scratch = rdx;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003843 Register result = rax;
3844
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003845 __ Pop(object);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003846
3847 Label need_conversion;
3848 Label index_out_of_range;
3849 Label done;
3850 StringCharAtGenerator generator(object,
3851 index,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003852 scratch,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003853 result,
3854 &need_conversion,
3855 &need_conversion,
3856 &index_out_of_range,
3857 STRING_INDEX_IS_NUMBER);
3858 generator.GenerateFast(masm_);
3859 __ jmp(&done);
3860
3861 __ bind(&index_out_of_range);
3862 // When the index is out of range, the spec requires us to return
3863 // the empty string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003864 __ LoadRoot(result, Heap::kempty_stringRootIndex);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003865 __ jmp(&done);
3866
3867 __ bind(&need_conversion);
3868 // Move smi zero into the result register, which will trigger
3869 // conversion.
3870 __ Move(result, Smi::FromInt(0));
3871 __ jmp(&done);
3872
3873 NopRuntimeCallHelper call_helper;
3874 generator.GenerateSlow(masm_, call_helper);
3875
3876 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003877 context()->Plug(result);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003878}
3879
3880
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003881void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3882 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003883 DCHECK_EQ(2, args->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003884 VisitForStackValue(args->at(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003885 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003886
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003887 __ Pop(rdx);
3888 StringAddStub stub(isolate(), STRING_ADD_CHECK_BOTH, NOT_TENURED);
Leon Clarkef7060e22010-06-03 12:02:55 +01003889 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003890 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003891}
3892
3893
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003894void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3895 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003896 DCHECK_EQ(2, args->length());
Leon Clarkef7060e22010-06-03 12:02:55 +01003897
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003898 VisitForStackValue(args->at(0));
3899 VisitForStackValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003900
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003901 StringCompareStub stub(isolate());
Leon Clarkef7060e22010-06-03 12:02:55 +01003902 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003903 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003904}
3905
3906
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003907void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3908 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003909 DCHECK(args->length() >= 2);
Leon Clarkef7060e22010-06-03 12:02:55 +01003910
Ben Murdoch257744e2011-11-30 15:57:28 +00003911 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3912 for (int i = 0; i < arg_count + 1; i++) {
3913 VisitForStackValue(args->at(i));
Leon Clarkef7060e22010-06-03 12:02:55 +01003914 }
Ben Murdoch257744e2011-11-30 15:57:28 +00003915 VisitForAccumulatorValue(args->last()); // Function.
Leon Clarkef7060e22010-06-03 12:02:55 +01003916
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003917 Label runtime, done;
3918 // Check for non-function argument (including proxy).
3919 __ JumpIfSmi(rax, &runtime);
3920 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
3921 __ j(not_equal, &runtime);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003922
Ben Murdoch257744e2011-11-30 15:57:28 +00003923 // InvokeFunction requires the function in rdi. Move it in there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003924 __ movp(rdi, result_register());
Leon Clarkef7060e22010-06-03 12:02:55 +01003925 ParameterCount count(arg_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003926 __ InvokeFunction(rdi, count, CALL_FUNCTION, NullCallWrapper());
3927 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003928 __ jmp(&done);
3929
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003930 __ bind(&runtime);
3931 __ Push(rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003932 __ CallRuntime(Runtime::kCall, args->length());
3933 __ bind(&done);
3934
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003935 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003936}
3937
3938
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003939void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003940 RegExpConstructResultStub stub(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003941 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003942 DCHECK(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003943 VisitForStackValue(args->at(0));
3944 VisitForStackValue(args->at(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003945 VisitForAccumulatorValue(args->at(2));
3946 __ Pop(rbx);
3947 __ Pop(rcx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003948 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003949 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003950}
3951
3952
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003953void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3954 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003955 DCHECK_EQ(2, args->length());
Leon Clarkef7060e22010-06-03 12:02:55 +01003956
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003957 DCHECK_NE(NULL, args->at(0)->AsLiteral());
3958 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003959
3960 Handle<FixedArray> jsfunction_result_caches(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003961 isolate()->native_context()->jsfunction_result_caches());
Leon Clarkef7060e22010-06-03 12:02:55 +01003962 if (jsfunction_result_caches->length() <= cache_id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003963 __ Abort(kAttemptToUseUndefinedCache);
Leon Clarkef7060e22010-06-03 12:02:55 +01003964 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003965 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003966 return;
3967 }
3968
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003969 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003970
3971 Register key = rax;
3972 Register cache = rbx;
3973 Register tmp = rcx;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003974 __ movp(cache, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX));
3975 __ movp(cache,
3976 FieldOperand(cache, GlobalObject::kNativeContextOffset));
3977 __ movp(cache,
Steve Block59151502010-09-22 15:07:15 +01003978 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003979 __ movp(cache,
Leon Clarkef7060e22010-06-03 12:02:55 +01003980 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3981
Ben Murdoch257744e2011-11-30 15:57:28 +00003982 Label done, not_found;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003983 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003984 __ movp(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3985 // tmp now holds finger offset as a smi.
Leon Clarkef7060e22010-06-03 12:02:55 +01003986 SmiIndex index =
3987 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003988 __ cmpp(key, FieldOperand(cache,
Leon Clarkef7060e22010-06-03 12:02:55 +01003989 index.reg,
3990 index.scale,
3991 FixedArray::kHeaderSize));
Ben Murdoch257744e2011-11-30 15:57:28 +00003992 __ j(not_equal, &not_found, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003993 __ movp(rax, FieldOperand(cache,
Leon Clarkef7060e22010-06-03 12:02:55 +01003994 index.reg,
3995 index.scale,
3996 FixedArray::kHeaderSize + kPointerSize));
Ben Murdoch257744e2011-11-30 15:57:28 +00003997 __ jmp(&done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01003998
3999 __ bind(&not_found);
4000 // Call runtime to perform the lookup.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004001 __ Push(cache);
4002 __ Push(key);
Leon Clarkef7060e22010-06-03 12:02:55 +01004003 __ CallRuntime(Runtime::kGetFromCache, 2);
4004
4005 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004006 context()->Plug(rax);
Leon Clarkef7060e22010-06-03 12:02:55 +01004007}
4008
4009
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004010void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
4011 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004012 DCHECK(args->length() == 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004013
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004014 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004015
4016 Label materialize_true, materialize_false;
4017 Label* if_true = NULL;
4018 Label* if_false = NULL;
4019 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004020 context()->PrepareTest(&materialize_true, &materialize_false,
4021 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004022
4023 __ testl(FieldOperand(rax, String::kHashFieldOffset),
4024 Immediate(String::kContainsCachedArrayIndexMask));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004025 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004026 __ j(zero, if_true);
4027 __ jmp(if_false);
4028
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004029 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004030}
4031
4032
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004033void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
4034 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004035 DCHECK(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004036 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004037
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004038 __ AssertString(rax);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004039
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004040 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004041 DCHECK(String::kHashShift >= kSmiTagSize);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004042 __ IndexFromHash(rax, rax);
4043
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004044 context()->Plug(rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004045}
4046
4047
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004048void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) {
Steve Block44f0eee2011-05-26 01:26:41 +01004049 Label bailout, return_result, done, one_char_separator, long_separator,
4050 non_trivial_array, not_size_one_array, loop,
4051 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004052 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004053 DCHECK(args->length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +01004054 // We will leave the separator on the stack until the end of the function.
4055 VisitForStackValue(args->at(1));
4056 // Load this to rax (= array)
4057 VisitForAccumulatorValue(args->at(0));
4058 // All aliases of the same register have disjoint lifetimes.
4059 Register array = rax;
4060 Register elements = no_reg; // Will be rax.
4061
4062 Register index = rdx;
4063
4064 Register string_length = rcx;
4065
4066 Register string = rsi;
4067
4068 Register scratch = rbx;
4069
4070 Register array_length = rdi;
4071 Register result_pos = no_reg; // Will be rdi.
4072
4073 Operand separator_operand = Operand(rsp, 2 * kPointerSize);
4074 Operand result_operand = Operand(rsp, 1 * kPointerSize);
4075 Operand array_length_operand = Operand(rsp, 0 * kPointerSize);
4076 // Separator operand is already pushed. Make room for the two
4077 // other stack fields, and clear the direction flag in anticipation
4078 // of calling CopyBytes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004079 __ subp(rsp, Immediate(2 * kPointerSize));
Steve Block44f0eee2011-05-26 01:26:41 +01004080 __ cld();
4081 // Check that the array is a JSArray
4082 __ JumpIfSmi(array, &bailout);
4083 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
4084 __ j(not_equal, &bailout);
4085
4086 // Check that the array has fast elements.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004087 __ CheckFastElements(scratch, &bailout);
Steve Block44f0eee2011-05-26 01:26:41 +01004088
4089 // Array has fast elements, so its length must be a smi.
4090 // If the array has length zero, return the empty string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004091 __ movp(array_length, FieldOperand(array, JSArray::kLengthOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01004092 __ SmiCompare(array_length, Smi::FromInt(0));
4093 __ j(not_zero, &non_trivial_array);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004094 __ LoadRoot(rax, Heap::kempty_stringRootIndex);
Steve Block44f0eee2011-05-26 01:26:41 +01004095 __ jmp(&return_result);
4096
4097 // Save the array length on the stack.
4098 __ bind(&non_trivial_array);
4099 __ SmiToInteger32(array_length, array_length);
4100 __ movl(array_length_operand, array_length);
4101
4102 // Save the FixedArray containing array's elements.
4103 // End of array's live range.
4104 elements = array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004105 __ movp(elements, FieldOperand(array, JSArray::kElementsOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01004106 array = no_reg;
4107
4108
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004109 // Check that all array elements are sequential one-byte strings, and
Steve Block44f0eee2011-05-26 01:26:41 +01004110 // accumulate the sum of their lengths, as a smi-encoded value.
4111 __ Set(index, 0);
4112 __ Set(string_length, 0);
4113 // Loop condition: while (index < array_length).
4114 // Live loop registers: index(int32), array_length(int32), string(String*),
4115 // scratch, string_length(int32), elements(FixedArray*).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004116 if (generate_debug_code_) {
4117 __ cmpp(index, array_length);
4118 __ Assert(below, kNoEmptyArraysHereInEmitFastOneByteArrayJoin);
Steve Block44f0eee2011-05-26 01:26:41 +01004119 }
4120 __ bind(&loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004121 __ movp(string, FieldOperand(elements,
Steve Block44f0eee2011-05-26 01:26:41 +01004122 index,
4123 times_pointer_size,
4124 FixedArray::kHeaderSize));
4125 __ JumpIfSmi(string, &bailout);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004126 __ movp(scratch, FieldOperand(string, HeapObject::kMapOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01004127 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
4128 __ andb(scratch, Immediate(
4129 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004130 __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag));
Steve Block44f0eee2011-05-26 01:26:41 +01004131 __ j(not_equal, &bailout);
4132 __ AddSmiField(string_length,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004133 FieldOperand(string, SeqOneByteString::kLengthOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01004134 __ j(overflow, &bailout);
4135 __ incl(index);
4136 __ cmpl(index, array_length);
4137 __ j(less, &loop);
4138
4139 // Live registers:
4140 // string_length: Sum of string lengths.
4141 // elements: FixedArray of strings.
4142 // index: Array length.
4143 // array_length: Array length.
4144
4145 // If array_length is 1, return elements[0], a string.
4146 __ cmpl(array_length, Immediate(1));
4147 __ j(not_equal, &not_size_one_array);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004148 __ movp(rax, FieldOperand(elements, FixedArray::kHeaderSize));
Steve Block44f0eee2011-05-26 01:26:41 +01004149 __ jmp(&return_result);
4150
4151 __ bind(&not_size_one_array);
4152
4153 // End of array_length live range.
4154 result_pos = array_length;
4155 array_length = no_reg;
4156
4157 // Live registers:
4158 // string_length: Sum of string lengths.
4159 // elements: FixedArray of strings.
4160 // index: Array length.
4161
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004162 // Check that the separator is a sequential one-byte string.
4163 __ movp(string, separator_operand);
Steve Block44f0eee2011-05-26 01:26:41 +01004164 __ JumpIfSmi(string, &bailout);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004165 __ movp(scratch, FieldOperand(string, HeapObject::kMapOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01004166 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
4167 __ andb(scratch, Immediate(
4168 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004169 __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag));
Steve Block44f0eee2011-05-26 01:26:41 +01004170 __ j(not_equal, &bailout);
4171
4172 // Live registers:
4173 // string_length: Sum of string lengths.
4174 // elements: FixedArray of strings.
4175 // index: Array length.
4176 // string: Separator string.
4177
4178 // Add (separator length times (array_length - 1)) to string_length.
4179 __ SmiToInteger32(scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004180 FieldOperand(string, SeqOneByteString::kLengthOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01004181 __ decl(index);
4182 __ imull(scratch, index);
4183 __ j(overflow, &bailout);
4184 __ addl(string_length, scratch);
4185 __ j(overflow, &bailout);
4186
4187 // Live registers and stack values:
4188 // string_length: Total length of result string.
4189 // elements: FixedArray of strings.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004190 __ AllocateOneByteString(result_pos, string_length, scratch, index, string,
4191 &bailout);
4192 __ movp(result_operand, result_pos);
4193 __ leap(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize));
Steve Block44f0eee2011-05-26 01:26:41 +01004194
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004195 __ movp(string, separator_operand);
4196 __ SmiCompare(FieldOperand(string, SeqOneByteString::kLengthOffset),
Steve Block44f0eee2011-05-26 01:26:41 +01004197 Smi::FromInt(1));
4198 __ j(equal, &one_char_separator);
4199 __ j(greater, &long_separator);
4200
4201
4202 // Empty separator case:
4203 __ Set(index, 0);
4204 __ movl(scratch, array_length_operand);
4205 __ jmp(&loop_1_condition);
4206 // Loop condition: while (index < array_length).
4207 __ bind(&loop_1);
4208 // Each iteration of the loop concatenates one string to the result.
4209 // Live values in registers:
4210 // index: which element of the elements array we are adding to the result.
4211 // result_pos: the position to which we are currently copying characters.
4212 // elements: the FixedArray of strings we are joining.
4213 // scratch: array length.
4214
4215 // Get string = array[index].
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004216 __ movp(string, FieldOperand(elements, index,
Steve Block44f0eee2011-05-26 01:26:41 +01004217 times_pointer_size,
4218 FixedArray::kHeaderSize));
4219 __ SmiToInteger32(string_length,
4220 FieldOperand(string, String::kLengthOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004221 __ leap(string,
4222 FieldOperand(string, SeqOneByteString::kHeaderSize));
Steve Block44f0eee2011-05-26 01:26:41 +01004223 __ CopyBytes(result_pos, string, string_length);
4224 __ incl(index);
4225 __ bind(&loop_1_condition);
4226 __ cmpl(index, scratch);
4227 __ j(less, &loop_1); // Loop while (index < array_length).
4228 __ jmp(&done);
4229
4230 // Generic bailout code used from several places.
4231 __ bind(&bailout);
4232 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
4233 __ jmp(&return_result);
4234
4235
4236 // One-character separator case
4237 __ bind(&one_char_separator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004238 // Get the separator one-byte character value.
Steve Block44f0eee2011-05-26 01:26:41 +01004239 // Register "string" holds the separator.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004240 __ movzxbl(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize));
Steve Block44f0eee2011-05-26 01:26:41 +01004241 __ Set(index, 0);
4242 // Jump into the loop after the code that copies the separator, so the first
4243 // element is not preceded by a separator
4244 __ jmp(&loop_2_entry);
4245 // Loop condition: while (index < length).
4246 __ bind(&loop_2);
4247 // Each iteration of the loop concatenates one string to the result.
4248 // Live values in registers:
4249 // elements: The FixedArray of strings we are joining.
4250 // index: which element of the elements array we are adding to the result.
4251 // result_pos: the position to which we are currently copying characters.
4252 // scratch: Separator character.
4253
4254 // Copy the separator character to the result.
4255 __ movb(Operand(result_pos, 0), scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004256 __ incp(result_pos);
Steve Block44f0eee2011-05-26 01:26:41 +01004257
4258 __ bind(&loop_2_entry);
4259 // Get string = array[index].
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004260 __ movp(string, FieldOperand(elements, index,
Steve Block44f0eee2011-05-26 01:26:41 +01004261 times_pointer_size,
4262 FixedArray::kHeaderSize));
4263 __ SmiToInteger32(string_length,
4264 FieldOperand(string, String::kLengthOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004265 __ leap(string,
4266 FieldOperand(string, SeqOneByteString::kHeaderSize));
Steve Block44f0eee2011-05-26 01:26:41 +01004267 __ CopyBytes(result_pos, string, string_length);
4268 __ incl(index);
4269 __ cmpl(index, array_length_operand);
4270 __ j(less, &loop_2); // End while (index < length).
4271 __ jmp(&done);
4272
4273
4274 // Long separator case (separator is more than one character).
4275 __ bind(&long_separator);
4276
4277 // Make elements point to end of elements array, and index
4278 // count from -array_length to zero, so we don't need to maintain
4279 // a loop limit.
4280 __ movl(index, array_length_operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004281 __ leap(elements, FieldOperand(elements, index, times_pointer_size,
Steve Block44f0eee2011-05-26 01:26:41 +01004282 FixedArray::kHeaderSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004283 __ negq(index);
Steve Block44f0eee2011-05-26 01:26:41 +01004284
4285 // Replace separator string with pointer to its first character, and
4286 // make scratch be its length.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004287 __ movp(string, separator_operand);
Steve Block44f0eee2011-05-26 01:26:41 +01004288 __ SmiToInteger32(scratch,
4289 FieldOperand(string, String::kLengthOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004290 __ leap(string,
4291 FieldOperand(string, SeqOneByteString::kHeaderSize));
4292 __ movp(separator_operand, string);
Steve Block44f0eee2011-05-26 01:26:41 +01004293
4294 // Jump into the loop after the code that copies the separator, so the first
4295 // element is not preceded by a separator
4296 __ jmp(&loop_3_entry);
4297 // Loop condition: while (index < length).
4298 __ bind(&loop_3);
4299 // Each iteration of the loop concatenates one string to the result.
4300 // Live values in registers:
4301 // index: which element of the elements array we are adding to the result.
4302 // result_pos: the position to which we are currently copying characters.
4303 // scratch: Separator length.
4304 // separator_operand (rsp[0x10]): Address of first char of separator.
4305
4306 // Copy the separator to the result.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004307 __ movp(string, separator_operand);
Steve Block44f0eee2011-05-26 01:26:41 +01004308 __ movl(string_length, scratch);
4309 __ CopyBytes(result_pos, string, string_length, 2);
4310
4311 __ bind(&loop_3_entry);
4312 // Get string = array[index].
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004313 __ movp(string, Operand(elements, index, times_pointer_size, 0));
Steve Block44f0eee2011-05-26 01:26:41 +01004314 __ SmiToInteger32(string_length,
4315 FieldOperand(string, String::kLengthOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004316 __ leap(string,
4317 FieldOperand(string, SeqOneByteString::kHeaderSize));
Steve Block44f0eee2011-05-26 01:26:41 +01004318 __ CopyBytes(result_pos, string, string_length);
4319 __ incq(index);
4320 __ j(not_equal, &loop_3); // Loop while (index < 0).
4321
4322 __ bind(&done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004323 __ movp(rax, result_operand);
Steve Block44f0eee2011-05-26 01:26:41 +01004324
4325 __ bind(&return_result);
4326 // Drop temp values from the stack, and restore context register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004327 __ addp(rsp, Immediate(3 * kPointerSize));
4328 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
4329 context()->Plug(rax);
4330}
4331
4332
4333void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
4334 DCHECK(expr->arguments()->length() == 0);
4335 ExternalReference debug_is_active =
4336 ExternalReference::debug_is_active_address(isolate());
4337 __ Move(kScratchRegister, debug_is_active);
4338 __ movzxbp(rax, Operand(kScratchRegister, 0));
4339 __ Integer32ToSmi(rax, rax);
Steve Block44f0eee2011-05-26 01:26:41 +01004340 context()->Plug(rax);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004341}
4342
4343
Leon Clarked91b9f72010-01-27 17:25:45 +00004344void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004345 if (expr->function() != NULL &&
4346 expr->function()->intrinsic_type == Runtime::INLINE) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004347 Comment cmnt(masm_, "[ InlineRuntimeCall");
4348 EmitInlineRuntimeCall(expr);
4349 return;
4350 }
4351
Steve Block3ce2e202009-11-05 08:53:23 +00004352 Comment cmnt(masm_, "[ CallRuntime");
4353 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00004354 int arg_count = args->length();
Steve Block3ce2e202009-11-05 08:53:23 +00004355
Steve Blockd0582a62009-12-15 09:54:21 +00004356 if (expr->is_jsruntime()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004357 // Push the builtins object as receiver.
4358 __ movp(rax, GlobalObjectOperand());
4359 __ Push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
4360
4361 // Load the function from the receiver.
4362 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
4363 __ Move(LoadDescriptor::NameRegister(), expr->name());
4364 if (FLAG_vector_ics) {
4365 __ Move(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004366 SmiFromSlot(expr->CallRuntimeFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004367 CallLoadIC(NOT_CONTEXTUAL);
4368 } else {
4369 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
4370 }
4371
4372 // Push the target function under the receiver.
4373 __ Push(Operand(rsp, 0));
4374 __ movp(Operand(rsp, kPointerSize), rax);
4375
4376 // Push the arguments ("left-to-right").
4377 for (int i = 0; i < arg_count; i++) {
4378 VisitForStackValue(args->at(i));
4379 }
4380
4381 // Record source position of the IC call.
4382 SetSourcePosition(expr->position());
4383 CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
4384 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
4385 __ CallStub(&stub);
4386
Steve Blockd0582a62009-12-15 09:54:21 +00004387 // Restore context register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004388 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
4389 context()->DropAndPlug(1, rax);
4390
Steve Block3ce2e202009-11-05 08:53:23 +00004391 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004392 // Push the arguments ("left-to-right").
4393 for (int i = 0; i < arg_count; i++) {
4394 VisitForStackValue(args->at(i));
4395 }
4396
4397 // Call the C runtime.
Steve Blockd0582a62009-12-15 09:54:21 +00004398 __ CallRuntime(expr->function(), arg_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004399 context()->Plug(rax);
Steve Blockd0582a62009-12-15 09:54:21 +00004400 }
4401}
4402
4403
Leon Clarked91b9f72010-01-27 17:25:45 +00004404void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004405 switch (expr->op()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004406 case Token::DELETE: {
4407 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
Ben Murdoch589d6972011-11-30 16:04:58 +00004408 Property* property = expr->expression()->AsProperty();
4409 VariableProxy* proxy = expr->expression()->AsVariableProxy();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004410
Ben Murdoch589d6972011-11-30 16:04:58 +00004411 if (property != NULL) {
4412 VisitForStackValue(property->obj());
4413 VisitForStackValue(property->key());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004414 __ Push(Smi::FromInt(strict_mode()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004415 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4416 context()->Plug(rax);
Ben Murdoch589d6972011-11-30 16:04:58 +00004417 } else if (proxy != NULL) {
4418 Variable* var = proxy->var();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004419 // Delete of an unqualified identifier is disallowed in strict mode
Ben Murdoch589d6972011-11-30 16:04:58 +00004420 // but "delete this" is allowed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004421 DCHECK(strict_mode() == SLOPPY || var->is_this());
Ben Murdoch589d6972011-11-30 16:04:58 +00004422 if (var->IsUnallocated()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004423 __ Push(GlobalObjectOperand());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004424 __ Push(var->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004425 __ Push(Smi::FromInt(SLOPPY));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004426 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4427 context()->Plug(rax);
Ben Murdoch589d6972011-11-30 16:04:58 +00004428 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
4429 // Result of deleting non-global variables is false. 'this' is
4430 // not really a variable, though we implement it as one. The
4431 // subexpression does not have side effects.
4432 context()->Plug(var->is_this());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004433 } else {
4434 // Non-global variable. Call the runtime to try to delete from the
4435 // context where the variable was introduced.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004436 __ Push(context_register());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004437 __ Push(var->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004438 __ CallRuntime(Runtime::kDeleteLookupSlot, 2);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004439 context()->Plug(rax);
4440 }
Steve Block1e0659c2011-05-24 12:43:12 +01004441 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004442 // Result of deleting non-property, non-variable reference is true.
4443 // The subexpression may have side effects.
4444 VisitForEffect(expr->expression());
4445 context()->Plug(true);
Leon Clarkef7060e22010-06-03 12:02:55 +01004446 }
4447 break;
4448 }
4449
Steve Blockd0582a62009-12-15 09:54:21 +00004450 case Token::VOID: {
4451 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
Leon Clarkee46be812010-01-19 14:06:41 +00004452 VisitForEffect(expr->expression());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004453 context()->Plug(Heap::kUndefinedValueRootIndex);
Steve Blockd0582a62009-12-15 09:54:21 +00004454 break;
4455 }
4456
4457 case Token::NOT: {
4458 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004459 if (context()->IsEffect()) {
4460 // Unary NOT has no side effects so it's only necessary to visit the
4461 // subexpression. Match the optimizing compiler by not branching.
4462 VisitForEffect(expr->expression());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004463 } else if (context()->IsTest()) {
4464 const TestContext* test = TestContext::cast(context());
4465 // The labels are swapped for the recursive call.
4466 VisitForControl(expr->expression(),
4467 test->false_label(),
4468 test->true_label(),
4469 test->fall_through());
4470 context()->Plug(test->true_label(), test->false_label());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004471 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004472 // We handle value contexts explicitly rather than simply visiting
4473 // for control and plugging the control flow into the context,
4474 // because we need to prepare a pair of extra administrative AST ids
4475 // for the optimizing compiler.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004476 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004477 Label materialize_true, materialize_false, done;
4478 VisitForControl(expr->expression(),
4479 &materialize_false,
4480 &materialize_true,
4481 &materialize_true);
4482 __ bind(&materialize_true);
4483 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4484 if (context()->IsAccumulatorValue()) {
4485 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
4486 } else {
4487 __ PushRoot(Heap::kTrueValueRootIndex);
4488 }
4489 __ jmp(&done, Label::kNear);
4490 __ bind(&materialize_false);
4491 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4492 if (context()->IsAccumulatorValue()) {
4493 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
4494 } else {
4495 __ PushRoot(Heap::kFalseValueRootIndex);
4496 }
4497 __ bind(&done);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004498 }
Steve Blockd0582a62009-12-15 09:54:21 +00004499 break;
4500 }
4501
4502 case Token::TYPEOF: {
4503 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004504 { StackValueContext context(this);
4505 VisitForTypeofValue(expr->expression());
4506 }
Steve Blockd0582a62009-12-15 09:54:21 +00004507 __ CallRuntime(Runtime::kTypeof, 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004508 context()->Plug(rax);
Steve Blockd0582a62009-12-15 09:54:21 +00004509 break;
4510 }
4511
4512 default:
4513 UNREACHABLE();
Steve Block3ce2e202009-11-05 08:53:23 +00004514 }
4515}
4516
4517
Leon Clarked91b9f72010-01-27 17:25:45 +00004518void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004519 DCHECK(expr->expression()->IsValidReferenceExpression());
4520
Leon Clarkee46be812010-01-19 14:06:41 +00004521 Comment cmnt(masm_, "[ CountOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004522 SetSourcePosition(expr->position());
Leon Clarkee46be812010-01-19 14:06:41 +00004523
Leon Clarkee46be812010-01-19 14:06:41 +00004524 Property* prop = expr->expression()->AsProperty();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004525 LhsKind assign_type = GetAssignType(prop);
Leon Clarkee46be812010-01-19 14:06:41 +00004526
4527 // Evaluate expression and get value.
4528 if (assign_type == VARIABLE) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004529 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004530 AccumulatorValueContext context(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004531 EmitVariableLoad(expr->expression()->AsVariableProxy());
Leon Clarkef7060e22010-06-03 12:02:55 +01004532 } else {
Leon Clarkee46be812010-01-19 14:06:41 +00004533 // Reserve space for result of postfix operation.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004534 if (expr->is_postfix() && !context()->IsEffect()) {
Leon Clarkee46be812010-01-19 14:06:41 +00004535 __ Push(Smi::FromInt(0));
4536 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004537 switch (assign_type) {
4538 case NAMED_PROPERTY: {
4539 VisitForStackValue(prop->obj());
4540 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
4541 EmitNamedPropertyLoad(prop);
4542 break;
4543 }
4544
4545 case NAMED_SUPER_PROPERTY: {
4546 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
4547 EmitLoadHomeObject(prop->obj()->AsSuperReference());
4548 __ Push(result_register());
4549 __ Push(MemOperand(rsp, kPointerSize));
4550 __ Push(result_register());
4551 EmitNamedSuperPropertyLoad(prop);
4552 break;
4553 }
4554
4555 case KEYED_SUPER_PROPERTY: {
4556 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
4557 EmitLoadHomeObject(prop->obj()->AsSuperReference());
4558 __ Push(result_register());
4559 VisitForAccumulatorValue(prop->key());
4560 __ Push(result_register());
4561 __ Push(MemOperand(rsp, 2 * kPointerSize));
4562 __ Push(MemOperand(rsp, 2 * kPointerSize));
4563 __ Push(result_register());
4564 EmitKeyedSuperPropertyLoad(prop);
4565 break;
4566 }
4567
4568 case KEYED_PROPERTY: {
4569 VisitForStackValue(prop->obj());
4570 VisitForStackValue(prop->key());
4571 // Leave receiver on stack
4572 __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
4573 // Copy of key, needed for later store.
4574 __ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
4575 EmitKeyedPropertyLoad(prop);
4576 break;
4577 }
4578
4579 case VARIABLE:
4580 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +00004581 }
Leon Clarkee46be812010-01-19 14:06:41 +00004582 }
4583
Ben Murdoch086aeea2011-05-13 15:57:08 +01004584 // We need a second deoptimization point after loading the value
4585 // in case evaluating the property load my have a side effect.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004586 if (assign_type == VARIABLE) {
4587 PrepareForBailout(expr->expression(), TOS_REG);
4588 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004589 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
Ben Murdoch8b112d22011-06-08 16:22:53 +01004590 }
Ben Murdoch086aeea2011-05-13 15:57:08 +01004591
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004592 // Inline smi case if we are in a loop.
4593 Label done, stub_call;
4594 JumpPatchSite patch_site(masm_);
4595 if (ShouldInlineSmiCase(expr->op())) {
4596 Label slow;
4597 patch_site.EmitJumpIfNotSmi(rax, &slow, Label::kNear);
4598
4599 // Save result for postfix expressions.
4600 if (expr->is_postfix()) {
4601 if (!context()->IsEffect()) {
4602 // Save the result on the stack. If we have a named or keyed property
4603 // we store the result under the receiver that is currently on top
4604 // of the stack.
4605 switch (assign_type) {
4606 case VARIABLE:
4607 __ Push(rax);
4608 break;
4609 case NAMED_PROPERTY:
4610 __ movp(Operand(rsp, kPointerSize), rax);
4611 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004612 case NAMED_SUPER_PROPERTY:
4613 __ movp(Operand(rsp, 2 * kPointerSize), rax);
4614 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004615 case KEYED_PROPERTY:
4616 __ movp(Operand(rsp, 2 * kPointerSize), rax);
4617 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004618 case KEYED_SUPER_PROPERTY:
4619 __ movp(Operand(rsp, 3 * kPointerSize), rax);
4620 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004621 }
4622 }
4623 }
4624
4625 SmiOperationExecutionMode mode;
4626 mode.Add(PRESERVE_SOURCE_REGISTER);
4627 mode.Add(BAILOUT_ON_NO_OVERFLOW);
4628 if (expr->op() == Token::INC) {
4629 __ SmiAddConstant(rax, rax, Smi::FromInt(1), mode, &done, Label::kNear);
4630 } else {
4631 __ SmiSubConstant(rax, rax, Smi::FromInt(1), mode, &done, Label::kNear);
4632 }
4633 __ jmp(&stub_call, Label::kNear);
4634 __ bind(&slow);
4635 }
4636
4637 ToNumberStub convert_stub(isolate());
Steve Block1e0659c2011-05-24 12:43:12 +01004638 __ CallStub(&convert_stub);
Leon Clarkee46be812010-01-19 14:06:41 +00004639
4640 // Save result for postfix expressions.
4641 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004642 if (!context()->IsEffect()) {
4643 // Save the result on the stack. If we have a named or keyed property
4644 // we store the result under the receiver that is currently on top
4645 // of the stack.
4646 switch (assign_type) {
4647 case VARIABLE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004648 __ Push(rax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004649 break;
4650 case NAMED_PROPERTY:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004651 __ movp(Operand(rsp, kPointerSize), rax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004652 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004653 case NAMED_SUPER_PROPERTY:
4654 __ movp(Operand(rsp, 2 * kPointerSize), rax);
4655 break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004656 case KEYED_PROPERTY:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004657 __ movp(Operand(rsp, 2 * kPointerSize), rax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004658 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004659 case KEYED_SUPER_PROPERTY:
4660 __ movp(Operand(rsp, 3 * kPointerSize), rax);
4661 break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004662 }
Leon Clarkee46be812010-01-19 14:06:41 +00004663 }
4664 }
4665
Ben Murdochb0fe1622011-05-05 13:52:32 +01004666 // Record position before stub call.
4667 SetSourcePosition(expr->position());
4668
Leon Clarkee46be812010-01-19 14:06:41 +00004669 // Call stub for +1/-1.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004670 __ bind(&stub_call);
4671 __ movp(rdx, rax);
4672 __ Move(rax, Smi::FromInt(1));
4673 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), expr->binary_op(),
4674 NO_OVERWRITE).code();
4675 CallIC(code, expr->CountBinOpFeedbackId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004676 patch_site.EmitPatchInfo();
Leon Clarked91b9f72010-01-27 17:25:45 +00004677 __ bind(&done);
Leon Clarkee46be812010-01-19 14:06:41 +00004678
4679 // Store the value returned in rax.
4680 switch (assign_type) {
4681 case VARIABLE:
4682 if (expr->is_postfix()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004683 // Perform the assignment as if via '='.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004684 { EffectContext context(this);
4685 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4686 Token::ASSIGN);
Ben Murdoch086aeea2011-05-13 15:57:08 +01004687 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004688 context.Plug(rax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004689 }
Leon Clarkee46be812010-01-19 14:06:41 +00004690 // For all contexts except kEffect: We have the result on
4691 // top of the stack.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004692 if (!context()->IsEffect()) {
4693 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004694 }
4695 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01004696 // Perform the assignment as if via '='.
Leon Clarkee46be812010-01-19 14:06:41 +00004697 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004698 Token::ASSIGN);
Ben Murdoch086aeea2011-05-13 15:57:08 +01004699 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004700 context()->Plug(rax);
Leon Clarkee46be812010-01-19 14:06:41 +00004701 }
4702 break;
4703 case NAMED_PROPERTY: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004704 __ Move(StoreDescriptor::NameRegister(),
4705 prop->key()->AsLiteral()->value());
4706 __ Pop(StoreDescriptor::ReceiverRegister());
4707 CallStoreIC(expr->CountStoreFeedbackId());
Ben Murdoch086aeea2011-05-13 15:57:08 +01004708 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00004709 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004710 if (!context()->IsEffect()) {
4711 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004712 }
4713 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004714 context()->Plug(rax);
Leon Clarkee46be812010-01-19 14:06:41 +00004715 }
4716 break;
4717 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004718 case NAMED_SUPER_PROPERTY: {
4719 EmitNamedSuperPropertyStore(prop);
4720 if (expr->is_postfix()) {
4721 if (!context()->IsEffect()) {
4722 context()->PlugTOS();
4723 }
4724 } else {
4725 context()->Plug(rax);
4726 }
4727 break;
4728 }
4729 case KEYED_SUPER_PROPERTY: {
4730 EmitKeyedSuperPropertyStore(prop);
4731 if (expr->is_postfix()) {
4732 if (!context()->IsEffect()) {
4733 context()->PlugTOS();
4734 }
4735 } else {
4736 context()->Plug(rax);
4737 }
4738 break;
4739 }
Leon Clarkee46be812010-01-19 14:06:41 +00004740 case KEYED_PROPERTY: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004741 __ Pop(StoreDescriptor::NameRegister());
4742 __ Pop(StoreDescriptor::ReceiverRegister());
4743 Handle<Code> ic =
4744 CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
4745 CallIC(ic, expr->CountStoreFeedbackId());
Ben Murdoch086aeea2011-05-13 15:57:08 +01004746 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00004747 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004748 if (!context()->IsEffect()) {
4749 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004750 }
4751 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004752 context()->Plug(rax);
Leon Clarkee46be812010-01-19 14:06:41 +00004753 }
4754 break;
4755 }
4756 }
4757}
4758
Steve Block3ce2e202009-11-05 08:53:23 +00004759
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004760void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004761 VariableProxy* proxy = expr->AsVariableProxy();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004762 DCHECK(!context()->IsEffect());
4763 DCHECK(!context()->IsTest());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004764
Ben Murdoch589d6972011-11-30 16:04:58 +00004765 if (proxy != NULL && proxy->var()->IsUnallocated()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004766 Comment cmnt(masm_, "[ Global variable");
4767 __ Move(LoadDescriptor::NameRegister(), proxy->name());
4768 __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
4769 if (FLAG_vector_ics) {
4770 __ Move(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004771 SmiFromSlot(proxy->VariableFeedbackSlot()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004772 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004773 // Use a regular load, not a contextual load, to avoid a reference
4774 // error.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004775 CallLoadIC(NOT_CONTEXTUAL);
Ben Murdoch086aeea2011-05-13 15:57:08 +01004776 PrepareForBailout(expr, TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004777 context()->Plug(rax);
Ben Murdoch589d6972011-11-30 16:04:58 +00004778 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004779 Comment cmnt(masm_, "[ Lookup slot");
Steve Block59151502010-09-22 15:07:15 +01004780 Label done, slow;
4781
4782 // Generate code for loading from variables potentially shadowed
4783 // by eval-introduced variables.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004784 EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done);
Steve Block59151502010-09-22 15:07:15 +01004785
4786 __ bind(&slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004787 __ Push(rsi);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004788 __ Push(proxy->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004789 __ CallRuntime(Runtime::kLoadLookupSlotNoReferenceError, 2);
Ben Murdoch086aeea2011-05-13 15:57:08 +01004790 PrepareForBailout(expr, TOS_REG);
Steve Block59151502010-09-22 15:07:15 +01004791 __ bind(&done);
4792
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004793 context()->Plug(rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004794 } else {
4795 // This expression cannot throw a reference error at the top level.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004796 VisitInDuplicateContext(expr);
Steve Block3ce2e202009-11-05 08:53:23 +00004797 }
Steve Block3ce2e202009-11-05 08:53:23 +00004798}
4799
4800
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004801void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004802 Expression* sub_expr,
4803 Handle<String> check) {
4804 Label materialize_true, materialize_false;
4805 Label* if_true = NULL;
4806 Label* if_false = NULL;
4807 Label* fall_through = NULL;
4808 context()->PrepareTest(&materialize_true, &materialize_false,
4809 &if_true, &if_false, &fall_through);
4810
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004811 { AccumulatorValueContext context(this);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004812 VisitForTypeofValue(sub_expr);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004813 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004814 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004815
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004816 Factory* factory = isolate()->factory();
4817 if (String::Equals(check, factory->number_string())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004818 __ JumpIfSmi(rax, if_true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004819 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004820 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
4821 Split(equal, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004822 } else if (String::Equals(check, factory->string_string())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004823 __ JumpIfSmi(rax, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004824 // Check for undetectable objects => false.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004825 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
4826 __ j(above_equal, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004827 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
Leon Clarkef7060e22010-06-03 12:02:55 +01004828 Immediate(1 << Map::kIsUndetectable));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004829 Split(zero, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004830 } else if (String::Equals(check, factory->symbol_string())) {
4831 __ JumpIfSmi(rax, if_false);
4832 __ CmpObjectType(rax, SYMBOL_TYPE, rdx);
4833 Split(equal, if_true, if_false, fall_through);
4834 } else if (String::Equals(check, factory->boolean_string())) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004835 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
4836 __ j(equal, if_true);
4837 __ CompareRoot(rax, Heap::kFalseValueRootIndex);
4838 Split(equal, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004839 } else if (String::Equals(check, factory->undefined_string())) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004840 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4841 __ j(equal, if_true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004842 __ JumpIfSmi(rax, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004843 // Check for undetectable objects => true.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004844 __ movp(rdx, FieldOperand(rax, HeapObject::kMapOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004845 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4846 Immediate(1 << Map::kIsUndetectable));
4847 Split(not_zero, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004848 } else if (String::Equals(check, factory->function_string())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004849 __ JumpIfSmi(rax, if_false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004850 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4851 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx);
4852 __ j(equal, if_true);
4853 __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
4854 Split(equal, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004855 } else if (String::Equals(check, factory->object_string())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004856 __ JumpIfSmi(rax, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004857 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4858 __ j(equal, if_true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004859 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004860 __ j(below, if_false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004861 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4862 __ j(above, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004863 // Check for undetectable objects => false.
4864 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4865 Immediate(1 << Map::kIsUndetectable));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004866 Split(zero, if_true, if_false, fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004867 } else {
4868 if (if_false != fall_through) __ jmp(if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01004869 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004870 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01004871}
4872
4873
Leon Clarked91b9f72010-01-27 17:25:45 +00004874void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004875 Comment cmnt(masm_, "[ CompareOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004876 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00004877
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004878 // First we try a fast inlined version of the compare when one of
4879 // the operands is a literal.
4880 if (TryLiteralCompare(expr)) return;
4881
Leon Clarkee46be812010-01-19 14:06:41 +00004882 // Always perform the comparison for its control flow. Pack the result
4883 // into the expression's context after the comparison is performed.
Leon Clarkef7060e22010-06-03 12:02:55 +01004884 Label materialize_true, materialize_false;
4885 Label* if_true = NULL;
4886 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004887 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004888 context()->PrepareTest(&materialize_true, &materialize_false,
4889 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004890
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004891 Token::Value op = expr->op();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004892 VisitForStackValue(expr->left());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004893 switch (op) {
Leon Clarkee46be812010-01-19 14:06:41 +00004894 case Token::IN:
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004895 VisitForStackValue(expr->right());
Steve Blockd0582a62009-12-15 09:54:21 +00004896 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004897 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00004898 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004899 Split(equal, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004900 break;
Steve Blockd0582a62009-12-15 09:54:21 +00004901
4902 case Token::INSTANCEOF: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004903 VisitForStackValue(expr->right());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004904 InstanceofStub stub(isolate(), InstanceofStub::kNoFlags);
Steve Blockd0582a62009-12-15 09:54:21 +00004905 __ CallStub(&stub);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004906 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004907 __ testp(rax, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004908 // The stub returns 0 for true.
4909 Split(zero, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004910 break;
4911 }
4912
4913 default: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004914 VisitForAccumulatorValue(expr->right());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004915 Condition cc = CompareIC::ComputeCondition(op);
4916 __ Pop(rdx);
Steve Blockd0582a62009-12-15 09:54:21 +00004917
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004918 bool inline_smi_code = ShouldInlineSmiCase(op);
Steve Block1e0659c2011-05-24 12:43:12 +01004919 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004920 if (inline_smi_code) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004921 Label slow_case;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004922 __ movp(rcx, rdx);
4923 __ orp(rcx, rax);
Ben Murdoch257744e2011-11-30 15:57:28 +00004924 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004925 __ cmpp(rdx, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004926 Split(cc, if_true, if_false, NULL);
4927 __ bind(&slow_case);
4928 }
Steve Blockd0582a62009-12-15 09:54:21 +00004929
Steve Block1e0659c2011-05-24 12:43:12 +01004930 // Record position and call the compare IC.
4931 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004932 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
4933 CallIC(ic, expr->CompareOperationFeedbackId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004934 patch_site.EmitPatchInfo();
Ben Murdoch086aeea2011-05-13 15:57:08 +01004935
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004936 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004937 __ testp(rax, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004938 Split(cc, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004939 }
4940 }
4941
Leon Clarkee46be812010-01-19 14:06:41 +00004942 // Convert the result of the comparison into one expected for this
4943 // expression's context.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004944 context()->Plug(if_true, if_false);
Steve Blockd0582a62009-12-15 09:54:21 +00004945}
4946
4947
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004948void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4949 Expression* sub_expr,
4950 NilValue nil) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004951 Label materialize_true, materialize_false;
4952 Label* if_true = NULL;
4953 Label* if_false = NULL;
4954 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004955 context()->PrepareTest(&materialize_true, &materialize_false,
4956 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004957
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004958 VisitForAccumulatorValue(sub_expr);
4959 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004960 if (expr->op() == Token::EQ_STRICT) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004961 Heap::RootListIndex nil_value = nil == kNullValue ?
4962 Heap::kNullValueRootIndex :
4963 Heap::kUndefinedValueRootIndex;
4964 __ CompareRoot(rax, nil_value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004965 Split(equal, if_true, if_false, fall_through);
4966 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004967 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
4968 CallIC(ic, expr->CompareOperationFeedbackId());
4969 __ testp(rax, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004970 Split(not_zero, if_true, if_false, fall_through);
4971 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004972 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004973}
4974
4975
Leon Clarked91b9f72010-01-27 17:25:45 +00004976void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004977 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004978 context()->Plug(rax);
Leon Clarkee46be812010-01-19 14:06:41 +00004979}
4980
4981
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004982Register FullCodeGenerator::result_register() {
4983 return rax;
4984}
Leon Clarkee46be812010-01-19 14:06:41 +00004985
4986
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004987Register FullCodeGenerator::context_register() {
4988 return rsi;
4989}
4990
4991
Leon Clarked91b9f72010-01-27 17:25:45 +00004992void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004993 DCHECK(IsAligned(frame_offset, kPointerSize));
4994 __ movp(Operand(rbp, frame_offset), value);
Leon Clarkee46be812010-01-19 14:06:41 +00004995}
4996
4997
Leon Clarked91b9f72010-01-27 17:25:45 +00004998void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004999 __ movp(dst, ContextOperand(rsi, context_index));
Leon Clarkee46be812010-01-19 14:06:41 +00005000}
5001
5002
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005003void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
5004 Scope* declaration_scope = scope()->DeclarationScope();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005005 if (declaration_scope->is_script_scope() ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005006 declaration_scope->is_module_scope()) {
5007 // Contexts nested in the native context have a canonical empty function
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005008 // as their closure, not the anonymous closure containing the global
5009 // code. Pass a smi sentinel and let the runtime look up the empty
5010 // function.
5011 __ Push(Smi::FromInt(0));
5012 } else if (declaration_scope->is_eval_scope()) {
5013 // Contexts created by a call to eval have the same closure as the
5014 // context calling eval, not the anonymous closure containing the eval
5015 // code. Fetch it from the context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005016 __ Push(ContextOperand(rsi, Context::CLOSURE_INDEX));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005017 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005018 DCHECK(declaration_scope->is_function_scope());
5019 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005020 }
5021}
5022
5023
Leon Clarkee46be812010-01-19 14:06:41 +00005024// ----------------------------------------------------------------------------
5025// Non-local control flow support.
5026
5027
Leon Clarked91b9f72010-01-27 17:25:45 +00005028void FullCodeGenerator::EnterFinallyBlock() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005029 DCHECK(!result_register().is(rdx));
5030 DCHECK(!result_register().is(rcx));
Leon Clarkee46be812010-01-19 14:06:41 +00005031 // Cook return address on top of stack (smi encoded Code* delta)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005032 __ PopReturnAddressTo(rdx);
Leon Clarkee46be812010-01-19 14:06:41 +00005033 __ Move(rcx, masm_->CodeObject());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005034 __ subp(rdx, rcx);
Leon Clarkee46be812010-01-19 14:06:41 +00005035 __ Integer32ToSmi(rdx, rdx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005036 __ Push(rdx);
5037
Leon Clarkee46be812010-01-19 14:06:41 +00005038 // Store result register while executing finally block.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005039 __ Push(result_register());
5040
5041 // Store pending message while executing finally block.
5042 ExternalReference pending_message_obj =
5043 ExternalReference::address_of_pending_message_obj(isolate());
5044 __ Load(rdx, pending_message_obj);
5045 __ Push(rdx);
5046
5047 ExternalReference has_pending_message =
5048 ExternalReference::address_of_has_pending_message(isolate());
5049 __ Load(rdx, has_pending_message);
5050 __ Integer32ToSmi(rdx, rdx);
5051 __ Push(rdx);
5052
5053 ExternalReference pending_message_script =
5054 ExternalReference::address_of_pending_message_script(isolate());
5055 __ Load(rdx, pending_message_script);
5056 __ Push(rdx);
Leon Clarkee46be812010-01-19 14:06:41 +00005057}
5058
5059
Leon Clarked91b9f72010-01-27 17:25:45 +00005060void FullCodeGenerator::ExitFinallyBlock() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005061 DCHECK(!result_register().is(rdx));
5062 DCHECK(!result_register().is(rcx));
5063 // Restore pending message from stack.
5064 __ Pop(rdx);
5065 ExternalReference pending_message_script =
5066 ExternalReference::address_of_pending_message_script(isolate());
5067 __ Store(pending_message_script, rdx);
5068
5069 __ Pop(rdx);
5070 __ SmiToInteger32(rdx, rdx);
5071 ExternalReference has_pending_message =
5072 ExternalReference::address_of_has_pending_message(isolate());
5073 __ Store(has_pending_message, rdx);
5074
5075 __ Pop(rdx);
5076 ExternalReference pending_message_obj =
5077 ExternalReference::address_of_pending_message_obj(isolate());
5078 __ Store(pending_message_obj, rdx);
5079
5080 // Restore result register from stack.
5081 __ Pop(result_register());
5082
Leon Clarkee46be812010-01-19 14:06:41 +00005083 // Uncook return address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005084 __ Pop(rdx);
Leon Clarkee46be812010-01-19 14:06:41 +00005085 __ SmiToInteger32(rdx, rdx);
5086 __ Move(rcx, masm_->CodeObject());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005087 __ addp(rdx, rcx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005088 __ jmp(rdx);
Steve Blockd0582a62009-12-15 09:54:21 +00005089}
5090
5091
5092#undef __
5093
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005094#define __ ACCESS_MASM(masm())
5095
5096FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
5097 int* stack_depth,
5098 int* context_length) {
5099 // The macros used here must preserve the result register.
5100
5101 // Because the handler block contains the context of the finally
5102 // code, we can restore it directly from there for the finally code
5103 // rather than iteratively unwinding contexts via their previous
5104 // links.
5105 __ Drop(*stack_depth); // Down to the handler block.
5106 if (*context_length > 0) {
5107 // Restore the context to its dedicated register and the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005108 __ movp(rsi, Operand(rsp, StackHandlerConstants::kContextOffset));
5109 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005110 }
5111 __ PopTryHandler();
5112 __ call(finally_entry_);
5113
5114 *stack_depth = 0;
5115 *context_length = 0;
5116 return previous_;
5117}
5118
5119
5120#undef __
Steve Blockd0582a62009-12-15 09:54:21 +00005121
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005122
5123static const byte kJnsInstruction = 0x79;
5124static const byte kNopByteOne = 0x66;
5125static const byte kNopByteTwo = 0x90;
5126#ifdef DEBUG
5127static const byte kCallInstruction = 0xe8;
5128#endif
5129
5130
5131void BackEdgeTable::PatchAt(Code* unoptimized_code,
5132 Address pc,
5133 BackEdgeState target_state,
5134 Code* replacement_code) {
5135 Address call_target_address = pc - kIntSize;
5136 Address jns_instr_address = call_target_address - 3;
5137 Address jns_offset_address = call_target_address - 2;
5138
5139 switch (target_state) {
5140 case INTERRUPT:
5141 // sub <profiling_counter>, <delta> ;; Not changed
5142 // jns ok
5143 // call <interrupt stub>
5144 // ok:
5145 *jns_instr_address = kJnsInstruction;
5146 *jns_offset_address = kJnsOffset;
5147 break;
5148 case ON_STACK_REPLACEMENT:
5149 case OSR_AFTER_STACK_CHECK:
5150 // sub <profiling_counter>, <delta> ;; Not changed
5151 // nop
5152 // nop
5153 // call <on-stack replacment>
5154 // ok:
5155 *jns_instr_address = kNopByteOne;
5156 *jns_offset_address = kNopByteTwo;
5157 break;
5158 }
5159
5160 Assembler::set_target_address_at(call_target_address,
5161 unoptimized_code,
5162 replacement_code->entry());
5163 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
5164 unoptimized_code, call_target_address, replacement_code);
5165}
5166
5167
5168BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
5169 Isolate* isolate,
5170 Code* unoptimized_code,
5171 Address pc) {
5172 Address call_target_address = pc - kIntSize;
5173 Address jns_instr_address = call_target_address - 3;
5174 DCHECK_EQ(kCallInstruction, *(call_target_address - 1));
5175
5176 if (*jns_instr_address == kJnsInstruction) {
5177 DCHECK_EQ(kJnsOffset, *(call_target_address - 2));
5178 DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(),
5179 Assembler::target_address_at(call_target_address,
5180 unoptimized_code));
5181 return INTERRUPT;
5182 }
5183
5184 DCHECK_EQ(kNopByteOne, *jns_instr_address);
5185 DCHECK_EQ(kNopByteTwo, *(call_target_address - 2));
5186
5187 if (Assembler::target_address_at(call_target_address,
5188 unoptimized_code) ==
5189 isolate->builtins()->OnStackReplacement()->entry()) {
5190 return ON_STACK_REPLACEMENT;
5191 }
5192
5193 DCHECK_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(),
5194 Assembler::target_address_at(call_target_address,
5195 unoptimized_code));
5196 return OSR_AFTER_STACK_CHECK;
5197}
5198
5199
Steve Block3ce2e202009-11-05 08:53:23 +00005200} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01005201
5202#endif // V8_TARGET_ARCH_X64