blob: 19fa0aaddd733e9b42efc901b452417da12de847 [file] [log] [blame]
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001// Copyright 2012 the V8 project authors. All rights reserved.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_X64)
31
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000032#include "code-stubs.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000034#include "compiler.h"
35#include "debug.h"
36#include "full-codegen.h"
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000037#include "isolate-inl.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000038#include "parser.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000039#include "scopes.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000040#include "stub-cache.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000041
42namespace v8 {
43namespace internal {
44
45#define __ ACCESS_MASM(masm_)
46
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000047
48class JumpPatchSite BASE_EMBEDDED {
49 public:
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000050 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000051#ifdef DEBUG
52 info_emitted_ = false;
53#endif
54 }
55
56 ~JumpPatchSite() {
57 ASSERT(patch_site_.is_bound() == info_emitted_);
58 }
59
karlklose@chromium.org83a47282011-05-11 11:54:09 +000060 void EmitJumpIfNotSmi(Register reg,
61 Label* target,
62 Label::Distance near_jump = Label::kFar) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000063 __ testb(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000064 EmitJump(not_carry, target, near_jump); // Always taken before patched.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000065 }
66
karlklose@chromium.org83a47282011-05-11 11:54:09 +000067 void EmitJumpIfSmi(Register reg,
68 Label* target,
69 Label::Distance near_jump = Label::kFar) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000070 __ testb(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000071 EmitJump(carry, target, near_jump); // Never taken before patched.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000072 }
73
74 void EmitPatchInfo() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000075 if (patch_site_.is_bound()) {
76 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
77 ASSERT(is_int8(delta_to_patch_site));
78 __ testl(rax, Immediate(delta_to_patch_site));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000079#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +000080 info_emitted_ = true;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000081#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +000082 } else {
83 __ nop(); // Signals no inlined code.
84 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000085 }
86
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000087 private:
88 // jc will be patched with jz, jnc will become jnz.
karlklose@chromium.org83a47282011-05-11 11:54:09 +000089 void EmitJump(Condition cc, Label* target, Label::Distance near_jump) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000090 ASSERT(!patch_site_.is_bound() && !info_emitted_);
91 ASSERT(cc == carry || cc == not_carry);
92 __ bind(&patch_site_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +000093 __ j(cc, target, near_jump);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000094 }
95
96 MacroAssembler* masm_;
97 Label patch_site_;
98#ifdef DEBUG
99 bool info_emitted_;
100#endif
101};
102
103
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000104// Generate code for a JS function. On entry to the function the receiver
105// and arguments have been pushed on the stack left to right, with the
106// return address on top of them. The actual argument count matches the
107// formal parameter count expected by the function.
108//
109// The live registers are:
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000110// o rdi: the JS function object being called (i.e. ourselves)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000111// o rsi: our context
112// o rbp: our caller's frame pointer
113// o rsp: stack pointer (pointing to return address)
114//
115// The function builds a JS frame. Please see JavaScriptFrameConstants in
116// frames-x64.h for its layout.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000117void FullCodeGenerator::Generate() {
118 CompilationInfo* info = info_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000119 handler_table_ =
120 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000121 profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000122 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000123 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000124 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000126 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
127
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000128#ifdef DEBUG
129 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000130 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000131 __ int3();
132 }
133#endif
134
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000135 // Strict mode functions and builtins need to replace the receiver
136 // with undefined when called as functions (without an explicit
137 // receiver object). rcx is zero for method calls and non-zero for
138 // function calls.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000139 if (!info->is_classic_mode() || info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000140 Label ok;
141 __ testq(rcx, rcx);
142 __ j(zero, &ok, Label::kNear);
143 // +1 for return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000144 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000145 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
146 __ movq(Operand(rsp, receiver_offset), kScratchRegister);
147 __ bind(&ok);
148 }
149
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000150 // Open a frame scope to indicate that there is a frame on the stack. The
151 // MANUAL indicates that the scope shouldn't actually generate code to set up
152 // the frame (that is done below).
153 FrameScope frame_scope(masm_, StackFrame::MANUAL);
154
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000155 info->set_prologue_offset(masm_->pc_offset());
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000156 __ push(rbp); // Caller's frame pointer.
157 __ movq(rbp, rsp);
158 __ push(rsi); // Callee's context.
159 __ push(rdi); // Callee's JS Function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000161 { Comment cmnt(masm_, "[ Allocate locals");
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000162 int locals_count = info->scope()->num_stack_slots();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000163 // Generators allocate locals, if any, in context slots.
164 ASSERT(!info->function()->is_generator() || locals_count == 0);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000165 if (locals_count == 1) {
166 __ PushRoot(Heap::kUndefinedValueRootIndex);
167 } else if (locals_count > 1) {
168 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
169 for (int i = 0; i < locals_count; i++) {
170 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000171 }
172 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000173 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000174
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000175 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000176
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000177 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000178 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000179 if (heap_slots > 0) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000180 Comment cmnt(masm_, "[ Allocate context");
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000181 // Argument to NewContext is the function, which is still in rdi.
182 __ push(rdi);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000183 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
184 __ Push(info->scope()->GetScopeInfo());
185 __ CallRuntime(Runtime::kNewGlobalContext, 2);
186 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000187 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000188 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000189 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000190 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000191 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000192 function_in_register = false;
193 // Context is returned in both rax and rsi. It replaces the context
194 // passed to us. It's saved in the stack and kept live in rsi.
195 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
196
197 // Copy any necessary parameters into the context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000198 int num_parameters = info->scope()->num_parameters();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000199 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000200 Variable* var = scope()->parameter(i);
201 if (var->IsContextSlot()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000202 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
203 (num_parameters - 1 - i) * kPointerSize;
204 // Load parameter from stack.
205 __ movq(rax, Operand(rbp, parameter_offset));
206 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000207 int context_offset = Context::SlotOffset(var->index());
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000208 __ movq(Operand(rsi, context_offset), rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000209 // Update the write barrier. This clobbers rax and rbx.
210 __ RecordWriteContextSlot(
211 rsi, context_offset, rax, rbx, kDontSaveFPRegs);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000212 }
213 }
214 }
215
216 // Possibly allocate an arguments object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000217 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000218 if (arguments != NULL) {
219 // Arguments object must be allocated after the context object, in
220 // case the "arguments" or ".arguments" variables are in the context.
221 Comment cmnt(masm_, "[ Allocate arguments object");
222 if (function_in_register) {
223 __ push(rdi);
224 } else {
225 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
226 }
227 // The receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000228 int num_parameters = info->scope()->num_parameters();
229 int offset = num_parameters * kPointerSize;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000230 __ lea(rdx,
231 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
232 __ push(rdx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000233 __ Push(Smi::FromInt(num_parameters));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000234 // Arguments to ArgumentsAccessStub:
235 // function, receiver address, parameter count.
236 // The stub will rewrite receiver and parameter count if the previous
237 // stack frame was an arguments adapter frame.
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000238 ArgumentsAccessStub::Type type;
239 if (!is_classic_mode()) {
240 type = ArgumentsAccessStub::NEW_STRICT;
241 } else if (function()->has_duplicate_parameters()) {
242 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
243 } else {
244 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
245 }
246 ArgumentsAccessStub stub(type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000247 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000248
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000249 SetVar(arguments, rax, rbx, rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000250 }
251
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000252 if (FLAG_trace) {
253 __ CallRuntime(Runtime::kTraceEnter, 0);
254 }
255
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000256 // Visit the declarations and body unless there is an illegal
257 // redeclaration.
258 if (scope()->HasIllegalRedeclaration()) {
259 Comment cmnt(masm_, "[ Declarations");
260 scope()->VisitIllegalRedeclaration(this);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000261
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000262 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000263 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000264 { Comment cmnt(masm_, "[ Declarations");
265 // For named function expressions, declare the function name as a
266 // constant.
267 if (scope()->is_function_scope() && scope()->function() != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000268 VariableDeclaration* function = scope()->function();
269 ASSERT(function->proxy()->var()->mode() == CONST ||
270 function->proxy()->var()->mode() == CONST_HARMONY);
271 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
272 VisitVariableDeclaration(function);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000273 }
274 VisitDeclarations(scope()->declarations());
275 }
276
277 { Comment cmnt(masm_, "[ Stack check");
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000278 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000279 Label ok;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000280 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000281 __ j(above_equal, &ok, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000282 StackCheckStub stub;
283 __ CallStub(&stub);
284 __ bind(&ok);
285 }
286
287 { Comment cmnt(masm_, "[ Body");
288 ASSERT(loop_depth() == 0);
289 VisitStatements(function()->body());
290 ASSERT(loop_depth() == 0);
291 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000292 }
293
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000294 // Always emit a 'return undefined' in case control fell off the end of
295 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000296 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000297 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000298 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000299 }
300}
301
302
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000303void FullCodeGenerator::ClearAccumulator() {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000304 __ Set(rax, 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000305}
306
307
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000308void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
309 __ movq(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
310 __ SmiAddConstant(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
311 Smi::FromInt(-delta));
312}
313
314
315void FullCodeGenerator::EmitProfilingCounterReset() {
316 int reset_value = FLAG_interrupt_budget;
317 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) {
318 // Self-optimization is a one-off thing; if it fails, don't try again.
319 reset_value = Smi::kMaxValue;
320 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000321 __ movq(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
322 __ movq(kScratchRegister,
323 reinterpret_cast<uint64_t>(Smi::FromInt(reset_value)),
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000324 RelocInfo::NONE64);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000325 __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
326 kScratchRegister);
327}
328
329
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000330void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
331 Label* back_edge_target) {
332 Comment cmnt(masm_, "[ Back edge bookkeeping");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000333 Label ok;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000334
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000335 int weight = 1;
336 if (FLAG_weighted_back_edges) {
337 ASSERT(back_edge_target->is_bound());
338 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
339 weight = Min(kMaxBackEdgeWeight,
340 Max(1, distance / kBackEdgeDistanceUnit));
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000341 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000342 EmitProfilingCounterDecrement(weight);
343 __ j(positive, &ok, Label::kNear);
344 InterruptStub stub;
345 __ CallStub(&stub);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000346
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000347 // Record a mapping of this PC offset to the OSR id. This is used to find
348 // the AST id from the unoptimized code in order to use it as a key into
349 // the deoptimization input data found in the optimized code.
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000350 RecordBackEdge(stmt->OsrEntryId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000351
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000352 EmitProfilingCounterReset();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000353
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000354 __ bind(&ok);
355 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000356 // Record a mapping of the OSR id to this PC. This is used if the OSR
357 // entry becomes the target of a bailout. We don't expect it to be, but
358 // we want it to work if it is.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000359 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000360}
361
362
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000363void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000364 Comment cmnt(masm_, "[ Return sequence");
365 if (return_label_.is_bound()) {
366 __ jmp(&return_label_);
367 } else {
368 __ bind(&return_label_);
369 if (FLAG_trace) {
370 __ push(rax);
371 __ CallRuntime(Runtime::kTraceExit, 1);
372 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000373 if (FLAG_interrupt_at_exit || FLAG_self_optimization) {
374 // Pretend that the exit is a backwards jump to the entry.
375 int weight = 1;
376 if (info_->ShouldSelfOptimize()) {
377 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
378 } else if (FLAG_weighted_back_edges) {
379 int distance = masm_->pc_offset();
380 weight = Min(kMaxBackEdgeWeight,
danno@chromium.org129d3982012-07-25 15:01:47 +0000381 Max(1, distance / kBackEdgeDistanceUnit));
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000382 }
383 EmitProfilingCounterDecrement(weight);
384 Label ok;
385 __ j(positive, &ok, Label::kNear);
386 __ push(rax);
387 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) {
388 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
389 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1);
390 } else {
391 InterruptStub stub;
392 __ CallStub(&stub);
393 }
394 __ pop(rax);
395 EmitProfilingCounterReset();
396 __ bind(&ok);
397 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000398#ifdef DEBUG
399 // Add a label for checking the size of the code used for returning.
400 Label check_exit_codesize;
401 masm_->bind(&check_exit_codesize);
402#endif
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000403 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000404 __ RecordJSReturn();
405 // Do not use the leave instruction here because it is too short to
406 // patch with the code required by the debugger.
407 __ movq(rsp, rbp);
408 __ pop(rbp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000409
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000410 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000411 __ Ret(arguments_bytes, rcx);
412
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000413#ifdef ENABLE_DEBUGGER_SUPPORT
414 // Add padding that will be overwritten by a debugger breakpoint. We
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000415 // have just generated at least 7 bytes: "movq rsp, rbp; pop rbp; ret k"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000416 // (3 + 1 + 3).
417 const int kPadding = Assembler::kJSReturnSequenceLength - 7;
418 for (int i = 0; i < kPadding; ++i) {
419 masm_->int3();
420 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000421 // Check that the size of the code used for returning is large enough
422 // for the debugger's requirements.
423 ASSERT(Assembler::kJSReturnSequenceLength <=
424 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000425#endif
426 }
427}
428
429
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000430void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
431 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000432}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000433
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000434
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000435void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
436 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
437 codegen()->GetVar(result_register(), var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000438}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000439
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000440
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000441void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
442 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
443 MemOperand operand = codegen()->VarOperand(var, result_register());
444 __ push(operand);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000445}
446
447
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000448void FullCodeGenerator::TestContext::Plug(Variable* var) const {
449 codegen()->GetVar(result_register(), var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000450 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000451 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000452}
453
454
455void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
456}
457
458
459void FullCodeGenerator::AccumulatorValueContext::Plug(
460 Heap::RootListIndex index) const {
461 __ LoadRoot(result_register(), index);
462}
463
464
465void FullCodeGenerator::StackValueContext::Plug(
466 Heap::RootListIndex index) const {
467 __ PushRoot(index);
468}
469
470
471void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000472 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000473 true,
474 true_label_,
475 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000476 if (index == Heap::kUndefinedValueRootIndex ||
477 index == Heap::kNullValueRootIndex ||
478 index == Heap::kFalseValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000479 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000480 } else if (index == Heap::kTrueValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000481 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000482 } else {
483 __ LoadRoot(result_register(), index);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000484 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000485 }
486}
487
488
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000489void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
490}
491
492
493void FullCodeGenerator::AccumulatorValueContext::Plug(
494 Handle<Object> lit) const {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000495 if (lit->IsSmi()) {
496 __ SafeMove(result_register(), Smi::cast(*lit));
497 } else {
498 __ Move(result_register(), lit);
499 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000500}
501
502
503void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000504 if (lit->IsSmi()) {
505 __ SafePush(Smi::cast(*lit));
506 } else {
507 __ Push(lit);
508 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000509}
510
511
512void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000513 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000514 true,
515 true_label_,
516 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000517 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
518 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000519 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000520 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000521 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000522 } else if (lit->IsString()) {
523 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000524 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000525 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000526 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000527 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000528 } else if (lit->IsSmi()) {
529 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000530 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000531 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000532 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000533 }
534 } else {
535 // For simplicity we always test the accumulator register.
536 __ Move(result_register(), lit);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000537 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000538 }
539}
540
541
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000542void FullCodeGenerator::EffectContext::DropAndPlug(int count,
543 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000544 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000545 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000546}
547
548
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000549void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
550 int count,
551 Register reg) const {
552 ASSERT(count > 0);
553 __ Drop(count);
554 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000555}
556
557
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000558void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
559 Register reg) const {
560 ASSERT(count > 0);
561 if (count > 1) __ Drop(count - 1);
562 __ movq(Operand(rsp, 0), reg);
563}
564
565
566void FullCodeGenerator::TestContext::DropAndPlug(int count,
567 Register reg) const {
568 ASSERT(count > 0);
569 // For simplicity we always test the accumulator register.
570 __ Drop(count);
571 __ Move(result_register(), reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000572 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000574}
575
576
577void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
578 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000579 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000580 __ bind(materialize_true);
581}
582
583
584void FullCodeGenerator::AccumulatorValueContext::Plug(
585 Label* materialize_true,
586 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000587 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000588 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 __ Move(result_register(), isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000590 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000591 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000592 __ Move(result_register(), isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000593 __ bind(&done);
594}
595
596
597void FullCodeGenerator::StackValueContext::Plug(
598 Label* materialize_true,
599 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000600 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000601 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 __ Push(isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000603 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000604 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000605 __ Push(isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000606 __ bind(&done);
607}
608
609
610void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
611 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000612 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000613 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000614}
615
616
617void FullCodeGenerator::EffectContext::Plug(bool flag) const {
618}
619
620
621void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
622 Heap::RootListIndex value_root_index =
623 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
624 __ LoadRoot(result_register(), value_root_index);
625}
626
627
628void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
629 Heap::RootListIndex value_root_index =
630 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
631 __ PushRoot(value_root_index);
632}
633
634
635void FullCodeGenerator::TestContext::Plug(bool flag) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000636 codegen()->PrepareForBailoutBeforeSplit(condition(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000637 true,
638 true_label_,
639 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000640 if (flag) {
641 if (true_label_ != fall_through_) __ jmp(true_label_);
642 } else {
643 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000644 }
645}
646
647
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000648void FullCodeGenerator::DoTest(Expression* condition,
649 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000650 Label* if_false,
651 Label* fall_through) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000652 ToBooleanStub stub(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000653 __ push(result_register());
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000654 __ CallStub(&stub, condition->test_id());
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000655 __ testq(result_register(), result_register());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000656 // The stub returns nonzero for true.
657 Split(not_zero, if_true, if_false, fall_through);
658}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000659
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000660
ricow@chromium.org65fae842010-08-25 15:26:24 +0000661void FullCodeGenerator::Split(Condition cc,
662 Label* if_true,
663 Label* if_false,
664 Label* fall_through) {
665 if (if_false == fall_through) {
666 __ j(cc, if_true);
667 } else if (if_true == fall_through) {
668 __ j(NegateCondition(cc), if_false);
669 } else {
670 __ j(cc, if_true);
671 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000672 }
673}
674
675
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000676MemOperand FullCodeGenerator::StackOperand(Variable* var) {
677 ASSERT(var->IsStackAllocated());
678 // Offset is negative because higher indexes are at lower addresses.
679 int offset = -var->index() * kPointerSize;
680 // Adjust by a (parameter or local) base offset.
681 if (var->IsParameter()) {
682 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
683 } else {
684 offset += JavaScriptFrameConstants::kLocal0Offset;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000685 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000686 return Operand(rbp, offset);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000687}
688
689
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000690MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
691 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
692 if (var->IsContextSlot()) {
693 int context_chain_length = scope()->ContextChainLength(var->scope());
694 __ LoadContext(scratch, context_chain_length);
695 return ContextOperand(scratch, var->index());
696 } else {
697 return StackOperand(var);
698 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000699}
700
701
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000702void FullCodeGenerator::GetVar(Register dest, Variable* var) {
703 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
704 MemOperand location = VarOperand(var, dest);
705 __ movq(dest, location);
706}
707
708
709void FullCodeGenerator::SetVar(Variable* var,
710 Register src,
711 Register scratch0,
712 Register scratch1) {
713 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
714 ASSERT(!scratch0.is(src));
715 ASSERT(!scratch0.is(scratch1));
716 ASSERT(!scratch1.is(src));
717 MemOperand location = VarOperand(var, scratch0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000718 __ movq(location, src);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000719
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000720 // Emit the write barrier code if the location is in the heap.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000721 if (var->IsContextSlot()) {
722 int offset = Context::SlotOffset(var->index());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000723 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000724 }
725}
726
727
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000728void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000729 bool should_normalize,
730 Label* if_true,
731 Label* if_false) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000732 // Only prepare for bailouts before splits if we're in a test
733 // context. Otherwise, we let the Visit function deal with the
734 // preparation to avoid preparing with the same AST id twice.
735 if (!context()->IsTest() || !info_->IsOptimizable()) return;
736
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000737 Label skip;
738 if (should_normalize) __ jmp(&skip, Label::kNear);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000739 PrepareForBailout(expr, TOS_REG);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000740 if (should_normalize) {
741 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
742 Split(equal, if_true, if_false, NULL);
743 __ bind(&skip);
744 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000745}
746
747
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000748void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000749 // The variable in the declaration always resides in the current context.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000750 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000751 if (generate_debug_code_) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000752 // Check that we're not inside a with or catch context.
753 __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
754 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
755 __ Check(not_equal, "Declaration in with context.");
756 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
757 __ Check(not_equal, "Declaration in catch context.");
758 }
759}
760
761
762void FullCodeGenerator::VisitVariableDeclaration(
763 VariableDeclaration* declaration) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000764 // If it was not possible to allocate the variable at compile time, we
765 // need to "declare" it at runtime to make sure it actually exists in the
766 // local context.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000767 VariableProxy* proxy = declaration->proxy();
768 VariableMode mode = declaration->mode();
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000769 Variable* variable = proxy->var();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000770 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000771 switch (variable->location()) {
772 case Variable::UNALLOCATED:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000773 globals_->Add(variable->name(), zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000774 globals_->Add(variable->binding_needs_init()
775 ? isolate()->factory()->the_hole_value()
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000776 : isolate()->factory()->undefined_value(),
777 zone());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000778 break;
779
780 case Variable::PARAMETER:
781 case Variable::LOCAL:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000782 if (hole_init) {
783 Comment cmnt(masm_, "[ VariableDeclaration");
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000784 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000785 __ movq(StackOperand(variable), kScratchRegister);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000786 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000787 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000788
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000789 case Variable::CONTEXT:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000790 if (hole_init) {
791 Comment cmnt(masm_, "[ VariableDeclaration");
792 EmitDebugCheckDeclarationContext(variable);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000793 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000794 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000795 // No write barrier since the hole value is in old space.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000796 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000797 }
798 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000799
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000800 case Variable::LOOKUP: {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000801 Comment cmnt(masm_, "[ VariableDeclaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000802 __ push(rsi);
803 __ Push(variable->name());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000804 // Declaration nodes are always introduced in one of four modes.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000805 ASSERT(IsDeclaredVariableMode(mode));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000806 PropertyAttributes attr =
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000807 IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000808 __ Push(Smi::FromInt(attr));
809 // Push initial value, if any.
810 // Note: For variables we must not push an initial value (such as
811 // 'undefined') because we may have a (legal) redeclaration and we
812 // must not destroy the current value.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000813 if (hole_init) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000814 __ PushRoot(Heap::kTheHoleValueRootIndex);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000815 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000816 __ Push(Smi::FromInt(0)); // Indicates no initial value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000817 }
818 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
819 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000820 }
821 }
822}
823
824
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000825void FullCodeGenerator::VisitFunctionDeclaration(
826 FunctionDeclaration* declaration) {
827 VariableProxy* proxy = declaration->proxy();
828 Variable* variable = proxy->var();
829 switch (variable->location()) {
830 case Variable::UNALLOCATED: {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000831 globals_->Add(variable->name(), zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000832 Handle<SharedFunctionInfo> function =
833 Compiler::BuildFunctionInfo(declaration->fun(), script());
834 // Check for stack-overflow exception.
835 if (function.is_null()) return SetStackOverflow();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000836 globals_->Add(function, zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000837 break;
838 }
839
840 case Variable::PARAMETER:
841 case Variable::LOCAL: {
842 Comment cmnt(masm_, "[ FunctionDeclaration");
843 VisitForAccumulatorValue(declaration->fun());
844 __ movq(StackOperand(variable), result_register());
845 break;
846 }
847
848 case Variable::CONTEXT: {
849 Comment cmnt(masm_, "[ FunctionDeclaration");
850 EmitDebugCheckDeclarationContext(variable);
851 VisitForAccumulatorValue(declaration->fun());
852 __ movq(ContextOperand(rsi, variable->index()), result_register());
853 int offset = Context::SlotOffset(variable->index());
854 // We know that we have written a function, which is not a smi.
855 __ RecordWriteContextSlot(rsi,
856 offset,
857 result_register(),
858 rcx,
859 kDontSaveFPRegs,
860 EMIT_REMEMBERED_SET,
861 OMIT_SMI_CHECK);
862 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
863 break;
864 }
865
866 case Variable::LOOKUP: {
867 Comment cmnt(masm_, "[ FunctionDeclaration");
868 __ push(rsi);
869 __ Push(variable->name());
870 __ Push(Smi::FromInt(NONE));
871 VisitForStackValue(declaration->fun());
872 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
873 break;
874 }
875 }
876}
877
878
879void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000880 Variable* variable = declaration->proxy()->var();
881 ASSERT(variable->location() == Variable::CONTEXT);
882 ASSERT(variable->interface()->IsFrozen());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000883
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000884 Comment cmnt(masm_, "[ ModuleDeclaration");
885 EmitDebugCheckDeclarationContext(variable);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000886
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000887 // Load instance object.
888 __ LoadContext(rax, scope_->ContextChainLength(scope_->GlobalScope()));
889 __ movq(rax, ContextOperand(rax, variable->interface()->Index()));
890 __ movq(rax, ContextOperand(rax, Context::EXTENSION_INDEX));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000891
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000892 // Assign it.
893 __ movq(ContextOperand(rsi, variable->index()), rax);
894 // We know that we have written a module, which is not a smi.
895 __ RecordWriteContextSlot(rsi,
896 Context::SlotOffset(variable->index()),
897 rax,
898 rcx,
899 kDontSaveFPRegs,
900 EMIT_REMEMBERED_SET,
901 OMIT_SMI_CHECK);
902 PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
903
904 // Traverse into body.
905 Visit(declaration->module());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000906}
907
908
909void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
910 VariableProxy* proxy = declaration->proxy();
911 Variable* variable = proxy->var();
912 switch (variable->location()) {
913 case Variable::UNALLOCATED:
914 // TODO(rossberg)
915 break;
916
917 case Variable::CONTEXT: {
918 Comment cmnt(masm_, "[ ImportDeclaration");
919 EmitDebugCheckDeclarationContext(variable);
920 // TODO(rossberg)
921 break;
922 }
923
924 case Variable::PARAMETER:
925 case Variable::LOCAL:
926 case Variable::LOOKUP:
927 UNREACHABLE();
928 }
929}
930
931
932void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
933 // TODO(rossberg)
934}
935
936
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000937void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
938 // Call the runtime to declare the globals.
939 __ push(rsi); // The context is the first argument.
940 __ Push(pairs);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000941 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
942 __ CallRuntime(Runtime::kDeclareGlobals, 3);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000943 // Return value is ignored.
944}
945
946
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000947void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
948 // Call the runtime to declare the modules.
949 __ Push(descriptions);
950 __ CallRuntime(Runtime::kDeclareModules, 1);
951 // Return value is ignored.
952}
953
954
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000955void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
956 Comment cmnt(masm_, "[ SwitchStatement");
957 Breakable nested_statement(this, stmt);
958 SetStatementPosition(stmt);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000959
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000960 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000961 VisitForStackValue(stmt->tag());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000962 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000963
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000964 ZoneList<CaseClause*>* clauses = stmt->cases();
965 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000966
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000967 Label next_test; // Recycled for each test.
968 // Compile all the tests with branches to their bodies.
969 for (int i = 0; i < clauses->length(); i++) {
970 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000971 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000972
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000973 // The default is not a test, but remember it as final fall through.
974 if (clause->is_default()) {
975 default_clause = clause;
976 continue;
977 }
978
979 Comment cmnt(masm_, "[ Case comparison");
980 __ bind(&next_test);
981 next_test.Unuse();
982
983 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000984 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000985
ricow@chromium.org65fae842010-08-25 15:26:24 +0000986 // Perform the comparison as if via '==='.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000987 __ movq(rdx, Operand(rsp, 0)); // Switch value.
988 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000989 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000990 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000991 Label slow_case;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000992 __ movq(rcx, rdx);
993 __ or_(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000994 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000995
996 __ cmpq(rdx, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000997 __ j(not_equal, &next_test);
998 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000999 __ jmp(clause->body_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001000 __ bind(&slow_case);
1001 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001002
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001003 // Record position before stub call for type feedback.
1004 SetSourcePosition(clause->position());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001005 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001006 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001007 patch_site.EmitPatchInfo();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001008
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001009 __ testq(rax, rax);
1010 __ j(not_equal, &next_test);
1011 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001012 __ jmp(clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001013 }
1014
1015 // Discard the test value and jump to the default if present, otherwise to
1016 // the end of the statement.
1017 __ bind(&next_test);
1018 __ Drop(1); // Switch value is no longer needed.
1019 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001020 __ jmp(nested_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001021 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001022 __ jmp(default_clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001023 }
1024
1025 // Compile all the case bodies.
1026 for (int i = 0; i < clauses->length(); i++) {
1027 Comment cmnt(masm_, "[ Case body");
1028 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001029 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001030 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001031 VisitStatements(clause->statements());
1032 }
1033
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001034 __ bind(nested_statement.break_label());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001035 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001036}
1037
1038
1039void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1040 Comment cmnt(masm_, "[ ForInStatement");
1041 SetStatementPosition(stmt);
1042
1043 Label loop, exit;
1044 ForIn loop_statement(this, stmt);
1045 increment_loop_depth();
1046
1047 // Get the object to enumerate over. Both SpiderMonkey and JSC
1048 // ignore null and undefined in contrast to the specification; see
1049 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001050 VisitForAccumulatorValue(stmt->enumerable());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001051 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
1052 __ j(equal, &exit);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001053 Register null_value = rdi;
1054 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
1055 __ cmpq(rax, null_value);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001056 __ j(equal, &exit);
1057
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001058 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1059
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001060 // Convert the object to a JS object.
1061 Label convert, done_convert;
1062 __ JumpIfSmi(rax, &convert);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001063 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001064 __ j(above_equal, &done_convert);
1065 __ bind(&convert);
1066 __ push(rax);
1067 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1068 __ bind(&done_convert);
1069 __ push(rax);
1070
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001071 // Check for proxies.
1072 Label call_runtime;
1073 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1074 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
1075 __ j(below_equal, &call_runtime);
1076
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001077 // Check cache validity in generated code. This is a fast case for
1078 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1079 // guarantee cache validity, call the runtime system to check cache
1080 // validity or get the property names in a fixed array.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001081 __ CheckEnumCache(null_value, &call_runtime);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001082
1083 // The enum cache is valid. Load the map of the object being
1084 // iterated over and use the cache for the iteration.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001085 Label use_cache;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001086 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001087 __ jmp(&use_cache, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001088
1089 // Get the set of properties to enumerate.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001090 __ bind(&call_runtime);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001091 __ push(rax); // Duplicate the enumerable object on the stack.
1092 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1093
1094 // If we got a map from the runtime call, we can do a fast
1095 // modification check. Otherwise, we got a fixed array, and we have
1096 // to do a slow check.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001097 Label fixed_array;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001098 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1099 Heap::kMetaMapRootIndex);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001100 __ j(not_equal, &fixed_array);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001101
1102 // We got a map in register rax. Get the enumeration cache from it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001103 __ bind(&use_cache);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001104
1105 Label no_descriptors;
1106
1107 __ EnumLength(rdx, rax);
1108 __ Cmp(rdx, Smi::FromInt(0));
1109 __ j(equal, &no_descriptors);
1110
danno@chromium.org40cb8782011-05-25 07:58:50 +00001111 __ LoadInstanceDescriptors(rax, rcx);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001112 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheOffset));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001113 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001114
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001115 // Set up the four remaining stack slots.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001116 __ push(rax); // Map.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001117 __ push(rcx); // Enumeration cache.
1118 __ push(rdx); // Number of valid entries for the map in the enum cache.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001119 __ Push(Smi::FromInt(0)); // Initial index.
1120 __ jmp(&loop);
1121
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001122 __ bind(&no_descriptors);
1123 __ addq(rsp, Immediate(kPointerSize));
1124 __ jmp(&exit);
1125
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001126 // We got a fixed array in register rax. Iterate through that.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001127 Label non_proxy;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001128 __ bind(&fixed_array);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001129
1130 Handle<JSGlobalPropertyCell> cell =
1131 isolate()->factory()->NewJSGlobalPropertyCell(
1132 Handle<Object>(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001133 Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker),
1134 isolate()));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001135 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001136 __ LoadHeapObject(rbx, cell);
1137 __ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
1138 Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker));
1139
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001140 __ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check
1141 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
1142 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1143 __ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx);
1144 __ j(above, &non_proxy);
1145 __ Move(rbx, Smi::FromInt(0)); // Zero indicates proxy
1146 __ bind(&non_proxy);
1147 __ push(rbx); // Smi
1148 __ push(rax); // Array
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001149 __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001150 __ push(rax); // Fixed array length (as smi).
1151 __ Push(Smi::FromInt(0)); // Initial index.
1152
1153 // Generate code for doing the condition check.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001154 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001155 __ bind(&loop);
1156 __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
1157 __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001158 __ j(above_equal, loop_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001159
1160 // Get the current entry of the array into register rbx.
1161 __ movq(rbx, Operand(rsp, 2 * kPointerSize));
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00001162 SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001163 __ movq(rbx, FieldOperand(rbx,
1164 index.reg,
1165 index.scale,
1166 FixedArray::kHeaderSize));
1167
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001168 // Get the expected map from the stack or a smi in the
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001169 // permanent slow case into register rdx.
1170 __ movq(rdx, Operand(rsp, 3 * kPointerSize));
1171
1172 // Check if the expected map still matches that of the enumerable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001173 // If not, we may have to filter the key.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001174 Label update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001175 __ movq(rcx, Operand(rsp, 4 * kPointerSize));
1176 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001177 __ j(equal, &update_each, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001178
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001179 // For proxies, no filtering is done.
1180 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1181 __ Cmp(rdx, Smi::FromInt(0));
1182 __ j(equal, &update_each, Label::kNear);
1183
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001184 // Convert the entry to a string or null if it isn't a property
1185 // anymore. If the property has been removed while iterating, we
1186 // just skip it.
1187 __ push(rcx); // Enumerable.
1188 __ push(rbx); // Current entry.
1189 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001190 __ Cmp(rax, Smi::FromInt(0));
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001191 __ j(equal, loop_statement.continue_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001192 __ movq(rbx, rax);
1193
1194 // Update the 'each' property or variable from the possibly filtered
1195 // entry in register rbx.
1196 __ bind(&update_each);
1197 __ movq(result_register(), rbx);
1198 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001199 { EffectContext context(this);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001200 EmitAssignment(stmt->each());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001201 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001202
1203 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001204 Visit(stmt->body());
1205
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001206 // Generate code for going to the next element by incrementing the
1207 // index (smi) stored on top of the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001208 __ bind(loop_statement.continue_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001209 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001210
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001211 EmitBackEdgeBookkeeping(stmt, &loop);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001212 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001213
1214 // Remove the pointers stored on the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001215 __ bind(loop_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001216 __ addq(rsp, Immediate(5 * kPointerSize));
1217
1218 // Exit and decrement the loop depth.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001219 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001220 __ bind(&exit);
1221 decrement_loop_depth();
1222}
1223
1224
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001225void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1226 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001227 // Use the fast case closure allocation code that allocates in new
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001228 // space for nested functions that don't need literals cloning. If
1229 // we're running with the --always-opt or the --prepare-always-opt
1230 // flag, we need to use the runtime function so that the new function
1231 // we are creating here gets a chance to have its code optimized and
1232 // doesn't just get a copy of the existing unoptimized code.
1233 if (!FLAG_always_opt &&
1234 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 !pretenure &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001236 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001237 info->num_literals() == 0) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001238 FastNewClosureStub stub(info->language_mode(), info->is_generator());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001239 __ Push(info);
1240 __ CallStub(&stub);
1241 } else {
1242 __ push(rsi);
1243 __ Push(info);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001244 __ Push(pretenure
1245 ? isolate()->factory()->true_value()
1246 : isolate()->factory()->false_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001247 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001248 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001249 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001250}
1251
1252
1253void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1254 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001255 EmitVariableLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001256}
1257
1258
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001259void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1260 TypeofState typeof_state,
1261 Label* slow) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001262 Register context = rsi;
1263 Register temp = rdx;
1264
1265 Scope* s = scope();
1266 while (s != NULL) {
1267 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001268 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001269 // Check that extension is NULL.
1270 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1271 Immediate(0));
1272 __ j(not_equal, slow);
1273 }
1274 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001275 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001276 // Walk the rest of the chain without clobbering rsi.
1277 context = temp;
1278 }
1279 // If no outer scope calls eval, we do not need to check more
1280 // context extensions. If we have reached an eval scope, we check
1281 // all extensions from this point.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001282 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001283 s = s->outer_scope();
1284 }
1285
1286 if (s != NULL && s->is_eval_scope()) {
1287 // Loop up the context chain. There is no frame effect so it is
1288 // safe to use raw labels here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001289 Label next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001290 if (!context.is(temp)) {
1291 __ movq(temp, context);
1292 }
1293 // Load map for comparison into register, outside loop.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001294 __ LoadRoot(kScratchRegister, Heap::kNativeContextMapRootIndex);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001295 __ bind(&next);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001296 // Terminate at native context.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001297 __ cmpq(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001298 __ j(equal, &fast, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001299 // Check that extension is NULL.
1300 __ cmpq(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1301 __ j(not_equal, slow);
1302 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001303 __ movq(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001304 __ jmp(&next);
1305 __ bind(&fast);
1306 }
1307
1308 // All extension objects were empty and it is safe to use a global
1309 // load IC call.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001310 __ movq(rax, GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001311 __ Move(rcx, var->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001312 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001313 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1314 ? RelocInfo::CODE_TARGET
1315 : RelocInfo::CODE_TARGET_CONTEXT;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001316 CallIC(ic, mode);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001317}
1318
1319
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001320MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1321 Label* slow) {
1322 ASSERT(var->IsContextSlot());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001323 Register context = rsi;
1324 Register temp = rbx;
1325
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001326 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001327 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001328 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001329 // Check that extension is NULL.
1330 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1331 Immediate(0));
1332 __ j(not_equal, slow);
1333 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001334 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001335 // Walk the rest of the chain without clobbering rsi.
1336 context = temp;
1337 }
1338 }
1339 // Check that last extension is NULL.
1340 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1341 __ j(not_equal, slow);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001342
1343 // This function is used only for loads, not stores, so it's safe to
1344 // return an rsi-based operand (the write barrier cannot be allowed to
1345 // destroy the rsi register).
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001346 return ContextOperand(context, var->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001347}
1348
1349
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001350void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1351 TypeofState typeof_state,
1352 Label* slow,
1353 Label* done) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001354 // Generate fast-case code for variables that might be shadowed by
1355 // eval-introduced variables. Eval is used a lot without
1356 // introducing variables. In those cases, we do not want to
1357 // perform a runtime call for all variables in the scope
1358 // containing the eval.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001359 if (var->mode() == DYNAMIC_GLOBAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001360 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001361 __ jmp(done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001362 } else if (var->mode() == DYNAMIC_LOCAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001363 Variable* local = var->local_if_not_shadowed();
1364 __ movq(rax, ContextSlotOperandCheckExtensions(local, slow));
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001365 if (local->mode() == LET ||
1366 local->mode() == CONST ||
1367 local->mode() == CONST_HARMONY) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001368 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1369 __ j(not_equal, done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001370 if (local->mode() == CONST) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001371 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001372 } else { // LET || CONST_HARMONY
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001373 __ Push(var->name());
1374 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1375 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001376 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001377 __ jmp(done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001378 }
1379}
1380
1381
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001382void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1383 // Record position before possible IC call.
1384 SetSourcePosition(proxy->position());
1385 Variable* var = proxy->var();
1386
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001387 // Three cases: global variables, lookup variables, and all other types of
1388 // variables.
1389 switch (var->location()) {
1390 case Variable::UNALLOCATED: {
1391 Comment cmnt(masm_, "Global variable");
1392 // Use inline caching. Variable name is passed in rcx and the global
1393 // object on the stack.
1394 __ Move(rcx, var->name());
1395 __ movq(rax, GlobalObjectOperand());
1396 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001397 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001398 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001399 break;
1400 }
1401
1402 case Variable::PARAMETER:
1403 case Variable::LOCAL:
1404 case Variable::CONTEXT: {
1405 Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot");
danno@chromium.orgc612e022011-11-10 11:38:15 +00001406 if (var->binding_needs_init()) {
1407 // var->scope() may be NULL when the proxy is located in eval code and
1408 // refers to a potential outside binding. Currently those bindings are
1409 // always looked up dynamically, i.e. in that case
1410 // var->location() == LOOKUP.
1411 // always holds.
1412 ASSERT(var->scope() != NULL);
1413
1414 // Check if the binding really needs an initialization check. The check
1415 // can be skipped in the following situation: we have a LET or CONST
1416 // binding in harmony mode, both the Variable and the VariableProxy have
1417 // the same declaration scope (i.e. they are both in global code, in the
1418 // same function or in the same eval code) and the VariableProxy is in
1419 // the source physically located after the initializer of the variable.
1420 //
1421 // We cannot skip any initialization checks for CONST in non-harmony
1422 // mode because const variables may be declared but never initialized:
1423 // if (false) { const x; }; var y = x;
1424 //
1425 // The condition on the declaration scopes is a conservative check for
1426 // nested functions that access a binding and are called before the
1427 // binding is initialized:
1428 // function() { f(); let x = 1; function f() { x = 2; } }
1429 //
1430 bool skip_init_check;
1431 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1432 skip_init_check = false;
jkummerow@chromium.orgac45fed2011-11-07 13:11:02 +00001433 } else {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001434 // Check that we always have valid source position.
1435 ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1436 ASSERT(proxy->position() != RelocInfo::kNoPosition);
1437 skip_init_check = var->mode() != CONST &&
1438 var->initializer_position() < proxy->position();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001439 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001440
1441 if (!skip_init_check) {
1442 // Let and const need a read barrier.
1443 Label done;
1444 GetVar(rax, var);
1445 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1446 __ j(not_equal, &done, Label::kNear);
1447 if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1448 // Throw a reference error when using an uninitialized let/const
1449 // binding in harmony mode.
1450 __ Push(var->name());
1451 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1452 } else {
1453 // Uninitalized const bindings outside of harmony mode are unholed.
1454 ASSERT(var->mode() == CONST);
1455 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1456 }
1457 __ bind(&done);
1458 context()->Plug(rax);
1459 break;
1460 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001461 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001462 context()->Plug(var);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001463 break;
1464 }
1465
1466 case Variable::LOOKUP: {
1467 Label done, slow;
1468 // Generate code for loading from variables potentially shadowed
1469 // by eval-introduced variables.
1470 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1471 __ bind(&slow);
1472 Comment cmnt(masm_, "Lookup slot");
1473 __ push(rsi); // Context.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001474 __ Push(var->name());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001475 __ CallRuntime(Runtime::kLoadContextSlot, 2);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001476 __ bind(&done);
1477 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001478 break;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001479 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001480 }
1481}
1482
1483
1484void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1485 Comment cmnt(masm_, "[ RegExpLiteral");
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001486 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001487 // Registers will be used as follows:
1488 // rdi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001489 // rcx = literals array.
1490 // rbx = regexp literal.
1491 // rax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001492 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001493 __ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001494 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001495 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001496 __ movq(rbx, FieldOperand(rcx, literal_offset));
1497 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001498 __ j(not_equal, &materialized, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001499
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001500 // Create regexp literal using runtime function
1501 // Result will be in rax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001502 __ push(rcx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001503 __ Push(Smi::FromInt(expr->literal_index()));
1504 __ Push(expr->pattern());
1505 __ Push(expr->flags());
1506 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001507 __ movq(rbx, rax);
1508
1509 __ bind(&materialized);
1510 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1511 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001512 __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001513 __ jmp(&allocated);
1514
1515 __ bind(&runtime_allocate);
1516 __ push(rbx);
1517 __ Push(Smi::FromInt(size));
1518 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1519 __ pop(rbx);
1520
1521 __ bind(&allocated);
1522 // Copy the content into the newly allocated memory.
1523 // (Unroll copy loop once for better throughput).
1524 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1525 __ movq(rdx, FieldOperand(rbx, i));
1526 __ movq(rcx, FieldOperand(rbx, i + kPointerSize));
1527 __ movq(FieldOperand(rax, i), rdx);
1528 __ movq(FieldOperand(rax, i + kPointerSize), rcx);
1529 }
1530 if ((size % (2 * kPointerSize)) != 0) {
1531 __ movq(rdx, FieldOperand(rbx, size - kPointerSize));
1532 __ movq(FieldOperand(rax, size - kPointerSize), rdx);
1533 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001534 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001535}
1536
1537
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001538void FullCodeGenerator::EmitAccessor(Expression* expression) {
1539 if (expression == NULL) {
1540 __ PushRoot(Heap::kNullValueRootIndex);
1541 } else {
1542 VisitForStackValue(expression);
1543 }
1544}
1545
1546
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001547void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1548 Comment cmnt(masm_, "[ ObjectLiteral");
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001549 Handle<FixedArray> constant_properties = expr->constant_properties();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001550 int flags = expr->fast_elements()
1551 ? ObjectLiteral::kFastElements
1552 : ObjectLiteral::kNoFlags;
1553 flags |= expr->has_function()
1554 ? ObjectLiteral::kHasFunction
1555 : ObjectLiteral::kNoFlags;
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001556 int properties_count = constant_properties->length() / 2;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001557 if ((FLAG_track_double_fields && expr->may_store_doubles()) ||
1558 expr->depth() > 1) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001559 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1560 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
1561 __ Push(Smi::FromInt(expr->literal_index()));
1562 __ Push(constant_properties);
1563 __ Push(Smi::FromInt(flags));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001564 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001565 } else if (Serializer::enabled() || flags != ObjectLiteral::kFastElements ||
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001566 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001567 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1568 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
1569 __ Push(Smi::FromInt(expr->literal_index()));
1570 __ Push(constant_properties);
1571 __ Push(Smi::FromInt(flags));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001572 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001573 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001574 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1575 __ movq(rax, FieldOperand(rdi, JSFunction::kLiteralsOffset));
1576 __ Move(rbx, Smi::FromInt(expr->literal_index()));
1577 __ Move(rcx, constant_properties);
1578 __ Move(rdx, Smi::FromInt(flags));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001579 FastCloneShallowObjectStub stub(properties_count);
1580 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001581 }
1582
1583 // If result_saved is true the result is on top of the stack. If
1584 // result_saved is false the result is in rax.
1585 bool result_saved = false;
1586
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001587 // Mark all computed expressions that are bound to a key that
1588 // is shadowed by a later occurrence of the same key. For the
1589 // marked expressions, no store code is emitted.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001590 expr->CalculateEmitStore(zone());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001591
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001592 AccessorTable accessor_table(zone());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001593 for (int i = 0; i < expr->properties()->length(); i++) {
1594 ObjectLiteral::Property* property = expr->properties()->at(i);
1595 if (property->IsCompileTimeValue()) continue;
1596
1597 Literal* key = property->key();
1598 Expression* value = property->value();
1599 if (!result_saved) {
1600 __ push(rax); // Save result on the stack
1601 result_saved = true;
1602 }
1603 switch (property->kind()) {
1604 case ObjectLiteral::Property::CONSTANT:
1605 UNREACHABLE();
1606 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1607 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1608 // Fall through.
1609 case ObjectLiteral::Property::COMPUTED:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001610 if (key->handle()->IsInternalizedString()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001611 if (property->emit_store()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001612 VisitForAccumulatorValue(value);
1613 __ Move(rcx, key->handle());
1614 __ movq(rdx, Operand(rsp, 0));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001615 Handle<Code> ic = is_classic_mode()
1616 ? isolate()->builtins()->StoreIC_Initialize()
1617 : isolate()->builtins()->StoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001618 CallIC(ic, RelocInfo::CODE_TARGET, key->LiteralFeedbackId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001619 PrepareForBailoutForId(key->id(), NO_REGISTERS);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001620 } else {
1621 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001622 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001623 break;
1624 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001625 __ push(Operand(rsp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001626 VisitForStackValue(key);
1627 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001628 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001629 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1630 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001631 } else {
1632 __ Drop(3);
1633 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001634 break;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001635 case ObjectLiteral::Property::PROTOTYPE:
1636 __ push(Operand(rsp, 0)); // Duplicate receiver.
1637 VisitForStackValue(value);
1638 if (property->emit_store()) {
1639 __ CallRuntime(Runtime::kSetPrototype, 2);
1640 } else {
1641 __ Drop(2);
1642 }
1643 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001644 case ObjectLiteral::Property::GETTER:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001645 accessor_table.lookup(key)->second->getter = value;
1646 break;
1647 case ObjectLiteral::Property::SETTER:
1648 accessor_table.lookup(key)->second->setter = value;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001649 break;
1650 }
1651 }
1652
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001653 // Emit code to define accessors, using only a single call to the runtime for
1654 // each pair of corresponding getters and setters.
1655 for (AccessorTable::Iterator it = accessor_table.begin();
1656 it != accessor_table.end();
1657 ++it) {
1658 __ push(Operand(rsp, 0)); // Duplicate receiver.
1659 VisitForStackValue(it->first);
1660 EmitAccessor(it->second->getter);
1661 EmitAccessor(it->second->setter);
1662 __ Push(Smi::FromInt(NONE));
1663 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
1664 }
1665
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001666 if (expr->has_function()) {
1667 ASSERT(result_saved);
1668 __ push(Operand(rsp, 0));
1669 __ CallRuntime(Runtime::kToFastProperties, 1);
1670 }
1671
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001672 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001673 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001674 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001675 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001676 }
1677}
1678
1679
1680void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1681 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001682
1683 ZoneList<Expression*>* subexprs = expr->values();
1684 int length = subexprs->length();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001685 Handle<FixedArray> constant_elements = expr->constant_elements();
1686 ASSERT_EQ(2, constant_elements->length());
1687 ElementsKind constant_elements_kind =
1688 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001689 bool has_constant_fast_elements =
1690 IsFastObjectElementsKind(constant_elements_kind);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001691 Handle<FixedArrayBase> constant_elements_values(
1692 FixedArrayBase::cast(constant_elements->get(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001693
erikcorry0ad885c2011-11-21 13:51:57 +00001694 Heap* heap = isolate()->heap();
1695 if (has_constant_fast_elements &&
1696 constant_elements_values->map() == heap->fixed_cow_array_map()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001697 // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
erikcorry0ad885c2011-11-21 13:51:57 +00001698 // change, so it's possible to specialize the stub in advance.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001699 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001700 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1701 __ movq(rax, FieldOperand(rbx, JSFunction::kLiteralsOffset));
1702 __ Move(rbx, Smi::FromInt(expr->literal_index()));
1703 __ Move(rcx, constant_elements);
erikcorry0ad885c2011-11-21 13:51:57 +00001704 FastCloneShallowArrayStub stub(
1705 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001706 DONT_TRACK_ALLOCATION_SITE,
erikcorry0ad885c2011-11-21 13:51:57 +00001707 length);
1708 __ CallStub(&stub);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001709 } else if (expr->depth() > 1) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001710 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1711 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1712 __ Push(Smi::FromInt(expr->literal_index()));
1713 __ Push(constant_elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001714 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001715 } else if (Serializer::enabled() ||
1716 length > FastCloneShallowArrayStub::kMaximumClonedLength) {
1717 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1718 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1719 __ Push(Smi::FromInt(expr->literal_index()));
1720 __ Push(constant_elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001721 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001722 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001723 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001724 FLAG_smi_only_arrays);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001725 FastCloneShallowArrayStub::Mode mode =
1726 FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
1727 AllocationSiteMode allocation_site_mode = FLAG_track_allocation_sites
1728 ? TRACK_ALLOCATION_SITE : DONT_TRACK_ALLOCATION_SITE;
1729
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001730 // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
erikcorry0ad885c2011-11-21 13:51:57 +00001731 // change, so it's possible to specialize the stub in advance.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001732 if (has_constant_fast_elements) {
1733 mode = FastCloneShallowArrayStub::CLONE_ELEMENTS;
1734 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001735 }
1736
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001737 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1738 __ movq(rax, FieldOperand(rbx, JSFunction::kLiteralsOffset));
1739 __ Move(rbx, Smi::FromInt(expr->literal_index()));
1740 __ Move(rcx, constant_elements);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001741 FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001742 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001743 }
1744
1745 bool result_saved = false; // Is the result saved to the stack?
1746
1747 // Emit code to evaluate all the non-constant subexpressions and to store
1748 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001749 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001750 Expression* subexpr = subexprs->at(i);
1751 // If the subexpression is a literal or a simple materialized literal it
1752 // is already set in the cloned array.
1753 if (subexpr->AsLiteral() != NULL ||
1754 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1755 continue;
1756 }
1757
1758 if (!result_saved) {
1759 __ push(rax);
1760 result_saved = true;
1761 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001762 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001763
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001764 if (IsFastObjectElementsKind(constant_elements_kind)) {
1765 // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
1766 // cannot transition and don't need to call the runtime stub.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001767 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1768 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1769 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
1770 // Store the subexpression value in the array's elements.
1771 __ movq(FieldOperand(rbx, offset), result_register());
1772 // Update the write barrier for the array store.
1773 __ RecordWriteField(rbx, offset, result_register(), rcx,
1774 kDontSaveFPRegs,
1775 EMIT_REMEMBERED_SET,
1776 INLINE_SMI_CHECK);
1777 } else {
1778 // Store the subexpression value in the array's elements.
1779 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1780 __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
1781 __ Move(rcx, Smi::FromInt(i));
1782 __ Move(rdx, Smi::FromInt(expr->literal_index()));
1783 StoreArrayLiteralElementStub stub;
1784 __ CallStub(&stub);
1785 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001786
1787 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001788 }
1789
1790 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001791 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001792 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001793 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001794 }
1795}
1796
1797
ager@chromium.org5c838252010-02-19 08:53:10 +00001798void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1799 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001800 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1801 // on the left-hand side.
1802 if (!expr->target()->IsValidLeftHandSide()) {
1803 VisitForEffect(expr->target());
1804 return;
1805 }
1806
ager@chromium.org5c838252010-02-19 08:53:10 +00001807 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001808 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001809 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1810 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001811 Property* property = expr->target()->AsProperty();
1812 if (property != NULL) {
1813 assign_type = (property->key()->IsPropertyName())
1814 ? NAMED_PROPERTY
1815 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001816 }
1817
1818 // Evaluate LHS expression.
1819 switch (assign_type) {
1820 case VARIABLE:
1821 // Nothing to do here.
1822 break;
1823 case NAMED_PROPERTY:
1824 if (expr->is_compound()) {
1825 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001826 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001827 __ push(result_register());
1828 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001829 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001830 }
1831 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001833 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001834 VisitForStackValue(property->obj());
1835 VisitForAccumulatorValue(property->key());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001836 __ movq(rdx, Operand(rsp, 0));
1837 __ push(rax);
1838 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001839 VisitForStackValue(property->obj());
1840 VisitForStackValue(property->key());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001841 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001842 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001843 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001844 }
1845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001846 // For compound assignments we need another deoptimization point after the
1847 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001848 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001849 { AccumulatorValueContext context(this);
1850 switch (assign_type) {
1851 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001852 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001853 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001854 break;
1855 case NAMED_PROPERTY:
1856 EmitNamedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001857 PrepareForBailoutForId(property->LoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001858 break;
1859 case KEYED_PROPERTY:
1860 EmitKeyedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001861 PrepareForBailoutForId(property->LoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001862 break;
1863 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001864 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001865
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001866 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001867 __ push(rax); // Left operand goes on the stack.
1868 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001869
ricow@chromium.org65fae842010-08-25 15:26:24 +00001870 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1871 ? OVERWRITE_RIGHT
1872 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001873 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001874 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001875 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001876 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001877 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001878 mode,
1879 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001880 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001881 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001882 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001883 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001884 // Deoptimization point in case the binary operation may have side effects.
1885 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001886 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001887 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001888 }
1889
1890 // Record source position before possible IC call.
1891 SetSourcePosition(expr->position());
1892
1893 // Store the value.
1894 switch (assign_type) {
1895 case VARIABLE:
1896 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001897 expr->op());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001898 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001899 context()->Plug(rax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001900 break;
1901 case NAMED_PROPERTY:
1902 EmitNamedPropertyAssignment(expr);
1903 break;
1904 case KEYED_PROPERTY:
1905 EmitKeyedPropertyAssignment(expr);
1906 break;
1907 }
1908}
1909
1910
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001911void FullCodeGenerator::VisitYield(Yield* expr) {
1912 Comment cmnt(masm_, "[ Yield");
1913 // Evaluate yielded value first; the initial iterator definition depends on
1914 // this. It stays on the stack while we update the iterator.
1915 VisitForStackValue(expr->expression());
1916
1917 switch (expr->yield_kind()) {
1918 case Yield::INITIAL:
1919 case Yield::SUSPEND: {
1920 VisitForStackValue(expr->generator_object());
1921 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
1922 __ movq(context_register(),
1923 Operand(rbp, StandardFrameConstants::kContextOffset));
1924
1925 Label resume;
1926 __ CompareRoot(result_register(), Heap::kTheHoleValueRootIndex);
1927 __ j(not_equal, &resume);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001928 if (expr->yield_kind() == Yield::SUSPEND) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001929 EmitReturnIteratorResult(false);
1930 } else {
1931 __ pop(result_register());
1932 EmitReturnSequence();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001933 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001934
1935 __ bind(&resume);
1936 context()->Plug(result_register());
1937 break;
1938 }
1939
1940 case Yield::FINAL: {
1941 VisitForAccumulatorValue(expr->generator_object());
1942 __ Move(FieldOperand(result_register(),
1943 JSGeneratorObject::kContinuationOffset),
1944 Smi::FromInt(JSGeneratorObject::kGeneratorClosed));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001945 EmitReturnIteratorResult(true);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001946 break;
1947 }
1948
1949 case Yield::DELEGATING:
1950 UNIMPLEMENTED();
1951 }
1952}
1953
1954
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001955void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
1956 Expression *value,
1957 JSGeneratorObject::ResumeMode resume_mode) {
1958 // The value stays in rax, and is ultimately read by the resumed generator, as
1959 // if the CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. rbx
1960 // will hold the generator object until the activation has been resumed.
1961 VisitForStackValue(generator);
1962 VisitForAccumulatorValue(value);
1963 __ pop(rbx);
1964
1965 // Check generator state.
1966 Label wrong_state, done;
1967 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0);
1968 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0);
1969 __ SmiCompare(FieldOperand(rbx, JSGeneratorObject::kContinuationOffset),
1970 Smi::FromInt(0));
1971 __ j(less_equal, &wrong_state);
1972
1973 // Load suspended function and context.
1974 __ movq(rsi, FieldOperand(rbx, JSGeneratorObject::kContextOffset));
1975 __ movq(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset));
1976
1977 // Push receiver.
1978 __ push(FieldOperand(rbx, JSGeneratorObject::kReceiverOffset));
1979
1980 // Push holes for arguments to generator function.
1981 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
1982 __ movsxlq(rdx,
1983 FieldOperand(rdx,
1984 SharedFunctionInfo::kFormalParameterCountOffset));
1985 __ LoadRoot(rcx, Heap::kTheHoleValueRootIndex);
1986 Label push_argument_holes, push_frame;
1987 __ bind(&push_argument_holes);
1988 __ subq(rdx, Immediate(1));
1989 __ j(carry, &push_frame);
1990 __ push(rcx);
1991 __ jmp(&push_argument_holes);
1992
1993 // Enter a new JavaScript frame, and initialize its slots as they were when
1994 // the generator was suspended.
1995 Label resume_frame;
1996 __ bind(&push_frame);
1997 __ call(&resume_frame);
1998 __ jmp(&done);
1999 __ bind(&resume_frame);
2000 __ push(rbp); // Caller's frame pointer.
2001 __ movq(rbp, rsp);
2002 __ push(rsi); // Callee's context.
2003 __ push(rdi); // Callee's JS Function.
2004
2005 // Load the operand stack size.
2006 __ movq(rdx, FieldOperand(rbx, JSGeneratorObject::kOperandStackOffset));
2007 __ movq(rdx, FieldOperand(rdx, FixedArray::kLengthOffset));
2008 __ SmiToInteger32(rdx, rdx);
2009
2010 // If we are sending a value and there is no operand stack, we can jump back
2011 // in directly.
2012 if (resume_mode == JSGeneratorObject::SEND) {
2013 Label slow_resume;
2014 __ cmpq(rdx, Immediate(0));
2015 __ j(not_zero, &slow_resume);
2016 __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2017 __ SmiToInteger64(rcx,
2018 FieldOperand(rbx, JSGeneratorObject::kContinuationOffset));
2019 __ addq(rdx, rcx);
2020 __ Move(FieldOperand(rbx, JSGeneratorObject::kContinuationOffset),
2021 Smi::FromInt(JSGeneratorObject::kGeneratorExecuting));
2022 __ jmp(rdx);
2023 __ bind(&slow_resume);
2024 }
2025
2026 // Otherwise, we push holes for the operand stack and call the runtime to fix
2027 // up the stack and the handlers.
2028 Label push_operand_holes, call_resume;
2029 __ bind(&push_operand_holes);
2030 __ subq(rdx, Immediate(1));
2031 __ j(carry, &call_resume);
2032 __ push(rcx);
2033 __ jmp(&push_operand_holes);
2034 __ bind(&call_resume);
2035 __ push(rbx);
2036 __ push(result_register());
2037 __ Push(Smi::FromInt(resume_mode));
2038 __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
2039 // Not reached: the runtime call returns elsewhere.
2040 __ Abort("Generator failed to resume.");
2041
2042 // Throw error if we attempt to operate on a running generator.
2043 __ bind(&wrong_state);
2044 __ push(rbx);
2045 __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
2046
2047 __ bind(&done);
2048 context()->Plug(result_register());
2049}
2050
2051
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002052void FullCodeGenerator::EmitReturnIteratorResult(bool done) {
2053 Label gc_required;
2054 Label allocated;
2055
2056 Handle<Map> map(isolate()->native_context()->generator_result_map());
2057
2058 __ Allocate(map->instance_size(), rax, rcx, rdx, &gc_required, TAG_OBJECT);
2059
2060 __ bind(&allocated);
2061 __ Move(rbx, map);
2062 __ pop(rcx);
2063 __ Move(rdx, isolate()->factory()->ToBoolean(done));
2064 ASSERT_EQ(map->instance_size(), 5 * kPointerSize);
2065 __ movq(FieldOperand(rax, HeapObject::kMapOffset), rbx);
2066 __ Move(FieldOperand(rax, JSObject::kPropertiesOffset),
2067 isolate()->factory()->empty_fixed_array());
2068 __ Move(FieldOperand(rax, JSObject::kElementsOffset),
2069 isolate()->factory()->empty_fixed_array());
2070 __ movq(FieldOperand(rax, JSGeneratorObject::kResultValuePropertyOffset),
2071 rcx);
2072 __ movq(FieldOperand(rax, JSGeneratorObject::kResultDonePropertyOffset),
2073 rdx);
2074
2075 // Only the value field needs a write barrier, as the other values are in the
2076 // root set.
2077 __ RecordWriteField(rax, JSGeneratorObject::kResultValuePropertyOffset,
2078 rcx, rdx, kDontSaveFPRegs);
2079
2080 if (done) {
2081 // Exit all nested statements.
2082 NestedStatement* current = nesting_stack_;
2083 int stack_depth = 0;
2084 int context_length = 0;
2085 while (current != NULL) {
2086 current = current->Exit(&stack_depth, &context_length);
2087 }
2088 __ Drop(stack_depth);
2089 }
2090
2091 EmitReturnSequence();
2092
2093 __ bind(&gc_required);
2094 __ Push(Smi::FromInt(map->instance_size()));
2095 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
2096 __ movq(context_register(),
2097 Operand(rbp, StandardFrameConstants::kContextOffset));
2098 __ jmp(&allocated);
2099}
2100
2101
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002102void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
2103 SetSourcePosition(prop->position());
2104 Literal* key = prop->key()->AsLiteral();
2105 __ Move(rcx, key->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002106 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002107 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002108}
2109
2110
2111void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
2112 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002113 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002114 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002115}
2116
2117
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002118void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002119 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002120 OverwriteMode mode,
2121 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002122 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002123 // Do combined smi check of the operands. Left operand is on the
2124 // stack (popped into rdx). Right operand is in rax but moved into
2125 // rcx to make the shifts easier.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002126 Label done, stub_call, smi_case;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002127 __ pop(rdx);
2128 __ movq(rcx, rax);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002129 __ or_(rax, rdx);
2130 JumpPatchSite patch_site(masm_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002131 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002132
2133 __ bind(&stub_call);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002134 __ movq(rax, rcx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002135 BinaryOpStub stub(op, mode);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002136 CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002137 expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002138 patch_site.EmitPatchInfo();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002139 __ jmp(&done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002140
2141 __ bind(&smi_case);
2142 switch (op) {
2143 case Token::SAR:
2144 __ SmiShiftArithmeticRight(rax, rdx, rcx);
2145 break;
2146 case Token::SHL:
2147 __ SmiShiftLeft(rax, rdx, rcx);
2148 break;
2149 case Token::SHR:
2150 __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
2151 break;
2152 case Token::ADD:
2153 __ SmiAdd(rax, rdx, rcx, &stub_call);
2154 break;
2155 case Token::SUB:
2156 __ SmiSub(rax, rdx, rcx, &stub_call);
2157 break;
2158 case Token::MUL:
2159 __ SmiMul(rax, rdx, rcx, &stub_call);
2160 break;
2161 case Token::BIT_OR:
2162 __ SmiOr(rax, rdx, rcx);
2163 break;
2164 case Token::BIT_AND:
2165 __ SmiAnd(rax, rdx, rcx);
2166 break;
2167 case Token::BIT_XOR:
2168 __ SmiXor(rax, rdx, rcx);
2169 break;
2170 default:
2171 UNREACHABLE();
2172 break;
2173 }
2174
2175 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002176 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002177}
2178
2179
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002180void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
2181 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00002182 OverwriteMode mode) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002183 __ pop(rdx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002184 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002185 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002186 CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002187 expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002188 patch_site.EmitPatchInfo();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002189 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002190}
2191
2192
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002193void FullCodeGenerator::EmitAssignment(Expression* expr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002194 // Invalid left-hand sides are rewritten by the parser to have a 'throw
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002195 // ReferenceError' on the left-hand side.
2196 if (!expr->IsValidLeftHandSide()) {
2197 VisitForEffect(expr);
2198 return;
2199 }
2200
2201 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00002202 // slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002203 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2204 LhsKind assign_type = VARIABLE;
2205 Property* prop = expr->AsProperty();
2206 if (prop != NULL) {
2207 assign_type = (prop->key()->IsPropertyName())
2208 ? NAMED_PROPERTY
2209 : KEYED_PROPERTY;
2210 }
2211
2212 switch (assign_type) {
2213 case VARIABLE: {
2214 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002215 EffectContext context(this);
2216 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002217 break;
2218 }
2219 case NAMED_PROPERTY: {
2220 __ push(rax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002221 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002222 __ movq(rdx, rax);
2223 __ pop(rax); // Restore value.
2224 __ Move(rcx, prop->key()->AsLiteral()->handle());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002225 Handle<Code> ic = is_classic_mode()
2226 ? isolate()->builtins()->StoreIC_Initialize()
2227 : isolate()->builtins()->StoreIC_Initialize_Strict();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002228 CallIC(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002229 break;
2230 }
2231 case KEYED_PROPERTY: {
2232 __ push(rax); // Preserve value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002233 VisitForStackValue(prop->obj());
2234 VisitForAccumulatorValue(prop->key());
2235 __ movq(rcx, rax);
2236 __ pop(rdx);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002237 __ pop(rax); // Restore value.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002238 Handle<Code> ic = is_classic_mode()
2239 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2240 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002241 CallIC(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002242 break;
2243 }
2244 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002245 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002246}
2247
2248
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002249void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002250 Token::Value op) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002251 if (var->IsUnallocated()) {
2252 // Global var, const, or let.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002253 __ Move(rcx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002254 __ movq(rdx, GlobalObjectOperand());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002255 Handle<Code> ic = is_classic_mode()
2256 ? isolate()->builtins()->StoreIC_Initialize()
2257 : isolate()->builtins()->StoreIC_Initialize_Strict();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002258 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002259 } else if (op == Token::INIT_CONST) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002260 // Const initializers need a write barrier.
2261 ASSERT(!var->IsParameter()); // No const parameters.
2262 if (var->IsStackLocal()) {
2263 Label skip;
2264 __ movq(rdx, StackOperand(var));
2265 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2266 __ j(not_equal, &skip);
2267 __ movq(StackOperand(var), rax);
2268 __ bind(&skip);
2269 } else {
2270 ASSERT(var->IsContextSlot() || var->IsLookupSlot());
2271 // Like var declarations, const declarations are hoisted to function
2272 // scope. However, unlike var initializers, const initializers are
2273 // able to drill a hole to that function context, even from inside a
2274 // 'with' context. We thus bypass the normal static scope lookup for
2275 // var->IsContextSlot().
2276 __ push(rax);
2277 __ push(rsi);
2278 __ Push(var->name());
2279 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002280 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002281
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002282 } else if (var->mode() == LET && op != Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002283 // Non-initializing assignment to let variable needs a write barrier.
2284 if (var->IsLookupSlot()) {
2285 __ push(rax); // Value.
2286 __ push(rsi); // Context.
2287 __ Push(var->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002288 __ Push(Smi::FromInt(language_mode()));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002289 __ CallRuntime(Runtime::kStoreContextSlot, 4);
2290 } else {
2291 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
2292 Label assign;
2293 MemOperand location = VarOperand(var, rcx);
2294 __ movq(rdx, location);
2295 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2296 __ j(not_equal, &assign, Label::kNear);
2297 __ Push(var->name());
2298 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2299 __ bind(&assign);
2300 __ movq(location, rax);
2301 if (var->IsContextSlot()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002302 __ movq(rdx, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002303 __ RecordWriteContextSlot(
2304 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002305 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002306 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002307
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002308 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
2309 // Assignment to var or initializing assignment to let/const
2310 // in harmony mode.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002311 if (var->IsStackAllocated() || var->IsContextSlot()) {
2312 MemOperand location = VarOperand(var, rcx);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002313 if (generate_debug_code_ && op == Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002314 // Check for an uninitialized let binding.
2315 __ movq(rdx, location);
2316 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
2317 __ Check(equal, "Let binding re-initialization.");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002318 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002319 // Perform the assignment.
2320 __ movq(location, rax);
2321 if (var->IsContextSlot()) {
2322 __ movq(rdx, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002323 __ RecordWriteContextSlot(
2324 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002325 }
2326 } else {
2327 ASSERT(var->IsLookupSlot());
2328 __ push(rax); // Value.
2329 __ push(rsi); // Context.
2330 __ Push(var->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002331 __ Push(Smi::FromInt(language_mode()));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002332 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002333 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002334 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002335 // Non-initializing assignments to consts are ignored.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002336}
2337
2338
2339void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2340 // Assignment to a property, using a named store IC.
2341 Property* prop = expr->target()->AsProperty();
2342 ASSERT(prop != NULL);
2343 ASSERT(prop->key()->AsLiteral() != NULL);
2344
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002345 // Record source code position before IC call.
2346 SetSourcePosition(expr->position());
2347 __ Move(rcx, prop->key()->AsLiteral()->handle());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002348 __ pop(rdx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002349 Handle<Code> ic = is_classic_mode()
2350 ? isolate()->builtins()->StoreIC_Initialize()
2351 : isolate()->builtins()->StoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002352 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002353
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002354 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002355 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002356}
2357
2358
2359void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2360 // Assignment to a property, using a keyed store IC.
2361
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002362 __ pop(rcx);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002363 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002364 // Record source code position before IC call.
2365 SetSourcePosition(expr->position());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002366 Handle<Code> ic = is_classic_mode()
2367 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2368 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002369 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002370
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002371 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002372 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002373}
2374
2375
2376void FullCodeGenerator::VisitProperty(Property* expr) {
2377 Comment cmnt(masm_, "[ Property");
2378 Expression* key = expr->key();
2379
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002380 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002381 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002382 EmitNamedPropertyLoad(expr);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002383 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002384 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002385 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002386 VisitForStackValue(expr->obj());
2387 VisitForAccumulatorValue(expr->key());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002388 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002389 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002390 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002391 }
2392}
2393
2394
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002395void FullCodeGenerator::CallIC(Handle<Code> code,
2396 RelocInfo::Mode rmode,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002397 TypeFeedbackId ast_id) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002398 ic_total_count_++;
2399 __ call(code, rmode, ast_id);
2400}
2401
2402
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002403void FullCodeGenerator::EmitCallWithIC(Call* expr,
ager@chromium.org5c838252010-02-19 08:53:10 +00002404 Handle<Object> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002405 RelocInfo::Mode mode) {
2406 // Code common for calls using the IC.
2407 ZoneList<Expression*>* args = expr->arguments();
2408 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002409 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002410 for (int i = 0; i < arg_count; i++) {
2411 VisitForStackValue(args->at(i));
2412 }
2413 __ Move(rcx, name);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002414 }
2415 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002416 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002417 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002418 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002419 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002420 CallIC(ic, mode, expr->CallFeedbackId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002421 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002422 // Restore context register.
2423 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002424 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002425}
2426
2427
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002428void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002429 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002430 // Load the key.
2431 VisitForAccumulatorValue(key);
2432
2433 // Swap the name of the function and the receiver on the stack to follow
2434 // the calling convention for call ICs.
2435 __ pop(rcx);
2436 __ push(rax);
2437 __ push(rcx);
2438
2439 // Load the arguments.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002440 ZoneList<Expression*>* args = expr->arguments();
2441 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002442 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002443 for (int i = 0; i < arg_count; i++) {
2444 VisitForStackValue(args->at(i));
2445 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002446 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002447 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002448 SetSourcePosition(expr->position());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002449 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002450 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002451 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002452 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002453 CallIC(ic, RelocInfo::CODE_TARGET, expr->CallFeedbackId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002454 RecordJSReturnSite(expr);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002455 // Restore context register.
2456 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002457 context()->DropAndPlug(1, rax); // Drop the key still on the stack.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002458}
2459
2460
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002461void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002462 // Code common for calls using the call stub.
2463 ZoneList<Expression*>* args = expr->arguments();
2464 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002465 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002466 for (int i = 0; i < arg_count; i++) {
2467 VisitForStackValue(args->at(i));
2468 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002469 }
2470 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002471 SetSourcePosition(expr->position());
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002472
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002473 // Record call targets in unoptimized code.
2474 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
2475 Handle<Object> uninitialized =
2476 TypeFeedbackCells::UninitializedSentinel(isolate());
2477 Handle<JSGlobalPropertyCell> cell =
2478 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002479 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002480 __ Move(rbx, cell);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002481
lrn@chromium.org34e60782011-09-15 07:25:40 +00002482 CallFunctionStub stub(arg_count, flags);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002483 __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002484 __ CallStub(&stub, expr->CallFeedbackId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002485 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002486 // Restore context register.
2487 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2488 // Discard the function left on TOS.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002489 context()->DropAndPlug(1, rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002490}
2491
2492
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002493void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002494 // Push copy of the first argument or undefined if it doesn't exist.
2495 if (arg_count > 0) {
2496 __ push(Operand(rsp, arg_count * kPointerSize));
2497 } else {
2498 __ PushRoot(Heap::kUndefinedValueRootIndex);
2499 }
2500
2501 // Push the receiver of the enclosing function and do runtime call.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002502 __ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002503
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002504 // Push the language mode.
2505 __ Push(Smi::FromInt(language_mode()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002506
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002507 // Push the start position of the scope the calls resides in.
2508 __ Push(Smi::FromInt(scope()->start_position()));
2509
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002510 // Do the runtime call.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002511 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002512}
2513
2514
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002515void FullCodeGenerator::VisitCall(Call* expr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002516#ifdef DEBUG
2517 // We want to verify that RecordJSReturnSite gets called on all paths
2518 // through this function. Avoid early returns.
2519 expr->return_is_recorded_ = false;
2520#endif
2521
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002522 Comment cmnt(masm_, "[ Call");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002523 Expression* callee = expr->expression();
2524 VariableProxy* proxy = callee->AsVariableProxy();
2525 Property* property = callee->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002526
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002527 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002528 // In a call to eval, we first call %ResolvePossiblyDirectEval to
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002529 // resolve the function we need to call and the receiver of the call.
2530 // Then we call the resolved function using the given arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002531 ZoneList<Expression*>* args = expr->arguments();
2532 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002533 { PreservePositionScope pos_scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002534 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002535 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002536
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002537 // Push the arguments.
2538 for (int i = 0; i < arg_count; i++) {
2539 VisitForStackValue(args->at(i));
2540 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002541
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002542 // Push a copy of the function (found below the arguments) and resolve
2543 // eval.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002544 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002545 EmitResolvePossiblyDirectEval(arg_count);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002546
2547 // The runtime call returns a pair of values in rax (function) and
2548 // rdx (receiver). Touch up the stack with the right values.
2549 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
2550 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002551 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002552 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002553 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002554 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002555 __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002556 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002557 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002558 // Restore context register.
2559 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002560 context()->DropAndPlug(1, rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002561 } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
2562 // Call to a global variable. Push global object as receiver for the
2563 // call IC lookup.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002564 __ push(GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002565 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
2566 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002567 // Call to a lookup slot (dynamically introduced variable).
2568 Label slow, done;
2569
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002570 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002571 // Generate code for loading from variables potentially shadowed by
2572 // eval-introduced variables.
2573 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002574 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002575 __ bind(&slow);
2576 // Call the runtime to find the function to call (returned in rax) and
2577 // the object holding it (returned in rdx).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002578 __ push(context_register());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002579 __ Push(proxy->name());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002580 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2581 __ push(rax); // Function.
2582 __ push(rdx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002583
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002584 // If fast case code has been generated, emit code to push the function
2585 // and receiver and have the slow path jump around this code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002586 if (done.is_linked()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002587 Label call;
2588 __ jmp(&call, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002589 __ bind(&done);
2590 // Push function.
2591 __ push(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002592 // The receiver is implicitly the global receiver. Indicate this by
2593 // passing the hole to the call function stub.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002594 __ PushRoot(Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002595 __ bind(&call);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002596 }
2597
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002598 // The receiver is either the global receiver or an object found by
2599 // LoadContextSlot. That object could be the hole if the receiver is
2600 // implicitly the global object.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002601 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002602 } else if (property != NULL) {
2603 { PreservePositionScope scope(masm()->positions_recorder());
2604 VisitForStackValue(property->obj());
2605 }
2606 if (property->key()->IsPropertyName()) {
2607 EmitCallWithIC(expr,
2608 property->key()->AsLiteral()->handle(),
2609 RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002610 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002611 EmitKeyedCallWithIC(expr, property->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002612 }
2613 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002614 // Call to an arbitrary expression not handled specially above.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002615 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002616 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002617 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002618 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002619 __ movq(rbx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002620 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
2621 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002622 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002623 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002624
2625#ifdef DEBUG
2626 // RecordJSReturnSite should have been called.
2627 ASSERT(expr->return_is_recorded_);
2628#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002629}
2630
2631
2632void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2633 Comment cmnt(masm_, "[ CallNew");
2634 // According to ECMA-262, section 11.2.2, page 44, the function
2635 // expression in new calls must be evaluated before the
2636 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002637
ricow@chromium.org65fae842010-08-25 15:26:24 +00002638 // Push constructor on the stack. If it's not a function it's used as
2639 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2640 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002641 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002642
2643 // Push the arguments ("left-to-right") on the stack.
2644 ZoneList<Expression*>* args = expr->arguments();
2645 int arg_count = args->length();
2646 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002647 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002648 }
2649
2650 // Call the construct call builtin that handles allocation and
2651 // constructor invocation.
2652 SetSourcePosition(expr->position());
2653
ricow@chromium.org65fae842010-08-25 15:26:24 +00002654 // Load function and argument count into rdi and rax.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002655 __ Set(rax, arg_count);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002656 __ movq(rdi, Operand(rsp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002657
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002658 // Record call targets in unoptimized code, but not in the snapshot.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002659 Handle<Object> uninitialized =
2660 TypeFeedbackCells::UninitializedSentinel(isolate());
2661 Handle<JSGlobalPropertyCell> cell =
2662 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002663 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002664 __ Move(rbx, cell);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002665
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002666 CallConstructStub stub(RECORD_CALL_TARGET);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002667 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL);
ulan@chromium.org967e2702012-02-28 09:49:15 +00002668 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002669 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002670}
2671
2672
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002673void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2674 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002675 ASSERT(args->length() == 1);
2676
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002677 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002678
2679 Label materialize_true, materialize_false;
2680 Label* if_true = NULL;
2681 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002682 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002683 context()->PrepareTest(&materialize_true, &materialize_false,
2684 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002685
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002686 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002687 __ JumpIfSmi(rax, if_true);
2688 __ jmp(if_false);
2689
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002690 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002691}
2692
2693
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002694void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2695 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002696 ASSERT(args->length() == 1);
2697
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002698 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002699
2700 Label materialize_true, materialize_false;
2701 Label* if_true = NULL;
2702 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002703 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002704 context()->PrepareTest(&materialize_true, &materialize_false,
2705 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002706
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002707 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00002708 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
2709 Split(non_negative_smi, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002710
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002711 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002712}
2713
2714
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002715void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2716 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002717 ASSERT(args->length() == 1);
2718
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002719 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002720
2721 Label materialize_true, materialize_false;
2722 Label* if_true = NULL;
2723 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002724 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002725 context()->PrepareTest(&materialize_true, &materialize_false,
2726 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002727
2728 __ JumpIfSmi(rax, if_false);
2729 __ CompareRoot(rax, Heap::kNullValueRootIndex);
2730 __ j(equal, if_true);
2731 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2732 // Undetectable objects behave like undefined when tested with typeof.
2733 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2734 Immediate(1 << Map::kIsUndetectable));
2735 __ j(not_zero, if_false);
2736 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002737 __ cmpq(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002738 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002739 __ cmpq(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002740 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002741 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002742
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002743 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002744}
2745
2746
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002747void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2748 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002749 ASSERT(args->length() == 1);
2750
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002751 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002752
2753 Label materialize_true, materialize_false;
2754 Label* if_true = NULL;
2755 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002756 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002757 context()->PrepareTest(&materialize_true, &materialize_false,
2758 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002759
2760 __ JumpIfSmi(rax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002761 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002762 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002763 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002764
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002765 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002766}
2767
2768
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002769void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2770 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002771 ASSERT(args->length() == 1);
2772
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002773 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002774
2775 Label materialize_true, materialize_false;
2776 Label* if_true = NULL;
2777 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002778 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002779 context()->PrepareTest(&materialize_true, &materialize_false,
2780 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002781
2782 __ JumpIfSmi(rax, if_false);
2783 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2784 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2785 Immediate(1 << Map::kIsUndetectable));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002786 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002787 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002788
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002789 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002790}
2791
2792
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002793void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002794 CallRuntime* expr) {
2795 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002796 ASSERT(args->length() == 1);
2797
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002798 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002799
2800 Label materialize_true, materialize_false;
2801 Label* if_true = NULL;
2802 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002803 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002804 context()->PrepareTest(&materialize_true, &materialize_false,
2805 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002806
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002807 __ AssertNotSmi(rax);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002808
2809 // Check whether this map has already been checked to be safe for default
2810 // valueOf.
2811 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2812 __ testb(FieldOperand(rbx, Map::kBitField2Offset),
2813 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2814 __ j(not_zero, if_true);
2815
2816 // Check for fast case object. Generate false result for slow case object.
2817 __ movq(rcx, FieldOperand(rax, JSObject::kPropertiesOffset));
2818 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2819 __ CompareRoot(rcx, Heap::kHashTableMapRootIndex);
2820 __ j(equal, if_false);
2821
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002822 // Look for valueOf string in the descriptor array, and indicate false if
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002823 // found. Since we omit an enumeration index check, if it is added via a
2824 // transition that shares its descriptor array, this is a false positive.
2825 Label entry, loop, done;
2826
2827 // Skip loop if no descriptors are valid.
2828 __ NumberOfOwnDescriptors(rcx, rbx);
2829 __ cmpq(rcx, Immediate(0));
2830 __ j(equal, &done);
2831
danno@chromium.org40cb8782011-05-25 07:58:50 +00002832 __ LoadInstanceDescriptors(rbx, rbx);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002833 // rbx: descriptor array.
2834 // rcx: valid entries in the descriptor array.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002835 // Calculate the end of the descriptor array.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002836 __ imul(rcx, rcx, Immediate(DescriptorArray::kDescriptorSize));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002837 SmiIndex index = masm_->SmiToIndex(rdx, rcx, kPointerSizeLog2);
2838 __ lea(rcx,
2839 Operand(
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002840 rbx, index.reg, index.scale, DescriptorArray::kFirstOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002841 // Calculate location of the first key name.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002842 __ addq(rbx, Immediate(DescriptorArray::kFirstOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002843 // Loop through all the keys in the descriptor array. If one of these is the
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002844 // internalized string "valueOf" the result is false.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002845 __ jmp(&entry);
2846 __ bind(&loop);
2847 __ movq(rdx, FieldOperand(rbx, 0));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002848 __ Cmp(rdx, FACTORY->value_of_string());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002849 __ j(equal, if_false);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002850 __ addq(rbx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002851 __ bind(&entry);
2852 __ cmpq(rbx, rcx);
2853 __ j(not_equal, &loop);
2854
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002855 __ bind(&done);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002856 // Reload map as register rbx was used as temporary above.
2857 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2858
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002859 // If a valueOf property is not found on the object check that its
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002860 // prototype is the un-modified String prototype. If not result is false.
2861 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
2862 __ testq(rcx, Immediate(kSmiTagMask));
2863 __ j(zero, if_false);
2864 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002865 __ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2866 __ movq(rdx, FieldOperand(rdx, GlobalObject::kNativeContextOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002867 __ cmpq(rcx,
2868 ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2869 __ j(not_equal, if_false);
2870 // Set the bit in the map to indicate that it has been checked safe for
2871 // default valueOf and set true result.
2872 __ or_(FieldOperand(rbx, Map::kBitField2Offset),
2873 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2874 __ jmp(if_true);
2875
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002876 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002877 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002878}
2879
2880
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002881void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
2882 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002883 ASSERT(args->length() == 1);
2884
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002885 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002886
2887 Label materialize_true, materialize_false;
2888 Label* if_true = NULL;
2889 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002890 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002891 context()->PrepareTest(&materialize_true, &materialize_false,
2892 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002893
2894 __ JumpIfSmi(rax, if_false);
2895 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002896 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002897 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002898
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002899 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002900}
2901
2902
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002903void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2904 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002905 ASSERT(args->length() == 1);
2906
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002907 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002908
2909 Label materialize_true, materialize_false;
2910 Label* if_true = NULL;
2911 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002912 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002913 context()->PrepareTest(&materialize_true, &materialize_false,
2914 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002915
2916 __ JumpIfSmi(rax, if_false);
2917 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002918 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002919 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002920
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002921 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002922}
2923
2924
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002925void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2926 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002927 ASSERT(args->length() == 1);
2928
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002929 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002930
2931 Label materialize_true, materialize_false;
2932 Label* if_true = NULL;
2933 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002934 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002935 context()->PrepareTest(&materialize_true, &materialize_false,
2936 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002937
2938 __ JumpIfSmi(rax, if_false);
2939 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002940 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002941 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002942
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002943 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002944}
2945
2946
2947
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002948void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
2949 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002950
2951 Label materialize_true, materialize_false;
2952 Label* if_true = NULL;
2953 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002954 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002955 context()->PrepareTest(&materialize_true, &materialize_false,
2956 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002957
2958 // Get the frame pointer for the calling frame.
2959 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2960
2961 // Skip the arguments adaptor frame if it exists.
2962 Label check_frame_marker;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002963 __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset),
2964 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002965 __ j(not_equal, &check_frame_marker);
2966 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
2967
2968 // Check the marker in the calling frame.
2969 __ bind(&check_frame_marker);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002970 __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
2971 Smi::FromInt(StackFrame::CONSTRUCT));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002972 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002973 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002974
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002975 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002976}
2977
2978
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002979void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
2980 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002981 ASSERT(args->length() == 2);
2982
2983 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002984 VisitForStackValue(args->at(0));
2985 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002986
2987 Label materialize_true, materialize_false;
2988 Label* if_true = NULL;
2989 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002990 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002991 context()->PrepareTest(&materialize_true, &materialize_false,
2992 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002993
2994 __ pop(rbx);
2995 __ cmpq(rax, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002996 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002997 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002998
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002999 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003000}
3001
3002
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003003void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3004 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003005 ASSERT(args->length() == 1);
3006
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003007 // ArgumentsAccessStub expects the key in rdx and the formal
3008 // parameter count in rax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003009 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003010 __ movq(rdx, rax);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003011 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003012 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
3013 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003014 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003015}
3016
3017
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003018void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
3019 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003020
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003021 Label exit;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003022 // Get the number of formal parameters.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003023 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003024
3025 // Check if the calling frame is an arguments adaptor frame.
3026 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003027 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
3028 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003029 __ j(not_equal, &exit, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003030
3031 // Arguments adaptor case: Read the arguments length from the
3032 // adaptor frame.
3033 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
3034
3035 __ bind(&exit);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003036 __ AssertSmi(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003037 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003038}
3039
3040
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003041void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3042 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003043 ASSERT(args->length() == 1);
3044 Label done, null, function, non_function_constructor;
3045
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003046 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003047
3048 // If the object is a smi, we return null.
3049 __ JumpIfSmi(rax, &null);
3050
3051 // Check that the object is a JS object but take special care of JS
3052 // functions to make sure they have 'Function' as their class.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003053 // Assume that there are only two callable types, and one of them is at
3054 // either end of the type range for JS object types. Saves extra comparisons.
3055 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003056 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
3057 // Map is now in rax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003058 __ j(below, &null);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003059 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3060 FIRST_SPEC_OBJECT_TYPE + 1);
3061 __ j(equal, &function);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003062
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003063 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
3064 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3065 LAST_SPEC_OBJECT_TYPE - 1);
3066 __ j(equal, &function);
3067 // Assume that there is no larger type.
3068 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003069
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003070 // Check if the constructor in the map is a JS function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003071 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
3072 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
3073 __ j(not_equal, &non_function_constructor);
3074
3075 // rax now contains the constructor function. Grab the
3076 // instance class name from there.
3077 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
3078 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
3079 __ jmp(&done);
3080
3081 // Functions have class 'Function'.
3082 __ bind(&function);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003083 __ Move(rax, isolate()->factory()->function_class_string());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003084 __ jmp(&done);
3085
3086 // Objects with a non-function constructor have class 'Object'.
3087 __ bind(&non_function_constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003088 __ Move(rax, isolate()->factory()->Object_string());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003089 __ jmp(&done);
3090
3091 // Non-JS objects have class null.
3092 __ bind(&null);
3093 __ LoadRoot(rax, Heap::kNullValueRootIndex);
3094
3095 // All done.
3096 __ bind(&done);
3097
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003098 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003099}
3100
3101
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003102void FullCodeGenerator::EmitLog(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003103 // Conditionally generate a log call.
3104 // Args:
3105 // 0 (literal string): The type of logging (corresponds to the flags).
3106 // This is used to determine whether or not to generate the log call.
3107 // 1 (string): Format string. Access the string at argument index 2
3108 // with '%2s' (see Logger::LogRuntime for all the formats).
3109 // 2 (array): Arguments to the format string.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003110 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003111 ASSERT_EQ(args->length(), 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003112 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003113 VisitForStackValue(args->at(1));
3114 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003115 __ CallRuntime(Runtime::kLog, 2);
3116 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003117 // Finally, we're expected to leave a value on the top of the stack.
3118 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003119 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003120}
3121
3122
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003123void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
3124 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003125
3126 Label slow_allocate_heapnumber;
3127 Label heapnumber_allocated;
3128
3129 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
3130 __ jmp(&heapnumber_allocated);
3131
3132 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003133 // Allocate a heap number.
3134 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003135 __ movq(rbx, rax);
3136
3137 __ bind(&heapnumber_allocated);
3138
3139 // Return a random uint32 number in rax.
3140 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003141 __ PrepareCallCFunction(1);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003142 __ movq(arg_reg_1,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003143 ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003144 __ movq(arg_reg_1,
3145 FieldOperand(arg_reg_1, GlobalObject::kNativeContextOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003146 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003147
3148 // Convert 32 random bits in rax to 0.(32 random bits) in a double
3149 // by computing:
3150 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
3151 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
3152 __ movd(xmm1, rcx);
3153 __ movd(xmm0, rax);
3154 __ cvtss2sd(xmm1, xmm1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003155 __ xorps(xmm0, xmm1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003156 __ subsd(xmm0, xmm1);
3157 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
3158
3159 __ movq(rax, rbx);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003160 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003161}
3162
3163
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003164void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003165 // Load the arguments on the stack and call the stub.
3166 SubStringStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003167 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003168 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003169 VisitForStackValue(args->at(0));
3170 VisitForStackValue(args->at(1));
3171 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003172 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003173 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003174}
3175
3176
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003177void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003178 // Load the arguments on the stack and call the stub.
3179 RegExpExecStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003180 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003181 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003182 VisitForStackValue(args->at(0));
3183 VisitForStackValue(args->at(1));
3184 VisitForStackValue(args->at(2));
3185 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003186 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003187 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003188}
3189
3190
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003191void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3192 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003193 ASSERT(args->length() == 1);
3194
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003195 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003196
3197 Label done;
3198 // If the object is a smi return the object.
3199 __ JumpIfSmi(rax, &done);
3200 // If the object is not a value type, return the object.
3201 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
3202 __ j(not_equal, &done);
3203 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset));
3204
3205 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003206 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003207}
3208
3209
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003210void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3211 ZoneList<Expression*>* args = expr->arguments();
3212 ASSERT(args->length() == 2);
3213 ASSERT_NE(NULL, args->at(1)->AsLiteral());
3214 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->handle()));
3215
3216 VisitForAccumulatorValue(args->at(0)); // Load the object.
3217
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003218 Label runtime, done, not_date_object;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003219 Register object = rax;
3220 Register result = rax;
3221 Register scratch = rcx;
3222
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003223 __ JumpIfSmi(object, &not_date_object);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003224 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003225 __ j(not_equal, &not_date_object);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003226
3227 if (index->value() == 0) {
3228 __ movq(result, FieldOperand(object, JSDate::kValueOffset));
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003229 __ jmp(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003230 } else {
3231 if (index->value() < JSDate::kFirstUncachedField) {
3232 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003233 Operand stamp_operand = __ ExternalOperand(stamp);
3234 __ movq(scratch, stamp_operand);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003235 __ cmpq(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
3236 __ j(not_equal, &runtime, Label::kNear);
3237 __ movq(result, FieldOperand(object, JSDate::kValueOffset +
3238 kPointerSize * index->value()));
3239 __ jmp(&done);
3240 }
3241 __ bind(&runtime);
3242 __ PrepareCallCFunction(2);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003243 __ movq(arg_reg_1, object);
3244 __ movq(arg_reg_2, index, RelocInfo::NONE64);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003245 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
3246 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003247 __ jmp(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003248 }
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003249
3250 __ bind(&not_date_object);
3251 __ CallRuntime(Runtime::kThrowNotDateError, 0);
3252 __ bind(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003253 context()->Plug(rax);
3254}
3255
3256
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003257void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3258 ZoneList<Expression*>* args = expr->arguments();
3259 ASSERT_EQ(3, args->length());
3260
3261 VisitForStackValue(args->at(1)); // index
3262 VisitForStackValue(args->at(2)); // value
3263 __ pop(rcx);
3264 __ pop(rbx);
3265 VisitForAccumulatorValue(args->at(0)); // string
3266
3267 static const String::Encoding encoding = String::ONE_BYTE_ENCODING;
3268 SeqStringSetCharGenerator::Generate(masm_, encoding, rax, rbx, rcx);
3269 context()->Plug(rax);
3270}
3271
3272
3273void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3274 ZoneList<Expression*>* args = expr->arguments();
3275 ASSERT_EQ(3, args->length());
3276
3277 VisitForStackValue(args->at(1)); // index
3278 VisitForStackValue(args->at(2)); // value
3279 __ pop(rcx);
3280 __ pop(rbx);
3281 VisitForAccumulatorValue(args->at(0)); // string
3282
3283 static const String::Encoding encoding = String::TWO_BYTE_ENCODING;
3284 SeqStringSetCharGenerator::Generate(masm_, encoding, rax, rbx, rcx);
3285 context()->Plug(rax);
3286}
3287
3288
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003289void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003290 // Load the arguments on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003291 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003292 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003293 VisitForStackValue(args->at(0));
3294 VisitForStackValue(args->at(1));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003295 MathPowStub stub(MathPowStub::ON_STACK);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003296 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003297 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003298}
3299
3300
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003301void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3302 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003303 ASSERT(args->length() == 2);
3304
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003305 VisitForStackValue(args->at(0)); // Load the object.
3306 VisitForAccumulatorValue(args->at(1)); // Load the value.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003307 __ pop(rbx); // rax = value. rbx = object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003308
3309 Label done;
3310 // If the object is a smi, return the value.
3311 __ JumpIfSmi(rbx, &done);
3312
3313 // If the object is not a value type, return the value.
3314 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
3315 __ j(not_equal, &done);
3316
3317 // Store the value.
3318 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax);
3319 // Update the write barrier. Save the value as it will be
3320 // overwritten by the write barrier code and is needed afterward.
3321 __ movq(rdx, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003322 __ RecordWriteField(rbx, JSValue::kValueOffset, rdx, rcx, kDontSaveFPRegs);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003323
3324 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003325 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003326}
3327
3328
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003329void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3330 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003331 ASSERT_EQ(args->length(), 1);
3332
3333 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003334 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003335
3336 NumberToStringStub stub;
3337 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003338 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003339}
3340
3341
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003342void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3343 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003344 ASSERT(args->length() == 1);
3345
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003346 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003347
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003348 Label done;
3349 StringCharFromCodeGenerator generator(rax, rbx);
3350 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003351 __ jmp(&done);
3352
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003353 NopRuntimeCallHelper call_helper;
3354 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003355
3356 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003357 context()->Plug(rbx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003358}
3359
3360
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003361void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3362 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003363 ASSERT(args->length() == 2);
3364
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003365 VisitForStackValue(args->at(0));
3366 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003367
3368 Register object = rbx;
3369 Register index = rax;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003370 Register result = rdx;
3371
3372 __ pop(object);
3373
3374 Label need_conversion;
3375 Label index_out_of_range;
3376 Label done;
3377 StringCharCodeAtGenerator generator(object,
3378 index,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003379 result,
3380 &need_conversion,
3381 &need_conversion,
3382 &index_out_of_range,
3383 STRING_INDEX_IS_NUMBER);
3384 generator.GenerateFast(masm_);
3385 __ jmp(&done);
3386
3387 __ bind(&index_out_of_range);
3388 // When the index is out of range, the spec requires us to return
3389 // NaN.
3390 __ LoadRoot(result, Heap::kNanValueRootIndex);
3391 __ jmp(&done);
3392
3393 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003394 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003395 // trigger conversion.
3396 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
3397 __ jmp(&done);
3398
3399 NopRuntimeCallHelper call_helper;
3400 generator.GenerateSlow(masm_, call_helper);
3401
3402 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003403 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003404}
3405
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003406
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003407void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3408 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003409 ASSERT(args->length() == 2);
3410
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003411 VisitForStackValue(args->at(0));
3412 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003413
3414 Register object = rbx;
3415 Register index = rax;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003416 Register scratch = rdx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003417 Register result = rax;
3418
3419 __ pop(object);
3420
3421 Label need_conversion;
3422 Label index_out_of_range;
3423 Label done;
3424 StringCharAtGenerator generator(object,
3425 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00003426 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003427 result,
3428 &need_conversion,
3429 &need_conversion,
3430 &index_out_of_range,
3431 STRING_INDEX_IS_NUMBER);
3432 generator.GenerateFast(masm_);
3433 __ jmp(&done);
3434
3435 __ bind(&index_out_of_range);
3436 // When the index is out of range, the spec requires us to return
3437 // the empty string.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003438 __ LoadRoot(result, Heap::kempty_stringRootIndex);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003439 __ jmp(&done);
3440
3441 __ bind(&need_conversion);
3442 // Move smi zero into the result register, which will trigger
3443 // conversion.
3444 __ Move(result, Smi::FromInt(0));
3445 __ jmp(&done);
3446
3447 NopRuntimeCallHelper call_helper;
3448 generator.GenerateSlow(masm_, call_helper);
3449
3450 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003451 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003452}
3453
3454
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003455void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3456 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003457 ASSERT_EQ(2, args->length());
3458
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003459 VisitForStackValue(args->at(0));
3460 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003461
3462 StringAddStub stub(NO_STRING_ADD_FLAGS);
3463 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003464 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003465}
3466
3467
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003468void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3469 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003470 ASSERT_EQ(2, args->length());
3471
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003472 VisitForStackValue(args->at(0));
3473 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003474
3475 StringCompareStub stub;
3476 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003477 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003478}
3479
3480
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003481void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003482 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003483 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3484 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003485 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003486 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003487 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003488 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003489 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003490}
3491
3492
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003493void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003494 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003495 TranscendentalCacheStub stub(TranscendentalCache::COS,
3496 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003497 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003498 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003499 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003500 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003501 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003502}
3503
3504
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003505void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
3506 // Load the argument on the stack and call the stub.
3507 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3508 TranscendentalCacheStub::TAGGED);
3509 ZoneList<Expression*>* args = expr->arguments();
3510 ASSERT(args->length() == 1);
3511 VisitForStackValue(args->at(0));
3512 __ CallStub(&stub);
3513 context()->Plug(rax);
3514}
3515
3516
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003517void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003518 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003519 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3520 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003521 ZoneList<Expression*>* args = expr->arguments();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003522 ASSERT(args->length() == 1);
3523 VisitForStackValue(args->at(0));
3524 __ CallStub(&stub);
3525 context()->Plug(rax);
3526}
3527
3528
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003529void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003530 // Load the argument on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003531 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003532 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003533 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003534 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003535 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003536}
3537
3538
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003539void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3540 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003541 ASSERT(args->length() >= 2);
3542
danno@chromium.org160a7b02011-04-18 15:51:38 +00003543 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3544 for (int i = 0; i < arg_count + 1; i++) {
3545 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003546 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003547 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003548
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003549 Label runtime, done;
3550 // Check for non-function argument (including proxy).
3551 __ JumpIfSmi(rax, &runtime);
3552 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
3553 __ j(not_equal, &runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003554
danno@chromium.org160a7b02011-04-18 15:51:38 +00003555 // InvokeFunction requires the function in rdi. Move it in there.
3556 __ movq(rdi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003557 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003558 __ InvokeFunction(rdi, count, CALL_FUNCTION,
3559 NullCallWrapper(), CALL_AS_METHOD);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003560 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003561 __ jmp(&done);
3562
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003563 __ bind(&runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003564 __ push(rax);
3565 __ CallRuntime(Runtime::kCall, args->length());
3566 __ bind(&done);
3567
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003568 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003569}
3570
3571
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003572void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003573 RegExpConstructResultStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003574 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003575 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003576 VisitForStackValue(args->at(0));
3577 VisitForStackValue(args->at(1));
3578 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003579 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003580 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003581}
3582
3583
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003584void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3585 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003586 ASSERT_EQ(2, args->length());
3587
3588 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3589 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3590
3591 Handle<FixedArray> jsfunction_result_caches(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003592 isolate()->native_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003593 if (jsfunction_result_caches->length() <= cache_id) {
3594 __ Abort("Attempt to use undefined cache.");
3595 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003596 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003597 return;
3598 }
3599
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003600 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003601
3602 Register key = rax;
3603 Register cache = rbx;
3604 Register tmp = rcx;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003605 __ movq(cache, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003606 __ movq(cache,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003607 FieldOperand(cache, GlobalObject::kNativeContextOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003608 __ movq(cache,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003609 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003610 __ movq(cache,
3611 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3612
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003613 Label done, not_found;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003614 // tmp now holds finger offset as a smi.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003615 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003616 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3617 SmiIndex index =
3618 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
3619 __ cmpq(key, FieldOperand(cache,
3620 index.reg,
3621 index.scale,
3622 FixedArray::kHeaderSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003623 __ j(not_equal, &not_found, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003624 __ movq(rax, FieldOperand(cache,
3625 index.reg,
3626 index.scale,
3627 FixedArray::kHeaderSize + kPointerSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003628 __ jmp(&done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003629
3630 __ bind(&not_found);
3631 // Call runtime to perform the lookup.
3632 __ push(cache);
3633 __ push(key);
3634 __ CallRuntime(Runtime::kGetFromCache, 2);
3635
3636 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003637 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003638}
3639
3640
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003641void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) {
3642 ZoneList<Expression*>* args = expr->arguments();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003643 ASSERT_EQ(2, args->length());
3644
3645 Register right = rax;
3646 Register left = rbx;
3647 Register tmp = rcx;
3648
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003649 VisitForStackValue(args->at(0));
3650 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003651 __ pop(left);
3652
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003653 Label done, fail, ok;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003654 __ cmpq(left, right);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003655 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003656 // Fail if either is a non-HeapObject.
3657 Condition either_smi = masm()->CheckEitherSmi(left, right, tmp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003658 __ j(either_smi, &fail, Label::kNear);
3659 __ j(zero, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003660 __ movq(tmp, FieldOperand(left, HeapObject::kMapOffset));
3661 __ cmpb(FieldOperand(tmp, Map::kInstanceTypeOffset),
3662 Immediate(JS_REGEXP_TYPE));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003663 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003664 __ cmpq(tmp, FieldOperand(right, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003665 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003666 __ movq(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3667 __ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003668 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003669 __ bind(&fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003670 __ Move(rax, isolate()->factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003671 __ jmp(&done, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003672 __ bind(&ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003673 __ Move(rax, isolate()->factory()->true_value());
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003674 __ bind(&done);
3675
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003676 context()->Plug(rax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003677}
3678
3679
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003680void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3681 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003682 ASSERT(args->length() == 1);
3683
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003684 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003685
3686 Label materialize_true, materialize_false;
3687 Label* if_true = NULL;
3688 Label* if_false = NULL;
3689 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003690 context()->PrepareTest(&materialize_true, &materialize_false,
3691 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003692
3693 __ testl(FieldOperand(rax, String::kHashFieldOffset),
3694 Immediate(String::kContainsCachedArrayIndexMask));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003695 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003696 __ j(zero, if_true);
3697 __ jmp(if_false);
3698
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003699 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003700}
3701
3702
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003703void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3704 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003705 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003706 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003707
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003708 __ AssertString(rax);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003709
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003710 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
3711 ASSERT(String::kHashShift >= kSmiTagSize);
3712 __ IndexFromHash(rax, rax);
3713
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003714 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003715}
3716
3717
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003718void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003719 Label bailout, return_result, done, one_char_separator, long_separator,
3720 non_trivial_array, not_size_one_array, loop,
3721 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003722 ZoneList<Expression*>* args = expr->arguments();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003723 ASSERT(args->length() == 2);
3724 // We will leave the separator on the stack until the end of the function.
3725 VisitForStackValue(args->at(1));
3726 // Load this to rax (= array)
3727 VisitForAccumulatorValue(args->at(0));
3728 // All aliases of the same register have disjoint lifetimes.
3729 Register array = rax;
3730 Register elements = no_reg; // Will be rax.
3731
3732 Register index = rdx;
3733
3734 Register string_length = rcx;
3735
3736 Register string = rsi;
3737
3738 Register scratch = rbx;
3739
3740 Register array_length = rdi;
3741 Register result_pos = no_reg; // Will be rdi.
3742
3743 Operand separator_operand = Operand(rsp, 2 * kPointerSize);
3744 Operand result_operand = Operand(rsp, 1 * kPointerSize);
3745 Operand array_length_operand = Operand(rsp, 0 * kPointerSize);
3746 // Separator operand is already pushed. Make room for the two
3747 // other stack fields, and clear the direction flag in anticipation
3748 // of calling CopyBytes.
3749 __ subq(rsp, Immediate(2 * kPointerSize));
3750 __ cld();
3751 // Check that the array is a JSArray
3752 __ JumpIfSmi(array, &bailout);
3753 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3754 __ j(not_equal, &bailout);
3755
3756 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003757 __ CheckFastElements(scratch, &bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003758
3759 // Array has fast elements, so its length must be a smi.
3760 // If the array has length zero, return the empty string.
3761 __ movq(array_length, FieldOperand(array, JSArray::kLengthOffset));
3762 __ SmiCompare(array_length, Smi::FromInt(0));
3763 __ j(not_zero, &non_trivial_array);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003764 __ LoadRoot(rax, Heap::kempty_stringRootIndex);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003765 __ jmp(&return_result);
3766
3767 // Save the array length on the stack.
3768 __ bind(&non_trivial_array);
3769 __ SmiToInteger32(array_length, array_length);
3770 __ movl(array_length_operand, array_length);
3771
3772 // Save the FixedArray containing array's elements.
3773 // End of array's live range.
3774 elements = array;
3775 __ movq(elements, FieldOperand(array, JSArray::kElementsOffset));
3776 array = no_reg;
3777
3778
3779 // Check that all array elements are sequential ASCII strings, and
3780 // accumulate the sum of their lengths, as a smi-encoded value.
3781 __ Set(index, 0);
3782 __ Set(string_length, 0);
3783 // Loop condition: while (index < array_length).
3784 // Live loop registers: index(int32), array_length(int32), string(String*),
3785 // scratch, string_length(int32), elements(FixedArray*).
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003786 if (generate_debug_code_) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003787 __ cmpq(index, array_length);
3788 __ Assert(below, "No empty arrays here in EmitFastAsciiArrayJoin");
3789 }
3790 __ bind(&loop);
3791 __ movq(string, FieldOperand(elements,
3792 index,
3793 times_pointer_size,
3794 FixedArray::kHeaderSize));
3795 __ JumpIfSmi(string, &bailout);
3796 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3797 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3798 __ andb(scratch, Immediate(
3799 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003800 __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003801 __ j(not_equal, &bailout);
3802 __ AddSmiField(string_length,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003803 FieldOperand(string, SeqOneByteString::kLengthOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003804 __ j(overflow, &bailout);
3805 __ incl(index);
3806 __ cmpl(index, array_length);
3807 __ j(less, &loop);
3808
3809 // Live registers:
3810 // string_length: Sum of string lengths.
3811 // elements: FixedArray of strings.
3812 // index: Array length.
3813 // array_length: Array length.
3814
3815 // If array_length is 1, return elements[0], a string.
3816 __ cmpl(array_length, Immediate(1));
3817 __ j(not_equal, &not_size_one_array);
3818 __ movq(rax, FieldOperand(elements, FixedArray::kHeaderSize));
3819 __ jmp(&return_result);
3820
3821 __ bind(&not_size_one_array);
3822
3823 // End of array_length live range.
3824 result_pos = array_length;
3825 array_length = no_reg;
3826
3827 // Live registers:
3828 // string_length: Sum of string lengths.
3829 // elements: FixedArray of strings.
3830 // index: Array length.
3831
3832 // Check that the separator is a sequential ASCII string.
3833 __ movq(string, separator_operand);
3834 __ JumpIfSmi(string, &bailout);
3835 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3836 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3837 __ andb(scratch, Immediate(
3838 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003839 __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003840 __ j(not_equal, &bailout);
3841
3842 // Live registers:
3843 // string_length: Sum of string lengths.
3844 // elements: FixedArray of strings.
3845 // index: Array length.
3846 // string: Separator string.
3847
3848 // Add (separator length times (array_length - 1)) to string_length.
3849 __ SmiToInteger32(scratch,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003850 FieldOperand(string, SeqOneByteString::kLengthOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003851 __ decl(index);
3852 __ imull(scratch, index);
3853 __ j(overflow, &bailout);
3854 __ addl(string_length, scratch);
3855 __ j(overflow, &bailout);
3856
3857 // Live registers and stack values:
3858 // string_length: Total length of result string.
3859 // elements: FixedArray of strings.
3860 __ AllocateAsciiString(result_pos, string_length, scratch,
3861 index, string, &bailout);
3862 __ movq(result_operand, result_pos);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003863 __ lea(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003864
3865 __ movq(string, separator_operand);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003866 __ SmiCompare(FieldOperand(string, SeqOneByteString::kLengthOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003867 Smi::FromInt(1));
3868 __ j(equal, &one_char_separator);
3869 __ j(greater, &long_separator);
3870
3871
3872 // Empty separator case:
3873 __ Set(index, 0);
3874 __ movl(scratch, array_length_operand);
3875 __ jmp(&loop_1_condition);
3876 // Loop condition: while (index < array_length).
3877 __ bind(&loop_1);
3878 // Each iteration of the loop concatenates one string to the result.
3879 // Live values in registers:
3880 // index: which element of the elements array we are adding to the result.
3881 // result_pos: the position to which we are currently copying characters.
3882 // elements: the FixedArray of strings we are joining.
3883 // scratch: array length.
3884
3885 // Get string = array[index].
3886 __ movq(string, FieldOperand(elements, index,
3887 times_pointer_size,
3888 FixedArray::kHeaderSize));
3889 __ SmiToInteger32(string_length,
3890 FieldOperand(string, String::kLengthOffset));
3891 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003892 FieldOperand(string, SeqOneByteString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003893 __ CopyBytes(result_pos, string, string_length);
3894 __ incl(index);
3895 __ bind(&loop_1_condition);
3896 __ cmpl(index, scratch);
3897 __ j(less, &loop_1); // Loop while (index < array_length).
3898 __ jmp(&done);
3899
3900 // Generic bailout code used from several places.
3901 __ bind(&bailout);
3902 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3903 __ jmp(&return_result);
3904
3905
3906 // One-character separator case
3907 __ bind(&one_char_separator);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003908 // Get the separator ASCII character value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003909 // Register "string" holds the separator.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003910 __ movzxbl(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003911 __ Set(index, 0);
3912 // Jump into the loop after the code that copies the separator, so the first
3913 // element is not preceded by a separator
3914 __ jmp(&loop_2_entry);
3915 // Loop condition: while (index < length).
3916 __ bind(&loop_2);
3917 // Each iteration of the loop concatenates one string to the result.
3918 // Live values in registers:
3919 // elements: The FixedArray of strings we are joining.
3920 // index: which element of the elements array we are adding to the result.
3921 // result_pos: the position to which we are currently copying characters.
3922 // scratch: Separator character.
3923
3924 // Copy the separator character to the result.
3925 __ movb(Operand(result_pos, 0), scratch);
3926 __ incq(result_pos);
3927
3928 __ bind(&loop_2_entry);
3929 // Get string = array[index].
3930 __ movq(string, FieldOperand(elements, index,
3931 times_pointer_size,
3932 FixedArray::kHeaderSize));
3933 __ SmiToInteger32(string_length,
3934 FieldOperand(string, String::kLengthOffset));
3935 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003936 FieldOperand(string, SeqOneByteString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003937 __ CopyBytes(result_pos, string, string_length);
3938 __ incl(index);
3939 __ cmpl(index, array_length_operand);
3940 __ j(less, &loop_2); // End while (index < length).
3941 __ jmp(&done);
3942
3943
3944 // Long separator case (separator is more than one character).
3945 __ bind(&long_separator);
3946
3947 // Make elements point to end of elements array, and index
3948 // count from -array_length to zero, so we don't need to maintain
3949 // a loop limit.
3950 __ movl(index, array_length_operand);
3951 __ lea(elements, FieldOperand(elements, index, times_pointer_size,
3952 FixedArray::kHeaderSize));
3953 __ neg(index);
3954
3955 // Replace separator string with pointer to its first character, and
3956 // make scratch be its length.
3957 __ movq(string, separator_operand);
3958 __ SmiToInteger32(scratch,
3959 FieldOperand(string, String::kLengthOffset));
3960 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003961 FieldOperand(string, SeqOneByteString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003962 __ movq(separator_operand, string);
3963
3964 // Jump into the loop after the code that copies the separator, so the first
3965 // element is not preceded by a separator
3966 __ jmp(&loop_3_entry);
3967 // Loop condition: while (index < length).
3968 __ bind(&loop_3);
3969 // Each iteration of the loop concatenates one string to the result.
3970 // Live values in registers:
3971 // index: which element of the elements array we are adding to the result.
3972 // result_pos: the position to which we are currently copying characters.
3973 // scratch: Separator length.
3974 // separator_operand (rsp[0x10]): Address of first char of separator.
3975
3976 // Copy the separator to the result.
3977 __ movq(string, separator_operand);
3978 __ movl(string_length, scratch);
3979 __ CopyBytes(result_pos, string, string_length, 2);
3980
3981 __ bind(&loop_3_entry);
3982 // Get string = array[index].
3983 __ movq(string, Operand(elements, index, times_pointer_size, 0));
3984 __ SmiToInteger32(string_length,
3985 FieldOperand(string, String::kLengthOffset));
3986 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003987 FieldOperand(string, SeqOneByteString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003988 __ CopyBytes(result_pos, string, string_length);
3989 __ incq(index);
3990 __ j(not_equal, &loop_3); // Loop while (index < 0).
3991
3992 __ bind(&done);
3993 __ movq(rax, result_operand);
3994
3995 __ bind(&return_result);
3996 // Drop temp values from the stack, and restore context register.
3997 __ addq(rsp, Immediate(3 * kPointerSize));
3998 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3999 context()->Plug(rax);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00004000}
4001
4002
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004003void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004004 Handle<String> name = expr->name();
4005 if (name->length() > 0 && name->Get(0) == '_') {
4006 Comment cmnt(masm_, "[ InlineRuntimeCall");
4007 EmitInlineRuntimeCall(expr);
4008 return;
4009 }
4010
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004011 Comment cmnt(masm_, "[ CallRuntime");
4012 ZoneList<Expression*>* args = expr->arguments();
4013
4014 if (expr->is_jsruntime()) {
4015 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004016 __ movq(rax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004017 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
4018 }
4019
4020 // Push the arguments ("left-to-right").
4021 int arg_count = args->length();
4022 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004023 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004024 }
4025
4026 if (expr->is_jsruntime()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004027 // Call the JS runtime function using a call IC.
4028 __ Move(rcx, expr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00004029 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004031 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004032 CallIC(ic, mode, expr->CallRuntimeFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004033 // Restore context register.
4034 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004035 } else {
4036 __ CallRuntime(expr->function(), arg_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004037 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004038 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004039}
4040
4041
4042void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
4043 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004044 case Token::DELETE: {
4045 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004046 Property* property = expr->expression()->AsProperty();
4047 VariableProxy* proxy = expr->expression()->AsVariableProxy();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004048
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004049 if (property != NULL) {
4050 VisitForStackValue(property->obj());
4051 VisitForStackValue(property->key());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004052 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
4053 ? kNonStrictMode : kStrictMode;
4054 __ Push(Smi::FromInt(strict_mode_flag));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004055 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4056 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004057 } else if (proxy != NULL) {
4058 Variable* var = proxy->var();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004059 // Delete of an unqualified identifier is disallowed in strict mode
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004060 // but "delete this" is allowed.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004061 ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004062 if (var->IsUnallocated()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004063 __ push(GlobalObjectOperand());
4064 __ Push(var->name());
4065 __ Push(Smi::FromInt(kNonStrictMode));
4066 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4067 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004068 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
4069 // Result of deleting non-global variables is false. 'this' is
4070 // not really a variable, though we implement it as one. The
4071 // subexpression does not have side effects.
4072 context()->Plug(var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004073 } else {
4074 // Non-global variable. Call the runtime to try to delete from the
4075 // context where the variable was introduced.
4076 __ push(context_register());
4077 __ Push(var->name());
4078 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
4079 context()->Plug(rax);
4080 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004081 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004082 // Result of deleting non-property, non-variable reference is true.
4083 // The subexpression may have side effects.
4084 VisitForEffect(expr->expression());
4085 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004086 }
4087 break;
4088 }
4089
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004090 case Token::VOID: {
4091 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
4092 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004093 context()->Plug(Heap::kUndefinedValueRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004094 break;
4095 }
4096
4097 case Token::NOT: {
4098 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004099 if (context()->IsEffect()) {
4100 // Unary NOT has no side effects so it's only necessary to visit the
4101 // subexpression. Match the optimizing compiler by not branching.
4102 VisitForEffect(expr->expression());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004103 } else if (context()->IsTest()) {
4104 const TestContext* test = TestContext::cast(context());
4105 // The labels are swapped for the recursive call.
4106 VisitForControl(expr->expression(),
4107 test->false_label(),
4108 test->true_label(),
4109 test->fall_through());
4110 context()->Plug(test->true_label(), test->false_label());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004111 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004112 // We handle value contexts explicitly rather than simply visiting
4113 // for control and plugging the control flow into the context,
4114 // because we need to prepare a pair of extra administrative AST ids
4115 // for the optimizing compiler.
4116 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
4117 Label materialize_true, materialize_false, done;
4118 VisitForControl(expr->expression(),
4119 &materialize_false,
4120 &materialize_true,
4121 &materialize_true);
4122 __ bind(&materialize_true);
4123 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4124 if (context()->IsAccumulatorValue()) {
4125 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
4126 } else {
4127 __ PushRoot(Heap::kTrueValueRootIndex);
4128 }
4129 __ jmp(&done, Label::kNear);
4130 __ bind(&materialize_false);
4131 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4132 if (context()->IsAccumulatorValue()) {
4133 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
4134 } else {
4135 __ PushRoot(Heap::kFalseValueRootIndex);
4136 }
4137 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004138 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004139 break;
4140 }
4141
4142 case Token::TYPEOF: {
4143 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004144 { StackValueContext context(this);
4145 VisitForTypeofValue(expr->expression());
4146 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004147 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004148 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004149 break;
4150 }
4151
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004152 case Token::SUB:
4153 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004154 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004155
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004156 case Token::BIT_NOT:
4157 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004158 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004159
4160 default:
4161 UNREACHABLE();
4162 }
4163}
4164
4165
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004166void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
4167 const char* comment) {
4168 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
4169 Comment cmt(masm_, comment);
4170 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
4171 UnaryOverwriteMode overwrite =
4172 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004173 UnaryOpStub stub(expr->op(), overwrite);
4174 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004175 // accumulator register rax.
4176 VisitForAccumulatorValue(expr->expression());
4177 SetSourcePosition(expr->position());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004178 CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004179 expr->UnaryOperationFeedbackId());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004180 context()->Plug(rax);
4181}
4182
4183
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004184void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
4185 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004186 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004187
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004188 // Invalid left-hand-sides are rewritten to have a 'throw
4189 // ReferenceError' as the left-hand side.
4190 if (!expr->expression()->IsValidLeftHandSide()) {
4191 VisitForEffect(expr->expression());
4192 return;
4193 }
4194
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004195 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00004196 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004197 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
4198 LhsKind assign_type = VARIABLE;
4199 Property* prop = expr->expression()->AsProperty();
4200 // In case of a property we use the uninitialized expression context
4201 // of the key to detect a named property.
4202 if (prop != NULL) {
4203 assign_type =
4204 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
4205 }
4206
4207 // Evaluate expression and get value.
4208 if (assign_type == VARIABLE) {
4209 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004210 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00004211 EmitVariableLoad(expr->expression()->AsVariableProxy());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004212 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004213 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004214 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004215 __ Push(Smi::FromInt(0));
4216 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004217 if (assign_type == NAMED_PROPERTY) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004218 VisitForAccumulatorValue(prop->obj());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00004219 __ push(rax); // Copy of receiver, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004220 EmitNamedPropertyLoad(prop);
4221 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004222 VisitForStackValue(prop->obj());
4223 VisitForAccumulatorValue(prop->key());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00004224 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack
4225 __ push(rax); // Copy of key, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004226 EmitKeyedPropertyLoad(prop);
4227 }
4228 }
4229
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004230 // We need a second deoptimization point after loading the value
4231 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004232 if (assign_type == VARIABLE) {
4233 PrepareForBailout(expr->expression(), TOS_REG);
4234 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004235 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004236 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004237
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004238 // Call ToNumber only if operand is not a smi.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004239 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004240 __ JumpIfSmi(rax, &no_conversion, Label::kNear);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00004241 ToNumberStub convert_stub;
4242 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004243 __ bind(&no_conversion);
4244
4245 // Save result for postfix expressions.
4246 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004247 if (!context()->IsEffect()) {
4248 // Save the result on the stack. If we have a named or keyed property
4249 // we store the result under the receiver that is currently on top
4250 // of the stack.
4251 switch (assign_type) {
4252 case VARIABLE:
4253 __ push(rax);
4254 break;
4255 case NAMED_PROPERTY:
4256 __ movq(Operand(rsp, kPointerSize), rax);
4257 break;
4258 case KEYED_PROPERTY:
4259 __ movq(Operand(rsp, 2 * kPointerSize), rax);
4260 break;
4261 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004262 }
4263 }
4264
4265 // Inline smi case if we are in a loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004266 Label done, stub_call;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004267 JumpPatchSite patch_site(masm_);
4268
ricow@chromium.org65fae842010-08-25 15:26:24 +00004269 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004270 if (expr->op() == Token::INC) {
4271 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
4272 } else {
4273 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
4274 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004275 __ j(overflow, &stub_call, Label::kNear);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004276 // We could eliminate this smi check if we split the code at
4277 // the first smi check before calling ToNumber.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004278 patch_site.EmitJumpIfSmi(rax, &done, Label::kNear);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004279
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004280 __ bind(&stub_call);
4281 // Call stub. Undo operation first.
4282 if (expr->op() == Token::INC) {
4283 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
4284 } else {
4285 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
4286 }
4287 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004288
4289 // Record position before stub call.
4290 SetSourcePosition(expr->position());
4291
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004292 // Call stub for +1/-1.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004293 __ movq(rdx, rax);
4294 __ Move(rax, Smi::FromInt(1));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004295 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004296 CallIC(stub.GetCode(isolate()),
4297 RelocInfo::CODE_TARGET,
4298 expr->CountBinOpFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004299 patch_site.EmitPatchInfo();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004300 __ bind(&done);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004301
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004302 // Store the value returned in rax.
4303 switch (assign_type) {
4304 case VARIABLE:
4305 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004306 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004307 { EffectContext context(this);
4308 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4309 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004310 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004311 context.Plug(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004312 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004313 // For all contexts except kEffect: We have the result on
4314 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004315 if (!context()->IsEffect()) {
4316 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004317 }
4318 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004319 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004320 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004321 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004322 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004323 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004324 }
4325 break;
4326 case NAMED_PROPERTY: {
4327 __ Move(rcx, prop->key()->AsLiteral()->handle());
4328 __ pop(rdx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004329 Handle<Code> ic = is_classic_mode()
4330 ? isolate()->builtins()->StoreIC_Initialize()
4331 : isolate()->builtins()->StoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004332 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004333 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004334 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004335 if (!context()->IsEffect()) {
4336 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004337 }
4338 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004339 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004340 }
4341 break;
4342 }
4343 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004344 __ pop(rcx);
4345 __ pop(rdx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004346 Handle<Code> ic = is_classic_mode()
4347 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4348 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004349 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004350 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004351 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004352 if (!context()->IsEffect()) {
4353 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004354 }
4355 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004356 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004357 }
4358 break;
4359 }
4360 }
4361}
4362
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004363
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004364void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004365 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004366 ASSERT(!context()->IsEffect());
4367 ASSERT(!context()->IsTest());
4368
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004369 if (proxy != NULL && proxy->var()->IsUnallocated()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004370 Comment cmnt(masm_, "Global variable");
4371 __ Move(rcx, proxy->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004372 __ movq(rax, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004373 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004374 // Use a regular load, not a contextual load, to avoid a reference
4375 // error.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004376 CallIC(ic);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004377 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004378 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004379 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004380 Label done, slow;
4381
4382 // Generate code for loading from variables potentially shadowed
4383 // by eval-introduced variables.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004384 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004385
4386 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004387 __ push(rsi);
4388 __ Push(proxy->name());
4389 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004390 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004391 __ bind(&done);
4392
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004393 context()->Plug(rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004394 } else {
4395 // This expression cannot throw a reference error at the top level.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004396 VisitInDuplicateContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004397 }
4398}
4399
4400
ager@chromium.org04921a82011-06-27 13:21:41 +00004401void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004402 Expression* sub_expr,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004403 Handle<String> check) {
4404 Label materialize_true, materialize_false;
4405 Label* if_true = NULL;
4406 Label* if_false = NULL;
4407 Label* fall_through = NULL;
4408 context()->PrepareTest(&materialize_true, &materialize_false,
4409 &if_true, &if_false, &fall_through);
4410
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004411 { AccumulatorValueContext context(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004412 VisitForTypeofValue(sub_expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004413 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004414 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004415
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004416 if (check->Equals(isolate()->heap()->number_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004417 __ JumpIfSmi(rax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004418 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
4419 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
4420 Split(equal, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004421 } else if (check->Equals(isolate()->heap()->string_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004422 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004423 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004424 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
4425 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004426 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004427 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004428 Split(zero, if_true, if_false, fall_through);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004429 } else if (check->Equals(isolate()->heap()->symbol_string())) {
4430 __ JumpIfSmi(rax, if_false);
4431 __ CmpObjectType(rax, SYMBOL_TYPE, rdx);
4432 Split(equal, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004433 } else if (check->Equals(isolate()->heap()->boolean_string())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004434 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
4435 __ j(equal, if_true);
4436 __ CompareRoot(rax, Heap::kFalseValueRootIndex);
4437 Split(equal, if_true, if_false, fall_through);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004438 } else if (FLAG_harmony_typeof &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004439 check->Equals(isolate()->heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004440 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4441 Split(equal, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004442 } else if (check->Equals(isolate()->heap()->undefined_string())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004443 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4444 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004445 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004446 // Check for undetectable objects => true.
4447 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
4448 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4449 Immediate(1 << Map::kIsUndetectable));
4450 Split(not_zero, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004451 } else if (check->Equals(isolate()->heap()->function_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004452 __ JumpIfSmi(rax, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004453 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4454 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx);
4455 __ j(equal, if_true);
4456 __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
4457 Split(equal, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004458 } else if (check->Equals(isolate()->heap()->object_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004459 __ JumpIfSmi(rax, if_false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004460 if (!FLAG_harmony_typeof) {
4461 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4462 __ j(equal, if_true);
4463 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004464 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004465 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004466 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4467 __ j(above, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004468 // Check for undetectable objects => false.
4469 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4470 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004471 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004472 } else {
4473 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004474 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004475 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004476}
4477
4478
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004479void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4480 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004481 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004482
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004483 // First we try a fast inlined version of the compare when one of
4484 // the operands is a literal.
4485 if (TryLiteralCompare(expr)) return;
4486
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004487 // Always perform the comparison for its control flow. Pack the result
4488 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004489 Label materialize_true, materialize_false;
4490 Label* if_true = NULL;
4491 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004492 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004493 context()->PrepareTest(&materialize_true, &materialize_false,
4494 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004495
ager@chromium.org04921a82011-06-27 13:21:41 +00004496 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004497 VisitForStackValue(expr->left());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004498 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004499 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004500 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004501 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004502 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004503 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004504 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004505 break;
4506
4507 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004508 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004509 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004510 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004511 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004512 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004513 // The stub returns 0 for true.
4514 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004515 break;
4516 }
4517
4518 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004519 VisitForAccumulatorValue(expr->right());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004520 Condition cc = CompareIC::ComputeCondition(op);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004521 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004522
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004523 bool inline_smi_code = ShouldInlineSmiCase(op);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004524 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004525 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004526 Label slow_case;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004527 __ movq(rcx, rdx);
4528 __ or_(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004529 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004530 __ cmpq(rdx, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004531 Split(cc, if_true, if_false, NULL);
4532 __ bind(&slow_case);
4533 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004534
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004535 // Record position and call the compare IC.
4536 SetSourcePosition(expr->position());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004537 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004538 CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004539 patch_site.EmitPatchInfo();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004540
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004541 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004542 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004543 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004544 }
4545 }
4546
4547 // Convert the result of the comparison into one expected for this
4548 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004549 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004550}
4551
4552
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004553void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4554 Expression* sub_expr,
4555 NilValue nil) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004556 Label materialize_true, materialize_false;
4557 Label* if_true = NULL;
4558 Label* if_false = NULL;
4559 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004560 context()->PrepareTest(&materialize_true, &materialize_false,
4561 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004562
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004563 VisitForAccumulatorValue(sub_expr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004564 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004565 EqualityKind kind = expr->op() == Token::EQ_STRICT
4566 ? kStrictEquality : kNonStrictEquality;
4567 if (kind == kStrictEquality) {
4568 Heap::RootListIndex nil_value = nil == kNullValue ?
4569 Heap::kNullValueRootIndex :
4570 Heap::kUndefinedValueRootIndex;
4571 __ CompareRoot(rax, nil_value);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004572 Split(equal, if_true, if_false, fall_through);
4573 } else {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004574 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(),
4575 kNonStrictEquality,
4576 nil);
4577 CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId());
4578 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004579 Split(not_zero, if_true, if_false, fall_through);
4580 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004581 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004582}
4583
4584
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004585void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4586 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004587 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004588}
4589
4590
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004591Register FullCodeGenerator::result_register() {
4592 return rax;
4593}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004594
4595
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004596Register FullCodeGenerator::context_register() {
4597 return rsi;
4598}
4599
4600
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004601void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4602 ASSERT(IsAligned(frame_offset, kPointerSize));
4603 __ movq(Operand(rbp, frame_offset), value);
4604}
4605
4606
4607void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004608 __ movq(dst, ContextOperand(rsi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004609}
4610
4611
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004612void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004613 Scope* declaration_scope = scope()->DeclarationScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004614 if (declaration_scope->is_global_scope() ||
4615 declaration_scope->is_module_scope()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004616 // Contexts nested in the native context have a canonical empty function
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004617 // as their closure, not the anonymous closure containing the global
4618 // code. Pass a smi sentinel and let the runtime look up the empty
4619 // function.
4620 __ Push(Smi::FromInt(0));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004621 } else if (declaration_scope->is_eval_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004622 // Contexts created by a call to eval have the same closure as the
4623 // context calling eval, not the anonymous closure containing the eval
4624 // code. Fetch it from the context.
4625 __ push(ContextOperand(rsi, Context::CLOSURE_INDEX));
4626 } else {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004627 ASSERT(declaration_scope->is_function_scope());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004628 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
4629 }
4630}
4631
4632
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004633// ----------------------------------------------------------------------------
4634// Non-local control flow support.
4635
4636
4637void FullCodeGenerator::EnterFinallyBlock() {
4638 ASSERT(!result_register().is(rdx));
4639 ASSERT(!result_register().is(rcx));
4640 // Cook return address on top of stack (smi encoded Code* delta)
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004641 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004642 __ Move(rcx, masm_->CodeObject());
4643 __ subq(rdx, rcx);
4644 __ Integer32ToSmi(rdx, rdx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004645 __ push(rdx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004646
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004647 // Store result register while executing finally block.
4648 __ push(result_register());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004649
4650 // Store pending message while executing finally block.
4651 ExternalReference pending_message_obj =
4652 ExternalReference::address_of_pending_message_obj(isolate());
4653 __ Load(rdx, pending_message_obj);
4654 __ push(rdx);
4655
4656 ExternalReference has_pending_message =
4657 ExternalReference::address_of_has_pending_message(isolate());
4658 __ Load(rdx, has_pending_message);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004659 __ Integer32ToSmi(rdx, rdx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004660 __ push(rdx);
4661
4662 ExternalReference pending_message_script =
4663 ExternalReference::address_of_pending_message_script(isolate());
4664 __ Load(rdx, pending_message_script);
4665 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004666}
4667
4668
4669void FullCodeGenerator::ExitFinallyBlock() {
4670 ASSERT(!result_register().is(rdx));
4671 ASSERT(!result_register().is(rcx));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004672 // Restore pending message from stack.
4673 __ pop(rdx);
4674 ExternalReference pending_message_script =
4675 ExternalReference::address_of_pending_message_script(isolate());
4676 __ Store(pending_message_script, rdx);
4677
4678 __ pop(rdx);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004679 __ SmiToInteger32(rdx, rdx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004680 ExternalReference has_pending_message =
4681 ExternalReference::address_of_has_pending_message(isolate());
4682 __ Store(has_pending_message, rdx);
4683
4684 __ pop(rdx);
4685 ExternalReference pending_message_obj =
4686 ExternalReference::address_of_pending_message_obj(isolate());
4687 __ Store(pending_message_obj, rdx);
4688
4689 // Restore result register from stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004690 __ pop(result_register());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004691
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004692 // Uncook return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004693 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004694 __ SmiToInteger32(rdx, rdx);
4695 __ Move(rcx, masm_->CodeObject());
4696 __ addq(rdx, rcx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004697 __ jmp(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004698}
4699
4700
4701#undef __
4702
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004703#define __ ACCESS_MASM(masm())
4704
4705FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4706 int* stack_depth,
4707 int* context_length) {
4708 // The macros used here must preserve the result register.
4709
4710 // Because the handler block contains the context of the finally
4711 // code, we can restore it directly from there for the finally code
4712 // rather than iteratively unwinding contexts via their previous
4713 // links.
4714 __ Drop(*stack_depth); // Down to the handler block.
4715 if (*context_length > 0) {
4716 // Restore the context to its dedicated register and the stack.
4717 __ movq(rsi, Operand(rsp, StackHandlerConstants::kContextOffset));
4718 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
4719 }
4720 __ PopTryHandler();
4721 __ call(finally_entry_);
4722
4723 *stack_depth = 0;
4724 *context_length = 0;
4725 return previous_;
4726}
4727
4728
4729#undef __
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004730
4731} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004732
4733#endif // V8_TARGET_ARCH_X64