blob: 49adf6af660454adabaf994c0c18bf946e974be7 [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);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001462 if (property->kind() == ObjectLiteral::Property::GETTER) {
1463 VisitForStackValue(value);
1464 __ PushRoot(Heap::kNullValueRootIndex);
1465 } else {
1466 __ PushRoot(Heap::kNullValueRootIndex);
1467 VisitForStackValue(value);
1468 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001469 __ Push(Smi::FromInt(NONE));
1470 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001471 break;
1472 }
1473 }
1474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 if (expr->has_function()) {
1476 ASSERT(result_saved);
1477 __ push(Operand(rsp, 0));
1478 __ CallRuntime(Runtime::kToFastProperties, 1);
1479 }
1480
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001481 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001482 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001483 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001484 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001485 }
1486}
1487
1488
1489void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1490 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001491
1492 ZoneList<Expression*>* subexprs = expr->values();
1493 int length = subexprs->length();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001494 Handle<FixedArray> constant_elements = expr->constant_elements();
1495 ASSERT_EQ(2, constant_elements->length());
1496 ElementsKind constant_elements_kind =
1497 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
erikcorry0ad885c2011-11-21 13:51:57 +00001498 bool has_constant_fast_elements = constant_elements_kind == FAST_ELEMENTS;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001499 Handle<FixedArrayBase> constant_elements_values(
1500 FixedArrayBase::cast(constant_elements->get(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001501
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001502 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1503 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1504 __ Push(Smi::FromInt(expr->literal_index()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001505 __ Push(constant_elements);
erikcorry0ad885c2011-11-21 13:51:57 +00001506 Heap* heap = isolate()->heap();
1507 if (has_constant_fast_elements &&
1508 constant_elements_values->map() == heap->fixed_cow_array_map()) {
1509 // If the elements are already FAST_ELEMENTS, the boilerplate cannot
1510 // change, so it's possible to specialize the stub in advance.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001511 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
erikcorry0ad885c2011-11-21 13:51:57 +00001512 FastCloneShallowArrayStub stub(
1513 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
1514 length);
1515 __ CallStub(&stub);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001516 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001517 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001518 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001519 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001520 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001521 ASSERT(constant_elements_kind == FAST_ELEMENTS ||
1522 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
1523 FLAG_smi_only_arrays);
erikcorry0ad885c2011-11-21 13:51:57 +00001524 // If the elements are already FAST_ELEMENTS, the boilerplate cannot
1525 // change, so it's possible to specialize the stub in advance.
1526 FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
1527 ? FastCloneShallowArrayStub::CLONE_ELEMENTS
1528 : FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001529 FastCloneShallowArrayStub stub(mode, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001530 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001531 }
1532
1533 bool result_saved = false; // Is the result saved to the stack?
1534
1535 // Emit code to evaluate all the non-constant subexpressions and to store
1536 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001537 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001538 Expression* subexpr = subexprs->at(i);
1539 // If the subexpression is a literal or a simple materialized literal it
1540 // is already set in the cloned array.
1541 if (subexpr->AsLiteral() != NULL ||
1542 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1543 continue;
1544 }
1545
1546 if (!result_saved) {
1547 __ push(rax);
1548 result_saved = true;
1549 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001550 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001551
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001552 if (constant_elements_kind == FAST_ELEMENTS) {
1553 // Fast-case array literal with ElementsKind of FAST_ELEMENTS, they cannot
1554 // transition and don't need to call the runtime stub.
1555 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1556 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1557 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
1558 // Store the subexpression value in the array's elements.
1559 __ movq(FieldOperand(rbx, offset), result_register());
1560 // Update the write barrier for the array store.
1561 __ RecordWriteField(rbx, offset, result_register(), rcx,
1562 kDontSaveFPRegs,
1563 EMIT_REMEMBERED_SET,
1564 INLINE_SMI_CHECK);
1565 } else {
1566 // Store the subexpression value in the array's elements.
1567 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1568 __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
1569 __ Move(rcx, Smi::FromInt(i));
1570 __ Move(rdx, Smi::FromInt(expr->literal_index()));
1571 StoreArrayLiteralElementStub stub;
1572 __ CallStub(&stub);
1573 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001574
1575 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001576 }
1577
1578 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001579 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001580 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001581 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001582 }
1583}
1584
1585
ager@chromium.org5c838252010-02-19 08:53:10 +00001586void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1587 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001588 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1589 // on the left-hand side.
1590 if (!expr->target()->IsValidLeftHandSide()) {
1591 VisitForEffect(expr->target());
1592 return;
1593 }
1594
ager@chromium.org5c838252010-02-19 08:53:10 +00001595 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001596 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001597 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1598 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001599 Property* property = expr->target()->AsProperty();
1600 if (property != NULL) {
1601 assign_type = (property->key()->IsPropertyName())
1602 ? NAMED_PROPERTY
1603 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001604 }
1605
1606 // Evaluate LHS expression.
1607 switch (assign_type) {
1608 case VARIABLE:
1609 // Nothing to do here.
1610 break;
1611 case NAMED_PROPERTY:
1612 if (expr->is_compound()) {
1613 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001614 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001615 __ push(result_register());
1616 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001617 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001618 }
1619 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001620 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001621 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001622 VisitForStackValue(property->obj());
1623 VisitForAccumulatorValue(property->key());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001624 __ movq(rdx, Operand(rsp, 0));
1625 __ push(rax);
1626 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001627 VisitForStackValue(property->obj());
1628 VisitForStackValue(property->key());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001629 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001630 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001631 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001632 }
1633
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001634 // For compound assignments we need another deoptimization point after the
1635 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001636 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001637 { AccumulatorValueContext context(this);
1638 switch (assign_type) {
1639 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001640 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001641 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001642 break;
1643 case NAMED_PROPERTY:
1644 EmitNamedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001645 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001646 break;
1647 case KEYED_PROPERTY:
1648 EmitKeyedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001649 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001650 break;
1651 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001652 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001653
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001654 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001655 __ push(rax); // Left operand goes on the stack.
1656 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001657
ricow@chromium.org65fae842010-08-25 15:26:24 +00001658 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1659 ? OVERWRITE_RIGHT
1660 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001661 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001662 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001663 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001664 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001665 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001666 mode,
1667 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001668 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001669 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001670 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001671 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001672 // Deoptimization point in case the binary operation may have side effects.
1673 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001674 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001675 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001676 }
1677
1678 // Record source position before possible IC call.
1679 SetSourcePosition(expr->position());
1680
1681 // Store the value.
1682 switch (assign_type) {
1683 case VARIABLE:
1684 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001685 expr->op());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001686 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001687 context()->Plug(rax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001688 break;
1689 case NAMED_PROPERTY:
1690 EmitNamedPropertyAssignment(expr);
1691 break;
1692 case KEYED_PROPERTY:
1693 EmitKeyedPropertyAssignment(expr);
1694 break;
1695 }
1696}
1697
1698
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001699void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1700 SetSourcePosition(prop->position());
1701 Literal* key = prop->key()->AsLiteral();
1702 __ Move(rcx, key->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001703 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001704 __ call(ic, RelocInfo::CODE_TARGET, prop->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001705}
1706
1707
1708void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1709 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001710 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001711 __ call(ic, RelocInfo::CODE_TARGET, prop->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001712}
1713
1714
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001715void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001716 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001717 OverwriteMode mode,
1718 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001719 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001720 // Do combined smi check of the operands. Left operand is on the
1721 // stack (popped into rdx). Right operand is in rax but moved into
1722 // rcx to make the shifts easier.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001723 Label done, stub_call, smi_case;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001724 __ pop(rdx);
1725 __ movq(rcx, rax);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001726 __ or_(rax, rdx);
1727 JumpPatchSite patch_site(masm_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001728 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001729
1730 __ bind(&stub_call);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001731 __ movq(rax, rcx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001732 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001733 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1734 patch_site.EmitPatchInfo();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001735 __ jmp(&done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001736
1737 __ bind(&smi_case);
1738 switch (op) {
1739 case Token::SAR:
1740 __ SmiShiftArithmeticRight(rax, rdx, rcx);
1741 break;
1742 case Token::SHL:
1743 __ SmiShiftLeft(rax, rdx, rcx);
1744 break;
1745 case Token::SHR:
1746 __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
1747 break;
1748 case Token::ADD:
1749 __ SmiAdd(rax, rdx, rcx, &stub_call);
1750 break;
1751 case Token::SUB:
1752 __ SmiSub(rax, rdx, rcx, &stub_call);
1753 break;
1754 case Token::MUL:
1755 __ SmiMul(rax, rdx, rcx, &stub_call);
1756 break;
1757 case Token::BIT_OR:
1758 __ SmiOr(rax, rdx, rcx);
1759 break;
1760 case Token::BIT_AND:
1761 __ SmiAnd(rax, rdx, rcx);
1762 break;
1763 case Token::BIT_XOR:
1764 __ SmiXor(rax, rdx, rcx);
1765 break;
1766 default:
1767 UNREACHABLE();
1768 break;
1769 }
1770
1771 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001772 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001773}
1774
1775
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001776void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1777 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001778 OverwriteMode mode) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001779 __ pop(rdx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001780 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001781 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
1782 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1783 patch_site.EmitPatchInfo();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001784 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001785}
1786
1787
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001788void FullCodeGenerator::EmitAssignment(Expression* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001789 // Invalid left-hand sides are rewritten to have a 'throw
1790 // ReferenceError' on the left-hand side.
1791 if (!expr->IsValidLeftHandSide()) {
1792 VisitForEffect(expr);
1793 return;
1794 }
1795
1796 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001797 // slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001798 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1799 LhsKind assign_type = VARIABLE;
1800 Property* prop = expr->AsProperty();
1801 if (prop != NULL) {
1802 assign_type = (prop->key()->IsPropertyName())
1803 ? NAMED_PROPERTY
1804 : KEYED_PROPERTY;
1805 }
1806
1807 switch (assign_type) {
1808 case VARIABLE: {
1809 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001810 EffectContext context(this);
1811 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001812 break;
1813 }
1814 case NAMED_PROPERTY: {
1815 __ push(rax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001816 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001817 __ movq(rdx, rax);
1818 __ pop(rax); // Restore value.
1819 __ Move(rcx, prop->key()->AsLiteral()->handle());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001820 Handle<Code> ic = is_classic_mode()
1821 ? isolate()->builtins()->StoreIC_Initialize()
1822 : isolate()->builtins()->StoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001823 __ call(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001824 break;
1825 }
1826 case KEYED_PROPERTY: {
1827 __ push(rax); // Preserve value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001828 VisitForStackValue(prop->obj());
1829 VisitForAccumulatorValue(prop->key());
1830 __ movq(rcx, rax);
1831 __ pop(rdx);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001832 __ pop(rax); // Restore value.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001833 Handle<Code> ic = is_classic_mode()
1834 ? isolate()->builtins()->KeyedStoreIC_Initialize()
1835 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001836 __ call(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001837 break;
1838 }
1839 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001840 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001841}
1842
1843
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001844void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001845 Token::Value op) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001846 if (var->IsUnallocated()) {
1847 // Global var, const, or let.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001848 __ Move(rcx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001849 __ movq(rdx, GlobalObjectOperand());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001850 Handle<Code> ic = is_classic_mode()
1851 ? isolate()->builtins()->StoreIC_Initialize()
1852 : isolate()->builtins()->StoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001853 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001854 } else if (op == Token::INIT_CONST) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001855 // Const initializers need a write barrier.
1856 ASSERT(!var->IsParameter()); // No const parameters.
1857 if (var->IsStackLocal()) {
1858 Label skip;
1859 __ movq(rdx, StackOperand(var));
1860 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1861 __ j(not_equal, &skip);
1862 __ movq(StackOperand(var), rax);
1863 __ bind(&skip);
1864 } else {
1865 ASSERT(var->IsContextSlot() || var->IsLookupSlot());
1866 // Like var declarations, const declarations are hoisted to function
1867 // scope. However, unlike var initializers, const initializers are
1868 // able to drill a hole to that function context, even from inside a
1869 // 'with' context. We thus bypass the normal static scope lookup for
1870 // var->IsContextSlot().
1871 __ push(rax);
1872 __ push(rsi);
1873 __ Push(var->name());
1874 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001875 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001876
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001877 } else if (var->mode() == LET && op != Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001878 // Non-initializing assignment to let variable needs a write barrier.
1879 if (var->IsLookupSlot()) {
1880 __ push(rax); // Value.
1881 __ push(rsi); // Context.
1882 __ Push(var->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001883 __ Push(Smi::FromInt(language_mode()));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001884 __ CallRuntime(Runtime::kStoreContextSlot, 4);
1885 } else {
1886 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
1887 Label assign;
1888 MemOperand location = VarOperand(var, rcx);
1889 __ movq(rdx, location);
1890 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1891 __ j(not_equal, &assign, Label::kNear);
1892 __ Push(var->name());
1893 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1894 __ bind(&assign);
1895 __ movq(location, rax);
1896 if (var->IsContextSlot()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001897 __ movq(rdx, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001898 __ RecordWriteContextSlot(
1899 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001900 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001901 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001902
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001903 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
1904 // Assignment to var or initializing assignment to let/const
1905 // in harmony mode.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001906 if (var->IsStackAllocated() || var->IsContextSlot()) {
1907 MemOperand location = VarOperand(var, rcx);
1908 if (FLAG_debug_code && op == Token::INIT_LET) {
1909 // Check for an uninitialized let binding.
1910 __ movq(rdx, location);
1911 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1912 __ Check(equal, "Let binding re-initialization.");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001913 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001914 // Perform the assignment.
1915 __ movq(location, rax);
1916 if (var->IsContextSlot()) {
1917 __ movq(rdx, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001918 __ RecordWriteContextSlot(
1919 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001920 }
1921 } else {
1922 ASSERT(var->IsLookupSlot());
1923 __ push(rax); // Value.
1924 __ push(rsi); // Context.
1925 __ Push(var->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001926 __ Push(Smi::FromInt(language_mode()));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001927 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001928 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001929 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001930 // Non-initializing assignments to consts are ignored.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001931}
1932
1933
1934void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1935 // Assignment to a property, using a named store IC.
1936 Property* prop = expr->target()->AsProperty();
1937 ASSERT(prop != NULL);
1938 ASSERT(prop->key()->AsLiteral() != NULL);
1939
1940 // If the assignment starts a block of assignments to the same object,
1941 // change to slow case to avoid the quadratic behavior of repeatedly
1942 // adding fast properties.
1943 if (expr->starts_initialization_block()) {
1944 __ push(result_register());
1945 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value.
1946 __ CallRuntime(Runtime::kToSlowProperties, 1);
1947 __ pop(result_register());
1948 }
1949
1950 // Record source code position before IC call.
1951 SetSourcePosition(expr->position());
1952 __ Move(rcx, prop->key()->AsLiteral()->handle());
1953 if (expr->ends_initialization_block()) {
1954 __ movq(rdx, Operand(rsp, 0));
1955 } else {
1956 __ pop(rdx);
1957 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001958 Handle<Code> ic = is_classic_mode()
1959 ? isolate()->builtins()->StoreIC_Initialize()
1960 : isolate()->builtins()->StoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001961 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001962
1963 // If the assignment ends an initialization block, revert to fast case.
1964 if (expr->ends_initialization_block()) {
1965 __ push(rax); // Result of assignment, saved even if not needed.
1966 __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
1967 __ CallRuntime(Runtime::kToFastProperties, 1);
1968 __ pop(rax);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001969 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001971 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001972 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001973}
1974
1975
1976void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1977 // Assignment to a property, using a keyed store IC.
1978
1979 // If the assignment starts a block of assignments to the same object,
1980 // change to slow case to avoid the quadratic behavior of repeatedly
1981 // adding fast properties.
1982 if (expr->starts_initialization_block()) {
1983 __ push(result_register());
1984 // Receiver is now under the key and value.
1985 __ push(Operand(rsp, 2 * kPointerSize));
1986 __ CallRuntime(Runtime::kToSlowProperties, 1);
1987 __ pop(result_register());
1988 }
1989
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001990 __ pop(rcx);
1991 if (expr->ends_initialization_block()) {
1992 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later.
1993 } else {
1994 __ pop(rdx);
1995 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001996 // Record source code position before IC call.
1997 SetSourcePosition(expr->position());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001998 Handle<Code> ic = is_classic_mode()
1999 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2000 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002001 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002002
2003 // If the assignment ends an initialization block, revert to fast case.
2004 if (expr->ends_initialization_block()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002005 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002006 __ push(rax); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002007 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002008 __ CallRuntime(Runtime::kToFastProperties, 1);
2009 __ pop(rax);
2010 }
2011
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002012 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002013 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002014}
2015
2016
2017void FullCodeGenerator::VisitProperty(Property* expr) {
2018 Comment cmnt(masm_, "[ Property");
2019 Expression* key = expr->key();
2020
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002021 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002022 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002023 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002024 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002025 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002026 VisitForStackValue(expr->obj());
2027 VisitForAccumulatorValue(expr->key());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002028 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002029 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002030 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002031 }
2032}
2033
2034
2035void FullCodeGenerator::EmitCallWithIC(Call* expr,
ager@chromium.org5c838252010-02-19 08:53:10 +00002036 Handle<Object> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002037 RelocInfo::Mode mode) {
2038 // Code common for calls using the IC.
2039 ZoneList<Expression*>* args = expr->arguments();
2040 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002041 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002042 for (int i = 0; i < arg_count; i++) {
2043 VisitForStackValue(args->at(i));
2044 }
2045 __ Move(rcx, name);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002046 }
2047 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002048 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002049 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002051 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002052 __ call(ic, mode, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002053 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002054 // Restore context register.
2055 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002056 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002057}
2058
2059
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002060void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002061 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002062 // Load the key.
2063 VisitForAccumulatorValue(key);
2064
2065 // Swap the name of the function and the receiver on the stack to follow
2066 // the calling convention for call ICs.
2067 __ pop(rcx);
2068 __ push(rax);
2069 __ push(rcx);
2070
2071 // Load the arguments.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002072 ZoneList<Expression*>* args = expr->arguments();
2073 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002074 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002075 for (int i = 0; i < arg_count; i++) {
2076 VisitForStackValue(args->at(i));
2077 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002078 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002079 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002080 SetSourcePosition(expr->position());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002081 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002082 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002083 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002084 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002085 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002086 RecordJSReturnSite(expr);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002087 // Restore context register.
2088 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002089 context()->DropAndPlug(1, rax); // Drop the key still on the stack.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002090}
2091
2092
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002093void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002094 // Code common for calls using the call stub.
2095 ZoneList<Expression*>* args = expr->arguments();
2096 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002097 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002098 for (int i = 0; i < arg_count; i++) {
2099 VisitForStackValue(args->at(i));
2100 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002101 }
2102 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002103 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002104 CallFunctionStub stub(arg_count, flags);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002105 __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002106 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002107 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002108 // Restore context register.
2109 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2110 // Discard the function left on TOS.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002111 context()->DropAndPlug(1, rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002112}
2113
2114
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002115void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002116 // Push copy of the first argument or undefined if it doesn't exist.
2117 if (arg_count > 0) {
2118 __ push(Operand(rsp, arg_count * kPointerSize));
2119 } else {
2120 __ PushRoot(Heap::kUndefinedValueRootIndex);
2121 }
2122
2123 // Push the receiver of the enclosing function and do runtime call.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002124 __ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002125
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002126 // Push the language mode.
2127 __ Push(Smi::FromInt(language_mode()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002128
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002129 // Push the start position of the scope the calls resides in.
2130 __ Push(Smi::FromInt(scope()->start_position()));
2131
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002132 // Do the runtime call.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002133 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002134}
2135
2136
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002137void FullCodeGenerator::VisitCall(Call* expr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002138#ifdef DEBUG
2139 // We want to verify that RecordJSReturnSite gets called on all paths
2140 // through this function. Avoid early returns.
2141 expr->return_is_recorded_ = false;
2142#endif
2143
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002144 Comment cmnt(masm_, "[ Call");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002145 Expression* callee = expr->expression();
2146 VariableProxy* proxy = callee->AsVariableProxy();
2147 Property* property = callee->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002148
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002149 if (proxy != NULL && proxy->var()->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002150 // In a call to eval, we first call %ResolvePossiblyDirectEval to
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002151 // resolve the function we need to call and the receiver of the call.
2152 // Then we call the resolved function using the given arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002153 ZoneList<Expression*>* args = expr->arguments();
2154 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002155 { PreservePositionScope pos_scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002156 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002157 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002158
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002159 // Push the arguments.
2160 for (int i = 0; i < arg_count; i++) {
2161 VisitForStackValue(args->at(i));
2162 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002163
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002164 // Push a copy of the function (found below the arguments) and resolve
2165 // eval.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002166 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002167 EmitResolvePossiblyDirectEval(arg_count);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002168
2169 // The runtime call returns a pair of values in rax (function) and
2170 // rdx (receiver). Touch up the stack with the right values.
2171 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
2172 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002173 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002174 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002175 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002176 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002177 __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002178 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002179 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002180 // Restore context register.
2181 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002182 context()->DropAndPlug(1, rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002183 } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
2184 // Call to a global variable. Push global object as receiver for the
2185 // call IC lookup.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002186 __ push(GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002187 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
2188 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002189 // Call to a lookup slot (dynamically introduced variable).
2190 Label slow, done;
2191
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002192 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002193 // Generate code for loading from variables potentially shadowed by
2194 // eval-introduced variables.
2195 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002196 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002197 __ bind(&slow);
2198 // Call the runtime to find the function to call (returned in rax) and
2199 // the object holding it (returned in rdx).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002200 __ push(context_register());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002201 __ Push(proxy->name());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002202 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2203 __ push(rax); // Function.
2204 __ push(rdx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002205
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002206 // If fast case code has been generated, emit code to push the function
2207 // and receiver and have the slow path jump around this code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002208 if (done.is_linked()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002209 Label call;
2210 __ jmp(&call, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002211 __ bind(&done);
2212 // Push function.
2213 __ push(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002214 // The receiver is implicitly the global receiver. Indicate this by
2215 // passing the hole to the call function stub.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002216 __ PushRoot(Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002217 __ bind(&call);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002218 }
2219
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002220 // The receiver is either the global receiver or an object found by
2221 // LoadContextSlot. That object could be the hole if the receiver is
2222 // implicitly the global object.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002223 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002224 } else if (property != NULL) {
2225 { PreservePositionScope scope(masm()->positions_recorder());
2226 VisitForStackValue(property->obj());
2227 }
2228 if (property->key()->IsPropertyName()) {
2229 EmitCallWithIC(expr,
2230 property->key()->AsLiteral()->handle(),
2231 RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002232 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002233 EmitKeyedCallWithIC(expr, property->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002234 }
2235 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002236 // Call to an arbitrary expression not handled specially above.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002237 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002238 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002239 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002240 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002241 __ movq(rbx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002242 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
2243 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002244 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002245 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002246
2247#ifdef DEBUG
2248 // RecordJSReturnSite should have been called.
2249 ASSERT(expr->return_is_recorded_);
2250#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002251}
2252
2253
2254void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2255 Comment cmnt(masm_, "[ CallNew");
2256 // According to ECMA-262, section 11.2.2, page 44, the function
2257 // expression in new calls must be evaluated before the
2258 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002259
ricow@chromium.org65fae842010-08-25 15:26:24 +00002260 // Push constructor on the stack. If it's not a function it's used as
2261 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2262 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002263 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002264
2265 // Push the arguments ("left-to-right") on the stack.
2266 ZoneList<Expression*>* args = expr->arguments();
2267 int arg_count = args->length();
2268 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002269 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002270 }
2271
2272 // Call the construct call builtin that handles allocation and
2273 // constructor invocation.
2274 SetSourcePosition(expr->position());
2275
ricow@chromium.org65fae842010-08-25 15:26:24 +00002276 // Load function and argument count into rdi and rax.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002277 __ Set(rax, arg_count);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002278 __ movq(rdi, Operand(rsp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002279
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002280 // Record call targets in unoptimized code, but not in the snapshot.
2281 CallFunctionFlags flags;
2282 if (!Serializer::enabled()) {
2283 flags = RECORD_CALL_TARGET;
2284 Handle<Object> uninitialized =
2285 TypeFeedbackCells::UninitializedSentinel(isolate());
2286 Handle<JSGlobalPropertyCell> cell =
2287 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
2288 RecordTypeFeedbackCell(expr->id(), cell);
2289 __ Move(rbx, cell);
2290 } else {
2291 flags = NO_CALL_FUNCTION_FLAGS;
2292 }
2293
2294 CallConstructStub stub(flags);
2295 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
ulan@chromium.org967e2702012-02-28 09:49:15 +00002296 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002297 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002298}
2299
2300
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002301void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2302 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002303 ASSERT(args->length() == 1);
2304
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002305 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002306
2307 Label materialize_true, materialize_false;
2308 Label* if_true = NULL;
2309 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002310 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002311 context()->PrepareTest(&materialize_true, &materialize_false,
2312 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002313
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002314 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002315 __ JumpIfSmi(rax, if_true);
2316 __ jmp(if_false);
2317
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002318 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002319}
2320
2321
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002322void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2323 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002324 ASSERT(args->length() == 1);
2325
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002326 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002327
2328 Label materialize_true, materialize_false;
2329 Label* if_true = NULL;
2330 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002331 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002332 context()->PrepareTest(&materialize_true, &materialize_false,
2333 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002334
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002335 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00002336 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
2337 Split(non_negative_smi, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002338
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002339 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002340}
2341
2342
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002343void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2344 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002345 ASSERT(args->length() == 1);
2346
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002347 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002348
2349 Label materialize_true, materialize_false;
2350 Label* if_true = NULL;
2351 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002352 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002353 context()->PrepareTest(&materialize_true, &materialize_false,
2354 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002355
2356 __ JumpIfSmi(rax, if_false);
2357 __ CompareRoot(rax, Heap::kNullValueRootIndex);
2358 __ j(equal, if_true);
2359 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2360 // Undetectable objects behave like undefined when tested with typeof.
2361 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2362 Immediate(1 << Map::kIsUndetectable));
2363 __ j(not_zero, if_false);
2364 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002365 __ cmpq(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002366 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002367 __ cmpq(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002368 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002369 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002370
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002371 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002372}
2373
2374
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002375void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2376 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002377 ASSERT(args->length() == 1);
2378
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002379 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002380
2381 Label materialize_true, materialize_false;
2382 Label* if_true = NULL;
2383 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002384 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002385 context()->PrepareTest(&materialize_true, &materialize_false,
2386 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002387
2388 __ JumpIfSmi(rax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002389 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002390 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002391 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002392
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002393 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002394}
2395
2396
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002397void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2398 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002399 ASSERT(args->length() == 1);
2400
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002401 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002402
2403 Label materialize_true, materialize_false;
2404 Label* if_true = NULL;
2405 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002406 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002407 context()->PrepareTest(&materialize_true, &materialize_false,
2408 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002409
2410 __ JumpIfSmi(rax, if_false);
2411 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2412 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2413 Immediate(1 << Map::kIsUndetectable));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002414 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002415 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002416
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002417 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002418}
2419
2420
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002421void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002422 CallRuntime* expr) {
2423 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002424 ASSERT(args->length() == 1);
2425
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002426 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002427
2428 Label materialize_true, materialize_false;
2429 Label* if_true = NULL;
2430 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002431 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002432 context()->PrepareTest(&materialize_true, &materialize_false,
2433 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002435 if (FLAG_debug_code) __ AbortIfSmi(rax);
2436
2437 // Check whether this map has already been checked to be safe for default
2438 // valueOf.
2439 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2440 __ testb(FieldOperand(rbx, Map::kBitField2Offset),
2441 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2442 __ j(not_zero, if_true);
2443
2444 // Check for fast case object. Generate false result for slow case object.
2445 __ movq(rcx, FieldOperand(rax, JSObject::kPropertiesOffset));
2446 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2447 __ CompareRoot(rcx, Heap::kHashTableMapRootIndex);
2448 __ j(equal, if_false);
2449
2450 // Look for valueOf symbol in the descriptor array, and indicate false if
2451 // found. The type is not checked, so if it is a transition it is a false
2452 // negative.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002453 __ LoadInstanceDescriptors(rbx, rbx);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002454 __ movq(rcx, FieldOperand(rbx, FixedArray::kLengthOffset));
2455 // rbx: descriptor array
2456 // rcx: length of descriptor array
2457 // Calculate the end of the descriptor array.
2458 SmiIndex index = masm_->SmiToIndex(rdx, rcx, kPointerSizeLog2);
2459 __ lea(rcx,
2460 Operand(
2461 rbx, index.reg, index.scale, FixedArray::kHeaderSize));
2462 // Calculate location of the first key name.
2463 __ addq(rbx,
2464 Immediate(FixedArray::kHeaderSize +
2465 DescriptorArray::kFirstIndex * kPointerSize));
2466 // Loop through all the keys in the descriptor array. If one of these is the
2467 // symbol valueOf the result is false.
2468 Label entry, loop;
2469 __ jmp(&entry);
2470 __ bind(&loop);
2471 __ movq(rdx, FieldOperand(rbx, 0));
2472 __ Cmp(rdx, FACTORY->value_of_symbol());
2473 __ j(equal, if_false);
2474 __ addq(rbx, Immediate(kPointerSize));
2475 __ bind(&entry);
2476 __ cmpq(rbx, rcx);
2477 __ j(not_equal, &loop);
2478
2479 // Reload map as register rbx was used as temporary above.
2480 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2481
2482 // If a valueOf property is not found on the object check that it's
2483 // prototype is the un-modified String prototype. If not result is false.
2484 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
2485 __ testq(rcx, Immediate(kSmiTagMask));
2486 __ j(zero, if_false);
2487 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2488 __ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2489 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
2490 __ cmpq(rcx,
2491 ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2492 __ j(not_equal, if_false);
2493 // Set the bit in the map to indicate that it has been checked safe for
2494 // default valueOf and set true result.
2495 __ or_(FieldOperand(rbx, Map::kBitField2Offset),
2496 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2497 __ jmp(if_true);
2498
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002499 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002500 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002501}
2502
2503
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002504void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
2505 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002506 ASSERT(args->length() == 1);
2507
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002508 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002509
2510 Label materialize_true, materialize_false;
2511 Label* if_true = NULL;
2512 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002513 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002514 context()->PrepareTest(&materialize_true, &materialize_false,
2515 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002516
2517 __ JumpIfSmi(rax, if_false);
2518 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002520 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002521
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002522 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002523}
2524
2525
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002526void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2527 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002528 ASSERT(args->length() == 1);
2529
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002530 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002531
2532 Label materialize_true, materialize_false;
2533 Label* if_true = NULL;
2534 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002535 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002536 context()->PrepareTest(&materialize_true, &materialize_false,
2537 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002538
2539 __ JumpIfSmi(rax, if_false);
2540 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002541 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002542 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002543
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002544 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002545}
2546
2547
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002548void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2549 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002550 ASSERT(args->length() == 1);
2551
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002552 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002553
2554 Label materialize_true, materialize_false;
2555 Label* if_true = NULL;
2556 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002557 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002558 context()->PrepareTest(&materialize_true, &materialize_false,
2559 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002560
2561 __ JumpIfSmi(rax, if_false);
2562 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002563 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002564 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002565
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002566 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002567}
2568
2569
2570
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002571void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
2572 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002573
2574 Label materialize_true, materialize_false;
2575 Label* if_true = NULL;
2576 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002577 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002578 context()->PrepareTest(&materialize_true, &materialize_false,
2579 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002580
2581 // Get the frame pointer for the calling frame.
2582 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2583
2584 // Skip the arguments adaptor frame if it exists.
2585 Label check_frame_marker;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002586 __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset),
2587 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002588 __ j(not_equal, &check_frame_marker);
2589 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
2590
2591 // Check the marker in the calling frame.
2592 __ bind(&check_frame_marker);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002593 __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
2594 Smi::FromInt(StackFrame::CONSTRUCT));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002595 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002596 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002597
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002598 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002599}
2600
2601
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002602void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
2603 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002604 ASSERT(args->length() == 2);
2605
2606 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002607 VisitForStackValue(args->at(0));
2608 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002609
2610 Label materialize_true, materialize_false;
2611 Label* if_true = NULL;
2612 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002613 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002614 context()->PrepareTest(&materialize_true, &materialize_false,
2615 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002616
2617 __ pop(rbx);
2618 __ cmpq(rax, rbx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002619 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002620 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002621
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002622 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002623}
2624
2625
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002626void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
2627 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002628 ASSERT(args->length() == 1);
2629
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002630 // ArgumentsAccessStub expects the key in rdx and the formal
2631 // parameter count in rax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002632 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002633 __ movq(rdx, rax);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002634 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002635 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2636 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002637 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002638}
2639
2640
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002641void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
2642 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002643
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002644 Label exit;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002645 // Get the number of formal parameters.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002646 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002647
2648 // Check if the calling frame is an arguments adaptor frame.
2649 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002650 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
2651 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002652 __ j(not_equal, &exit, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002653
2654 // Arguments adaptor case: Read the arguments length from the
2655 // adaptor frame.
2656 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2657
2658 __ bind(&exit);
2659 if (FLAG_debug_code) __ AbortIfNotSmi(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002660 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002661}
2662
2663
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002664void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2665 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002666 ASSERT(args->length() == 1);
2667 Label done, null, function, non_function_constructor;
2668
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002669 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002670
2671 // If the object is a smi, we return null.
2672 __ JumpIfSmi(rax, &null);
2673
2674 // Check that the object is a JS object but take special care of JS
2675 // functions to make sure they have 'Function' as their class.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002676 // Assume that there are only two callable types, and one of them is at
2677 // either end of the type range for JS object types. Saves extra comparisons.
2678 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002679 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
2680 // Map is now in rax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002681 __ j(below, &null);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002682 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2683 FIRST_SPEC_OBJECT_TYPE + 1);
2684 __ j(equal, &function);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002685
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002686 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
2687 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2688 LAST_SPEC_OBJECT_TYPE - 1);
2689 __ j(equal, &function);
2690 // Assume that there is no larger type.
2691 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002692
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002693 // Check if the constructor in the map is a JS function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002694 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
2695 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2696 __ j(not_equal, &non_function_constructor);
2697
2698 // rax now contains the constructor function. Grab the
2699 // instance class name from there.
2700 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
2701 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
2702 __ jmp(&done);
2703
2704 // Functions have class 'Function'.
2705 __ bind(&function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002706 __ Move(rax, isolate()->factory()->function_class_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002707 __ jmp(&done);
2708
2709 // Objects with a non-function constructor have class 'Object'.
2710 __ bind(&non_function_constructor);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002711 __ Move(rax, isolate()->factory()->Object_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002712 __ jmp(&done);
2713
2714 // Non-JS objects have class null.
2715 __ bind(&null);
2716 __ LoadRoot(rax, Heap::kNullValueRootIndex);
2717
2718 // All done.
2719 __ bind(&done);
2720
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002721 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002722}
2723
2724
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002725void FullCodeGenerator::EmitLog(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002726 // Conditionally generate a log call.
2727 // Args:
2728 // 0 (literal string): The type of logging (corresponds to the flags).
2729 // This is used to determine whether or not to generate the log call.
2730 // 1 (string): Format string. Access the string at argument index 2
2731 // with '%2s' (see Logger::LogRuntime for all the formats).
2732 // 2 (array): Arguments to the format string.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002733 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002734 ASSERT_EQ(args->length(), 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002735 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002736 VisitForStackValue(args->at(1));
2737 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002738 __ CallRuntime(Runtime::kLog, 2);
2739 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002740 // Finally, we're expected to leave a value on the top of the stack.
2741 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002742 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002743}
2744
2745
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002746void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
2747 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002748
2749 Label slow_allocate_heapnumber;
2750 Label heapnumber_allocated;
2751
2752 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
2753 __ jmp(&heapnumber_allocated);
2754
2755 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002756 // Allocate a heap number.
2757 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002758 __ movq(rbx, rax);
2759
2760 __ bind(&heapnumber_allocated);
2761
2762 // Return a random uint32 number in rax.
2763 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002764 __ PrepareCallCFunction(1);
2765#ifdef _WIN64
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002766 __ movq(rcx, ContextOperand(context_register(), Context::GLOBAL_INDEX));
2767 __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset));
2768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002769#else
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002770 __ movq(rdi, ContextOperand(context_register(), Context::GLOBAL_INDEX));
2771 __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002772#endif
2773 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002774
2775 // Convert 32 random bits in rax to 0.(32 random bits) in a double
2776 // by computing:
2777 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2778 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2779 __ movd(xmm1, rcx);
2780 __ movd(xmm0, rax);
2781 __ cvtss2sd(xmm1, xmm1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002782 __ xorps(xmm0, xmm1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002783 __ subsd(xmm0, xmm1);
2784 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
2785
2786 __ movq(rax, rbx);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002787 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002788}
2789
2790
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002791void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002792 // Load the arguments on the stack and call the stub.
2793 SubStringStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002794 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002795 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002796 VisitForStackValue(args->at(0));
2797 VisitForStackValue(args->at(1));
2798 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002799 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002800 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002801}
2802
2803
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002804void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002805 // Load the arguments on the stack and call the stub.
2806 RegExpExecStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002807 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002808 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002809 VisitForStackValue(args->at(0));
2810 VisitForStackValue(args->at(1));
2811 VisitForStackValue(args->at(2));
2812 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002813 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002814 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002815}
2816
2817
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002818void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
2819 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002820 ASSERT(args->length() == 1);
2821
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002822 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002823
2824 Label done;
2825 // If the object is a smi return the object.
2826 __ JumpIfSmi(rax, &done);
2827 // If the object is not a value type, return the object.
2828 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
2829 __ j(not_equal, &done);
2830 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset));
2831
2832 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002833 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002834}
2835
2836
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002837void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002838 // Load the arguments on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002839 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002840 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002841 VisitForStackValue(args->at(0));
2842 VisitForStackValue(args->at(1));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002843 MathPowStub stub(MathPowStub::ON_STACK);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002844 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002845 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002846}
2847
2848
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002849void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
2850 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002851 ASSERT(args->length() == 2);
2852
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002853 VisitForStackValue(args->at(0)); // Load the object.
2854 VisitForAccumulatorValue(args->at(1)); // Load the value.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002855 __ pop(rbx); // rax = value. rbx = object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002856
2857 Label done;
2858 // If the object is a smi, return the value.
2859 __ JumpIfSmi(rbx, &done);
2860
2861 // If the object is not a value type, return the value.
2862 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
2863 __ j(not_equal, &done);
2864
2865 // Store the value.
2866 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax);
2867 // Update the write barrier. Save the value as it will be
2868 // overwritten by the write barrier code and is needed afterward.
2869 __ movq(rdx, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002870 __ RecordWriteField(rbx, JSValue::kValueOffset, rdx, rcx, kDontSaveFPRegs);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002871
2872 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002873 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002874}
2875
2876
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002877void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
2878 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002879 ASSERT_EQ(args->length(), 1);
2880
2881 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002882 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002883
2884 NumberToStringStub stub;
2885 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002886 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002887}
2888
2889
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002890void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
2891 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002892 ASSERT(args->length() == 1);
2893
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002894 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002895
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002896 Label done;
2897 StringCharFromCodeGenerator generator(rax, rbx);
2898 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002899 __ jmp(&done);
2900
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002901 NopRuntimeCallHelper call_helper;
2902 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002903
2904 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002905 context()->Plug(rbx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002906}
2907
2908
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002909void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
2910 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002911 ASSERT(args->length() == 2);
2912
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002913 VisitForStackValue(args->at(0));
2914 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002915
2916 Register object = rbx;
2917 Register index = rax;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002918 Register result = rdx;
2919
2920 __ pop(object);
2921
2922 Label need_conversion;
2923 Label index_out_of_range;
2924 Label done;
2925 StringCharCodeAtGenerator generator(object,
2926 index,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002927 result,
2928 &need_conversion,
2929 &need_conversion,
2930 &index_out_of_range,
2931 STRING_INDEX_IS_NUMBER);
2932 generator.GenerateFast(masm_);
2933 __ jmp(&done);
2934
2935 __ bind(&index_out_of_range);
2936 // When the index is out of range, the spec requires us to return
2937 // NaN.
2938 __ LoadRoot(result, Heap::kNanValueRootIndex);
2939 __ jmp(&done);
2940
2941 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002942 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002943 // trigger conversion.
2944 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2945 __ jmp(&done);
2946
2947 NopRuntimeCallHelper call_helper;
2948 generator.GenerateSlow(masm_, call_helper);
2949
2950 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002951 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002952}
2953
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002954
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002955void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
2956 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002957 ASSERT(args->length() == 2);
2958
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002959 VisitForStackValue(args->at(0));
2960 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002961
2962 Register object = rbx;
2963 Register index = rax;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002964 Register scratch = rdx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002965 Register result = rax;
2966
2967 __ pop(object);
2968
2969 Label need_conversion;
2970 Label index_out_of_range;
2971 Label done;
2972 StringCharAtGenerator generator(object,
2973 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002974 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002975 result,
2976 &need_conversion,
2977 &need_conversion,
2978 &index_out_of_range,
2979 STRING_INDEX_IS_NUMBER);
2980 generator.GenerateFast(masm_);
2981 __ jmp(&done);
2982
2983 __ bind(&index_out_of_range);
2984 // When the index is out of range, the spec requires us to return
2985 // the empty string.
2986 __ LoadRoot(result, Heap::kEmptyStringRootIndex);
2987 __ jmp(&done);
2988
2989 __ bind(&need_conversion);
2990 // Move smi zero into the result register, which will trigger
2991 // conversion.
2992 __ Move(result, Smi::FromInt(0));
2993 __ jmp(&done);
2994
2995 NopRuntimeCallHelper call_helper;
2996 generator.GenerateSlow(masm_, call_helper);
2997
2998 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002999 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003000}
3001
3002
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003003void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3004 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003005 ASSERT_EQ(2, args->length());
3006
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003007 VisitForStackValue(args->at(0));
3008 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003009
3010 StringAddStub stub(NO_STRING_ADD_FLAGS);
3011 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003012 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003013}
3014
3015
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003016void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3017 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003018 ASSERT_EQ(2, args->length());
3019
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003020 VisitForStackValue(args->at(0));
3021 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003022
3023 StringCompareStub stub;
3024 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003025 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003026}
3027
3028
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003029void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003030 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003031 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3032 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003033 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003034 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003035 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003036 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003037 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003038}
3039
3040
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003041void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003042 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003043 TranscendentalCacheStub stub(TranscendentalCache::COS,
3044 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003045 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003046 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003047 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003048 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003049 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003050}
3051
3052
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003053void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
3054 // Load the argument on the stack and call the stub.
3055 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3056 TranscendentalCacheStub::TAGGED);
3057 ZoneList<Expression*>* args = expr->arguments();
3058 ASSERT(args->length() == 1);
3059 VisitForStackValue(args->at(0));
3060 __ CallStub(&stub);
3061 context()->Plug(rax);
3062}
3063
3064
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003065void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003066 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003067 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3068 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003069 ZoneList<Expression*>* args = expr->arguments();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003070 ASSERT(args->length() == 1);
3071 VisitForStackValue(args->at(0));
3072 __ CallStub(&stub);
3073 context()->Plug(rax);
3074}
3075
3076
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003077void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003078 // Load the argument on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003079 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003080 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003081 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003082 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003083 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003084}
3085
3086
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003087void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3088 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003089 ASSERT(args->length() >= 2);
3090
danno@chromium.org160a7b02011-04-18 15:51:38 +00003091 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3092 for (int i = 0; i < arg_count + 1; i++) {
3093 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003094 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003095 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003096
danno@chromium.orgc612e022011-11-10 11:38:15 +00003097 // Check for proxy.
3098 Label proxy, done;
3099 __ CmpObjectType(rax, JS_FUNCTION_PROXY_TYPE, rbx);
3100 __ j(equal, &proxy);
3101
danno@chromium.org160a7b02011-04-18 15:51:38 +00003102 // InvokeFunction requires the function in rdi. Move it in there.
3103 __ movq(rdi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003104 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003105 __ InvokeFunction(rdi, count, CALL_FUNCTION,
3106 NullCallWrapper(), CALL_AS_METHOD);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003107 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003108 __ jmp(&done);
3109
3110 __ bind(&proxy);
3111 __ push(rax);
3112 __ CallRuntime(Runtime::kCall, args->length());
3113 __ bind(&done);
3114
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003115 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003116}
3117
3118
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003119void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003120 RegExpConstructResultStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003121 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003122 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003123 VisitForStackValue(args->at(0));
3124 VisitForStackValue(args->at(1));
3125 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003126 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003127 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003128}
3129
3130
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003131void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) {
3132 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003133 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003134 VisitForStackValue(args->at(0));
3135 VisitForStackValue(args->at(1));
3136 VisitForStackValue(args->at(2));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003137 Label done;
3138 Label slow_case;
3139 Register object = rax;
3140 Register index_1 = rbx;
3141 Register index_2 = rcx;
3142 Register elements = rdi;
3143 Register temp = rdx;
3144 __ movq(object, Operand(rsp, 2 * kPointerSize));
3145 // Fetch the map and check if array is in fast case.
3146 // Check that object doesn't require security checks and
3147 // has no indexed interceptor.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003148 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3149 __ j(not_equal, &slow_case);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003150 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
3151 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
3152 __ j(not_zero, &slow_case);
3153
3154 // Check the object's elements are in fast case and writable.
3155 __ movq(elements, FieldOperand(object, JSObject::kElementsOffset));
3156 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
3157 Heap::kFixedArrayMapRootIndex);
3158 __ j(not_equal, &slow_case);
3159
3160 // Check that both indices are smis.
3161 __ movq(index_1, Operand(rsp, 1 * kPointerSize));
3162 __ movq(index_2, Operand(rsp, 0 * kPointerSize));
3163 __ JumpIfNotBothSmi(index_1, index_2, &slow_case);
3164
3165 // Check that both indices are valid.
3166 // The JSArray length field is a smi since the array is in fast case mode.
3167 __ movq(temp, FieldOperand(object, JSArray::kLengthOffset));
3168 __ SmiCompare(temp, index_1);
3169 __ j(below_equal, &slow_case);
3170 __ SmiCompare(temp, index_2);
3171 __ j(below_equal, &slow_case);
3172
3173 __ SmiToInteger32(index_1, index_1);
3174 __ SmiToInteger32(index_2, index_2);
3175 // Bring addresses into index1 and index2.
3176 __ lea(index_1, FieldOperand(elements, index_1, times_pointer_size,
3177 FixedArray::kHeaderSize));
3178 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size,
3179 FixedArray::kHeaderSize));
3180
3181 // Swap elements. Use object and temp as scratch registers.
3182 __ movq(object, Operand(index_1, 0));
3183 __ movq(temp, Operand(index_2, 0));
3184 __ movq(Operand(index_2, 0), object);
3185 __ movq(Operand(index_1, 0), temp);
3186
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003187 Label no_remembered_set;
3188 __ CheckPageFlag(elements,
3189 temp,
3190 1 << MemoryChunk::SCAN_ON_SCAVENGE,
3191 not_zero,
3192 &no_remembered_set,
3193 Label::kNear);
3194 // Possible optimization: do a check that both values are Smis
3195 // (or them and test against Smi mask.)
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003196
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003197 // We are swapping two objects in an array and the incremental marker never
3198 // pauses in the middle of scanning a single object. Therefore the
3199 // incremental marker is not disturbed, so we don't need to call the
3200 // RecordWrite stub that notifies the incremental marker.
3201 __ RememberedSetHelper(elements,
3202 index_1,
3203 temp,
3204 kDontSaveFPRegs,
3205 MacroAssembler::kFallThroughAtEnd);
3206 __ RememberedSetHelper(elements,
3207 index_2,
3208 temp,
3209 kDontSaveFPRegs,
3210 MacroAssembler::kFallThroughAtEnd);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003211
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003212 __ bind(&no_remembered_set);
3213
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003214 // We are done. Drop elements from the stack, and return undefined.
3215 __ addq(rsp, Immediate(3 * kPointerSize));
3216 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3217 __ jmp(&done);
3218
3219 __ bind(&slow_case);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003220 __ CallRuntime(Runtime::kSwapElements, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003221
3222 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003223 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003224}
3225
3226
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003227void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3228 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003229 ASSERT_EQ(2, args->length());
3230
3231 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3232 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3233
3234 Handle<FixedArray> jsfunction_result_caches(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003235 isolate()->global_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003236 if (jsfunction_result_caches->length() <= cache_id) {
3237 __ Abort("Attempt to use undefined cache.");
3238 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003239 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003240 return;
3241 }
3242
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003243 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003244
3245 Register key = rax;
3246 Register cache = rbx;
3247 Register tmp = rcx;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003248 __ movq(cache, ContextOperand(rsi, Context::GLOBAL_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003249 __ movq(cache,
3250 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
3251 __ movq(cache,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003252 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003253 __ movq(cache,
3254 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3255
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003256 Label done, not_found;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003257 // tmp now holds finger offset as a smi.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003258 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003259 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3260 SmiIndex index =
3261 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
3262 __ cmpq(key, FieldOperand(cache,
3263 index.reg,
3264 index.scale,
3265 FixedArray::kHeaderSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003266 __ j(not_equal, &not_found, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003267 __ movq(rax, FieldOperand(cache,
3268 index.reg,
3269 index.scale,
3270 FixedArray::kHeaderSize + kPointerSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003271 __ jmp(&done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003272
3273 __ bind(&not_found);
3274 // Call runtime to perform the lookup.
3275 __ push(cache);
3276 __ push(key);
3277 __ CallRuntime(Runtime::kGetFromCache, 2);
3278
3279 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003280 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003281}
3282
3283
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003284void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) {
3285 ZoneList<Expression*>* args = expr->arguments();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003286 ASSERT_EQ(2, args->length());
3287
3288 Register right = rax;
3289 Register left = rbx;
3290 Register tmp = rcx;
3291
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003292 VisitForStackValue(args->at(0));
3293 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003294 __ pop(left);
3295
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003296 Label done, fail, ok;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003297 __ cmpq(left, right);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003298 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003299 // Fail if either is a non-HeapObject.
3300 Condition either_smi = masm()->CheckEitherSmi(left, right, tmp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003301 __ j(either_smi, &fail, Label::kNear);
3302 __ j(zero, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003303 __ movq(tmp, FieldOperand(left, HeapObject::kMapOffset));
3304 __ cmpb(FieldOperand(tmp, Map::kInstanceTypeOffset),
3305 Immediate(JS_REGEXP_TYPE));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003306 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003307 __ cmpq(tmp, FieldOperand(right, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003308 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003309 __ movq(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3310 __ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003311 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003312 __ bind(&fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003313 __ Move(rax, isolate()->factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003314 __ jmp(&done, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003315 __ bind(&ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003316 __ Move(rax, isolate()->factory()->true_value());
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003317 __ bind(&done);
3318
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003319 context()->Plug(rax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003320}
3321
3322
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003323void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3324 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003325 ASSERT(args->length() == 1);
3326
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003327 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003328
3329 Label materialize_true, materialize_false;
3330 Label* if_true = NULL;
3331 Label* if_false = NULL;
3332 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003333 context()->PrepareTest(&materialize_true, &materialize_false,
3334 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003335
3336 __ testl(FieldOperand(rax, String::kHashFieldOffset),
3337 Immediate(String::kContainsCachedArrayIndexMask));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003338 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003339 __ j(zero, if_true);
3340 __ jmp(if_false);
3341
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003342 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003343}
3344
3345
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003346void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3347 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003348 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003349 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003350
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003351 if (FLAG_debug_code) {
3352 __ AbortIfNotString(rax);
3353 }
3354
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003355 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
3356 ASSERT(String::kHashShift >= kSmiTagSize);
3357 __ IndexFromHash(rax, rax);
3358
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003359 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003360}
3361
3362
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003363void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003364 Label bailout, return_result, done, one_char_separator, long_separator,
3365 non_trivial_array, not_size_one_array, loop,
3366 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003367 ZoneList<Expression*>* args = expr->arguments();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003368 ASSERT(args->length() == 2);
3369 // We will leave the separator on the stack until the end of the function.
3370 VisitForStackValue(args->at(1));
3371 // Load this to rax (= array)
3372 VisitForAccumulatorValue(args->at(0));
3373 // All aliases of the same register have disjoint lifetimes.
3374 Register array = rax;
3375 Register elements = no_reg; // Will be rax.
3376
3377 Register index = rdx;
3378
3379 Register string_length = rcx;
3380
3381 Register string = rsi;
3382
3383 Register scratch = rbx;
3384
3385 Register array_length = rdi;
3386 Register result_pos = no_reg; // Will be rdi.
3387
3388 Operand separator_operand = Operand(rsp, 2 * kPointerSize);
3389 Operand result_operand = Operand(rsp, 1 * kPointerSize);
3390 Operand array_length_operand = Operand(rsp, 0 * kPointerSize);
3391 // Separator operand is already pushed. Make room for the two
3392 // other stack fields, and clear the direction flag in anticipation
3393 // of calling CopyBytes.
3394 __ subq(rsp, Immediate(2 * kPointerSize));
3395 __ cld();
3396 // Check that the array is a JSArray
3397 __ JumpIfSmi(array, &bailout);
3398 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3399 __ j(not_equal, &bailout);
3400
3401 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003402 __ CheckFastElements(scratch, &bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003403
3404 // Array has fast elements, so its length must be a smi.
3405 // If the array has length zero, return the empty string.
3406 __ movq(array_length, FieldOperand(array, JSArray::kLengthOffset));
3407 __ SmiCompare(array_length, Smi::FromInt(0));
3408 __ j(not_zero, &non_trivial_array);
3409 __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
3410 __ jmp(&return_result);
3411
3412 // Save the array length on the stack.
3413 __ bind(&non_trivial_array);
3414 __ SmiToInteger32(array_length, array_length);
3415 __ movl(array_length_operand, array_length);
3416
3417 // Save the FixedArray containing array's elements.
3418 // End of array's live range.
3419 elements = array;
3420 __ movq(elements, FieldOperand(array, JSArray::kElementsOffset));
3421 array = no_reg;
3422
3423
3424 // Check that all array elements are sequential ASCII strings, and
3425 // accumulate the sum of their lengths, as a smi-encoded value.
3426 __ Set(index, 0);
3427 __ Set(string_length, 0);
3428 // Loop condition: while (index < array_length).
3429 // Live loop registers: index(int32), array_length(int32), string(String*),
3430 // scratch, string_length(int32), elements(FixedArray*).
3431 if (FLAG_debug_code) {
3432 __ cmpq(index, array_length);
3433 __ Assert(below, "No empty arrays here in EmitFastAsciiArrayJoin");
3434 }
3435 __ bind(&loop);
3436 __ movq(string, FieldOperand(elements,
3437 index,
3438 times_pointer_size,
3439 FixedArray::kHeaderSize));
3440 __ JumpIfSmi(string, &bailout);
3441 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3442 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3443 __ andb(scratch, Immediate(
3444 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3445 __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
3446 __ j(not_equal, &bailout);
3447 __ AddSmiField(string_length,
3448 FieldOperand(string, SeqAsciiString::kLengthOffset));
3449 __ j(overflow, &bailout);
3450 __ incl(index);
3451 __ cmpl(index, array_length);
3452 __ j(less, &loop);
3453
3454 // Live registers:
3455 // string_length: Sum of string lengths.
3456 // elements: FixedArray of strings.
3457 // index: Array length.
3458 // array_length: Array length.
3459
3460 // If array_length is 1, return elements[0], a string.
3461 __ cmpl(array_length, Immediate(1));
3462 __ j(not_equal, &not_size_one_array);
3463 __ movq(rax, FieldOperand(elements, FixedArray::kHeaderSize));
3464 __ jmp(&return_result);
3465
3466 __ bind(&not_size_one_array);
3467
3468 // End of array_length live range.
3469 result_pos = array_length;
3470 array_length = no_reg;
3471
3472 // Live registers:
3473 // string_length: Sum of string lengths.
3474 // elements: FixedArray of strings.
3475 // index: Array length.
3476
3477 // Check that the separator is a sequential ASCII string.
3478 __ movq(string, separator_operand);
3479 __ JumpIfSmi(string, &bailout);
3480 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3481 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3482 __ andb(scratch, Immediate(
3483 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3484 __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
3485 __ j(not_equal, &bailout);
3486
3487 // Live registers:
3488 // string_length: Sum of string lengths.
3489 // elements: FixedArray of strings.
3490 // index: Array length.
3491 // string: Separator string.
3492
3493 // Add (separator length times (array_length - 1)) to string_length.
3494 __ SmiToInteger32(scratch,
3495 FieldOperand(string, SeqAsciiString::kLengthOffset));
3496 __ decl(index);
3497 __ imull(scratch, index);
3498 __ j(overflow, &bailout);
3499 __ addl(string_length, scratch);
3500 __ j(overflow, &bailout);
3501
3502 // Live registers and stack values:
3503 // string_length: Total length of result string.
3504 // elements: FixedArray of strings.
3505 __ AllocateAsciiString(result_pos, string_length, scratch,
3506 index, string, &bailout);
3507 __ movq(result_operand, result_pos);
3508 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3509
3510 __ movq(string, separator_operand);
3511 __ SmiCompare(FieldOperand(string, SeqAsciiString::kLengthOffset),
3512 Smi::FromInt(1));
3513 __ j(equal, &one_char_separator);
3514 __ j(greater, &long_separator);
3515
3516
3517 // Empty separator case:
3518 __ Set(index, 0);
3519 __ movl(scratch, array_length_operand);
3520 __ jmp(&loop_1_condition);
3521 // Loop condition: while (index < array_length).
3522 __ bind(&loop_1);
3523 // Each iteration of the loop concatenates one string to the result.
3524 // Live values in registers:
3525 // index: which element of the elements array we are adding to the result.
3526 // result_pos: the position to which we are currently copying characters.
3527 // elements: the FixedArray of strings we are joining.
3528 // scratch: array length.
3529
3530 // Get string = array[index].
3531 __ movq(string, FieldOperand(elements, index,
3532 times_pointer_size,
3533 FixedArray::kHeaderSize));
3534 __ SmiToInteger32(string_length,
3535 FieldOperand(string, String::kLengthOffset));
3536 __ lea(string,
3537 FieldOperand(string, SeqAsciiString::kHeaderSize));
3538 __ CopyBytes(result_pos, string, string_length);
3539 __ incl(index);
3540 __ bind(&loop_1_condition);
3541 __ cmpl(index, scratch);
3542 __ j(less, &loop_1); // Loop while (index < array_length).
3543 __ jmp(&done);
3544
3545 // Generic bailout code used from several places.
3546 __ bind(&bailout);
3547 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3548 __ jmp(&return_result);
3549
3550
3551 // One-character separator case
3552 __ bind(&one_char_separator);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003553 // Get the separator ASCII character value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003554 // Register "string" holds the separator.
3555 __ movzxbl(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3556 __ Set(index, 0);
3557 // Jump into the loop after the code that copies the separator, so the first
3558 // element is not preceded by a separator
3559 __ jmp(&loop_2_entry);
3560 // Loop condition: while (index < length).
3561 __ bind(&loop_2);
3562 // Each iteration of the loop concatenates one string to the result.
3563 // Live values in registers:
3564 // elements: The FixedArray of strings we are joining.
3565 // index: which element of the elements array we are adding to the result.
3566 // result_pos: the position to which we are currently copying characters.
3567 // scratch: Separator character.
3568
3569 // Copy the separator character to the result.
3570 __ movb(Operand(result_pos, 0), scratch);
3571 __ incq(result_pos);
3572
3573 __ bind(&loop_2_entry);
3574 // Get string = array[index].
3575 __ movq(string, FieldOperand(elements, index,
3576 times_pointer_size,
3577 FixedArray::kHeaderSize));
3578 __ SmiToInteger32(string_length,
3579 FieldOperand(string, String::kLengthOffset));
3580 __ lea(string,
3581 FieldOperand(string, SeqAsciiString::kHeaderSize));
3582 __ CopyBytes(result_pos, string, string_length);
3583 __ incl(index);
3584 __ cmpl(index, array_length_operand);
3585 __ j(less, &loop_2); // End while (index < length).
3586 __ jmp(&done);
3587
3588
3589 // Long separator case (separator is more than one character).
3590 __ bind(&long_separator);
3591
3592 // Make elements point to end of elements array, and index
3593 // count from -array_length to zero, so we don't need to maintain
3594 // a loop limit.
3595 __ movl(index, array_length_operand);
3596 __ lea(elements, FieldOperand(elements, index, times_pointer_size,
3597 FixedArray::kHeaderSize));
3598 __ neg(index);
3599
3600 // Replace separator string with pointer to its first character, and
3601 // make scratch be its length.
3602 __ movq(string, separator_operand);
3603 __ SmiToInteger32(scratch,
3604 FieldOperand(string, String::kLengthOffset));
3605 __ lea(string,
3606 FieldOperand(string, SeqAsciiString::kHeaderSize));
3607 __ movq(separator_operand, string);
3608
3609 // Jump into the loop after the code that copies the separator, so the first
3610 // element is not preceded by a separator
3611 __ jmp(&loop_3_entry);
3612 // Loop condition: while (index < length).
3613 __ bind(&loop_3);
3614 // Each iteration of the loop concatenates one string to the result.
3615 // Live values in registers:
3616 // index: which element of the elements array we are adding to the result.
3617 // result_pos: the position to which we are currently copying characters.
3618 // scratch: Separator length.
3619 // separator_operand (rsp[0x10]): Address of first char of separator.
3620
3621 // Copy the separator to the result.
3622 __ movq(string, separator_operand);
3623 __ movl(string_length, scratch);
3624 __ CopyBytes(result_pos, string, string_length, 2);
3625
3626 __ bind(&loop_3_entry);
3627 // Get string = array[index].
3628 __ movq(string, Operand(elements, index, times_pointer_size, 0));
3629 __ SmiToInteger32(string_length,
3630 FieldOperand(string, String::kLengthOffset));
3631 __ lea(string,
3632 FieldOperand(string, SeqAsciiString::kHeaderSize));
3633 __ CopyBytes(result_pos, string, string_length);
3634 __ incq(index);
3635 __ j(not_equal, &loop_3); // Loop while (index < 0).
3636
3637 __ bind(&done);
3638 __ movq(rax, result_operand);
3639
3640 __ bind(&return_result);
3641 // Drop temp values from the stack, and restore context register.
3642 __ addq(rsp, Immediate(3 * kPointerSize));
3643 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3644 context()->Plug(rax);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003645}
3646
3647
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003648void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003649 Handle<String> name = expr->name();
3650 if (name->length() > 0 && name->Get(0) == '_') {
3651 Comment cmnt(masm_, "[ InlineRuntimeCall");
3652 EmitInlineRuntimeCall(expr);
3653 return;
3654 }
3655
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003656 Comment cmnt(masm_, "[ CallRuntime");
3657 ZoneList<Expression*>* args = expr->arguments();
3658
3659 if (expr->is_jsruntime()) {
3660 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003661 __ movq(rax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003662 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
3663 }
3664
3665 // Push the arguments ("left-to-right").
3666 int arg_count = args->length();
3667 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003668 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003669 }
3670
3671 if (expr->is_jsruntime()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003672 // Call the JS runtime function using a call IC.
3673 __ Move(rcx, expr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003674 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003675 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003676 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003677 __ call(ic, mode, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003678 // Restore context register.
3679 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003680 } else {
3681 __ CallRuntime(expr->function(), arg_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003682 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003683 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003684}
3685
3686
3687void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3688 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003689 case Token::DELETE: {
3690 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003691 Property* property = expr->expression()->AsProperty();
3692 VariableProxy* proxy = expr->expression()->AsVariableProxy();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003693
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003694 if (property != NULL) {
3695 VisitForStackValue(property->obj());
3696 VisitForStackValue(property->key());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003697 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
3698 ? kNonStrictMode : kStrictMode;
3699 __ Push(Smi::FromInt(strict_mode_flag));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003700 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3701 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003702 } else if (proxy != NULL) {
3703 Variable* var = proxy->var();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003704 // Delete of an unqualified identifier is disallowed in strict mode
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003705 // but "delete this" is allowed.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003706 ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003707 if (var->IsUnallocated()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003708 __ push(GlobalObjectOperand());
3709 __ Push(var->name());
3710 __ Push(Smi::FromInt(kNonStrictMode));
3711 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3712 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003713 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
3714 // Result of deleting non-global variables is false. 'this' is
3715 // not really a variable, though we implement it as one. The
3716 // subexpression does not have side effects.
3717 context()->Plug(var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003718 } else {
3719 // Non-global variable. Call the runtime to try to delete from the
3720 // context where the variable was introduced.
3721 __ push(context_register());
3722 __ Push(var->name());
3723 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3724 context()->Plug(rax);
3725 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003726 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003727 // Result of deleting non-property, non-variable reference is true.
3728 // The subexpression may have side effects.
3729 VisitForEffect(expr->expression());
3730 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003731 }
3732 break;
3733 }
3734
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003735 case Token::VOID: {
3736 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3737 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003738 context()->Plug(Heap::kUndefinedValueRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003739 break;
3740 }
3741
3742 case Token::NOT: {
3743 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003744 if (context()->IsEffect()) {
3745 // Unary NOT has no side effects so it's only necessary to visit the
3746 // subexpression. Match the optimizing compiler by not branching.
3747 VisitForEffect(expr->expression());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003748 } else if (context()->IsTest()) {
3749 const TestContext* test = TestContext::cast(context());
3750 // The labels are swapped for the recursive call.
3751 VisitForControl(expr->expression(),
3752 test->false_label(),
3753 test->true_label(),
3754 test->fall_through());
3755 context()->Plug(test->true_label(), test->false_label());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003756 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003757 // We handle value contexts explicitly rather than simply visiting
3758 // for control and plugging the control flow into the context,
3759 // because we need to prepare a pair of extra administrative AST ids
3760 // for the optimizing compiler.
3761 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
3762 Label materialize_true, materialize_false, done;
3763 VisitForControl(expr->expression(),
3764 &materialize_false,
3765 &materialize_true,
3766 &materialize_true);
3767 __ bind(&materialize_true);
3768 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
3769 if (context()->IsAccumulatorValue()) {
3770 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
3771 } else {
3772 __ PushRoot(Heap::kTrueValueRootIndex);
3773 }
3774 __ jmp(&done, Label::kNear);
3775 __ bind(&materialize_false);
3776 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
3777 if (context()->IsAccumulatorValue()) {
3778 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
3779 } else {
3780 __ PushRoot(Heap::kFalseValueRootIndex);
3781 }
3782 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003783 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003784 break;
3785 }
3786
3787 case Token::TYPEOF: {
3788 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003789 { StackValueContext context(this);
3790 VisitForTypeofValue(expr->expression());
3791 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003792 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003793 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003794 break;
3795 }
3796
3797 case Token::ADD: {
3798 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003799 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003800 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003801 __ JumpIfSmi(result_register(), &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003802 ToNumberStub convert_stub;
3803 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003804 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003805 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003806 break;
3807 }
3808
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003809 case Token::SUB:
3810 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003811 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003812
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003813 case Token::BIT_NOT:
3814 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003815 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003816
3817 default:
3818 UNREACHABLE();
3819 }
3820}
3821
3822
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003823void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3824 const char* comment) {
3825 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
3826 Comment cmt(masm_, comment);
3827 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3828 UnaryOverwriteMode overwrite =
3829 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003830 UnaryOpStub stub(expr->op(), overwrite);
3831 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003832 // accumulator register rax.
3833 VisitForAccumulatorValue(expr->expression());
3834 SetSourcePosition(expr->position());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003835 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003836 context()->Plug(rax);
3837}
3838
3839
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003840void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3841 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003842 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003843
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003844 // Invalid left-hand-sides are rewritten to have a 'throw
3845 // ReferenceError' as the left-hand side.
3846 if (!expr->expression()->IsValidLeftHandSide()) {
3847 VisitForEffect(expr->expression());
3848 return;
3849 }
3850
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003851 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00003852 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003853 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3854 LhsKind assign_type = VARIABLE;
3855 Property* prop = expr->expression()->AsProperty();
3856 // In case of a property we use the uninitialized expression context
3857 // of the key to detect a named property.
3858 if (prop != NULL) {
3859 assign_type =
3860 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3861 }
3862
3863 // Evaluate expression and get value.
3864 if (assign_type == VARIABLE) {
3865 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003866 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003867 EmitVariableLoad(expr->expression()->AsVariableProxy());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003868 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003869 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003870 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003871 __ Push(Smi::FromInt(0));
3872 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003873 if (assign_type == NAMED_PROPERTY) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003874 VisitForAccumulatorValue(prop->obj());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00003875 __ push(rax); // Copy of receiver, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003876 EmitNamedPropertyLoad(prop);
3877 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003878 VisitForStackValue(prop->obj());
3879 VisitForAccumulatorValue(prop->key());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003880 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack
3881 __ push(rax); // Copy of key, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003882 EmitKeyedPropertyLoad(prop);
3883 }
3884 }
3885
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003886 // We need a second deoptimization point after loading the value
3887 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003888 if (assign_type == VARIABLE) {
3889 PrepareForBailout(expr->expression(), TOS_REG);
3890 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003891 PrepareForBailoutForId(expr->CountId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003892 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003893
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003894 // Call ToNumber only if operand is not a smi.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003895 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003896 __ JumpIfSmi(rax, &no_conversion, Label::kNear);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003897 ToNumberStub convert_stub;
3898 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003899 __ bind(&no_conversion);
3900
3901 // Save result for postfix expressions.
3902 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003903 if (!context()->IsEffect()) {
3904 // Save the result on the stack. If we have a named or keyed property
3905 // we store the result under the receiver that is currently on top
3906 // of the stack.
3907 switch (assign_type) {
3908 case VARIABLE:
3909 __ push(rax);
3910 break;
3911 case NAMED_PROPERTY:
3912 __ movq(Operand(rsp, kPointerSize), rax);
3913 break;
3914 case KEYED_PROPERTY:
3915 __ movq(Operand(rsp, 2 * kPointerSize), rax);
3916 break;
3917 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003918 }
3919 }
3920
3921 // Inline smi case if we are in a loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003922 Label done, stub_call;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003923 JumpPatchSite patch_site(masm_);
3924
ricow@chromium.org65fae842010-08-25 15:26:24 +00003925 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003926 if (expr->op() == Token::INC) {
3927 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
3928 } else {
3929 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
3930 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003931 __ j(overflow, &stub_call, Label::kNear);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003932 // We could eliminate this smi check if we split the code at
3933 // the first smi check before calling ToNumber.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003934 patch_site.EmitJumpIfSmi(rax, &done, Label::kNear);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003935
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003936 __ bind(&stub_call);
3937 // Call stub. Undo operation first.
3938 if (expr->op() == Token::INC) {
3939 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
3940 } else {
3941 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
3942 }
3943 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003944
3945 // Record position before stub call.
3946 SetSourcePosition(expr->position());
3947
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003948 // Call stub for +1/-1.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003949 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003950 if (expr->op() == Token::INC) {
3951 __ Move(rdx, Smi::FromInt(1));
3952 } else {
3953 __ movq(rdx, rax);
3954 __ Move(rax, Smi::FromInt(1));
3955 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003956 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
3957 patch_site.EmitPatchInfo();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003958 __ bind(&done);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003959
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003960 // Store the value returned in rax.
3961 switch (assign_type) {
3962 case VARIABLE:
3963 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003964 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003965 { EffectContext context(this);
3966 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3967 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003968 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003969 context.Plug(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003970 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003971 // For all contexts except kEffect: We have the result on
3972 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003973 if (!context()->IsEffect()) {
3974 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003975 }
3976 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003977 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003978 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003979 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003980 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003981 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003982 }
3983 break;
3984 case NAMED_PROPERTY: {
3985 __ Move(rcx, prop->key()->AsLiteral()->handle());
3986 __ pop(rdx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003987 Handle<Code> ic = is_classic_mode()
3988 ? isolate()->builtins()->StoreIC_Initialize()
3989 : isolate()->builtins()->StoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003990 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003991 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003992 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003993 if (!context()->IsEffect()) {
3994 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003995 }
3996 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003997 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003998 }
3999 break;
4000 }
4001 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004002 __ pop(rcx);
4003 __ pop(rdx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004004 Handle<Code> ic = is_classic_mode()
4005 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4006 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004007 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004008 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004009 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004010 if (!context()->IsEffect()) {
4011 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004012 }
4013 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004014 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004015 }
4016 break;
4017 }
4018 }
4019}
4020
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004021
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004022void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004023 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004024 ASSERT(!context()->IsEffect());
4025 ASSERT(!context()->IsTest());
4026
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004027 if (proxy != NULL && proxy->var()->IsUnallocated()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004028 Comment cmnt(masm_, "Global variable");
4029 __ Move(rcx, proxy->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004030 __ movq(rax, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004031 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004032 // Use a regular load, not a contextual load, to avoid a reference
4033 // error.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004034 __ call(ic);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004035 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004036 context()->Plug(rax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004037 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004038 Label done, slow;
4039
4040 // Generate code for loading from variables potentially shadowed
4041 // by eval-introduced variables.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004042 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004043
4044 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004045 __ push(rsi);
4046 __ Push(proxy->name());
4047 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004048 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004049 __ bind(&done);
4050
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004051 context()->Plug(rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004052 } else {
4053 // This expression cannot throw a reference error at the top level.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004054 VisitInDuplicateContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004055 }
4056}
4057
4058
ager@chromium.org04921a82011-06-27 13:21:41 +00004059void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004060 Expression* sub_expr,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004061 Handle<String> check) {
4062 Label materialize_true, materialize_false;
4063 Label* if_true = NULL;
4064 Label* if_false = NULL;
4065 Label* fall_through = NULL;
4066 context()->PrepareTest(&materialize_true, &materialize_false,
4067 &if_true, &if_false, &fall_through);
4068
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004069 { AccumulatorValueContext context(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004070 VisitForTypeofValue(sub_expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004071 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004072 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004074 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004075 __ JumpIfSmi(rax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004076 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
4077 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
4078 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004079 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004080 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004081 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004082 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
4083 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004084 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004085 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004086 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004087 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004088 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
4089 __ j(equal, if_true);
4090 __ CompareRoot(rax, Heap::kFalseValueRootIndex);
4091 Split(equal, if_true, if_false, fall_through);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004092 } else if (FLAG_harmony_typeof &&
4093 check->Equals(isolate()->heap()->null_symbol())) {
4094 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4095 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004096 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004097 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4098 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004099 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004100 // Check for undetectable objects => true.
4101 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
4102 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4103 Immediate(1 << Map::kIsUndetectable));
4104 Split(not_zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004106 __ JumpIfSmi(rax, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004107 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4108 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx);
4109 __ j(equal, if_true);
4110 __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
4111 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004112 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004113 __ JumpIfSmi(rax, if_false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004114 if (!FLAG_harmony_typeof) {
4115 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4116 __ j(equal, if_true);
4117 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004118 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004119 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004120 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4121 __ j(above, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004122 // Check for undetectable objects => false.
4123 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4124 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004125 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004126 } else {
4127 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004128 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004129 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004130}
4131
4132
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004133void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4134 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004135 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004136
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004137 // First we try a fast inlined version of the compare when one of
4138 // the operands is a literal.
4139 if (TryLiteralCompare(expr)) return;
4140
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004141 // Always perform the comparison for its control flow. Pack the result
4142 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004143 Label materialize_true, materialize_false;
4144 Label* if_true = NULL;
4145 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004146 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004147 context()->PrepareTest(&materialize_true, &materialize_false,
4148 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004149
ager@chromium.org04921a82011-06-27 13:21:41 +00004150 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004151 VisitForStackValue(expr->left());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004152 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004153 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004154 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004155 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004156 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004157 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004158 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004159 break;
4160
4161 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004162 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004163 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004164 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004165 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004166 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004167 // The stub returns 0 for true.
4168 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004169 break;
4170 }
4171
4172 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004173 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004174 Condition cc = no_condition;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004175 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004176 case Token::EQ_STRICT:
ricow@chromium.org65fae842010-08-25 15:26:24 +00004177 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004178 cc = equal;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004179 break;
4180 case Token::LT:
4181 cc = less;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004182 break;
4183 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004184 cc = greater;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004185 break;
4186 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004187 cc = less_equal;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004188 break;
4189 case Token::GTE:
4190 cc = greater_equal;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004191 break;
4192 case Token::IN:
4193 case Token::INSTANCEOF:
4194 default:
4195 UNREACHABLE();
4196 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004197 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004198
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004199 bool inline_smi_code = ShouldInlineSmiCase(op);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004200 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004201 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004202 Label slow_case;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004203 __ movq(rcx, rdx);
4204 __ or_(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004205 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004206 __ cmpq(rdx, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004207 Split(cc, if_true, if_false, NULL);
4208 __ bind(&slow_case);
4209 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004210
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004211 // Record position and call the compare IC.
4212 SetSourcePosition(expr->position());
4213 Handle<Code> ic = CompareIC::GetUninitialized(op);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004214 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
4215 patch_site.EmitPatchInfo();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004216
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004217 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004218 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004219 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004220 }
4221 }
4222
4223 // Convert the result of the comparison into one expected for this
4224 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004225 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004226}
4227
4228
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004229void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4230 Expression* sub_expr,
4231 NilValue nil) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004232 Label materialize_true, materialize_false;
4233 Label* if_true = NULL;
4234 Label* if_false = NULL;
4235 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004236 context()->PrepareTest(&materialize_true, &materialize_false,
4237 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004238
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004239 VisitForAccumulatorValue(sub_expr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004240 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004241 Heap::RootListIndex nil_value = nil == kNullValue ?
4242 Heap::kNullValueRootIndex :
4243 Heap::kUndefinedValueRootIndex;
4244 __ CompareRoot(rax, nil_value);
4245 if (expr->op() == Token::EQ_STRICT) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004246 Split(equal, if_true, if_false, fall_through);
4247 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004248 Heap::RootListIndex other_nil_value = nil == kNullValue ?
4249 Heap::kUndefinedValueRootIndex :
4250 Heap::kNullValueRootIndex;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004251 __ j(equal, if_true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004252 __ CompareRoot(rax, other_nil_value);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004253 __ j(equal, if_true);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004254 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004255 // It can be an undetectable object.
4256 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
4257 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4258 Immediate(1 << Map::kIsUndetectable));
4259 Split(not_zero, if_true, if_false, fall_through);
4260 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004261 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004262}
4263
4264
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004265void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4266 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004267 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004268}
4269
4270
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004271Register FullCodeGenerator::result_register() {
4272 return rax;
4273}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004274
4275
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004276Register FullCodeGenerator::context_register() {
4277 return rsi;
4278}
4279
4280
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004281void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4282 ASSERT(IsAligned(frame_offset, kPointerSize));
4283 __ movq(Operand(rbp, frame_offset), value);
4284}
4285
4286
4287void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004288 __ movq(dst, ContextOperand(rsi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004289}
4290
4291
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004292void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004293 Scope* declaration_scope = scope()->DeclarationScope();
4294 if (declaration_scope->is_global_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004295 // Contexts nested in the global context have a canonical empty function
4296 // as their closure, not the anonymous closure containing the global
4297 // code. Pass a smi sentinel and let the runtime look up the empty
4298 // function.
4299 __ Push(Smi::FromInt(0));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004300 } else if (declaration_scope->is_eval_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004301 // Contexts created by a call to eval have the same closure as the
4302 // context calling eval, not the anonymous closure containing the eval
4303 // code. Fetch it from the context.
4304 __ push(ContextOperand(rsi, Context::CLOSURE_INDEX));
4305 } else {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004306 ASSERT(declaration_scope->is_function_scope());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004307 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
4308 }
4309}
4310
4311
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004312// ----------------------------------------------------------------------------
4313// Non-local control flow support.
4314
4315
4316void FullCodeGenerator::EnterFinallyBlock() {
4317 ASSERT(!result_register().is(rdx));
4318 ASSERT(!result_register().is(rcx));
4319 // Cook return address on top of stack (smi encoded Code* delta)
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004320 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004321 __ Move(rcx, masm_->CodeObject());
4322 __ subq(rdx, rcx);
4323 __ Integer32ToSmi(rdx, rdx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004324 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004325 // Store result register while executing finally block.
4326 __ push(result_register());
4327}
4328
4329
4330void FullCodeGenerator::ExitFinallyBlock() {
4331 ASSERT(!result_register().is(rdx));
4332 ASSERT(!result_register().is(rcx));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004333 __ pop(result_register());
4334 // Uncook return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004335 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004336 __ SmiToInteger32(rdx, rdx);
4337 __ Move(rcx, masm_->CodeObject());
4338 __ addq(rdx, rcx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004339 __ jmp(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004340}
4341
4342
4343#undef __
4344
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004345#define __ ACCESS_MASM(masm())
4346
4347FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4348 int* stack_depth,
4349 int* context_length) {
4350 // The macros used here must preserve the result register.
4351
4352 // Because the handler block contains the context of the finally
4353 // code, we can restore it directly from there for the finally code
4354 // rather than iteratively unwinding contexts via their previous
4355 // links.
4356 __ Drop(*stack_depth); // Down to the handler block.
4357 if (*context_length > 0) {
4358 // Restore the context to its dedicated register and the stack.
4359 __ movq(rsi, Operand(rsp, StackHandlerConstants::kContextOffset));
4360 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
4361 }
4362 __ PopTryHandler();
4363 __ call(finally_entry_);
4364
4365 *stack_depth = 0;
4366 *context_length = 0;
4367 return previous_;
4368}
4369
4370
4371#undef __
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004372
4373} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004374
4375#endif // V8_TARGET_ARCH_X64