blob: 7a60adc0b37db09bf368fc6ee61556f461d016a6 [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"
37#include "parser.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000038#include "scopes.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000039#include "stub-cache.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000040
41namespace v8 {
42namespace internal {
43
44#define __ ACCESS_MASM(masm_)
45
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000046
47class JumpPatchSite BASE_EMBEDDED {
48 public:
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000049 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000050#ifdef DEBUG
51 info_emitted_ = false;
52#endif
53 }
54
55 ~JumpPatchSite() {
56 ASSERT(patch_site_.is_bound() == info_emitted_);
57 }
58
karlklose@chromium.org83a47282011-05-11 11:54:09 +000059 void EmitJumpIfNotSmi(Register reg,
60 Label* target,
61 Label::Distance near_jump = Label::kFar) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000062 __ testb(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000063 EmitJump(not_carry, target, near_jump); // Always taken before patched.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000064 }
65
karlklose@chromium.org83a47282011-05-11 11:54:09 +000066 void EmitJumpIfSmi(Register reg,
67 Label* target,
68 Label::Distance near_jump = Label::kFar) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000069 __ testb(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000070 EmitJump(carry, target, near_jump); // Never taken before patched.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000071 }
72
73 void EmitPatchInfo() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000074 if (patch_site_.is_bound()) {
75 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
76 ASSERT(is_int8(delta_to_patch_site));
77 __ testl(rax, Immediate(delta_to_patch_site));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000078#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +000079 info_emitted_ = true;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000080#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +000081 } else {
82 __ nop(); // Signals no inlined code.
83 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000084 }
85
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000086 private:
87 // jc will be patched with jz, jnc will become jnz.
karlklose@chromium.org83a47282011-05-11 11:54:09 +000088 void EmitJump(Condition cc, Label* target, Label::Distance near_jump) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000089 ASSERT(!patch_site_.is_bound() && !info_emitted_);
90 ASSERT(cc == carry || cc == not_carry);
91 __ bind(&patch_site_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +000092 __ j(cc, target, near_jump);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000093 }
94
95 MacroAssembler* masm_;
96 Label patch_site_;
97#ifdef DEBUG
98 bool info_emitted_;
99#endif
100};
101
102
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000103int FullCodeGenerator::self_optimization_header_size() {
104 return 20;
105}
106
107
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000108// Generate code for a JS function. On entry to the function the receiver
109// and arguments have been pushed on the stack left to right, with the
110// return address on top of them. The actual argument count matches the
111// formal parameter count expected by the function.
112//
113// The live registers are:
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000114// o rdi: the JS function object being called (i.e. ourselves)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000115// o rsi: our context
116// o rbp: our caller's frame pointer
117// o rsp: stack pointer (pointing to return address)
118//
119// The function builds a JS frame. Please see JavaScriptFrameConstants in
120// frames-x64.h for its layout.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000121void FullCodeGenerator::Generate() {
122 CompilationInfo* info = info_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000123 handler_table_ =
124 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
ager@chromium.org5c838252010-02-19 08:53:10 +0000125 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000126 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000128 // We can optionally optimize based on counters rather than statistical
129 // sampling.
130 if (info->ShouldSelfOptimize()) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000131 if (FLAG_trace_opt_verbose) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000132 PrintF("[adding self-optimization header to %s]\n",
133 *info->function()->debug_name()->ToCString());
134 }
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000135 has_self_optimization_header_ = true;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000136 MaybeObject* maybe_cell = isolate()->heap()->AllocateJSGlobalPropertyCell(
137 Smi::FromInt(Compiler::kCallsUntilPrimitiveOpt));
138 JSGlobalPropertyCell* cell;
139 if (maybe_cell->To(&cell)) {
140 __ movq(rax, Handle<JSGlobalPropertyCell>(cell),
141 RelocInfo::EMBEDDED_OBJECT);
142 __ SmiAddConstant(FieldOperand(rax, JSGlobalPropertyCell::kValueOffset),
143 Smi::FromInt(-1));
144 Handle<Code> compile_stub(
145 isolate()->builtins()->builtin(Builtins::kLazyRecompile));
146 __ j(zero, compile_stub, RelocInfo::CODE_TARGET);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000147 ASSERT(masm_->pc_offset() == self_optimization_header_size());
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000148 }
149 }
150
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000151#ifdef DEBUG
152 if (strlen(FLAG_stop_at) > 0 &&
153 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
154 __ int3();
155 }
156#endif
157
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000158 // Strict mode functions and builtins need to replace the receiver
159 // with undefined when called as functions (without an explicit
160 // receiver object). rcx is zero for method calls and non-zero for
161 // function calls.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000162 if (!info->is_classic_mode() || info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000163 Label ok;
164 __ testq(rcx, rcx);
165 __ j(zero, &ok, Label::kNear);
166 // +1 for return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000167 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000168 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
169 __ movq(Operand(rsp, receiver_offset), kScratchRegister);
170 __ bind(&ok);
171 }
172
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000173 // Open a frame scope to indicate that there is a frame on the stack. The
174 // MANUAL indicates that the scope shouldn't actually generate code to set up
175 // the frame (that is done below).
176 FrameScope frame_scope(masm_, StackFrame::MANUAL);
177
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000178 __ push(rbp); // Caller's frame pointer.
179 __ movq(rbp, rsp);
180 __ push(rsi); // Callee's context.
181 __ push(rdi); // Callee's JS Function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000182
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000183 { Comment cmnt(masm_, "[ Allocate locals");
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000184 int locals_count = info->scope()->num_stack_slots();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000185 if (locals_count == 1) {
186 __ PushRoot(Heap::kUndefinedValueRootIndex);
187 } else if (locals_count > 1) {
188 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
189 for (int i = 0; i < locals_count; i++) {
190 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000191 }
192 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000193 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000195 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000196
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000197 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000198 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000199 if (heap_slots > 0) {
200 Comment cmnt(masm_, "[ Allocate local context");
201 // Argument to NewContext is the function, which is still in rdi.
202 __ push(rdi);
203 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
204 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000206 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000207 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000209 function_in_register = false;
210 // Context is returned in both rax and rsi. It replaces the context
211 // passed to us. It's saved in the stack and kept live in rsi.
212 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
213
214 // Copy any necessary parameters into the context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000215 int num_parameters = info->scope()->num_parameters();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000216 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000217 Variable* var = scope()->parameter(i);
218 if (var->IsContextSlot()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000219 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
220 (num_parameters - 1 - i) * kPointerSize;
221 // Load parameter from stack.
222 __ movq(rax, Operand(rbp, parameter_offset));
223 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000224 int context_offset = Context::SlotOffset(var->index());
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000225 __ movq(Operand(rsi, context_offset), rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000226 // Update the write barrier. This clobbers rax and rbx.
227 __ RecordWriteContextSlot(
228 rsi, context_offset, rax, rbx, kDontSaveFPRegs);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000229 }
230 }
231 }
232
233 // Possibly allocate an arguments object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000234 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000235 if (arguments != NULL) {
236 // Arguments object must be allocated after the context object, in
237 // case the "arguments" or ".arguments" variables are in the context.
238 Comment cmnt(masm_, "[ Allocate arguments object");
239 if (function_in_register) {
240 __ push(rdi);
241 } else {
242 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
243 }
244 // The receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000245 int num_parameters = info->scope()->num_parameters();
246 int offset = num_parameters * kPointerSize;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000247 __ lea(rdx,
248 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
249 __ push(rdx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000250 __ Push(Smi::FromInt(num_parameters));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000251 // Arguments to ArgumentsAccessStub:
252 // function, receiver address, parameter count.
253 // The stub will rewrite receiver and parameter count if the previous
254 // stack frame was an arguments adapter frame.
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000255 ArgumentsAccessStub::Type type;
256 if (!is_classic_mode()) {
257 type = ArgumentsAccessStub::NEW_STRICT;
258 } else if (function()->has_duplicate_parameters()) {
259 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
260 } else {
261 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
262 }
263 ArgumentsAccessStub stub(type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000264 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000265
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000266 SetVar(arguments, rax, rbx, rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000267 }
268
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000269 if (FLAG_trace) {
270 __ CallRuntime(Runtime::kTraceEnter, 0);
271 }
272
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000273 // Visit the declarations and body unless there is an illegal
274 // redeclaration.
275 if (scope()->HasIllegalRedeclaration()) {
276 Comment cmnt(masm_, "[ Declarations");
277 scope()->VisitIllegalRedeclaration(this);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000278
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000279 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000280 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000281 { Comment cmnt(masm_, "[ Declarations");
282 // For named function expressions, declare the function name as a
283 // constant.
284 if (scope()->is_function_scope() && scope()->function() != NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000285 VariableProxy* proxy = scope()->function();
286 ASSERT(proxy->var()->mode() == CONST ||
287 proxy->var()->mode() == CONST_HARMONY);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000288 ASSERT(proxy->var()->location() != Variable::UNALLOCATED);
289 EmitDeclaration(proxy, proxy->var()->mode(), NULL);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000290 }
291 VisitDeclarations(scope()->declarations());
292 }
293
294 { Comment cmnt(masm_, "[ Stack check");
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000295 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000296 Label ok;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000297 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000298 __ j(above_equal, &ok, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000299 StackCheckStub stub;
300 __ CallStub(&stub);
301 __ bind(&ok);
302 }
303
304 { Comment cmnt(masm_, "[ Body");
305 ASSERT(loop_depth() == 0);
306 VisitStatements(function()->body());
307 ASSERT(loop_depth() == 0);
308 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000309 }
310
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000311 // Always emit a 'return undefined' in case control fell off the end of
312 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000313 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000314 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000315 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000316 }
317}
318
319
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000320void FullCodeGenerator::ClearAccumulator() {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000321 __ Set(rax, 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000322}
323
324
yangguo@chromium.org56454712012-02-16 15:33:53 +0000325void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt,
326 Label* back_edge_target) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000327 Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000328 Label ok;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000329 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000330 __ j(above_equal, &ok, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000331 StackCheckStub stub;
332 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000333 // Record a mapping of this PC offset to the OSR id. This is used to find
334 // the AST id from the unoptimized code in order to use it as a key into
335 // the deoptimization input data found in the optimized code.
336 RecordStackCheck(stmt->OsrEntryId());
337
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000338 // Loop stack checks can be patched to perform on-stack replacement. In
339 // order to decide whether or not to perform OSR we embed the loop depth
340 // in a test instruction after the call so we can extract it from the OSR
341 // builtin.
342 ASSERT(loop_depth() > 0);
343 __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
344
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000345 __ bind(&ok);
346 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000347 // Record a mapping of the OSR id to this PC. This is used if the OSR
348 // entry becomes the target of a bailout. We don't expect it to be, but
349 // we want it to work if it is.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000350 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000351}
352
353
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000354void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000355 Comment cmnt(masm_, "[ Return sequence");
356 if (return_label_.is_bound()) {
357 __ jmp(&return_label_);
358 } else {
359 __ bind(&return_label_);
360 if (FLAG_trace) {
361 __ push(rax);
362 __ CallRuntime(Runtime::kTraceExit, 1);
363 }
364#ifdef DEBUG
365 // Add a label for checking the size of the code used for returning.
366 Label check_exit_codesize;
367 masm_->bind(&check_exit_codesize);
368#endif
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000369 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000370 __ RecordJSReturn();
371 // Do not use the leave instruction here because it is too short to
372 // patch with the code required by the debugger.
373 __ movq(rsp, rbp);
374 __ pop(rbp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000375
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000376 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000377 __ Ret(arguments_bytes, rcx);
378
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000379#ifdef ENABLE_DEBUGGER_SUPPORT
380 // Add padding that will be overwritten by a debugger breakpoint. We
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000381 // have just generated at least 7 bytes: "movq rsp, rbp; pop rbp; ret k"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000382 // (3 + 1 + 3).
383 const int kPadding = Assembler::kJSReturnSequenceLength - 7;
384 for (int i = 0; i < kPadding; ++i) {
385 masm_->int3();
386 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000387 // Check that the size of the code used for returning is large enough
388 // for the debugger's requirements.
389 ASSERT(Assembler::kJSReturnSequenceLength <=
390 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000391#endif
392 }
393}
394
395
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000396void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
397 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000398}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000399
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000400
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000401void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
402 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
403 codegen()->GetVar(result_register(), var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000404}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000405
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000406
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000407void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
408 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
409 MemOperand operand = codegen()->VarOperand(var, result_register());
410 __ push(operand);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000411}
412
413
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000414void FullCodeGenerator::TestContext::Plug(Variable* var) const {
415 codegen()->GetVar(result_register(), var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000416 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000417 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000418}
419
420
421void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
422}
423
424
425void FullCodeGenerator::AccumulatorValueContext::Plug(
426 Heap::RootListIndex index) const {
427 __ LoadRoot(result_register(), index);
428}
429
430
431void FullCodeGenerator::StackValueContext::Plug(
432 Heap::RootListIndex index) const {
433 __ PushRoot(index);
434}
435
436
437void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000438 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000439 true,
440 true_label_,
441 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000442 if (index == Heap::kUndefinedValueRootIndex ||
443 index == Heap::kNullValueRootIndex ||
444 index == Heap::kFalseValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000445 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000446 } else if (index == Heap::kTrueValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000447 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000448 } else {
449 __ LoadRoot(result_register(), index);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000450 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000451 }
452}
453
454
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000455void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
456}
457
458
459void FullCodeGenerator::AccumulatorValueContext::Plug(
460 Handle<Object> lit) const {
461 __ Move(result_register(), lit);
462}
463
464
465void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
466 __ Push(lit);
467}
468
469
470void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000471 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000472 true,
473 true_label_,
474 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000475 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
476 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000477 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000478 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000479 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000480 } else if (lit->IsString()) {
481 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000482 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000483 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000484 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000485 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000486 } else if (lit->IsSmi()) {
487 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000488 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000489 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000490 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000491 }
492 } else {
493 // For simplicity we always test the accumulator register.
494 __ Move(result_register(), lit);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000495 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000496 }
497}
498
499
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000500void FullCodeGenerator::EffectContext::DropAndPlug(int count,
501 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000502 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000503 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000504}
505
506
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000507void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
508 int count,
509 Register reg) const {
510 ASSERT(count > 0);
511 __ Drop(count);
512 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000513}
514
515
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000516void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
517 Register reg) const {
518 ASSERT(count > 0);
519 if (count > 1) __ Drop(count - 1);
520 __ movq(Operand(rsp, 0), reg);
521}
522
523
524void FullCodeGenerator::TestContext::DropAndPlug(int count,
525 Register reg) const {
526 ASSERT(count > 0);
527 // For simplicity we always test the accumulator register.
528 __ Drop(count);
529 __ Move(result_register(), reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000530 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000531 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000532}
533
534
535void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
536 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000537 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000538 __ bind(materialize_true);
539}
540
541
542void FullCodeGenerator::AccumulatorValueContext::Plug(
543 Label* materialize_true,
544 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000545 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000546 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 __ Move(result_register(), isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000548 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000549 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 __ Move(result_register(), isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000551 __ bind(&done);
552}
553
554
555void FullCodeGenerator::StackValueContext::Plug(
556 Label* materialize_true,
557 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000558 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000559 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 __ Push(isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000561 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000562 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 __ Push(isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000564 __ bind(&done);
565}
566
567
568void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
569 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000570 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000571 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000572}
573
574
575void FullCodeGenerator::EffectContext::Plug(bool flag) const {
576}
577
578
579void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
580 Heap::RootListIndex value_root_index =
581 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
582 __ LoadRoot(result_register(), value_root_index);
583}
584
585
586void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
587 Heap::RootListIndex value_root_index =
588 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
589 __ PushRoot(value_root_index);
590}
591
592
593void FullCodeGenerator::TestContext::Plug(bool flag) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000594 codegen()->PrepareForBailoutBeforeSplit(condition(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000595 true,
596 true_label_,
597 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000598 if (flag) {
599 if (true_label_ != fall_through_) __ jmp(true_label_);
600 } else {
601 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000602 }
603}
604
605
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000606void FullCodeGenerator::DoTest(Expression* condition,
607 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000608 Label* if_false,
609 Label* fall_through) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000610 ToBooleanStub stub(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000611 __ push(result_register());
612 __ CallStub(&stub);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000613 __ testq(result_register(), result_register());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000614 // The stub returns nonzero for true.
615 Split(not_zero, if_true, if_false, fall_through);
616}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000617
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000618
ricow@chromium.org65fae842010-08-25 15:26:24 +0000619void FullCodeGenerator::Split(Condition cc,
620 Label* if_true,
621 Label* if_false,
622 Label* fall_through) {
623 if (if_false == fall_through) {
624 __ j(cc, if_true);
625 } else if (if_true == fall_through) {
626 __ j(NegateCondition(cc), if_false);
627 } else {
628 __ j(cc, if_true);
629 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000630 }
631}
632
633
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000634MemOperand FullCodeGenerator::StackOperand(Variable* var) {
635 ASSERT(var->IsStackAllocated());
636 // Offset is negative because higher indexes are at lower addresses.
637 int offset = -var->index() * kPointerSize;
638 // Adjust by a (parameter or local) base offset.
639 if (var->IsParameter()) {
640 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
641 } else {
642 offset += JavaScriptFrameConstants::kLocal0Offset;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000643 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000644 return Operand(rbp, offset);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000645}
646
647
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000648MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
649 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
650 if (var->IsContextSlot()) {
651 int context_chain_length = scope()->ContextChainLength(var->scope());
652 __ LoadContext(scratch, context_chain_length);
653 return ContextOperand(scratch, var->index());
654 } else {
655 return StackOperand(var);
656 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000657}
658
659
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000660void FullCodeGenerator::GetVar(Register dest, Variable* var) {
661 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
662 MemOperand location = VarOperand(var, dest);
663 __ movq(dest, location);
664}
665
666
667void FullCodeGenerator::SetVar(Variable* var,
668 Register src,
669 Register scratch0,
670 Register scratch1) {
671 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
672 ASSERT(!scratch0.is(src));
673 ASSERT(!scratch0.is(scratch1));
674 ASSERT(!scratch1.is(src));
675 MemOperand location = VarOperand(var, scratch0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000676 __ movq(location, src);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000677
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000678 // Emit the write barrier code if the location is in the heap.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000679 if (var->IsContextSlot()) {
680 int offset = Context::SlotOffset(var->index());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000681 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000682 }
683}
684
685
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000686void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000687 bool should_normalize,
688 Label* if_true,
689 Label* if_false) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000690 // Only prepare for bailouts before splits if we're in a test
691 // context. Otherwise, we let the Visit function deal with the
692 // preparation to avoid preparing with the same AST id twice.
693 if (!context()->IsTest() || !info_->IsOptimizable()) return;
694
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000695 Label skip;
696 if (should_normalize) __ jmp(&skip, Label::kNear);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000697 PrepareForBailout(expr, TOS_REG);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000698 if (should_normalize) {
699 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
700 Split(equal, if_true, if_false, NULL);
701 __ bind(&skip);
702 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000703}
704
705
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000706void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000707 VariableMode mode,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000708 FunctionLiteral* function) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000709 // If it was not possible to allocate the variable at compile time, we
710 // need to "declare" it at runtime to make sure it actually exists in the
711 // local context.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000712 Variable* variable = proxy->var();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000713 bool binding_needs_init = (function == NULL) &&
714 (mode == CONST || mode == CONST_HARMONY || mode == LET);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000715 switch (variable->location()) {
716 case Variable::UNALLOCATED:
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000717 ++global_count_;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000718 break;
719
720 case Variable::PARAMETER:
721 case Variable::LOCAL:
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000722 if (function != NULL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000723 Comment cmnt(masm_, "[ Declaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000724 VisitForAccumulatorValue(function);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000725 __ movq(StackOperand(variable), result_register());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000726 } else if (binding_needs_init) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000727 Comment cmnt(masm_, "[ Declaration");
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000728 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000729 __ movq(StackOperand(variable), kScratchRegister);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000730 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000731 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000732
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000733 case Variable::CONTEXT:
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000734 // The variable in the decl always resides in the current function
735 // context.
736 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
737 if (FLAG_debug_code) {
738 // Check that we're not inside a with or catch context.
739 __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
740 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
741 __ Check(not_equal, "Declaration in with context.");
742 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
743 __ Check(not_equal, "Declaration in catch context.");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000744 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000745 if (function != NULL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000746 Comment cmnt(masm_, "[ Declaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000747 VisitForAccumulatorValue(function);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000748 __ movq(ContextOperand(rsi, variable->index()), result_register());
749 int offset = Context::SlotOffset(variable->index());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000750 // We know that we have written a function, which is not a smi.
751 __ RecordWriteContextSlot(rsi,
752 offset,
753 result_register(),
754 rcx,
755 kDontSaveFPRegs,
756 EMIT_REMEMBERED_SET,
757 OMIT_SMI_CHECK);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000758 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000759 } else if (binding_needs_init) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000760 Comment cmnt(masm_, "[ Declaration");
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000761 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000762 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000763 // No write barrier since the hole value is in old space.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000764 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000765 }
766 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000767
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000768 case Variable::LOOKUP: {
769 Comment cmnt(masm_, "[ Declaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000770 __ push(rsi);
771 __ Push(variable->name());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000772 // Declaration nodes are always introduced in one of four modes.
773 ASSERT(mode == VAR ||
774 mode == CONST ||
775 mode == CONST_HARMONY ||
776 mode == LET);
777 PropertyAttributes attr =
778 (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000779 __ Push(Smi::FromInt(attr));
780 // Push initial value, if any.
781 // Note: For variables we must not push an initial value (such as
782 // 'undefined') because we may have a (legal) redeclaration and we
783 // must not destroy the current value.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000784 if (function != NULL) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000785 VisitForStackValue(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000786 } else if (binding_needs_init) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000787 __ PushRoot(Heap::kTheHoleValueRootIndex);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000788 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000789 __ Push(Smi::FromInt(0)); // Indicates no initial value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000790 }
791 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
792 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000793 }
794 }
795}
796
797
798void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
799 // Call the runtime to declare the globals.
800 __ push(rsi); // The context is the first argument.
801 __ Push(pairs);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000802 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
803 __ CallRuntime(Runtime::kDeclareGlobals, 3);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000804 // Return value is ignored.
805}
806
807
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000808void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
809 Comment cmnt(masm_, "[ SwitchStatement");
810 Breakable nested_statement(this, stmt);
811 SetStatementPosition(stmt);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000812
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000813 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000814 VisitForStackValue(stmt->tag());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000815 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000816
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000817 ZoneList<CaseClause*>* clauses = stmt->cases();
818 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000819
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000820 Label next_test; // Recycled for each test.
821 // Compile all the tests with branches to their bodies.
822 for (int i = 0; i < clauses->length(); i++) {
823 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000824 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000825
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000826 // The default is not a test, but remember it as final fall through.
827 if (clause->is_default()) {
828 default_clause = clause;
829 continue;
830 }
831
832 Comment cmnt(masm_, "[ Case comparison");
833 __ bind(&next_test);
834 next_test.Unuse();
835
836 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000837 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000838
ricow@chromium.org65fae842010-08-25 15:26:24 +0000839 // Perform the comparison as if via '==='.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000840 __ movq(rdx, Operand(rsp, 0)); // Switch value.
841 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000842 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000843 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000844 Label slow_case;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000845 __ movq(rcx, rdx);
846 __ or_(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000847 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000848
849 __ cmpq(rdx, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000850 __ j(not_equal, &next_test);
851 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000852 __ jmp(clause->body_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000853 __ bind(&slow_case);
854 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000855
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000856 // Record position before stub call for type feedback.
857 SetSourcePosition(clause->position());
858 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000859 __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
860 patch_site.EmitPatchInfo();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000861
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000862 __ testq(rax, rax);
863 __ j(not_equal, &next_test);
864 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000865 __ jmp(clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000866 }
867
868 // Discard the test value and jump to the default if present, otherwise to
869 // the end of the statement.
870 __ bind(&next_test);
871 __ Drop(1); // Switch value is no longer needed.
872 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000873 __ jmp(nested_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000874 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000875 __ jmp(default_clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000876 }
877
878 // Compile all the case bodies.
879 for (int i = 0; i < clauses->length(); i++) {
880 Comment cmnt(masm_, "[ Case body");
881 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000882 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000883 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000884 VisitStatements(clause->statements());
885 }
886
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000887 __ bind(nested_statement.break_label());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000888 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000889}
890
891
892void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
893 Comment cmnt(masm_, "[ ForInStatement");
894 SetStatementPosition(stmt);
895
896 Label loop, exit;
897 ForIn loop_statement(this, stmt);
898 increment_loop_depth();
899
900 // Get the object to enumerate over. Both SpiderMonkey and JSC
901 // ignore null and undefined in contrast to the specification; see
902 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000903 VisitForAccumulatorValue(stmt->enumerable());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000904 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
905 __ j(equal, &exit);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000906 Register null_value = rdi;
907 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
908 __ cmpq(rax, null_value);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000909 __ j(equal, &exit);
910
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000911 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
912
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000913 // Convert the object to a JS object.
914 Label convert, done_convert;
915 __ JumpIfSmi(rax, &convert);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000916 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000917 __ j(above_equal, &done_convert);
918 __ bind(&convert);
919 __ push(rax);
920 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
921 __ bind(&done_convert);
922 __ push(rax);
923
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000924 // Check for proxies.
925 Label call_runtime;
926 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
927 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
928 __ j(below_equal, &call_runtime);
929
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000930 // Check cache validity in generated code. This is a fast case for
931 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
932 // guarantee cache validity, call the runtime system to check cache
933 // validity or get the property names in a fixed array.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000934 __ CheckEnumCache(null_value, &call_runtime);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000935
936 // The enum cache is valid. Load the map of the object being
937 // iterated over and use the cache for the iteration.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000938 Label use_cache;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000939 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000940 __ jmp(&use_cache, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000941
942 // Get the set of properties to enumerate.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000943 __ bind(&call_runtime);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000944 __ push(rax); // Duplicate the enumerable object on the stack.
945 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
946
947 // If we got a map from the runtime call, we can do a fast
948 // modification check. Otherwise, we got a fixed array, and we have
949 // to do a slow check.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000950 Label fixed_array;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000951 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
952 Heap::kMetaMapRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000953 __ j(not_equal, &fixed_array, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000954
955 // We got a map in register rax. Get the enumeration cache from it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000956 __ bind(&use_cache);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000957 __ LoadInstanceDescriptors(rax, rcx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000958 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
959 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
960
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000961 // Set up the four remaining stack slots.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000962 __ push(rax); // Map.
963 __ push(rdx); // Enumeration cache.
964 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000965 __ push(rax); // Enumeration cache length (as smi).
966 __ Push(Smi::FromInt(0)); // Initial index.
967 __ jmp(&loop);
968
969 // We got a fixed array in register rax. Iterate through that.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000970 Label non_proxy;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000971 __ bind(&fixed_array);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000972
973 Handle<JSGlobalPropertyCell> cell =
974 isolate()->factory()->NewJSGlobalPropertyCell(
975 Handle<Object>(
976 Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker)));
977 RecordTypeFeedbackCell(stmt->PrepareId(), cell);
978 __ LoadHeapObject(rbx, cell);
979 __ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
980 Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker));
981
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000982 __ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check
983 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
984 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
985 __ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx);
986 __ j(above, &non_proxy);
987 __ Move(rbx, Smi::FromInt(0)); // Zero indicates proxy
988 __ bind(&non_proxy);
989 __ push(rbx); // Smi
990 __ push(rax); // Array
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000991 __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000992 __ push(rax); // Fixed array length (as smi).
993 __ Push(Smi::FromInt(0)); // Initial index.
994
995 // Generate code for doing the condition check.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000996 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000997 __ bind(&loop);
998 __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
999 __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001000 __ j(above_equal, loop_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001001
1002 // Get the current entry of the array into register rbx.
1003 __ movq(rbx, Operand(rsp, 2 * kPointerSize));
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00001004 SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001005 __ movq(rbx, FieldOperand(rbx,
1006 index.reg,
1007 index.scale,
1008 FixedArray::kHeaderSize));
1009
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001010 // Get the expected map from the stack or a smi in the
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001011 // permanent slow case into register rdx.
1012 __ movq(rdx, Operand(rsp, 3 * kPointerSize));
1013
1014 // Check if the expected map still matches that of the enumerable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001015 // If not, we may have to filter the key.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001016 Label update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001017 __ movq(rcx, Operand(rsp, 4 * kPointerSize));
1018 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001019 __ j(equal, &update_each, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001020
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001021 // For proxies, no filtering is done.
1022 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1023 __ Cmp(rdx, Smi::FromInt(0));
1024 __ j(equal, &update_each, Label::kNear);
1025
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001026 // Convert the entry to a string or null if it isn't a property
1027 // anymore. If the property has been removed while iterating, we
1028 // just skip it.
1029 __ push(rcx); // Enumerable.
1030 __ push(rbx); // Current entry.
1031 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001032 __ Cmp(rax, Smi::FromInt(0));
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001033 __ j(equal, loop_statement.continue_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001034 __ movq(rbx, rax);
1035
1036 // Update the 'each' property or variable from the possibly filtered
1037 // entry in register rbx.
1038 __ bind(&update_each);
1039 __ movq(result_register(), rbx);
1040 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001041 { EffectContext context(this);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001042 EmitAssignment(stmt->each());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001043 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001044
1045 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001046 Visit(stmt->body());
1047
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001048 // Generate code for going to the next element by incrementing the
1049 // index (smi) stored on top of the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001050 __ bind(loop_statement.continue_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001051 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001052
yangguo@chromium.org56454712012-02-16 15:33:53 +00001053 EmitStackCheck(stmt, &loop);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001054 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001055
1056 // Remove the pointers stored on the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001057 __ bind(loop_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001058 __ addq(rsp, Immediate(5 * kPointerSize));
1059
1060 // Exit and decrement the loop depth.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001061 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001062 __ bind(&exit);
1063 decrement_loop_depth();
1064}
1065
1066
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001067void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1068 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001069 // Use the fast case closure allocation code that allocates in new
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001070 // space for nested functions that don't need literals cloning. If
1071 // we're running with the --always-opt or the --prepare-always-opt
1072 // flag, we need to use the runtime function so that the new function
1073 // we are creating here gets a chance to have its code optimized and
1074 // doesn't just get a copy of the existing unoptimized code.
1075 if (!FLAG_always_opt &&
1076 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077 !pretenure &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001078 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079 info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001080 FastNewClosureStub stub(info->language_mode());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001081 __ Push(info);
1082 __ CallStub(&stub);
1083 } else {
1084 __ push(rsi);
1085 __ Push(info);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001086 __ Push(pretenure
1087 ? isolate()->factory()->true_value()
1088 : isolate()->factory()->false_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001089 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001090 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001091 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001092}
1093
1094
1095void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1096 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001097 EmitVariableLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001098}
1099
1100
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001101void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1102 TypeofState typeof_state,
1103 Label* slow) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001104 Register context = rsi;
1105 Register temp = rdx;
1106
1107 Scope* s = scope();
1108 while (s != NULL) {
1109 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001110 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001111 // Check that extension is NULL.
1112 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1113 Immediate(0));
1114 __ j(not_equal, slow);
1115 }
1116 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001117 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001118 // Walk the rest of the chain without clobbering rsi.
1119 context = temp;
1120 }
1121 // If no outer scope calls eval, we do not need to check more
1122 // context extensions. If we have reached an eval scope, we check
1123 // all extensions from this point.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001124 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001125 s = s->outer_scope();
1126 }
1127
1128 if (s != NULL && s->is_eval_scope()) {
1129 // Loop up the context chain. There is no frame effect so it is
1130 // safe to use raw labels here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001131 Label next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001132 if (!context.is(temp)) {
1133 __ movq(temp, context);
1134 }
1135 // Load map for comparison into register, outside loop.
1136 __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex);
1137 __ bind(&next);
1138 // Terminate at global context.
1139 __ cmpq(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001140 __ j(equal, &fast, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001141 // Check that extension is NULL.
1142 __ cmpq(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1143 __ j(not_equal, slow);
1144 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001145 __ movq(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001146 __ jmp(&next);
1147 __ bind(&fast);
1148 }
1149
1150 // All extension objects were empty and it is safe to use a global
1151 // load IC call.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001152 __ movq(rax, GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001153 __ Move(rcx, var->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001154 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001155 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1156 ? RelocInfo::CODE_TARGET
1157 : RelocInfo::CODE_TARGET_CONTEXT;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001158 __ call(ic, mode);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001159}
1160
1161
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001162MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1163 Label* slow) {
1164 ASSERT(var->IsContextSlot());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001165 Register context = rsi;
1166 Register temp = rbx;
1167
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001168 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001169 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001170 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001171 // Check that extension is NULL.
1172 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1173 Immediate(0));
1174 __ j(not_equal, slow);
1175 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001176 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001177 // Walk the rest of the chain without clobbering rsi.
1178 context = temp;
1179 }
1180 }
1181 // Check that last extension is NULL.
1182 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1183 __ j(not_equal, slow);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001184
1185 // This function is used only for loads, not stores, so it's safe to
1186 // return an rsi-based operand (the write barrier cannot be allowed to
1187 // destroy the rsi register).
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001188 return ContextOperand(context, var->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001189}
1190
1191
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001192void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1193 TypeofState typeof_state,
1194 Label* slow,
1195 Label* done) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001196 // Generate fast-case code for variables that might be shadowed by
1197 // eval-introduced variables. Eval is used a lot without
1198 // introducing variables. In those cases, we do not want to
1199 // perform a runtime call for all variables in the scope
1200 // containing the eval.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001201 if (var->mode() == DYNAMIC_GLOBAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001202 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001203 __ jmp(done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001204 } else if (var->mode() == DYNAMIC_LOCAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001205 Variable* local = var->local_if_not_shadowed();
1206 __ movq(rax, ContextSlotOperandCheckExtensions(local, slow));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001207 if (local->mode() == CONST ||
1208 local->mode() == CONST_HARMONY ||
1209 local->mode() == LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001210 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1211 __ j(not_equal, done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001212 if (local->mode() == CONST) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001213 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001214 } else { // LET || CONST_HARMONY
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001215 __ Push(var->name());
1216 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1217 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001218 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001219 __ jmp(done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001220 }
1221}
1222
1223
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001224void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1225 // Record position before possible IC call.
1226 SetSourcePosition(proxy->position());
1227 Variable* var = proxy->var();
1228
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001229 // Three cases: global variables, lookup variables, and all other types of
1230 // variables.
1231 switch (var->location()) {
1232 case Variable::UNALLOCATED: {
1233 Comment cmnt(masm_, "Global variable");
1234 // Use inline caching. Variable name is passed in rcx and the global
1235 // object on the stack.
1236 __ Move(rcx, var->name());
1237 __ movq(rax, GlobalObjectOperand());
1238 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
1239 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001240 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001241 break;
1242 }
1243
1244 case Variable::PARAMETER:
1245 case Variable::LOCAL:
1246 case Variable::CONTEXT: {
1247 Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot");
danno@chromium.orgc612e022011-11-10 11:38:15 +00001248 if (var->binding_needs_init()) {
1249 // var->scope() may be NULL when the proxy is located in eval code and
1250 // refers to a potential outside binding. Currently those bindings are
1251 // always looked up dynamically, i.e. in that case
1252 // var->location() == LOOKUP.
1253 // always holds.
1254 ASSERT(var->scope() != NULL);
1255
1256 // Check if the binding really needs an initialization check. The check
1257 // can be skipped in the following situation: we have a LET or CONST
1258 // binding in harmony mode, both the Variable and the VariableProxy have
1259 // the same declaration scope (i.e. they are both in global code, in the
1260 // same function or in the same eval code) and the VariableProxy is in
1261 // the source physically located after the initializer of the variable.
1262 //
1263 // We cannot skip any initialization checks for CONST in non-harmony
1264 // mode because const variables may be declared but never initialized:
1265 // if (false) { const x; }; var y = x;
1266 //
1267 // The condition on the declaration scopes is a conservative check for
1268 // nested functions that access a binding and are called before the
1269 // binding is initialized:
1270 // function() { f(); let x = 1; function f() { x = 2; } }
1271 //
1272 bool skip_init_check;
1273 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1274 skip_init_check = false;
jkummerow@chromium.orgac45fed2011-11-07 13:11:02 +00001275 } else {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001276 // Check that we always have valid source position.
1277 ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1278 ASSERT(proxy->position() != RelocInfo::kNoPosition);
1279 skip_init_check = var->mode() != CONST &&
1280 var->initializer_position() < proxy->position();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001281 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001282
1283 if (!skip_init_check) {
1284 // Let and const need a read barrier.
1285 Label done;
1286 GetVar(rax, var);
1287 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1288 __ j(not_equal, &done, Label::kNear);
1289 if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1290 // Throw a reference error when using an uninitialized let/const
1291 // binding in harmony mode.
1292 __ Push(var->name());
1293 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1294 } else {
1295 // Uninitalized const bindings outside of harmony mode are unholed.
1296 ASSERT(var->mode() == CONST);
1297 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1298 }
1299 __ bind(&done);
1300 context()->Plug(rax);
1301 break;
1302 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001303 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001304 context()->Plug(var);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001305 break;
1306 }
1307
1308 case Variable::LOOKUP: {
1309 Label done, slow;
1310 // Generate code for loading from variables potentially shadowed
1311 // by eval-introduced variables.
1312 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1313 __ bind(&slow);
1314 Comment cmnt(masm_, "Lookup slot");
1315 __ push(rsi); // Context.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001316 __ Push(var->name());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001317 __ CallRuntime(Runtime::kLoadContextSlot, 2);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001318 __ bind(&done);
1319 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001320 break;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001321 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001322 }
1323}
1324
1325
1326void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1327 Comment cmnt(masm_, "[ RegExpLiteral");
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001328 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001329 // Registers will be used as follows:
1330 // rdi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001331 // rcx = literals array.
1332 // rbx = regexp literal.
1333 // rax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001334 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001335 __ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001336 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001337 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001338 __ movq(rbx, FieldOperand(rcx, literal_offset));
1339 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001340 __ j(not_equal, &materialized, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001341
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001342 // Create regexp literal using runtime function
1343 // Result will be in rax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001344 __ push(rcx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001345 __ Push(Smi::FromInt(expr->literal_index()));
1346 __ Push(expr->pattern());
1347 __ Push(expr->flags());
1348 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001349 __ movq(rbx, rax);
1350
1351 __ bind(&materialized);
1352 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1353 Label allocated, runtime_allocate;
1354 __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
1355 __ jmp(&allocated);
1356
1357 __ bind(&runtime_allocate);
1358 __ push(rbx);
1359 __ Push(Smi::FromInt(size));
1360 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1361 __ pop(rbx);
1362
1363 __ bind(&allocated);
1364 // Copy the content into the newly allocated memory.
1365 // (Unroll copy loop once for better throughput).
1366 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1367 __ movq(rdx, FieldOperand(rbx, i));
1368 __ movq(rcx, FieldOperand(rbx, i + kPointerSize));
1369 __ movq(FieldOperand(rax, i), rdx);
1370 __ movq(FieldOperand(rax, i + kPointerSize), rcx);
1371 }
1372 if ((size % (2 * kPointerSize)) != 0) {
1373 __ movq(rdx, FieldOperand(rbx, size - kPointerSize));
1374 __ movq(FieldOperand(rax, size - kPointerSize), rdx);
1375 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001376 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001377}
1378
1379
1380void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1381 Comment cmnt(masm_, "[ ObjectLiteral");
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001382 Handle<FixedArray> constant_properties = expr->constant_properties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001383 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1384 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
1385 __ Push(Smi::FromInt(expr->literal_index()));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001386 __ Push(constant_properties);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 int flags = expr->fast_elements()
1388 ? ObjectLiteral::kFastElements
1389 : ObjectLiteral::kNoFlags;
1390 flags |= expr->has_function()
1391 ? ObjectLiteral::kHasFunction
1392 : ObjectLiteral::kNoFlags;
1393 __ Push(Smi::FromInt(flags));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001394 int properties_count = constant_properties->length() / 2;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001395 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001396 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001397 } else if (flags != ObjectLiteral::kFastElements ||
1398 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001399 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001400 } else {
1401 FastCloneShallowObjectStub stub(properties_count);
1402 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001403 }
1404
1405 // If result_saved is true the result is on top of the stack. If
1406 // result_saved is false the result is in rax.
1407 bool result_saved = false;
1408
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001409 // Mark all computed expressions that are bound to a key that
1410 // is shadowed by a later occurrence of the same key. For the
1411 // marked expressions, no store code is emitted.
1412 expr->CalculateEmitStore();
1413
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001414 for (int i = 0; i < expr->properties()->length(); i++) {
1415 ObjectLiteral::Property* property = expr->properties()->at(i);
1416 if (property->IsCompileTimeValue()) continue;
1417
1418 Literal* key = property->key();
1419 Expression* value = property->value();
1420 if (!result_saved) {
1421 __ push(rax); // Save result on the stack
1422 result_saved = true;
1423 }
1424 switch (property->kind()) {
1425 case ObjectLiteral::Property::CONSTANT:
1426 UNREACHABLE();
1427 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1428 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1429 // Fall through.
1430 case ObjectLiteral::Property::COMPUTED:
1431 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001432 if (property->emit_store()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001433 VisitForAccumulatorValue(value);
1434 __ Move(rcx, key->handle());
1435 __ movq(rdx, Operand(rsp, 0));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001436 Handle<Code> ic = is_classic_mode()
1437 ? isolate()->builtins()->StoreIC_Initialize()
1438 : isolate()->builtins()->StoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001439 __ call(ic, RelocInfo::CODE_TARGET, key->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001440 PrepareForBailoutForId(key->id(), NO_REGISTERS);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001441 } else {
1442 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001443 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001444 break;
1445 }
1446 // Fall through.
1447 case ObjectLiteral::Property::PROTOTYPE:
1448 __ push(Operand(rsp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001449 VisitForStackValue(key);
1450 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001451 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001452 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1453 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001454 } else {
1455 __ Drop(3);
1456 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001457 break;
1458 case ObjectLiteral::Property::SETTER:
1459 case ObjectLiteral::Property::GETTER:
1460 __ push(Operand(rsp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001461 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001462 __ Push(property->kind() == ObjectLiteral::Property::SETTER ?
1463 Smi::FromInt(1) :
1464 Smi::FromInt(0));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001465 VisitForStackValue(value);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001466 __ Push(Smi::FromInt(NONE));
1467 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001468 break;
1469 }
1470 }
1471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001472 if (expr->has_function()) {
1473 ASSERT(result_saved);
1474 __ push(Operand(rsp, 0));
1475 __ CallRuntime(Runtime::kToFastProperties, 1);
1476 }
1477
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001478 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001479 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001480 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001481 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001482 }
1483}
1484
1485
1486void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1487 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001488
1489 ZoneList<Expression*>* subexprs = expr->values();
1490 int length = subexprs->length();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001491 Handle<FixedArray> constant_elements = expr->constant_elements();
1492 ASSERT_EQ(2, constant_elements->length());
1493 ElementsKind constant_elements_kind =
1494 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
erikcorry0ad885c2011-11-21 13:51:57 +00001495 bool has_constant_fast_elements = constant_elements_kind == FAST_ELEMENTS;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001496 Handle<FixedArrayBase> constant_elements_values(
1497 FixedArrayBase::cast(constant_elements->get(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001498
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001499 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1500 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1501 __ Push(Smi::FromInt(expr->literal_index()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001502 __ Push(constant_elements);
erikcorry0ad885c2011-11-21 13:51:57 +00001503 Heap* heap = isolate()->heap();
1504 if (has_constant_fast_elements &&
1505 constant_elements_values->map() == heap->fixed_cow_array_map()) {
1506 // If the elements are already FAST_ELEMENTS, the boilerplate cannot
1507 // change, so it's possible to specialize the stub in advance.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001508 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
erikcorry0ad885c2011-11-21 13:51:57 +00001509 FastCloneShallowArrayStub stub(
1510 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
1511 length);
1512 __ CallStub(&stub);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001513 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001514 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001515 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001516 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001517 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001518 ASSERT(constant_elements_kind == FAST_ELEMENTS ||
1519 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
1520 FLAG_smi_only_arrays);
erikcorry0ad885c2011-11-21 13:51:57 +00001521 // If the elements are already FAST_ELEMENTS, the boilerplate cannot
1522 // change, so it's possible to specialize the stub in advance.
1523 FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
1524 ? FastCloneShallowArrayStub::CLONE_ELEMENTS
1525 : FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001526 FastCloneShallowArrayStub stub(mode, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001527 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001528 }
1529
1530 bool result_saved = false; // Is the result saved to the stack?
1531
1532 // Emit code to evaluate all the non-constant subexpressions and to store
1533 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001534 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001535 Expression* subexpr = subexprs->at(i);
1536 // If the subexpression is a literal or a simple materialized literal it
1537 // is already set in the cloned array.
1538 if (subexpr->AsLiteral() != NULL ||
1539 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1540 continue;
1541 }
1542
1543 if (!result_saved) {
1544 __ push(rax);
1545 result_saved = true;
1546 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001547 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001548
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001549 if (constant_elements_kind == FAST_ELEMENTS) {
1550 // Fast-case array literal with ElementsKind of FAST_ELEMENTS, they cannot
1551 // transition and don't need to call the runtime stub.
1552 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1553 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1554 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
1555 // Store the subexpression value in the array's elements.
1556 __ movq(FieldOperand(rbx, offset), result_register());
1557 // Update the write barrier for the array store.
1558 __ RecordWriteField(rbx, offset, result_register(), rcx,
1559 kDontSaveFPRegs,
1560 EMIT_REMEMBERED_SET,
1561 INLINE_SMI_CHECK);
1562 } else {
1563 // Store the subexpression value in the array's elements.
1564 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1565 __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
1566 __ Move(rcx, Smi::FromInt(i));
1567 __ Move(rdx, Smi::FromInt(expr->literal_index()));
1568 StoreArrayLiteralElementStub stub;
1569 __ CallStub(&stub);
1570 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001571
1572 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001573 }
1574
1575 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001576 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001577 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001578 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001579 }
1580}
1581
1582
ager@chromium.org5c838252010-02-19 08:53:10 +00001583void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1584 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001585 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1586 // on the left-hand side.
1587 if (!expr->target()->IsValidLeftHandSide()) {
1588 VisitForEffect(expr->target());
1589 return;
1590 }
1591
ager@chromium.org5c838252010-02-19 08:53:10 +00001592 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001593 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001594 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1595 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001596 Property* property = expr->target()->AsProperty();
1597 if (property != NULL) {
1598 assign_type = (property->key()->IsPropertyName())
1599 ? NAMED_PROPERTY
1600 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001601 }
1602
1603 // Evaluate LHS expression.
1604 switch (assign_type) {
1605 case VARIABLE:
1606 // Nothing to do here.
1607 break;
1608 case NAMED_PROPERTY:
1609 if (expr->is_compound()) {
1610 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001611 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001612 __ push(result_register());
1613 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001614 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001615 }
1616 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001617 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001618 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001619 VisitForStackValue(property->obj());
1620 VisitForAccumulatorValue(property->key());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001621 __ movq(rdx, Operand(rsp, 0));
1622 __ push(rax);
1623 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001624 VisitForStackValue(property->obj());
1625 VisitForStackValue(property->key());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001626 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001627 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001628 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001629 }
1630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001631 // For compound assignments we need another deoptimization point after the
1632 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001633 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001634 { AccumulatorValueContext context(this);
1635 switch (assign_type) {
1636 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001637 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001638 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001639 break;
1640 case NAMED_PROPERTY:
1641 EmitNamedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001642 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001643 break;
1644 case KEYED_PROPERTY:
1645 EmitKeyedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001646 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001647 break;
1648 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001649 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001650
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001651 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001652 __ push(rax); // Left operand goes on the stack.
1653 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001654
ricow@chromium.org65fae842010-08-25 15:26:24 +00001655 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1656 ? OVERWRITE_RIGHT
1657 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001658 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001659 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001660 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001661 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001662 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001663 mode,
1664 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001665 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001666 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001667 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001668 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001669 // Deoptimization point in case the binary operation may have side effects.
1670 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001671 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001672 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001673 }
1674
1675 // Record source position before possible IC call.
1676 SetSourcePosition(expr->position());
1677
1678 // Store the value.
1679 switch (assign_type) {
1680 case VARIABLE:
1681 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001682 expr->op());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001683 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001684 context()->Plug(rax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001685 break;
1686 case NAMED_PROPERTY:
1687 EmitNamedPropertyAssignment(expr);
1688 break;
1689 case KEYED_PROPERTY:
1690 EmitKeyedPropertyAssignment(expr);
1691 break;
1692 }
1693}
1694
1695
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001696void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1697 SetSourcePosition(prop->position());
1698 Literal* key = prop->key()->AsLiteral();
1699 __ Move(rcx, key->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001700 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001701 __ call(ic, RelocInfo::CODE_TARGET, prop->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001702}
1703
1704
1705void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1706 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001707 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001708 __ call(ic, RelocInfo::CODE_TARGET, prop->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001709}
1710
1711
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001712void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001713 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001714 OverwriteMode mode,
1715 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001716 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001717 // Do combined smi check of the operands. Left operand is on the
1718 // stack (popped into rdx). Right operand is in rax but moved into
1719 // rcx to make the shifts easier.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001720 Label done, stub_call, smi_case;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001721 __ pop(rdx);
1722 __ movq(rcx, rax);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001723 __ or_(rax, rdx);
1724 JumpPatchSite patch_site(masm_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001725 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001726
1727 __ bind(&stub_call);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001728 __ movq(rax, rcx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001729 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001730 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1731 patch_site.EmitPatchInfo();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001732 __ jmp(&done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001733
1734 __ bind(&smi_case);
1735 switch (op) {
1736 case Token::SAR:
1737 __ SmiShiftArithmeticRight(rax, rdx, rcx);
1738 break;
1739 case Token::SHL:
1740 __ SmiShiftLeft(rax, rdx, rcx);
1741 break;
1742 case Token::SHR:
1743 __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
1744 break;
1745 case Token::ADD:
1746 __ SmiAdd(rax, rdx, rcx, &stub_call);
1747 break;
1748 case Token::SUB:
1749 __ SmiSub(rax, rdx, rcx, &stub_call);
1750 break;
1751 case Token::MUL:
1752 __ SmiMul(rax, rdx, rcx, &stub_call);
1753 break;
1754 case Token::BIT_OR:
1755 __ SmiOr(rax, rdx, rcx);
1756 break;
1757 case Token::BIT_AND:
1758 __ SmiAnd(rax, rdx, rcx);
1759 break;
1760 case Token::BIT_XOR:
1761 __ SmiXor(rax, rdx, rcx);
1762 break;
1763 default:
1764 UNREACHABLE();
1765 break;
1766 }
1767
1768 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001769 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001770}
1771
1772
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001773void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1774 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001775 OverwriteMode mode) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001776 __ pop(rdx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001777 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001778 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
1779 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1780 patch_site.EmitPatchInfo();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001781 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001782}
1783
1784
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001785void FullCodeGenerator::EmitAssignment(Expression* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001786 // Invalid left-hand sides are rewritten to have a 'throw
1787 // ReferenceError' on the left-hand side.
1788 if (!expr->IsValidLeftHandSide()) {
1789 VisitForEffect(expr);
1790 return;
1791 }
1792
1793 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001794 // slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001795 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1796 LhsKind assign_type = VARIABLE;
1797 Property* prop = expr->AsProperty();
1798 if (prop != NULL) {
1799 assign_type = (prop->key()->IsPropertyName())
1800 ? NAMED_PROPERTY
1801 : KEYED_PROPERTY;
1802 }
1803
1804 switch (assign_type) {
1805 case VARIABLE: {
1806 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001807 EffectContext context(this);
1808 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001809 break;
1810 }
1811 case NAMED_PROPERTY: {
1812 __ push(rax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001813 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001814 __ movq(rdx, rax);
1815 __ pop(rax); // Restore value.
1816 __ Move(rcx, prop->key()->AsLiteral()->handle());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001817 Handle<Code> ic = is_classic_mode()
1818 ? isolate()->builtins()->StoreIC_Initialize()
1819 : isolate()->builtins()->StoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001820 __ call(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001821 break;
1822 }
1823 case KEYED_PROPERTY: {
1824 __ push(rax); // Preserve value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001825 VisitForStackValue(prop->obj());
1826 VisitForAccumulatorValue(prop->key());
1827 __ movq(rcx, rax);
1828 __ pop(rdx);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001829 __ pop(rax); // Restore value.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001830 Handle<Code> ic = is_classic_mode()
1831 ? isolate()->builtins()->KeyedStoreIC_Initialize()
1832 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001833 __ call(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001834 break;
1835 }
1836 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001837 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001838}
1839
1840
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001841void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001842 Token::Value op) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001843 if (var->IsUnallocated()) {
1844 // Global var, const, or let.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001845 __ Move(rcx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001846 __ movq(rdx, GlobalObjectOperand());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001847 Handle<Code> ic = is_classic_mode()
1848 ? isolate()->builtins()->StoreIC_Initialize()
1849 : isolate()->builtins()->StoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001850 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001851 } else if (op == Token::INIT_CONST) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001852 // Const initializers need a write barrier.
1853 ASSERT(!var->IsParameter()); // No const parameters.
1854 if (var->IsStackLocal()) {
1855 Label skip;
1856 __ movq(rdx, StackOperand(var));
1857 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1858 __ j(not_equal, &skip);
1859 __ movq(StackOperand(var), rax);
1860 __ bind(&skip);
1861 } else {
1862 ASSERT(var->IsContextSlot() || var->IsLookupSlot());
1863 // Like var declarations, const declarations are hoisted to function
1864 // scope. However, unlike var initializers, const initializers are
1865 // able to drill a hole to that function context, even from inside a
1866 // 'with' context. We thus bypass the normal static scope lookup for
1867 // var->IsContextSlot().
1868 __ push(rax);
1869 __ push(rsi);
1870 __ Push(var->name());
1871 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001872 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001873
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001874 } else if (var->mode() == LET && op != Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001875 // Non-initializing assignment to let variable needs a write barrier.
1876 if (var->IsLookupSlot()) {
1877 __ push(rax); // Value.
1878 __ push(rsi); // Context.
1879 __ Push(var->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001880 __ Push(Smi::FromInt(language_mode()));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001881 __ CallRuntime(Runtime::kStoreContextSlot, 4);
1882 } else {
1883 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
1884 Label assign;
1885 MemOperand location = VarOperand(var, rcx);
1886 __ movq(rdx, location);
1887 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1888 __ j(not_equal, &assign, Label::kNear);
1889 __ Push(var->name());
1890 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1891 __ bind(&assign);
1892 __ movq(location, rax);
1893 if (var->IsContextSlot()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001894 __ movq(rdx, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001895 __ RecordWriteContextSlot(
1896 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001897 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001898 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001899
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001900 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
1901 // Assignment to var or initializing assignment to let/const
1902 // in harmony mode.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001903 if (var->IsStackAllocated() || var->IsContextSlot()) {
1904 MemOperand location = VarOperand(var, rcx);
1905 if (FLAG_debug_code && op == Token::INIT_LET) {
1906 // Check for an uninitialized let binding.
1907 __ movq(rdx, location);
1908 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1909 __ Check(equal, "Let binding re-initialization.");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001910 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001911 // Perform the assignment.
1912 __ movq(location, rax);
1913 if (var->IsContextSlot()) {
1914 __ movq(rdx, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001915 __ RecordWriteContextSlot(
1916 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001917 }
1918 } else {
1919 ASSERT(var->IsLookupSlot());
1920 __ push(rax); // Value.
1921 __ push(rsi); // Context.
1922 __ Push(var->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001923 __ Push(Smi::FromInt(language_mode()));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001924 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001925 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001926 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001927 // Non-initializing assignments to consts are ignored.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001928}
1929
1930
1931void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1932 // Assignment to a property, using a named store IC.
1933 Property* prop = expr->target()->AsProperty();
1934 ASSERT(prop != NULL);
1935 ASSERT(prop->key()->AsLiteral() != NULL);
1936
1937 // If the assignment starts a block of assignments to the same object,
1938 // change to slow case to avoid the quadratic behavior of repeatedly
1939 // adding fast properties.
1940 if (expr->starts_initialization_block()) {
1941 __ push(result_register());
1942 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value.
1943 __ CallRuntime(Runtime::kToSlowProperties, 1);
1944 __ pop(result_register());
1945 }
1946
1947 // Record source code position before IC call.
1948 SetSourcePosition(expr->position());
1949 __ Move(rcx, prop->key()->AsLiteral()->handle());
1950 if (expr->ends_initialization_block()) {
1951 __ movq(rdx, Operand(rsp, 0));
1952 } else {
1953 __ pop(rdx);
1954 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001955 Handle<Code> ic = is_classic_mode()
1956 ? isolate()->builtins()->StoreIC_Initialize()
1957 : isolate()->builtins()->StoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001958 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001959
1960 // If the assignment ends an initialization block, revert to fast case.
1961 if (expr->ends_initialization_block()) {
1962 __ push(rax); // Result of assignment, saved even if not needed.
1963 __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
1964 __ CallRuntime(Runtime::kToFastProperties, 1);
1965 __ pop(rax);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001966 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001967 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001968 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001969 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970}
1971
1972
1973void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1974 // Assignment to a property, using a keyed store IC.
1975
1976 // If the assignment starts a block of assignments to the same object,
1977 // change to slow case to avoid the quadratic behavior of repeatedly
1978 // adding fast properties.
1979 if (expr->starts_initialization_block()) {
1980 __ push(result_register());
1981 // Receiver is now under the key and value.
1982 __ push(Operand(rsp, 2 * kPointerSize));
1983 __ CallRuntime(Runtime::kToSlowProperties, 1);
1984 __ pop(result_register());
1985 }
1986
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001987 __ pop(rcx);
1988 if (expr->ends_initialization_block()) {
1989 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later.
1990 } else {
1991 __ pop(rdx);
1992 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001993 // Record source code position before IC call.
1994 SetSourcePosition(expr->position());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001995 Handle<Code> ic = is_classic_mode()
1996 ? isolate()->builtins()->KeyedStoreIC_Initialize()
1997 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001998 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001999
2000 // If the assignment ends an initialization block, revert to fast case.
2001 if (expr->ends_initialization_block()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002002 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002003 __ push(rax); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002004 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002005 __ CallRuntime(Runtime::kToFastProperties, 1);
2006 __ pop(rax);
2007 }
2008
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002009 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002010 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002011}
2012
2013
2014void FullCodeGenerator::VisitProperty(Property* expr) {
2015 Comment cmnt(masm_, "[ Property");
2016 Expression* key = expr->key();
2017
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002018 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002019 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002020 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002021 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002022 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002023 VisitForStackValue(expr->obj());
2024 VisitForAccumulatorValue(expr->key());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002025 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002026 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002027 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002028 }
2029}
2030
2031
2032void FullCodeGenerator::EmitCallWithIC(Call* expr,
ager@chromium.org5c838252010-02-19 08:53:10 +00002033 Handle<Object> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002034 RelocInfo::Mode mode) {
2035 // Code common for calls using the IC.
2036 ZoneList<Expression*>* args = expr->arguments();
2037 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002038 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002039 for (int i = 0; i < arg_count; i++) {
2040 VisitForStackValue(args->at(i));
2041 }
2042 __ Move(rcx, name);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002043 }
2044 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002045 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002046 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002047 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002048 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002049 __ call(ic, mode, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002050 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002051 // Restore context register.
2052 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002053 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002054}
2055
2056
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002057void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002058 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002059 // Load the key.
2060 VisitForAccumulatorValue(key);
2061
2062 // Swap the name of the function and the receiver on the stack to follow
2063 // the calling convention for call ICs.
2064 __ pop(rcx);
2065 __ push(rax);
2066 __ push(rcx);
2067
2068 // Load the arguments.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002069 ZoneList<Expression*>* args = expr->arguments();
2070 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002071 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002072 for (int i = 0; i < arg_count; i++) {
2073 VisitForStackValue(args->at(i));
2074 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002075 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002076 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002077 SetSourcePosition(expr->position());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002078 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002079 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002080 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002081 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002082 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002083 RecordJSReturnSite(expr);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002084 // Restore context register.
2085 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002086 context()->DropAndPlug(1, rax); // Drop the key still on the stack.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002087}
2088
2089
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002090void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002091 // Code common for calls using the call stub.
2092 ZoneList<Expression*>* args = expr->arguments();
2093 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002094 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002095 for (int i = 0; i < arg_count; i++) {
2096 VisitForStackValue(args->at(i));
2097 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002098 }
2099 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002100 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002101 CallFunctionStub stub(arg_count, flags);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002102 __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002103 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002104 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002105 // Restore context register.
2106 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2107 // Discard the function left on TOS.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002108 context()->DropAndPlug(1, rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002109}
2110
2111
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002112void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002113 // Push copy of the first argument or undefined if it doesn't exist.
2114 if (arg_count > 0) {
2115 __ push(Operand(rsp, arg_count * kPointerSize));
2116 } else {
2117 __ PushRoot(Heap::kUndefinedValueRootIndex);
2118 }
2119
2120 // Push the receiver of the enclosing function and do runtime call.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002121 __ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002122
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002123 // Push the language mode.
2124 __ Push(Smi::FromInt(language_mode()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002125
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002126 // Push the start position of the scope the calls resides in.
2127 __ Push(Smi::FromInt(scope()->start_position()));
2128
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002129 // Do the runtime call.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002130 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002131}
2132
2133
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002134void FullCodeGenerator::VisitCall(Call* expr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002135#ifdef DEBUG
2136 // We want to verify that RecordJSReturnSite gets called on all paths
2137 // through this function. Avoid early returns.
2138 expr->return_is_recorded_ = false;
2139#endif
2140
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002141 Comment cmnt(masm_, "[ Call");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002142 Expression* callee = expr->expression();
2143 VariableProxy* proxy = callee->AsVariableProxy();
2144 Property* property = callee->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002145
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002146 if (proxy != NULL && proxy->var()->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002147 // In a call to eval, we first call %ResolvePossiblyDirectEval to
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002148 // resolve the function we need to call and the receiver of the call.
2149 // Then we call the resolved function using the given arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002150 ZoneList<Expression*>* args = expr->arguments();
2151 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002152 { PreservePositionScope pos_scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002153 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002154 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002155
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002156 // Push the arguments.
2157 for (int i = 0; i < arg_count; i++) {
2158 VisitForStackValue(args->at(i));
2159 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002160
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002161 // Push a copy of the function (found below the arguments) and resolve
2162 // eval.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002163 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002164 EmitResolvePossiblyDirectEval(arg_count);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002165
2166 // The runtime call returns a pair of values in rax (function) and
2167 // rdx (receiver). Touch up the stack with the right values.
2168 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
2169 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002170 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002171 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002172 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002173 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002174 __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002175 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002176 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002177 // Restore context register.
2178 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002179 context()->DropAndPlug(1, rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002180 } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
2181 // Call to a global variable. Push global object as receiver for the
2182 // call IC lookup.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002183 __ push(GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002184 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
2185 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002186 // Call to a lookup slot (dynamically introduced variable).
2187 Label slow, done;
2188
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002189 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002190 // Generate code for loading from variables potentially shadowed by
2191 // eval-introduced variables.
2192 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002193 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002194 __ bind(&slow);
2195 // Call the runtime to find the function to call (returned in rax) and
2196 // the object holding it (returned in rdx).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002197 __ push(context_register());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002198 __ Push(proxy->name());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002199 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2200 __ push(rax); // Function.
2201 __ push(rdx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002202
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002203 // If fast case code has been generated, emit code to push the function
2204 // and receiver and have the slow path jump around this code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002205 if (done.is_linked()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002206 Label call;
2207 __ jmp(&call, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002208 __ bind(&done);
2209 // Push function.
2210 __ push(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002211 // The receiver is implicitly the global receiver. Indicate this by
2212 // passing the hole to the call function stub.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002213 __ PushRoot(Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002214 __ bind(&call);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002215 }
2216
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002217 // The receiver is either the global receiver or an object found by
2218 // LoadContextSlot. That object could be the hole if the receiver is
2219 // implicitly the global object.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002220 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002221 } else if (property != NULL) {
2222 { PreservePositionScope scope(masm()->positions_recorder());
2223 VisitForStackValue(property->obj());
2224 }
2225 if (property->key()->IsPropertyName()) {
2226 EmitCallWithIC(expr,
2227 property->key()->AsLiteral()->handle(),
2228 RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002229 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002230 EmitKeyedCallWithIC(expr, property->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002231 }
2232 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002233 // Call to an arbitrary expression not handled specially above.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002234 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002235 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002236 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002237 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002238 __ movq(rbx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002239 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
2240 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002241 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002242 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002243
2244#ifdef DEBUG
2245 // RecordJSReturnSite should have been called.
2246 ASSERT(expr->return_is_recorded_);
2247#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002248}
2249
2250
2251void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2252 Comment cmnt(masm_, "[ CallNew");
2253 // According to ECMA-262, section 11.2.2, page 44, the function
2254 // expression in new calls must be evaluated before the
2255 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002256
ricow@chromium.org65fae842010-08-25 15:26:24 +00002257 // Push constructor on the stack. If it's not a function it's used as
2258 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2259 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002260 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002261
2262 // Push the arguments ("left-to-right") on the stack.
2263 ZoneList<Expression*>* args = expr->arguments();
2264 int arg_count = args->length();
2265 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002266 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002267 }
2268
2269 // Call the construct call builtin that handles allocation and
2270 // constructor invocation.
2271 SetSourcePosition(expr->position());
2272
ricow@chromium.org65fae842010-08-25 15:26:24 +00002273 // Load function and argument count into rdi and rax.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002274 __ Set(rax, arg_count);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002275 __ movq(rdi, Operand(rsp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002276
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002277 // Record call targets in unoptimized code, but not in the snapshot.
2278 CallFunctionFlags flags;
2279 if (!Serializer::enabled()) {
2280 flags = RECORD_CALL_TARGET;
2281 Handle<Object> uninitialized =
2282 TypeFeedbackCells::UninitializedSentinel(isolate());
2283 Handle<JSGlobalPropertyCell> cell =
2284 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
2285 RecordTypeFeedbackCell(expr->id(), cell);
2286 __ Move(rbx, cell);
2287 } else {
2288 flags = NO_CALL_FUNCTION_FLAGS;
2289 }
2290
2291 CallConstructStub stub(flags);
2292 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
ulan@chromium.org967e2702012-02-28 09:49:15 +00002293 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002294 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002295}
2296
2297
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002298void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2299 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002300 ASSERT(args->length() == 1);
2301
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002302 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002303
2304 Label materialize_true, materialize_false;
2305 Label* if_true = NULL;
2306 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002307 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002308 context()->PrepareTest(&materialize_true, &materialize_false,
2309 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002310
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002311 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002312 __ JumpIfSmi(rax, if_true);
2313 __ jmp(if_false);
2314
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002315 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002316}
2317
2318
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002319void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2320 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002321 ASSERT(args->length() == 1);
2322
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002323 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002324
2325 Label materialize_true, materialize_false;
2326 Label* if_true = NULL;
2327 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002328 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002329 context()->PrepareTest(&materialize_true, &materialize_false,
2330 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002331
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002332 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00002333 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
2334 Split(non_negative_smi, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002335
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002336 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002337}
2338
2339
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002340void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2341 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002342 ASSERT(args->length() == 1);
2343
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002344 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002345
2346 Label materialize_true, materialize_false;
2347 Label* if_true = NULL;
2348 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002349 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002350 context()->PrepareTest(&materialize_true, &materialize_false,
2351 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002352
2353 __ JumpIfSmi(rax, if_false);
2354 __ CompareRoot(rax, Heap::kNullValueRootIndex);
2355 __ j(equal, if_true);
2356 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2357 // Undetectable objects behave like undefined when tested with typeof.
2358 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2359 Immediate(1 << Map::kIsUndetectable));
2360 __ j(not_zero, if_false);
2361 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002362 __ cmpq(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002363 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002364 __ cmpq(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002365 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002366 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002367
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002368 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002369}
2370
2371
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002372void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2373 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002374 ASSERT(args->length() == 1);
2375
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002376 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002377
2378 Label materialize_true, materialize_false;
2379 Label* if_true = NULL;
2380 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002381 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002382 context()->PrepareTest(&materialize_true, &materialize_false,
2383 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002384
2385 __ JumpIfSmi(rax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002386 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002387 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002388 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002389
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002390 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002391}
2392
2393
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002394void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2395 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002396 ASSERT(args->length() == 1);
2397
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002398 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002399
2400 Label materialize_true, materialize_false;
2401 Label* if_true = NULL;
2402 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002403 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002404 context()->PrepareTest(&materialize_true, &materialize_false,
2405 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002406
2407 __ JumpIfSmi(rax, if_false);
2408 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2409 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2410 Immediate(1 << Map::kIsUndetectable));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002411 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002412 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002413
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002414 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002415}
2416
2417
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002418void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002419 CallRuntime* expr) {
2420 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002421 ASSERT(args->length() == 1);
2422
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002423 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002424
2425 Label materialize_true, materialize_false;
2426 Label* if_true = NULL;
2427 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002428 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002429 context()->PrepareTest(&materialize_true, &materialize_false,
2430 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002431
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002432 if (FLAG_debug_code) __ AbortIfSmi(rax);
2433
2434 // Check whether this map has already been checked to be safe for default
2435 // valueOf.
2436 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2437 __ testb(FieldOperand(rbx, Map::kBitField2Offset),
2438 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2439 __ j(not_zero, if_true);
2440
2441 // Check for fast case object. Generate false result for slow case object.
2442 __ movq(rcx, FieldOperand(rax, JSObject::kPropertiesOffset));
2443 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2444 __ CompareRoot(rcx, Heap::kHashTableMapRootIndex);
2445 __ j(equal, if_false);
2446
2447 // Look for valueOf symbol in the descriptor array, and indicate false if
2448 // found. The type is not checked, so if it is a transition it is a false
2449 // negative.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002450 __ LoadInstanceDescriptors(rbx, rbx);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002451 __ movq(rcx, FieldOperand(rbx, FixedArray::kLengthOffset));
2452 // rbx: descriptor array
2453 // rcx: length of descriptor array
2454 // Calculate the end of the descriptor array.
2455 SmiIndex index = masm_->SmiToIndex(rdx, rcx, kPointerSizeLog2);
2456 __ lea(rcx,
2457 Operand(
2458 rbx, index.reg, index.scale, FixedArray::kHeaderSize));
2459 // Calculate location of the first key name.
2460 __ addq(rbx,
2461 Immediate(FixedArray::kHeaderSize +
2462 DescriptorArray::kFirstIndex * kPointerSize));
2463 // Loop through all the keys in the descriptor array. If one of these is the
2464 // symbol valueOf the result is false.
2465 Label entry, loop;
2466 __ jmp(&entry);
2467 __ bind(&loop);
2468 __ movq(rdx, FieldOperand(rbx, 0));
2469 __ Cmp(rdx, FACTORY->value_of_symbol());
2470 __ j(equal, if_false);
2471 __ addq(rbx, Immediate(kPointerSize));
2472 __ bind(&entry);
2473 __ cmpq(rbx, rcx);
2474 __ j(not_equal, &loop);
2475
2476 // Reload map as register rbx was used as temporary above.
2477 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2478
2479 // If a valueOf property is not found on the object check that it's
2480 // prototype is the un-modified String prototype. If not result is false.
2481 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
2482 __ testq(rcx, Immediate(kSmiTagMask));
2483 __ j(zero, if_false);
2484 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2485 __ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2486 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
2487 __ cmpq(rcx,
2488 ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2489 __ j(not_equal, if_false);
2490 // Set the bit in the map to indicate that it has been checked safe for
2491 // default valueOf and set true result.
2492 __ or_(FieldOperand(rbx, Map::kBitField2Offset),
2493 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2494 __ jmp(if_true);
2495
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002496 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002497 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002498}
2499
2500
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002501void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
2502 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002503 ASSERT(args->length() == 1);
2504
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002505 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002506
2507 Label materialize_true, materialize_false;
2508 Label* if_true = NULL;
2509 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002510 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002511 context()->PrepareTest(&materialize_true, &materialize_false,
2512 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002513
2514 __ JumpIfSmi(rax, if_false);
2515 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002516 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002517 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002518
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002519 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002520}
2521
2522
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002523void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2524 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002525 ASSERT(args->length() == 1);
2526
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002527 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002528
2529 Label materialize_true, materialize_false;
2530 Label* if_true = NULL;
2531 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002532 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002533 context()->PrepareTest(&materialize_true, &materialize_false,
2534 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002535
2536 __ JumpIfSmi(rax, if_false);
2537 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002538 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002539 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002540
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002541 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002542}
2543
2544
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002545void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2546 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002547 ASSERT(args->length() == 1);
2548
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002549 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002550
2551 Label materialize_true, materialize_false;
2552 Label* if_true = NULL;
2553 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002554 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002555 context()->PrepareTest(&materialize_true, &materialize_false,
2556 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002557
2558 __ JumpIfSmi(rax, if_false);
2559 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002560 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002561 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002562
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002563 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002564}
2565
2566
2567
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002568void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
2569 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002570
2571 Label materialize_true, materialize_false;
2572 Label* if_true = NULL;
2573 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002574 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002575 context()->PrepareTest(&materialize_true, &materialize_false,
2576 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002577
2578 // Get the frame pointer for the calling frame.
2579 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2580
2581 // Skip the arguments adaptor frame if it exists.
2582 Label check_frame_marker;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002583 __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset),
2584 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002585 __ j(not_equal, &check_frame_marker);
2586 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
2587
2588 // Check the marker in the calling frame.
2589 __ bind(&check_frame_marker);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002590 __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
2591 Smi::FromInt(StackFrame::CONSTRUCT));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002592 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002593 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002594
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002595 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002596}
2597
2598
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002599void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
2600 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002601 ASSERT(args->length() == 2);
2602
2603 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002604 VisitForStackValue(args->at(0));
2605 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002606
2607 Label materialize_true, materialize_false;
2608 Label* if_true = NULL;
2609 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002610 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002611 context()->PrepareTest(&materialize_true, &materialize_false,
2612 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002613
2614 __ pop(rbx);
2615 __ cmpq(rax, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002616 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002617 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002618
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002619 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002620}
2621
2622
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002623void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
2624 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002625 ASSERT(args->length() == 1);
2626
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002627 // ArgumentsAccessStub expects the key in rdx and the formal
2628 // parameter count in rax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002629 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002630 __ movq(rdx, rax);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002631 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002632 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2633 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002634 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002635}
2636
2637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002638void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
2639 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002640
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002641 Label exit;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002642 // Get the number of formal parameters.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002643 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002644
2645 // Check if the calling frame is an arguments adaptor frame.
2646 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002647 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
2648 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002649 __ j(not_equal, &exit, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002650
2651 // Arguments adaptor case: Read the arguments length from the
2652 // adaptor frame.
2653 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2654
2655 __ bind(&exit);
2656 if (FLAG_debug_code) __ AbortIfNotSmi(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002657 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002658}
2659
2660
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002661void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2662 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002663 ASSERT(args->length() == 1);
2664 Label done, null, function, non_function_constructor;
2665
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002666 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002667
2668 // If the object is a smi, we return null.
2669 __ JumpIfSmi(rax, &null);
2670
2671 // Check that the object is a JS object but take special care of JS
2672 // functions to make sure they have 'Function' as their class.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002673 // Assume that there are only two callable types, and one of them is at
2674 // either end of the type range for JS object types. Saves extra comparisons.
2675 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002676 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
2677 // Map is now in rax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002678 __ j(below, &null);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002679 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2680 FIRST_SPEC_OBJECT_TYPE + 1);
2681 __ j(equal, &function);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002682
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002683 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
2684 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2685 LAST_SPEC_OBJECT_TYPE - 1);
2686 __ j(equal, &function);
2687 // Assume that there is no larger type.
2688 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002689
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002690 // Check if the constructor in the map is a JS function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002691 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
2692 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2693 __ j(not_equal, &non_function_constructor);
2694
2695 // rax now contains the constructor function. Grab the
2696 // instance class name from there.
2697 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
2698 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
2699 __ jmp(&done);
2700
2701 // Functions have class 'Function'.
2702 __ bind(&function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002703 __ Move(rax, isolate()->factory()->function_class_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002704 __ jmp(&done);
2705
2706 // Objects with a non-function constructor have class 'Object'.
2707 __ bind(&non_function_constructor);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002708 __ Move(rax, isolate()->factory()->Object_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002709 __ jmp(&done);
2710
2711 // Non-JS objects have class null.
2712 __ bind(&null);
2713 __ LoadRoot(rax, Heap::kNullValueRootIndex);
2714
2715 // All done.
2716 __ bind(&done);
2717
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002718 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002719}
2720
2721
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002722void FullCodeGenerator::EmitLog(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002723 // Conditionally generate a log call.
2724 // Args:
2725 // 0 (literal string): The type of logging (corresponds to the flags).
2726 // This is used to determine whether or not to generate the log call.
2727 // 1 (string): Format string. Access the string at argument index 2
2728 // with '%2s' (see Logger::LogRuntime for all the formats).
2729 // 2 (array): Arguments to the format string.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002730 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002731 ASSERT_EQ(args->length(), 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002732 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002733 VisitForStackValue(args->at(1));
2734 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002735 __ CallRuntime(Runtime::kLog, 2);
2736 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002737 // Finally, we're expected to leave a value on the top of the stack.
2738 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002739 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002740}
2741
2742
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002743void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
2744 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002745
2746 Label slow_allocate_heapnumber;
2747 Label heapnumber_allocated;
2748
2749 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
2750 __ jmp(&heapnumber_allocated);
2751
2752 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002753 // Allocate a heap number.
2754 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002755 __ movq(rbx, rax);
2756
2757 __ bind(&heapnumber_allocated);
2758
2759 // Return a random uint32 number in rax.
2760 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002761 __ PrepareCallCFunction(1);
2762#ifdef _WIN64
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002763 __ movq(rcx, ContextOperand(context_register(), Context::GLOBAL_INDEX));
2764 __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset));
2765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002766#else
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002767 __ movq(rdi, ContextOperand(context_register(), Context::GLOBAL_INDEX));
2768 __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002769#endif
2770 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002771
2772 // Convert 32 random bits in rax to 0.(32 random bits) in a double
2773 // by computing:
2774 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2775 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2776 __ movd(xmm1, rcx);
2777 __ movd(xmm0, rax);
2778 __ cvtss2sd(xmm1, xmm1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002779 __ xorps(xmm0, xmm1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002780 __ subsd(xmm0, xmm1);
2781 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
2782
2783 __ movq(rax, rbx);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002784 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002785}
2786
2787
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002788void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002789 // Load the arguments on the stack and call the stub.
2790 SubStringStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002791 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002792 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002793 VisitForStackValue(args->at(0));
2794 VisitForStackValue(args->at(1));
2795 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002796 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002797 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002798}
2799
2800
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002801void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002802 // Load the arguments on the stack and call the stub.
2803 RegExpExecStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002804 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002805 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002806 VisitForStackValue(args->at(0));
2807 VisitForStackValue(args->at(1));
2808 VisitForStackValue(args->at(2));
2809 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002810 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002811 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002812}
2813
2814
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002815void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
2816 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002817 ASSERT(args->length() == 1);
2818
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002819 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002820
2821 Label done;
2822 // If the object is a smi return the object.
2823 __ JumpIfSmi(rax, &done);
2824 // If the object is not a value type, return the object.
2825 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
2826 __ j(not_equal, &done);
2827 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset));
2828
2829 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002830 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002831}
2832
2833
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002834void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002835 // Load the arguments on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002836 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002837 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002838 VisitForStackValue(args->at(0));
2839 VisitForStackValue(args->at(1));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002840 MathPowStub stub(MathPowStub::ON_STACK);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002841 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002842 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002843}
2844
2845
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002846void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
2847 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002848 ASSERT(args->length() == 2);
2849
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002850 VisitForStackValue(args->at(0)); // Load the object.
2851 VisitForAccumulatorValue(args->at(1)); // Load the value.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002852 __ pop(rbx); // rax = value. rbx = object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002853
2854 Label done;
2855 // If the object is a smi, return the value.
2856 __ JumpIfSmi(rbx, &done);
2857
2858 // If the object is not a value type, return the value.
2859 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
2860 __ j(not_equal, &done);
2861
2862 // Store the value.
2863 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax);
2864 // Update the write barrier. Save the value as it will be
2865 // overwritten by the write barrier code and is needed afterward.
2866 __ movq(rdx, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002867 __ RecordWriteField(rbx, JSValue::kValueOffset, rdx, rcx, kDontSaveFPRegs);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002868
2869 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002870 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002871}
2872
2873
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002874void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
2875 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002876 ASSERT_EQ(args->length(), 1);
2877
2878 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002879 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002880
2881 NumberToStringStub stub;
2882 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002883 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002884}
2885
2886
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002887void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
2888 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002889 ASSERT(args->length() == 1);
2890
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002891 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002892
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002893 Label done;
2894 StringCharFromCodeGenerator generator(rax, rbx);
2895 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002896 __ jmp(&done);
2897
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002898 NopRuntimeCallHelper call_helper;
2899 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002900
2901 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002902 context()->Plug(rbx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002903}
2904
2905
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002906void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
2907 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002908 ASSERT(args->length() == 2);
2909
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002910 VisitForStackValue(args->at(0));
2911 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002912
2913 Register object = rbx;
2914 Register index = rax;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002915 Register result = rdx;
2916
2917 __ pop(object);
2918
2919 Label need_conversion;
2920 Label index_out_of_range;
2921 Label done;
2922 StringCharCodeAtGenerator generator(object,
2923 index,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002924 result,
2925 &need_conversion,
2926 &need_conversion,
2927 &index_out_of_range,
2928 STRING_INDEX_IS_NUMBER);
2929 generator.GenerateFast(masm_);
2930 __ jmp(&done);
2931
2932 __ bind(&index_out_of_range);
2933 // When the index is out of range, the spec requires us to return
2934 // NaN.
2935 __ LoadRoot(result, Heap::kNanValueRootIndex);
2936 __ jmp(&done);
2937
2938 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002939 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002940 // trigger conversion.
2941 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2942 __ jmp(&done);
2943
2944 NopRuntimeCallHelper call_helper;
2945 generator.GenerateSlow(masm_, call_helper);
2946
2947 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002948 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002949}
2950
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002951
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002952void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
2953 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002954 ASSERT(args->length() == 2);
2955
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002956 VisitForStackValue(args->at(0));
2957 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002958
2959 Register object = rbx;
2960 Register index = rax;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002961 Register scratch = rdx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002962 Register result = rax;
2963
2964 __ pop(object);
2965
2966 Label need_conversion;
2967 Label index_out_of_range;
2968 Label done;
2969 StringCharAtGenerator generator(object,
2970 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002971 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002972 result,
2973 &need_conversion,
2974 &need_conversion,
2975 &index_out_of_range,
2976 STRING_INDEX_IS_NUMBER);
2977 generator.GenerateFast(masm_);
2978 __ jmp(&done);
2979
2980 __ bind(&index_out_of_range);
2981 // When the index is out of range, the spec requires us to return
2982 // the empty string.
2983 __ LoadRoot(result, Heap::kEmptyStringRootIndex);
2984 __ jmp(&done);
2985
2986 __ bind(&need_conversion);
2987 // Move smi zero into the result register, which will trigger
2988 // conversion.
2989 __ Move(result, Smi::FromInt(0));
2990 __ jmp(&done);
2991
2992 NopRuntimeCallHelper call_helper;
2993 generator.GenerateSlow(masm_, call_helper);
2994
2995 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002996 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002997}
2998
2999
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003000void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3001 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003002 ASSERT_EQ(2, args->length());
3003
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003004 VisitForStackValue(args->at(0));
3005 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003006
3007 StringAddStub stub(NO_STRING_ADD_FLAGS);
3008 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003009 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003010}
3011
3012
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003013void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3014 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003015 ASSERT_EQ(2, args->length());
3016
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003017 VisitForStackValue(args->at(0));
3018 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003019
3020 StringCompareStub stub;
3021 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003022 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003023}
3024
3025
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003026void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003027 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003028 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3029 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003030 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003031 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003032 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003033 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003034 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003035}
3036
3037
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003038void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003039 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003040 TranscendentalCacheStub stub(TranscendentalCache::COS,
3041 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003042 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003043 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003044 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003045 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003046 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003047}
3048
3049
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003050void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
3051 // Load the argument on the stack and call the stub.
3052 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3053 TranscendentalCacheStub::TAGGED);
3054 ZoneList<Expression*>* args = expr->arguments();
3055 ASSERT(args->length() == 1);
3056 VisitForStackValue(args->at(0));
3057 __ CallStub(&stub);
3058 context()->Plug(rax);
3059}
3060
3061
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003062void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003063 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003064 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3065 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003066 ZoneList<Expression*>* args = expr->arguments();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003067 ASSERT(args->length() == 1);
3068 VisitForStackValue(args->at(0));
3069 __ CallStub(&stub);
3070 context()->Plug(rax);
3071}
3072
3073
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003074void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003075 // Load the argument on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003076 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003077 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003078 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003079 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003080 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003081}
3082
3083
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003084void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3085 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003086 ASSERT(args->length() >= 2);
3087
danno@chromium.org160a7b02011-04-18 15:51:38 +00003088 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3089 for (int i = 0; i < arg_count + 1; i++) {
3090 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003091 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003092 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003093
danno@chromium.orgc612e022011-11-10 11:38:15 +00003094 // Check for proxy.
3095 Label proxy, done;
3096 __ CmpObjectType(rax, JS_FUNCTION_PROXY_TYPE, rbx);
3097 __ j(equal, &proxy);
3098
danno@chromium.org160a7b02011-04-18 15:51:38 +00003099 // InvokeFunction requires the function in rdi. Move it in there.
3100 __ movq(rdi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003101 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003102 __ InvokeFunction(rdi, count, CALL_FUNCTION,
3103 NullCallWrapper(), CALL_AS_METHOD);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003104 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003105 __ jmp(&done);
3106
3107 __ bind(&proxy);
3108 __ push(rax);
3109 __ CallRuntime(Runtime::kCall, args->length());
3110 __ bind(&done);
3111
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003112 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003113}
3114
3115
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003116void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003117 RegExpConstructResultStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003118 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003119 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003120 VisitForStackValue(args->at(0));
3121 VisitForStackValue(args->at(1));
3122 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003123 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003124 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003125}
3126
3127
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003128void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) {
3129 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003130 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003131 VisitForStackValue(args->at(0));
3132 VisitForStackValue(args->at(1));
3133 VisitForStackValue(args->at(2));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003134 Label done;
3135 Label slow_case;
3136 Register object = rax;
3137 Register index_1 = rbx;
3138 Register index_2 = rcx;
3139 Register elements = rdi;
3140 Register temp = rdx;
3141 __ movq(object, Operand(rsp, 2 * kPointerSize));
3142 // Fetch the map and check if array is in fast case.
3143 // Check that object doesn't require security checks and
3144 // has no indexed interceptor.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003145 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3146 __ j(not_equal, &slow_case);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003147 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
3148 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
3149 __ j(not_zero, &slow_case);
3150
3151 // Check the object's elements are in fast case and writable.
3152 __ movq(elements, FieldOperand(object, JSObject::kElementsOffset));
3153 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
3154 Heap::kFixedArrayMapRootIndex);
3155 __ j(not_equal, &slow_case);
3156
3157 // Check that both indices are smis.
3158 __ movq(index_1, Operand(rsp, 1 * kPointerSize));
3159 __ movq(index_2, Operand(rsp, 0 * kPointerSize));
3160 __ JumpIfNotBothSmi(index_1, index_2, &slow_case);
3161
3162 // Check that both indices are valid.
3163 // The JSArray length field is a smi since the array is in fast case mode.
3164 __ movq(temp, FieldOperand(object, JSArray::kLengthOffset));
3165 __ SmiCompare(temp, index_1);
3166 __ j(below_equal, &slow_case);
3167 __ SmiCompare(temp, index_2);
3168 __ j(below_equal, &slow_case);
3169
3170 __ SmiToInteger32(index_1, index_1);
3171 __ SmiToInteger32(index_2, index_2);
3172 // Bring addresses into index1 and index2.
3173 __ lea(index_1, FieldOperand(elements, index_1, times_pointer_size,
3174 FixedArray::kHeaderSize));
3175 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size,
3176 FixedArray::kHeaderSize));
3177
3178 // Swap elements. Use object and temp as scratch registers.
3179 __ movq(object, Operand(index_1, 0));
3180 __ movq(temp, Operand(index_2, 0));
3181 __ movq(Operand(index_2, 0), object);
3182 __ movq(Operand(index_1, 0), temp);
3183
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003184 Label no_remembered_set;
3185 __ CheckPageFlag(elements,
3186 temp,
3187 1 << MemoryChunk::SCAN_ON_SCAVENGE,
3188 not_zero,
3189 &no_remembered_set,
3190 Label::kNear);
3191 // Possible optimization: do a check that both values are Smis
3192 // (or them and test against Smi mask.)
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003193
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003194 // We are swapping two objects in an array and the incremental marker never
3195 // pauses in the middle of scanning a single object. Therefore the
3196 // incremental marker is not disturbed, so we don't need to call the
3197 // RecordWrite stub that notifies the incremental marker.
3198 __ RememberedSetHelper(elements,
3199 index_1,
3200 temp,
3201 kDontSaveFPRegs,
3202 MacroAssembler::kFallThroughAtEnd);
3203 __ RememberedSetHelper(elements,
3204 index_2,
3205 temp,
3206 kDontSaveFPRegs,
3207 MacroAssembler::kFallThroughAtEnd);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003208
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003209 __ bind(&no_remembered_set);
3210
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003211 // We are done. Drop elements from the stack, and return undefined.
3212 __ addq(rsp, Immediate(3 * kPointerSize));
3213 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3214 __ jmp(&done);
3215
3216 __ bind(&slow_case);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003217 __ CallRuntime(Runtime::kSwapElements, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003218
3219 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003220 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003221}
3222
3223
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003224void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3225 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003226 ASSERT_EQ(2, args->length());
3227
3228 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3229 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3230
3231 Handle<FixedArray> jsfunction_result_caches(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003232 isolate()->global_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003233 if (jsfunction_result_caches->length() <= cache_id) {
3234 __ Abort("Attempt to use undefined cache.");
3235 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003236 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003237 return;
3238 }
3239
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003240 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003241
3242 Register key = rax;
3243 Register cache = rbx;
3244 Register tmp = rcx;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003245 __ movq(cache, ContextOperand(rsi, Context::GLOBAL_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003246 __ movq(cache,
3247 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
3248 __ movq(cache,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003249 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003250 __ movq(cache,
3251 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3252
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003253 Label done, not_found;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003254 // tmp now holds finger offset as a smi.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003255 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003256 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3257 SmiIndex index =
3258 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
3259 __ cmpq(key, FieldOperand(cache,
3260 index.reg,
3261 index.scale,
3262 FixedArray::kHeaderSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003263 __ j(not_equal, &not_found, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003264 __ movq(rax, FieldOperand(cache,
3265 index.reg,
3266 index.scale,
3267 FixedArray::kHeaderSize + kPointerSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003268 __ jmp(&done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003269
3270 __ bind(&not_found);
3271 // Call runtime to perform the lookup.
3272 __ push(cache);
3273 __ push(key);
3274 __ CallRuntime(Runtime::kGetFromCache, 2);
3275
3276 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003277 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003278}
3279
3280
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003281void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) {
3282 ZoneList<Expression*>* args = expr->arguments();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003283 ASSERT_EQ(2, args->length());
3284
3285 Register right = rax;
3286 Register left = rbx;
3287 Register tmp = rcx;
3288
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003289 VisitForStackValue(args->at(0));
3290 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003291 __ pop(left);
3292
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003293 Label done, fail, ok;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003294 __ cmpq(left, right);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003295 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003296 // Fail if either is a non-HeapObject.
3297 Condition either_smi = masm()->CheckEitherSmi(left, right, tmp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003298 __ j(either_smi, &fail, Label::kNear);
3299 __ j(zero, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003300 __ movq(tmp, FieldOperand(left, HeapObject::kMapOffset));
3301 __ cmpb(FieldOperand(tmp, Map::kInstanceTypeOffset),
3302 Immediate(JS_REGEXP_TYPE));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003303 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003304 __ cmpq(tmp, FieldOperand(right, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003305 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003306 __ movq(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3307 __ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003308 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003309 __ bind(&fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003310 __ Move(rax, isolate()->factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003311 __ jmp(&done, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003312 __ bind(&ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003313 __ Move(rax, isolate()->factory()->true_value());
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003314 __ bind(&done);
3315
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003316 context()->Plug(rax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003317}
3318
3319
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003320void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3321 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003322 ASSERT(args->length() == 1);
3323
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003324 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003325
3326 Label materialize_true, materialize_false;
3327 Label* if_true = NULL;
3328 Label* if_false = NULL;
3329 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003330 context()->PrepareTest(&materialize_true, &materialize_false,
3331 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003332
3333 __ testl(FieldOperand(rax, String::kHashFieldOffset),
3334 Immediate(String::kContainsCachedArrayIndexMask));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003335 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003336 __ j(zero, if_true);
3337 __ jmp(if_false);
3338
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003339 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003340}
3341
3342
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003343void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3344 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003345 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003346 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003347
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003348 if (FLAG_debug_code) {
3349 __ AbortIfNotString(rax);
3350 }
3351
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003352 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
3353 ASSERT(String::kHashShift >= kSmiTagSize);
3354 __ IndexFromHash(rax, rax);
3355
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003356 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003357}
3358
3359
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003360void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003361 Label bailout, return_result, done, one_char_separator, long_separator,
3362 non_trivial_array, not_size_one_array, loop,
3363 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003364 ZoneList<Expression*>* args = expr->arguments();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003365 ASSERT(args->length() == 2);
3366 // We will leave the separator on the stack until the end of the function.
3367 VisitForStackValue(args->at(1));
3368 // Load this to rax (= array)
3369 VisitForAccumulatorValue(args->at(0));
3370 // All aliases of the same register have disjoint lifetimes.
3371 Register array = rax;
3372 Register elements = no_reg; // Will be rax.
3373
3374 Register index = rdx;
3375
3376 Register string_length = rcx;
3377
3378 Register string = rsi;
3379
3380 Register scratch = rbx;
3381
3382 Register array_length = rdi;
3383 Register result_pos = no_reg; // Will be rdi.
3384
3385 Operand separator_operand = Operand(rsp, 2 * kPointerSize);
3386 Operand result_operand = Operand(rsp, 1 * kPointerSize);
3387 Operand array_length_operand = Operand(rsp, 0 * kPointerSize);
3388 // Separator operand is already pushed. Make room for the two
3389 // other stack fields, and clear the direction flag in anticipation
3390 // of calling CopyBytes.
3391 __ subq(rsp, Immediate(2 * kPointerSize));
3392 __ cld();
3393 // Check that the array is a JSArray
3394 __ JumpIfSmi(array, &bailout);
3395 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3396 __ j(not_equal, &bailout);
3397
3398 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003399 __ CheckFastElements(scratch, &bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003400
3401 // Array has fast elements, so its length must be a smi.
3402 // If the array has length zero, return the empty string.
3403 __ movq(array_length, FieldOperand(array, JSArray::kLengthOffset));
3404 __ SmiCompare(array_length, Smi::FromInt(0));
3405 __ j(not_zero, &non_trivial_array);
3406 __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
3407 __ jmp(&return_result);
3408
3409 // Save the array length on the stack.
3410 __ bind(&non_trivial_array);
3411 __ SmiToInteger32(array_length, array_length);
3412 __ movl(array_length_operand, array_length);
3413
3414 // Save the FixedArray containing array's elements.
3415 // End of array's live range.
3416 elements = array;
3417 __ movq(elements, FieldOperand(array, JSArray::kElementsOffset));
3418 array = no_reg;
3419
3420
3421 // Check that all array elements are sequential ASCII strings, and
3422 // accumulate the sum of their lengths, as a smi-encoded value.
3423 __ Set(index, 0);
3424 __ Set(string_length, 0);
3425 // Loop condition: while (index < array_length).
3426 // Live loop registers: index(int32), array_length(int32), string(String*),
3427 // scratch, string_length(int32), elements(FixedArray*).
3428 if (FLAG_debug_code) {
3429 __ cmpq(index, array_length);
3430 __ Assert(below, "No empty arrays here in EmitFastAsciiArrayJoin");
3431 }
3432 __ bind(&loop);
3433 __ movq(string, FieldOperand(elements,
3434 index,
3435 times_pointer_size,
3436 FixedArray::kHeaderSize));
3437 __ JumpIfSmi(string, &bailout);
3438 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3439 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3440 __ andb(scratch, Immediate(
3441 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3442 __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
3443 __ j(not_equal, &bailout);
3444 __ AddSmiField(string_length,
3445 FieldOperand(string, SeqAsciiString::kLengthOffset));
3446 __ j(overflow, &bailout);
3447 __ incl(index);
3448 __ cmpl(index, array_length);
3449 __ j(less, &loop);
3450
3451 // Live registers:
3452 // string_length: Sum of string lengths.
3453 // elements: FixedArray of strings.
3454 // index: Array length.
3455 // array_length: Array length.
3456
3457 // If array_length is 1, return elements[0], a string.
3458 __ cmpl(array_length, Immediate(1));
3459 __ j(not_equal, &not_size_one_array);
3460 __ movq(rax, FieldOperand(elements, FixedArray::kHeaderSize));
3461 __ jmp(&return_result);
3462
3463 __ bind(&not_size_one_array);
3464
3465 // End of array_length live range.
3466 result_pos = array_length;
3467 array_length = no_reg;
3468
3469 // Live registers:
3470 // string_length: Sum of string lengths.
3471 // elements: FixedArray of strings.
3472 // index: Array length.
3473
3474 // Check that the separator is a sequential ASCII string.
3475 __ movq(string, separator_operand);
3476 __ JumpIfSmi(string, &bailout);
3477 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3478 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3479 __ andb(scratch, Immediate(
3480 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3481 __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
3482 __ j(not_equal, &bailout);
3483
3484 // Live registers:
3485 // string_length: Sum of string lengths.
3486 // elements: FixedArray of strings.
3487 // index: Array length.
3488 // string: Separator string.
3489
3490 // Add (separator length times (array_length - 1)) to string_length.
3491 __ SmiToInteger32(scratch,
3492 FieldOperand(string, SeqAsciiString::kLengthOffset));
3493 __ decl(index);
3494 __ imull(scratch, index);
3495 __ j(overflow, &bailout);
3496 __ addl(string_length, scratch);
3497 __ j(overflow, &bailout);
3498
3499 // Live registers and stack values:
3500 // string_length: Total length of result string.
3501 // elements: FixedArray of strings.
3502 __ AllocateAsciiString(result_pos, string_length, scratch,
3503 index, string, &bailout);
3504 __ movq(result_operand, result_pos);
3505 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3506
3507 __ movq(string, separator_operand);
3508 __ SmiCompare(FieldOperand(string, SeqAsciiString::kLengthOffset),
3509 Smi::FromInt(1));
3510 __ j(equal, &one_char_separator);
3511 __ j(greater, &long_separator);
3512
3513
3514 // Empty separator case:
3515 __ Set(index, 0);
3516 __ movl(scratch, array_length_operand);
3517 __ jmp(&loop_1_condition);
3518 // Loop condition: while (index < array_length).
3519 __ bind(&loop_1);
3520 // Each iteration of the loop concatenates one string to the result.
3521 // Live values in registers:
3522 // index: which element of the elements array we are adding to the result.
3523 // result_pos: the position to which we are currently copying characters.
3524 // elements: the FixedArray of strings we are joining.
3525 // scratch: array length.
3526
3527 // Get string = array[index].
3528 __ movq(string, FieldOperand(elements, index,
3529 times_pointer_size,
3530 FixedArray::kHeaderSize));
3531 __ SmiToInteger32(string_length,
3532 FieldOperand(string, String::kLengthOffset));
3533 __ lea(string,
3534 FieldOperand(string, SeqAsciiString::kHeaderSize));
3535 __ CopyBytes(result_pos, string, string_length);
3536 __ incl(index);
3537 __ bind(&loop_1_condition);
3538 __ cmpl(index, scratch);
3539 __ j(less, &loop_1); // Loop while (index < array_length).
3540 __ jmp(&done);
3541
3542 // Generic bailout code used from several places.
3543 __ bind(&bailout);
3544 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3545 __ jmp(&return_result);
3546
3547
3548 // One-character separator case
3549 __ bind(&one_char_separator);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003550 // Get the separator ASCII character value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003551 // Register "string" holds the separator.
3552 __ movzxbl(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3553 __ Set(index, 0);
3554 // Jump into the loop after the code that copies the separator, so the first
3555 // element is not preceded by a separator
3556 __ jmp(&loop_2_entry);
3557 // Loop condition: while (index < length).
3558 __ bind(&loop_2);
3559 // Each iteration of the loop concatenates one string to the result.
3560 // Live values in registers:
3561 // elements: The FixedArray of strings we are joining.
3562 // index: which element of the elements array we are adding to the result.
3563 // result_pos: the position to which we are currently copying characters.
3564 // scratch: Separator character.
3565
3566 // Copy the separator character to the result.
3567 __ movb(Operand(result_pos, 0), scratch);
3568 __ incq(result_pos);
3569
3570 __ bind(&loop_2_entry);
3571 // Get string = array[index].
3572 __ movq(string, FieldOperand(elements, index,
3573 times_pointer_size,
3574 FixedArray::kHeaderSize));
3575 __ SmiToInteger32(string_length,
3576 FieldOperand(string, String::kLengthOffset));
3577 __ lea(string,
3578 FieldOperand(string, SeqAsciiString::kHeaderSize));
3579 __ CopyBytes(result_pos, string, string_length);
3580 __ incl(index);
3581 __ cmpl(index, array_length_operand);
3582 __ j(less, &loop_2); // End while (index < length).
3583 __ jmp(&done);
3584
3585
3586 // Long separator case (separator is more than one character).
3587 __ bind(&long_separator);
3588
3589 // Make elements point to end of elements array, and index
3590 // count from -array_length to zero, so we don't need to maintain
3591 // a loop limit.
3592 __ movl(index, array_length_operand);
3593 __ lea(elements, FieldOperand(elements, index, times_pointer_size,
3594 FixedArray::kHeaderSize));
3595 __ neg(index);
3596
3597 // Replace separator string with pointer to its first character, and
3598 // make scratch be its length.
3599 __ movq(string, separator_operand);
3600 __ SmiToInteger32(scratch,
3601 FieldOperand(string, String::kLengthOffset));
3602 __ lea(string,
3603 FieldOperand(string, SeqAsciiString::kHeaderSize));
3604 __ movq(separator_operand, string);
3605
3606 // Jump into the loop after the code that copies the separator, so the first
3607 // element is not preceded by a separator
3608 __ jmp(&loop_3_entry);
3609 // Loop condition: while (index < length).
3610 __ bind(&loop_3);
3611 // Each iteration of the loop concatenates one string to the result.
3612 // Live values in registers:
3613 // index: which element of the elements array we are adding to the result.
3614 // result_pos: the position to which we are currently copying characters.
3615 // scratch: Separator length.
3616 // separator_operand (rsp[0x10]): Address of first char of separator.
3617
3618 // Copy the separator to the result.
3619 __ movq(string, separator_operand);
3620 __ movl(string_length, scratch);
3621 __ CopyBytes(result_pos, string, string_length, 2);
3622
3623 __ bind(&loop_3_entry);
3624 // Get string = array[index].
3625 __ movq(string, Operand(elements, index, times_pointer_size, 0));
3626 __ SmiToInteger32(string_length,
3627 FieldOperand(string, String::kLengthOffset));
3628 __ lea(string,
3629 FieldOperand(string, SeqAsciiString::kHeaderSize));
3630 __ CopyBytes(result_pos, string, string_length);
3631 __ incq(index);
3632 __ j(not_equal, &loop_3); // Loop while (index < 0).
3633
3634 __ bind(&done);
3635 __ movq(rax, result_operand);
3636
3637 __ bind(&return_result);
3638 // Drop temp values from the stack, and restore context register.
3639 __ addq(rsp, Immediate(3 * kPointerSize));
3640 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3641 context()->Plug(rax);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003642}
3643
3644
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003645void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003646 Handle<String> name = expr->name();
3647 if (name->length() > 0 && name->Get(0) == '_') {
3648 Comment cmnt(masm_, "[ InlineRuntimeCall");
3649 EmitInlineRuntimeCall(expr);
3650 return;
3651 }
3652
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003653 Comment cmnt(masm_, "[ CallRuntime");
3654 ZoneList<Expression*>* args = expr->arguments();
3655
3656 if (expr->is_jsruntime()) {
3657 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003658 __ movq(rax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003659 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
3660 }
3661
3662 // Push the arguments ("left-to-right").
3663 int arg_count = args->length();
3664 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003665 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003666 }
3667
3668 if (expr->is_jsruntime()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003669 // Call the JS runtime function using a call IC.
3670 __ Move(rcx, expr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003671 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003672 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003673 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003674 __ call(ic, mode, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003675 // Restore context register.
3676 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003677 } else {
3678 __ CallRuntime(expr->function(), arg_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003679 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003680 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003681}
3682
3683
3684void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3685 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003686 case Token::DELETE: {
3687 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003688 Property* property = expr->expression()->AsProperty();
3689 VariableProxy* proxy = expr->expression()->AsVariableProxy();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003690
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003691 if (property != NULL) {
3692 VisitForStackValue(property->obj());
3693 VisitForStackValue(property->key());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003694 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
3695 ? kNonStrictMode : kStrictMode;
3696 __ Push(Smi::FromInt(strict_mode_flag));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003697 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3698 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003699 } else if (proxy != NULL) {
3700 Variable* var = proxy->var();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003701 // Delete of an unqualified identifier is disallowed in strict mode
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003702 // but "delete this" is allowed.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003703 ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003704 if (var->IsUnallocated()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003705 __ push(GlobalObjectOperand());
3706 __ Push(var->name());
3707 __ Push(Smi::FromInt(kNonStrictMode));
3708 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3709 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003710 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
3711 // Result of deleting non-global variables is false. 'this' is
3712 // not really a variable, though we implement it as one. The
3713 // subexpression does not have side effects.
3714 context()->Plug(var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003715 } else {
3716 // Non-global variable. Call the runtime to try to delete from the
3717 // context where the variable was introduced.
3718 __ push(context_register());
3719 __ Push(var->name());
3720 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3721 context()->Plug(rax);
3722 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003723 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003724 // Result of deleting non-property, non-variable reference is true.
3725 // The subexpression may have side effects.
3726 VisitForEffect(expr->expression());
3727 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003728 }
3729 break;
3730 }
3731
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003732 case Token::VOID: {
3733 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3734 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003735 context()->Plug(Heap::kUndefinedValueRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003736 break;
3737 }
3738
3739 case Token::NOT: {
3740 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003741 if (context()->IsEffect()) {
3742 // Unary NOT has no side effects so it's only necessary to visit the
3743 // subexpression. Match the optimizing compiler by not branching.
3744 VisitForEffect(expr->expression());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003745 } else if (context()->IsTest()) {
3746 const TestContext* test = TestContext::cast(context());
3747 // The labels are swapped for the recursive call.
3748 VisitForControl(expr->expression(),
3749 test->false_label(),
3750 test->true_label(),
3751 test->fall_through());
3752 context()->Plug(test->true_label(), test->false_label());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003753 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003754 // We handle value contexts explicitly rather than simply visiting
3755 // for control and plugging the control flow into the context,
3756 // because we need to prepare a pair of extra administrative AST ids
3757 // for the optimizing compiler.
3758 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
3759 Label materialize_true, materialize_false, done;
3760 VisitForControl(expr->expression(),
3761 &materialize_false,
3762 &materialize_true,
3763 &materialize_true);
3764 __ bind(&materialize_true);
3765 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
3766 if (context()->IsAccumulatorValue()) {
3767 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
3768 } else {
3769 __ PushRoot(Heap::kTrueValueRootIndex);
3770 }
3771 __ jmp(&done, Label::kNear);
3772 __ bind(&materialize_false);
3773 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
3774 if (context()->IsAccumulatorValue()) {
3775 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
3776 } else {
3777 __ PushRoot(Heap::kFalseValueRootIndex);
3778 }
3779 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003780 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003781 break;
3782 }
3783
3784 case Token::TYPEOF: {
3785 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003786 { StackValueContext context(this);
3787 VisitForTypeofValue(expr->expression());
3788 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003789 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003790 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003791 break;
3792 }
3793
3794 case Token::ADD: {
3795 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003796 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003797 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003798 __ JumpIfSmi(result_register(), &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003799 ToNumberStub convert_stub;
3800 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003801 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003802 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003803 break;
3804 }
3805
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003806 case Token::SUB:
3807 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003808 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003809
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003810 case Token::BIT_NOT:
3811 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003812 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003813
3814 default:
3815 UNREACHABLE();
3816 }
3817}
3818
3819
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003820void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3821 const char* comment) {
3822 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
3823 Comment cmt(masm_, comment);
3824 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3825 UnaryOverwriteMode overwrite =
3826 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003827 UnaryOpStub stub(expr->op(), overwrite);
3828 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003829 // accumulator register rax.
3830 VisitForAccumulatorValue(expr->expression());
3831 SetSourcePosition(expr->position());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003832 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003833 context()->Plug(rax);
3834}
3835
3836
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003837void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3838 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003839 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003840
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003841 // Invalid left-hand-sides are rewritten to have a 'throw
3842 // ReferenceError' as the left-hand side.
3843 if (!expr->expression()->IsValidLeftHandSide()) {
3844 VisitForEffect(expr->expression());
3845 return;
3846 }
3847
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003848 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00003849 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003850 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3851 LhsKind assign_type = VARIABLE;
3852 Property* prop = expr->expression()->AsProperty();
3853 // In case of a property we use the uninitialized expression context
3854 // of the key to detect a named property.
3855 if (prop != NULL) {
3856 assign_type =
3857 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3858 }
3859
3860 // Evaluate expression and get value.
3861 if (assign_type == VARIABLE) {
3862 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003863 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003864 EmitVariableLoad(expr->expression()->AsVariableProxy());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003865 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003866 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003867 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003868 __ Push(Smi::FromInt(0));
3869 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003870 if (assign_type == NAMED_PROPERTY) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003871 VisitForAccumulatorValue(prop->obj());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00003872 __ push(rax); // Copy of receiver, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003873 EmitNamedPropertyLoad(prop);
3874 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003875 VisitForStackValue(prop->obj());
3876 VisitForAccumulatorValue(prop->key());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003877 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack
3878 __ push(rax); // Copy of key, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003879 EmitKeyedPropertyLoad(prop);
3880 }
3881 }
3882
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003883 // We need a second deoptimization point after loading the value
3884 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003885 if (assign_type == VARIABLE) {
3886 PrepareForBailout(expr->expression(), TOS_REG);
3887 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003888 PrepareForBailoutForId(expr->CountId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003889 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003890
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003891 // Call ToNumber only if operand is not a smi.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003892 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003893 __ JumpIfSmi(rax, &no_conversion, Label::kNear);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003894 ToNumberStub convert_stub;
3895 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003896 __ bind(&no_conversion);
3897
3898 // Save result for postfix expressions.
3899 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003900 if (!context()->IsEffect()) {
3901 // Save the result on the stack. If we have a named or keyed property
3902 // we store the result under the receiver that is currently on top
3903 // of the stack.
3904 switch (assign_type) {
3905 case VARIABLE:
3906 __ push(rax);
3907 break;
3908 case NAMED_PROPERTY:
3909 __ movq(Operand(rsp, kPointerSize), rax);
3910 break;
3911 case KEYED_PROPERTY:
3912 __ movq(Operand(rsp, 2 * kPointerSize), rax);
3913 break;
3914 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003915 }
3916 }
3917
3918 // Inline smi case if we are in a loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003919 Label done, stub_call;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003920 JumpPatchSite patch_site(masm_);
3921
ricow@chromium.org65fae842010-08-25 15:26:24 +00003922 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003923 if (expr->op() == Token::INC) {
3924 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
3925 } else {
3926 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
3927 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003928 __ j(overflow, &stub_call, Label::kNear);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003929 // We could eliminate this smi check if we split the code at
3930 // the first smi check before calling ToNumber.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003931 patch_site.EmitJumpIfSmi(rax, &done, Label::kNear);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003932
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003933 __ bind(&stub_call);
3934 // Call stub. Undo operation first.
3935 if (expr->op() == Token::INC) {
3936 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
3937 } else {
3938 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
3939 }
3940 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003941
3942 // Record position before stub call.
3943 SetSourcePosition(expr->position());
3944
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003945 // Call stub for +1/-1.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003946 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003947 if (expr->op() == Token::INC) {
3948 __ Move(rdx, Smi::FromInt(1));
3949 } else {
3950 __ movq(rdx, rax);
3951 __ Move(rax, Smi::FromInt(1));
3952 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003953 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
3954 patch_site.EmitPatchInfo();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003955 __ bind(&done);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003956
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003957 // Store the value returned in rax.
3958 switch (assign_type) {
3959 case VARIABLE:
3960 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003961 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003962 { EffectContext context(this);
3963 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3964 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003965 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003966 context.Plug(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003967 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003968 // For all contexts except kEffect: We have the result on
3969 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003970 if (!context()->IsEffect()) {
3971 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003972 }
3973 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003974 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003975 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003976 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003977 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003978 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003979 }
3980 break;
3981 case NAMED_PROPERTY: {
3982 __ Move(rcx, prop->key()->AsLiteral()->handle());
3983 __ pop(rdx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003984 Handle<Code> ic = is_classic_mode()
3985 ? isolate()->builtins()->StoreIC_Initialize()
3986 : isolate()->builtins()->StoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003987 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003988 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003989 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003990 if (!context()->IsEffect()) {
3991 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003992 }
3993 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003994 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003995 }
3996 break;
3997 }
3998 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003999 __ pop(rcx);
4000 __ pop(rdx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004001 Handle<Code> ic = is_classic_mode()
4002 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4003 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004004 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004005 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004006 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004007 if (!context()->IsEffect()) {
4008 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004009 }
4010 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004011 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004012 }
4013 break;
4014 }
4015 }
4016}
4017
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004018
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004019void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004020 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004021 ASSERT(!context()->IsEffect());
4022 ASSERT(!context()->IsTest());
4023
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004024 if (proxy != NULL && proxy->var()->IsUnallocated()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004025 Comment cmnt(masm_, "Global variable");
4026 __ Move(rcx, proxy->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004027 __ movq(rax, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004028 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004029 // Use a regular load, not a contextual load, to avoid a reference
4030 // error.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004031 __ call(ic);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004032 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004033 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004034 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004035 Label done, slow;
4036
4037 // Generate code for loading from variables potentially shadowed
4038 // by eval-introduced variables.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004039 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004040
4041 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004042 __ push(rsi);
4043 __ Push(proxy->name());
4044 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004045 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004046 __ bind(&done);
4047
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004048 context()->Plug(rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004049 } else {
4050 // This expression cannot throw a reference error at the top level.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004051 VisitInDuplicateContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004052 }
4053}
4054
4055
ager@chromium.org04921a82011-06-27 13:21:41 +00004056void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004057 Expression* sub_expr,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004058 Handle<String> check) {
4059 Label materialize_true, materialize_false;
4060 Label* if_true = NULL;
4061 Label* if_false = NULL;
4062 Label* fall_through = NULL;
4063 context()->PrepareTest(&materialize_true, &materialize_false,
4064 &if_true, &if_false, &fall_through);
4065
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004066 { AccumulatorValueContext context(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004067 VisitForTypeofValue(sub_expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004068 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004069 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004070
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004071 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004072 __ JumpIfSmi(rax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004073 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
4074 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
4075 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004076 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004077 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004078 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004079 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
4080 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004081 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004082 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004083 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004084 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004085 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
4086 __ j(equal, if_true);
4087 __ CompareRoot(rax, Heap::kFalseValueRootIndex);
4088 Split(equal, if_true, if_false, fall_through);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004089 } else if (FLAG_harmony_typeof &&
4090 check->Equals(isolate()->heap()->null_symbol())) {
4091 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4092 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004093 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004094 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4095 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004096 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004097 // Check for undetectable objects => true.
4098 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
4099 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4100 Immediate(1 << Map::kIsUndetectable));
4101 Split(not_zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004102 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004103 __ JumpIfSmi(rax, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004104 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4105 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx);
4106 __ j(equal, if_true);
4107 __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
4108 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004109 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004110 __ JumpIfSmi(rax, if_false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004111 if (!FLAG_harmony_typeof) {
4112 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4113 __ j(equal, if_true);
4114 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004115 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004116 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004117 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4118 __ j(above, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004119 // Check for undetectable objects => false.
4120 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4121 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004122 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004123 } else {
4124 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004125 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004126 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004127}
4128
4129
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004130void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4131 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004132 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004133
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004134 // First we try a fast inlined version of the compare when one of
4135 // the operands is a literal.
4136 if (TryLiteralCompare(expr)) return;
4137
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004138 // Always perform the comparison for its control flow. Pack the result
4139 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004140 Label materialize_true, materialize_false;
4141 Label* if_true = NULL;
4142 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004143 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004144 context()->PrepareTest(&materialize_true, &materialize_false,
4145 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004146
ager@chromium.org04921a82011-06-27 13:21:41 +00004147 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004148 VisitForStackValue(expr->left());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004149 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004150 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004151 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004152 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004153 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004154 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004155 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004156 break;
4157
4158 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004159 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004160 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004161 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004162 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004163 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004164 // The stub returns 0 for true.
4165 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004166 break;
4167 }
4168
4169 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004170 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004171 Condition cc = no_condition;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004172 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004173 case Token::EQ_STRICT:
ricow@chromium.org65fae842010-08-25 15:26:24 +00004174 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004175 cc = equal;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004176 break;
4177 case Token::LT:
4178 cc = less;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004179 break;
4180 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004181 cc = greater;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004182 break;
4183 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004184 cc = less_equal;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004185 break;
4186 case Token::GTE:
4187 cc = greater_equal;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004188 break;
4189 case Token::IN:
4190 case Token::INSTANCEOF:
4191 default:
4192 UNREACHABLE();
4193 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004194 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004195
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004196 bool inline_smi_code = ShouldInlineSmiCase(op);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004197 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004198 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004199 Label slow_case;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004200 __ movq(rcx, rdx);
4201 __ or_(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004202 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004203 __ cmpq(rdx, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004204 Split(cc, if_true, if_false, NULL);
4205 __ bind(&slow_case);
4206 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004207
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004208 // Record position and call the compare IC.
4209 SetSourcePosition(expr->position());
4210 Handle<Code> ic = CompareIC::GetUninitialized(op);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004211 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
4212 patch_site.EmitPatchInfo();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004213
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004214 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004215 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004216 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004217 }
4218 }
4219
4220 // Convert the result of the comparison into one expected for this
4221 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004222 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004223}
4224
4225
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004226void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4227 Expression* sub_expr,
4228 NilValue nil) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004229 Label materialize_true, materialize_false;
4230 Label* if_true = NULL;
4231 Label* if_false = NULL;
4232 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004233 context()->PrepareTest(&materialize_true, &materialize_false,
4234 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004235
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004236 VisitForAccumulatorValue(sub_expr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004237 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004238 Heap::RootListIndex nil_value = nil == kNullValue ?
4239 Heap::kNullValueRootIndex :
4240 Heap::kUndefinedValueRootIndex;
4241 __ CompareRoot(rax, nil_value);
4242 if (expr->op() == Token::EQ_STRICT) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004243 Split(equal, if_true, if_false, fall_through);
4244 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004245 Heap::RootListIndex other_nil_value = nil == kNullValue ?
4246 Heap::kUndefinedValueRootIndex :
4247 Heap::kNullValueRootIndex;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004248 __ j(equal, if_true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004249 __ CompareRoot(rax, other_nil_value);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004250 __ j(equal, if_true);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004251 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004252 // It can be an undetectable object.
4253 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
4254 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4255 Immediate(1 << Map::kIsUndetectable));
4256 Split(not_zero, if_true, if_false, fall_through);
4257 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004258 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004259}
4260
4261
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004262void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4263 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004264 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004265}
4266
4267
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004268Register FullCodeGenerator::result_register() {
4269 return rax;
4270}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004271
4272
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004273Register FullCodeGenerator::context_register() {
4274 return rsi;
4275}
4276
4277
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004278void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4279 ASSERT(IsAligned(frame_offset, kPointerSize));
4280 __ movq(Operand(rbp, frame_offset), value);
4281}
4282
4283
4284void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004285 __ movq(dst, ContextOperand(rsi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004286}
4287
4288
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004289void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004290 Scope* declaration_scope = scope()->DeclarationScope();
4291 if (declaration_scope->is_global_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004292 // Contexts nested in the global context have a canonical empty function
4293 // as their closure, not the anonymous closure containing the global
4294 // code. Pass a smi sentinel and let the runtime look up the empty
4295 // function.
4296 __ Push(Smi::FromInt(0));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004297 } else if (declaration_scope->is_eval_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004298 // Contexts created by a call to eval have the same closure as the
4299 // context calling eval, not the anonymous closure containing the eval
4300 // code. Fetch it from the context.
4301 __ push(ContextOperand(rsi, Context::CLOSURE_INDEX));
4302 } else {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004303 ASSERT(declaration_scope->is_function_scope());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004304 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
4305 }
4306}
4307
4308
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004309// ----------------------------------------------------------------------------
4310// Non-local control flow support.
4311
4312
4313void FullCodeGenerator::EnterFinallyBlock() {
4314 ASSERT(!result_register().is(rdx));
4315 ASSERT(!result_register().is(rcx));
4316 // Cook return address on top of stack (smi encoded Code* delta)
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004317 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004318 __ Move(rcx, masm_->CodeObject());
4319 __ subq(rdx, rcx);
4320 __ Integer32ToSmi(rdx, rdx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004321 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004322 // Store result register while executing finally block.
4323 __ push(result_register());
4324}
4325
4326
4327void FullCodeGenerator::ExitFinallyBlock() {
4328 ASSERT(!result_register().is(rdx));
4329 ASSERT(!result_register().is(rcx));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004330 __ pop(result_register());
4331 // Uncook return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004332 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004333 __ SmiToInteger32(rdx, rdx);
4334 __ Move(rcx, masm_->CodeObject());
4335 __ addq(rdx, rcx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004336 __ jmp(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004337}
4338
4339
4340#undef __
4341
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004342#define __ ACCESS_MASM(masm())
4343
4344FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4345 int* stack_depth,
4346 int* context_length) {
4347 // The macros used here must preserve the result register.
4348
4349 // Because the handler block contains the context of the finally
4350 // code, we can restore it directly from there for the finally code
4351 // rather than iteratively unwinding contexts via their previous
4352 // links.
4353 __ Drop(*stack_depth); // Down to the handler block.
4354 if (*context_length > 0) {
4355 // Restore the context to its dedicated register and the stack.
4356 __ movq(rsi, Operand(rsp, StackHandlerConstants::kContextOffset));
4357 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
4358 }
4359 __ PopTryHandler();
4360 __ call(finally_entry_);
4361
4362 *stack_depth = 0;
4363 *context_length = 0;
4364 return previous_;
4365}
4366
4367
4368#undef __
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004369
4370} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004371
4372#endif // V8_TARGET_ARCH_X64