blob: 5567df2fa62c1fda148e053137525511bc9509e9 [file] [log] [blame]
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001// Copyright 2011 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
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000047static unsigned GetPropertyId(Property* property) {
48 if (property->is_synthetic()) return AstNode::kNoNumber;
49 return property->id();
50}
51
52
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000053class JumpPatchSite BASE_EMBEDDED {
54 public:
55 explicit JumpPatchSite(MacroAssembler* masm)
56 : masm_(masm) {
57#ifdef DEBUG
58 info_emitted_ = false;
59#endif
60 }
61
62 ~JumpPatchSite() {
63 ASSERT(patch_site_.is_bound() == info_emitted_);
64 }
65
karlklose@chromium.org83a47282011-05-11 11:54:09 +000066 void EmitJumpIfNotSmi(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(not_carry, target, near_jump); // Always taken before patched.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000071 }
72
karlklose@chromium.org83a47282011-05-11 11:54:09 +000073 void EmitJumpIfSmi(Register reg,
74 Label* target,
75 Label::Distance near_jump = Label::kFar) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000076 __ testb(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000077 EmitJump(carry, target, near_jump); // Never taken before patched.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000078 }
79
80 void EmitPatchInfo() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000081 if (patch_site_.is_bound()) {
82 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
83 ASSERT(is_int8(delta_to_patch_site));
84 __ testl(rax, Immediate(delta_to_patch_site));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000085#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +000086 info_emitted_ = true;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000087#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +000088 } else {
89 __ nop(); // Signals no inlined code.
90 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000091 }
92
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000093 private:
94 // jc will be patched with jz, jnc will become jnz.
karlklose@chromium.org83a47282011-05-11 11:54:09 +000095 void EmitJump(Condition cc, Label* target, Label::Distance near_jump) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000096 ASSERT(!patch_site_.is_bound() && !info_emitted_);
97 ASSERT(cc == carry || cc == not_carry);
98 __ bind(&patch_site_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +000099 __ j(cc, target, near_jump);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000100 }
101
102 MacroAssembler* masm_;
103 Label patch_site_;
104#ifdef DEBUG
105 bool info_emitted_;
106#endif
107};
108
109
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000110// Generate code for a JS function. On entry to the function the receiver
111// and arguments have been pushed on the stack left to right, with the
112// return address on top of them. The actual argument count matches the
113// formal parameter count expected by the function.
114//
115// The live registers are:
116// o rdi: the JS function object being called (ie, ourselves)
117// o rsi: our context
118// o rbp: our caller's frame pointer
119// o rsp: stack pointer (pointing to return address)
120//
121// The function builds a JS frame. Please see JavaScriptFrameConstants in
122// frames-x64.h for its layout.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000123void FullCodeGenerator::Generate(CompilationInfo* info) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000124 ASSERT(info_ == NULL);
125 info_ = info;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000126 scope_ = info->scope();
ager@chromium.org5c838252010-02-19 08:53:10 +0000127 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000128 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129
vegorov@chromium.org42841962010-10-18 11:18:59 +0000130#ifdef DEBUG
131 if (strlen(FLAG_stop_at) > 0 &&
132 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
133 __ int3();
134 }
135#endif
danno@chromium.org40cb8782011-05-25 07:58:50 +0000136
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000137 // Strict mode functions and builtins need to replace the receiver
138 // with undefined when called as functions (without an explicit
139 // receiver object). rcx is zero for method calls and non-zero for
140 // function calls.
141 if (info->is_strict_mode() || info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000142 Label ok;
143 __ testq(rcx, rcx);
144 __ j(zero, &ok, Label::kNear);
145 // +1 for return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000146 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000147 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
148 __ movq(Operand(rsp, receiver_offset), kScratchRegister);
149 __ bind(&ok);
150 }
151
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000152 __ push(rbp); // Caller's frame pointer.
153 __ movq(rbp, rsp);
154 __ push(rsi); // Callee's context.
155 __ push(rdi); // Callee's JS Function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000157 { Comment cmnt(masm_, "[ Allocate locals");
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000158 int locals_count = info->scope()->num_stack_slots();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000159 if (locals_count == 1) {
160 __ PushRoot(Heap::kUndefinedValueRootIndex);
161 } else if (locals_count > 1) {
162 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
163 for (int i = 0; i < locals_count; i++) {
164 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000165 }
166 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000167 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000168
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000169 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000170
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000171 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000172 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000173 if (heap_slots > 0) {
174 Comment cmnt(masm_, "[ Allocate local context");
175 // Argument to NewContext is the function, which is still in rdi.
176 __ push(rdi);
177 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
178 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000179 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000180 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000181 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000182 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000183 function_in_register = false;
184 // Context is returned in both rax and rsi. It replaces the context
185 // passed to us. It's saved in the stack and kept live in rsi.
186 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
187
188 // Copy any necessary parameters into the context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000189 int num_parameters = info->scope()->num_parameters();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000190 for (int i = 0; i < num_parameters; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000191 Slot* slot = scope()->parameter(i)->AsSlot();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000192 if (slot != NULL && slot->type() == Slot::CONTEXT) {
193 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
194 (num_parameters - 1 - i) * kPointerSize;
195 // Load parameter from stack.
196 __ movq(rax, Operand(rbp, parameter_offset));
197 // Store it in the context.
198 int context_offset = Context::SlotOffset(slot->index());
199 __ movq(Operand(rsi, context_offset), rax);
200 // Update the write barrier. This clobbers all involved
201 // registers, so we have use a third register to avoid
202 // clobbering rsi.
203 __ movq(rcx, rsi);
204 __ RecordWrite(rcx, context_offset, rax, rbx);
205 }
206 }
207 }
208
209 // Possibly allocate an arguments object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000210 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000211 if (arguments != NULL) {
212 // Arguments object must be allocated after the context object, in
213 // case the "arguments" or ".arguments" variables are in the context.
214 Comment cmnt(masm_, "[ Allocate arguments object");
215 if (function_in_register) {
216 __ push(rdi);
217 } else {
218 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
219 }
220 // The receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000221 int num_parameters = info->scope()->num_parameters();
222 int offset = num_parameters * kPointerSize;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000223 __ lea(rdx,
224 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
225 __ push(rdx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000226 __ Push(Smi::FromInt(num_parameters));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000227 // Arguments to ArgumentsAccessStub:
228 // function, receiver address, parameter count.
229 // The stub will rewrite receiver and parameter count if the previous
230 // stack frame was an arguments adapter frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 ArgumentsAccessStub stub(
232 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
whesse@chromium.org7b260152011-06-20 15:33:18 +0000233 : ArgumentsAccessStub::NEW_NON_STRICT_SLOW);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000234 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000235
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000236 Move(arguments->AsSlot(), rax, rbx, rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000237 }
238
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000239 if (FLAG_trace) {
240 __ CallRuntime(Runtime::kTraceEnter, 0);
241 }
242
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000243 // Visit the declarations and body unless there is an illegal
244 // redeclaration.
245 if (scope()->HasIllegalRedeclaration()) {
246 Comment cmnt(masm_, "[ Declarations");
247 scope()->VisitIllegalRedeclaration(this);
248 } else {
249 { Comment cmnt(masm_, "[ Declarations");
250 // For named function expressions, declare the function name as a
251 // constant.
252 if (scope()->is_function_scope() && scope()->function() != NULL) {
253 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
254 }
255 VisitDeclarations(scope()->declarations());
256 }
257
258 { Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000259 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000260 Label ok;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000261 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000262 __ j(above_equal, &ok, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000263 StackCheckStub stub;
264 __ CallStub(&stub);
265 __ bind(&ok);
266 }
267
268 { Comment cmnt(masm_, "[ Body");
269 ASSERT(loop_depth() == 0);
270 VisitStatements(function()->body());
271 ASSERT(loop_depth() == 0);
272 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000273 }
274
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000275 // Always emit a 'return undefined' in case control fell off the end of
276 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000277 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000278 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000279 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000280 }
281}
282
283
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000284void FullCodeGenerator::ClearAccumulator() {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000285 __ Set(rax, 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000286}
287
288
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000289void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
290 Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000291 Label ok;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000292 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000293 __ j(above_equal, &ok, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000294 StackCheckStub stub;
295 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000296 // Record a mapping of this PC offset to the OSR id. This is used to find
297 // the AST id from the unoptimized code in order to use it as a key into
298 // the deoptimization input data found in the optimized code.
299 RecordStackCheck(stmt->OsrEntryId());
300
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000301 // Loop stack checks can be patched to perform on-stack replacement. In
302 // order to decide whether or not to perform OSR we embed the loop depth
303 // in a test instruction after the call so we can extract it from the OSR
304 // builtin.
305 ASSERT(loop_depth() > 0);
306 __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
307
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000308 __ bind(&ok);
309 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000310 // Record a mapping of the OSR id to this PC. This is used if the OSR
311 // entry becomes the target of a bailout. We don't expect it to be, but
312 // we want it to work if it is.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000313 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000314}
315
316
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000317void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000318 Comment cmnt(masm_, "[ Return sequence");
319 if (return_label_.is_bound()) {
320 __ jmp(&return_label_);
321 } else {
322 __ bind(&return_label_);
323 if (FLAG_trace) {
324 __ push(rax);
325 __ CallRuntime(Runtime::kTraceExit, 1);
326 }
327#ifdef DEBUG
328 // Add a label for checking the size of the code used for returning.
329 Label check_exit_codesize;
330 masm_->bind(&check_exit_codesize);
331#endif
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000332 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000333 __ RecordJSReturn();
334 // Do not use the leave instruction here because it is too short to
335 // patch with the code required by the debugger.
336 __ movq(rsp, rbp);
337 __ pop(rbp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000338
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000339 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000340 __ Ret(arguments_bytes, rcx);
341
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000342#ifdef ENABLE_DEBUGGER_SUPPORT
343 // Add padding that will be overwritten by a debugger breakpoint. We
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000344 // have just generated at least 7 bytes: "movq rsp, rbp; pop rbp; ret k"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000345 // (3 + 1 + 3).
346 const int kPadding = Assembler::kJSReturnSequenceLength - 7;
347 for (int i = 0; i < kPadding; ++i) {
348 masm_->int3();
349 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000350 // Check that the size of the code used for returning is large enough
351 // for the debugger's requirements.
352 ASSERT(Assembler::kJSReturnSequenceLength <=
353 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000354#endif
355 }
356}
357
358
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000359void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
360}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000361
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000362
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000363void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
364 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
365 __ movq(result_register(), slot_operand);
366}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000367
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000368
369void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
370 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
371 __ push(slot_operand);
372}
373
374
375void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
376 codegen()->Move(result_register(), slot);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000377 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000378 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000379}
380
381
382void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
383}
384
385
386void FullCodeGenerator::AccumulatorValueContext::Plug(
387 Heap::RootListIndex index) const {
388 __ LoadRoot(result_register(), index);
389}
390
391
392void FullCodeGenerator::StackValueContext::Plug(
393 Heap::RootListIndex index) const {
394 __ PushRoot(index);
395}
396
397
398void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000399 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
400 true,
401 true_label_,
402 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000403 if (index == Heap::kUndefinedValueRootIndex ||
404 index == Heap::kNullValueRootIndex ||
405 index == Heap::kFalseValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000406 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000407 } else if (index == Heap::kTrueValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000408 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000409 } else {
410 __ LoadRoot(result_register(), index);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000411 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000412 }
413}
414
415
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000416void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
417}
418
419
420void FullCodeGenerator::AccumulatorValueContext::Plug(
421 Handle<Object> lit) const {
422 __ Move(result_register(), lit);
423}
424
425
426void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
427 __ Push(lit);
428}
429
430
431void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000432 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
433 true,
434 true_label_,
435 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000436 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
437 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000438 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000439 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000440 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000441 } else if (lit->IsString()) {
442 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000443 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000444 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000445 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000446 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000447 } else if (lit->IsSmi()) {
448 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000449 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000450 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000451 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000452 }
453 } else {
454 // For simplicity we always test the accumulator register.
455 __ Move(result_register(), lit);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000456 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000457 }
458}
459
460
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000461void FullCodeGenerator::EffectContext::DropAndPlug(int count,
462 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000463 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000464 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000465}
466
467
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000468void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
469 int count,
470 Register reg) const {
471 ASSERT(count > 0);
472 __ Drop(count);
473 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000474}
475
476
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000477void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
478 Register reg) const {
479 ASSERT(count > 0);
480 if (count > 1) __ Drop(count - 1);
481 __ movq(Operand(rsp, 0), reg);
482}
483
484
485void FullCodeGenerator::TestContext::DropAndPlug(int count,
486 Register reg) const {
487 ASSERT(count > 0);
488 // For simplicity we always test the accumulator register.
489 __ Drop(count);
490 __ Move(result_register(), reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000491 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000492 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000493}
494
495
496void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
497 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000498 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000499 __ bind(materialize_true);
500}
501
502
503void FullCodeGenerator::AccumulatorValueContext::Plug(
504 Label* materialize_true,
505 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000506 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000507 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000508 __ Move(result_register(), isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000509 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000510 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000511 __ Move(result_register(), isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000512 __ bind(&done);
513}
514
515
516void FullCodeGenerator::StackValueContext::Plug(
517 Label* materialize_true,
518 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000519 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000520 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 __ Push(isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000522 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000523 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 __ Push(isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000525 __ bind(&done);
526}
527
528
529void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
530 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000531 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000532 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000533}
534
535
536void FullCodeGenerator::EffectContext::Plug(bool flag) const {
537}
538
539
540void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
541 Heap::RootListIndex value_root_index =
542 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
543 __ LoadRoot(result_register(), value_root_index);
544}
545
546
547void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
548 Heap::RootListIndex value_root_index =
549 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
550 __ PushRoot(value_root_index);
551}
552
553
554void FullCodeGenerator::TestContext::Plug(bool flag) const {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000555 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
556 true,
557 true_label_,
558 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000559 if (flag) {
560 if (true_label_ != fall_through_) __ jmp(true_label_);
561 } else {
562 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000563 }
564}
565
566
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000567void FullCodeGenerator::DoTest(Expression* condition,
568 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000569 Label* if_false,
570 Label* fall_through) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000571 ToBooleanStub stub(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000572 __ push(result_register());
573 __ CallStub(&stub);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000574 __ testq(result_register(), result_register());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000575 // The stub returns nonzero for true.
576 Split(not_zero, if_true, if_false, fall_through);
577}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000578
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000579
ricow@chromium.org65fae842010-08-25 15:26:24 +0000580void FullCodeGenerator::Split(Condition cc,
581 Label* if_true,
582 Label* if_false,
583 Label* fall_through) {
584 if (if_false == fall_through) {
585 __ j(cc, if_true);
586 } else if (if_true == fall_through) {
587 __ j(NegateCondition(cc), if_false);
588 } else {
589 __ j(cc, if_true);
590 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000591 }
592}
593
594
595MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
596 switch (slot->type()) {
597 case Slot::PARAMETER:
598 case Slot::LOCAL:
599 return Operand(rbp, SlotOffset(slot));
600 case Slot::CONTEXT: {
601 int context_chain_length =
ager@chromium.org5c838252010-02-19 08:53:10 +0000602 scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000603 __ LoadContext(scratch, context_chain_length);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000604 return ContextOperand(scratch, slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000605 }
606 case Slot::LOOKUP:
607 UNREACHABLE();
608 }
609 UNREACHABLE();
610 return Operand(rax, 0);
611}
612
613
614void FullCodeGenerator::Move(Register destination, Slot* source) {
615 MemOperand location = EmitSlotSearch(source, destination);
616 __ movq(destination, location);
617}
618
619
620void FullCodeGenerator::Move(Slot* dst,
621 Register src,
622 Register scratch1,
623 Register scratch2) {
624 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
625 ASSERT(!scratch1.is(src) && !scratch2.is(src));
626 MemOperand location = EmitSlotSearch(dst, scratch1);
627 __ movq(location, src);
628 // Emit the write barrier code if the location is in the heap.
629 if (dst->type() == Slot::CONTEXT) {
630 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
631 __ RecordWrite(scratch1, offset, src, scratch2);
632 }
633}
634
635
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000636void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
637 bool should_normalize,
638 Label* if_true,
639 Label* if_false) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000640 // Only prepare for bailouts before splits if we're in a test
641 // context. Otherwise, we let the Visit function deal with the
642 // preparation to avoid preparing with the same AST id twice.
643 if (!context()->IsTest() || !info_->IsOptimizable()) return;
644
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000645 Label skip;
646 if (should_normalize) __ jmp(&skip, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000647
648 ForwardBailoutStack* current = forward_bailout_stack_;
649 while (current != NULL) {
650 PrepareForBailout(current->expr(), state);
651 current = current->parent();
652 }
653
654 if (should_normalize) {
655 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
656 Split(equal, if_true, if_false, NULL);
657 __ bind(&skip);
658 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000659}
660
661
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000662void FullCodeGenerator::EmitDeclaration(Variable* variable,
663 Variable::Mode mode,
664 FunctionLiteral* function) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000665 Comment cmnt(masm_, "[ Declaration");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000666 ASSERT(variable != NULL); // Must have been resolved.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000667 Slot* slot = variable->AsSlot();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000668 Property* prop = variable->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000669
670 if (slot != NULL) {
671 switch (slot->type()) {
672 case Slot::PARAMETER:
673 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000674 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000675 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
676 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000677 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000678 VisitForAccumulatorValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000679 __ movq(Operand(rbp, SlotOffset(slot)), result_register());
680 }
681 break;
682
683 case Slot::CONTEXT:
684 // We bypass the general EmitSlotSearch because we know more about
685 // this specific context.
686
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000687 // The variable in the decl always resides in the current function
688 // context.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000689 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000690 if (FLAG_debug_code) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000691 // Check that we're not inside a with or catch context.
692 __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
693 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
694 __ Check(not_equal, "Declaration in with context.");
695 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
696 __ Check(not_equal, "Declaration in catch context.");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000697 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000698 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000699 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000700 __ movq(ContextOperand(rsi, slot->index()), kScratchRegister);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000701 // No write barrier since the hole value is in old space.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000702 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000703 VisitForAccumulatorValue(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000704 __ movq(ContextOperand(rsi, slot->index()), result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000705 int offset = Context::SlotOffset(slot->index());
706 __ movq(rbx, rsi);
707 __ RecordWrite(rbx, offset, result_register(), rcx);
708 }
709 break;
710
711 case Slot::LOOKUP: {
712 __ push(rsi);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000713 __ Push(variable->name());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000714 // Declaration nodes are always introduced in one of two modes.
danno@chromium.orgb6451162011-08-17 14:33:23 +0000715 ASSERT(mode == Variable::VAR ||
716 mode == Variable::CONST ||
717 mode == Variable::LET);
718 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000719 __ Push(Smi::FromInt(attr));
720 // Push initial value, if any.
721 // Note: For variables we must not push an initial value (such as
722 // 'undefined') because we may have a (legal) redeclaration and we
723 // must not destroy the current value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000724 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000725 __ PushRoot(Heap::kTheHoleValueRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000726 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000727 VisitForStackValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000728 } else {
729 __ Push(Smi::FromInt(0)); // no initial value!
730 }
731 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
732 break;
733 }
734 }
735
736 } else if (prop != NULL) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000737 // A const declaration aliasing a parameter is an illegal redeclaration.
738 ASSERT(mode != Variable::CONST);
739 if (function != NULL) {
740 // We are declaring a function that rewrites to a property.
741 // Use (keyed) IC to set the initial value. We cannot visit the
742 // rewrite because it's shared and we risk recording duplicate AST
743 // IDs for bailouts from optimized code.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000744 ASSERT(prop->obj()->AsVariableProxy() != NULL);
745 { AccumulatorValueContext for_object(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000746 EmitVariableLoad(prop->obj()->AsVariableProxy());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000747 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000748 __ push(rax);
749 VisitForAccumulatorValue(function);
750 __ pop(rdx);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000751 ASSERT(prop->key()->AsLiteral() != NULL &&
752 prop->key()->AsLiteral()->handle()->IsSmi());
753 __ Move(rcx, prop->key()->AsLiteral()->handle());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000754
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000755 Handle<Code> ic = is_strict_mode()
756 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
757 : isolate()->builtins()->KeyedStoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000758 __ call(ic);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000759 }
760 }
761}
762
763
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000764void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
765 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
766}
767
768
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000769void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
770 // Call the runtime to declare the globals.
771 __ push(rsi); // The context is the first argument.
772 __ Push(pairs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000773 __ Push(Smi::FromInt(is_eval() ? 1 : 0));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000774 __ Push(Smi::FromInt(strict_mode_flag()));
775 __ CallRuntime(Runtime::kDeclareGlobals, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000776 // Return value is ignored.
777}
778
779
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000780void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
781 Comment cmnt(masm_, "[ SwitchStatement");
782 Breakable nested_statement(this, stmt);
783 SetStatementPosition(stmt);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000784
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000785 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000786 VisitForStackValue(stmt->tag());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000787 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000788
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000789 ZoneList<CaseClause*>* clauses = stmt->cases();
790 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000791
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000792 Label next_test; // Recycled for each test.
793 // Compile all the tests with branches to their bodies.
794 for (int i = 0; i < clauses->length(); i++) {
795 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000796 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000797
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000798 // The default is not a test, but remember it as final fall through.
799 if (clause->is_default()) {
800 default_clause = clause;
801 continue;
802 }
803
804 Comment cmnt(masm_, "[ Case comparison");
805 __ bind(&next_test);
806 next_test.Unuse();
807
808 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000809 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000810
ricow@chromium.org65fae842010-08-25 15:26:24 +0000811 // Perform the comparison as if via '==='.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000812 __ movq(rdx, Operand(rsp, 0)); // Switch value.
813 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000814 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000815 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000816 Label slow_case;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000817 __ movq(rcx, rdx);
818 __ or_(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000819 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000820
821 __ cmpq(rdx, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000822 __ j(not_equal, &next_test);
823 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000824 __ jmp(clause->body_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000825 __ bind(&slow_case);
826 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000827
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000828 // Record position before stub call for type feedback.
829 SetSourcePosition(clause->position());
830 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000831 __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
832 patch_site.EmitPatchInfo();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000833
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000834 __ testq(rax, rax);
835 __ j(not_equal, &next_test);
836 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000837 __ jmp(clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000838 }
839
840 // Discard the test value and jump to the default if present, otherwise to
841 // the end of the statement.
842 __ bind(&next_test);
843 __ Drop(1); // Switch value is no longer needed.
844 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000845 __ jmp(nested_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000846 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000847 __ jmp(default_clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000848 }
849
850 // Compile all the case bodies.
851 for (int i = 0; i < clauses->length(); i++) {
852 Comment cmnt(masm_, "[ Case body");
853 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000854 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000855 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000856 VisitStatements(clause->statements());
857 }
858
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000859 __ bind(nested_statement.break_label());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000860 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000861}
862
863
864void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
865 Comment cmnt(masm_, "[ ForInStatement");
866 SetStatementPosition(stmt);
867
868 Label loop, exit;
869 ForIn loop_statement(this, stmt);
870 increment_loop_depth();
871
872 // Get the object to enumerate over. Both SpiderMonkey and JSC
873 // ignore null and undefined in contrast to the specification; see
874 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000875 VisitForAccumulatorValue(stmt->enumerable());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000876 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
877 __ j(equal, &exit);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000878 Register null_value = rdi;
879 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
880 __ cmpq(rax, null_value);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000881 __ j(equal, &exit);
882
883 // Convert the object to a JS object.
884 Label convert, done_convert;
885 __ JumpIfSmi(rax, &convert);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000886 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000887 __ j(above_equal, &done_convert);
888 __ bind(&convert);
889 __ push(rax);
890 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
891 __ bind(&done_convert);
892 __ push(rax);
893
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000894 // Check cache validity in generated code. This is a fast case for
895 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
896 // guarantee cache validity, call the runtime system to check cache
897 // validity or get the property names in a fixed array.
898 Label next, call_runtime;
899 Register empty_fixed_array_value = r8;
900 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
901 Register empty_descriptor_array_value = r9;
902 __ LoadRoot(empty_descriptor_array_value,
903 Heap::kEmptyDescriptorArrayRootIndex);
904 __ movq(rcx, rax);
905 __ bind(&next);
906
907 // Check that there are no elements. Register rcx contains the
908 // current JS object we've reached through the prototype chain.
909 __ cmpq(empty_fixed_array_value,
910 FieldOperand(rcx, JSObject::kElementsOffset));
911 __ j(not_equal, &call_runtime);
912
913 // Check that instance descriptors are not empty so that we can
914 // check for an enum cache. Leave the map in rbx for the subsequent
915 // prototype load.
916 __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000917 __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOrBitField3Offset));
918 __ JumpIfSmi(rdx, &call_runtime);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000919
920 // Check that there is an enum cache in the non-empty instance
921 // descriptors (rdx). This is the case if the next enumeration
922 // index field does not contain a smi.
923 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
924 __ JumpIfSmi(rdx, &call_runtime);
925
926 // For all objects but the receiver, check that the cache is empty.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000927 Label check_prototype;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000928 __ cmpq(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000929 __ j(equal, &check_prototype, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000930 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
931 __ cmpq(rdx, empty_fixed_array_value);
932 __ j(not_equal, &call_runtime);
933
934 // Load the prototype from the map and loop if non-null.
935 __ bind(&check_prototype);
936 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
937 __ cmpq(rcx, null_value);
938 __ j(not_equal, &next);
939
940 // The enum cache is valid. Load the map of the object being
941 // iterated over and use the cache for the iteration.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000942 Label use_cache;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000943 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000944 __ jmp(&use_cache, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000945
946 // Get the set of properties to enumerate.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000947 __ bind(&call_runtime);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000948 __ push(rax); // Duplicate the enumerable object on the stack.
949 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
950
951 // If we got a map from the runtime call, we can do a fast
952 // modification check. Otherwise, we got a fixed array, and we have
953 // to do a slow check.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000954 Label fixed_array;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000955 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
956 Heap::kMetaMapRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000957 __ j(not_equal, &fixed_array, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000958
959 // We got a map in register rax. Get the enumeration cache from it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000960 __ bind(&use_cache);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000961 __ LoadInstanceDescriptors(rax, rcx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000962 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
963 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
964
965 // Setup the four remaining stack slots.
966 __ push(rax); // Map.
967 __ push(rdx); // Enumeration cache.
968 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000969 __ push(rax); // Enumeration cache length (as smi).
970 __ Push(Smi::FromInt(0)); // Initial index.
971 __ jmp(&loop);
972
973 // We got a fixed array in register rax. Iterate through that.
974 __ bind(&fixed_array);
975 __ Push(Smi::FromInt(0)); // Map (0) - force slow check.
976 __ push(rax);
977 __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000978 __ push(rax); // Fixed array length (as smi).
979 __ Push(Smi::FromInt(0)); // Initial index.
980
981 // Generate code for doing the condition check.
982 __ bind(&loop);
983 __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
984 __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000985 __ j(above_equal, loop_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000986
987 // Get the current entry of the array into register rbx.
988 __ movq(rbx, Operand(rsp, 2 * kPointerSize));
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000989 SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000990 __ movq(rbx, FieldOperand(rbx,
991 index.reg,
992 index.scale,
993 FixedArray::kHeaderSize));
994
995 // Get the expected map from the stack or a zero map in the
996 // permanent slow case into register rdx.
997 __ movq(rdx, Operand(rsp, 3 * kPointerSize));
998
999 // Check if the expected map still matches that of the enumerable.
1000 // If not, we have to filter the key.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001001 Label update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001002 __ movq(rcx, Operand(rsp, 4 * kPointerSize));
1003 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001004 __ j(equal, &update_each, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001005
1006 // Convert the entry to a string or null if it isn't a property
1007 // anymore. If the property has been removed while iterating, we
1008 // just skip it.
1009 __ push(rcx); // Enumerable.
1010 __ push(rbx); // Current entry.
1011 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001012 __ Cmp(rax, Smi::FromInt(0));
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001013 __ j(equal, loop_statement.continue_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001014 __ movq(rbx, rax);
1015
1016 // Update the 'each' property or variable from the possibly filtered
1017 // entry in register rbx.
1018 __ bind(&update_each);
1019 __ movq(result_register(), rbx);
1020 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001021 { EffectContext context(this);
1022 EmitAssignment(stmt->each(), stmt->AssignmentId());
1023 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001024
1025 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001026 Visit(stmt->body());
1027
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001028 // Generate code for going to the next element by incrementing the
1029 // index (smi) stored on top of the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001030 __ bind(loop_statement.continue_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001031 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001032
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001033 EmitStackCheck(stmt);
1034 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001035
1036 // Remove the pointers stored on the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001037 __ bind(loop_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001038 __ addq(rsp, Immediate(5 * kPointerSize));
1039
1040 // Exit and decrement the loop depth.
1041 __ bind(&exit);
1042 decrement_loop_depth();
1043}
1044
1045
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001046void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1047 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001048 // Use the fast case closure allocation code that allocates in new
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001049 // space for nested functions that don't need literals cloning. If
1050 // we're running with the --always-opt or the --prepare-always-opt
1051 // flag, we need to use the runtime function so that the new function
1052 // we are creating here gets a chance to have its code optimized and
1053 // doesn't just get a copy of the existing unoptimized code.
1054 if (!FLAG_always_opt &&
1055 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 !pretenure &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001057 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001058 info->num_literals() == 0) {
1059 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001060 __ Push(info);
1061 __ CallStub(&stub);
1062 } else {
1063 __ push(rsi);
1064 __ Push(info);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001065 __ Push(pretenure
1066 ? isolate()->factory()->true_value()
1067 : isolate()->factory()->false_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001068 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001069 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001070 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001071}
1072
1073
1074void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1075 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001076 EmitVariableLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001077}
1078
1079
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001080void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
1081 Slot* slot,
1082 TypeofState typeof_state,
1083 Label* slow) {
1084 Register context = rsi;
1085 Register temp = rdx;
1086
1087 Scope* s = scope();
1088 while (s != NULL) {
1089 if (s->num_heap_slots() > 0) {
1090 if (s->calls_eval()) {
1091 // Check that extension is NULL.
1092 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1093 Immediate(0));
1094 __ j(not_equal, slow);
1095 }
1096 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001097 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001098 // Walk the rest of the chain without clobbering rsi.
1099 context = temp;
1100 }
1101 // If no outer scope calls eval, we do not need to check more
1102 // context extensions. If we have reached an eval scope, we check
1103 // all extensions from this point.
1104 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1105 s = s->outer_scope();
1106 }
1107
1108 if (s != NULL && s->is_eval_scope()) {
1109 // Loop up the context chain. There is no frame effect so it is
1110 // safe to use raw labels here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001111 Label next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001112 if (!context.is(temp)) {
1113 __ movq(temp, context);
1114 }
1115 // Load map for comparison into register, outside loop.
1116 __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex);
1117 __ bind(&next);
1118 // Terminate at global context.
1119 __ cmpq(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001120 __ j(equal, &fast, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001121 // Check that extension is NULL.
1122 __ cmpq(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1123 __ j(not_equal, slow);
1124 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001125 __ movq(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001126 __ jmp(&next);
1127 __ bind(&fast);
1128 }
1129
1130 // All extension objects were empty and it is safe to use a global
1131 // load IC call.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001132 __ movq(rax, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001133 __ Move(rcx, slot->var()->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001134 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001135 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1136 ? RelocInfo::CODE_TARGET
1137 : RelocInfo::CODE_TARGET_CONTEXT;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001138 __ call(ic, mode);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001139}
1140
1141
1142MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1143 Slot* slot,
1144 Label* slow) {
1145 ASSERT(slot->type() == Slot::CONTEXT);
1146 Register context = rsi;
1147 Register temp = rbx;
1148
1149 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1150 if (s->num_heap_slots() > 0) {
1151 if (s->calls_eval()) {
1152 // Check that extension is NULL.
1153 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1154 Immediate(0));
1155 __ j(not_equal, slow);
1156 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001157 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001158 // Walk the rest of the chain without clobbering rsi.
1159 context = temp;
1160 }
1161 }
1162 // Check that last extension is NULL.
1163 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1164 __ j(not_equal, slow);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001165
1166 // This function is used only for loads, not stores, so it's safe to
1167 // return an rsi-based operand (the write barrier cannot be allowed to
1168 // destroy the rsi register).
1169 return ContextOperand(context, slot->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001170}
1171
1172
1173void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1174 Slot* slot,
1175 TypeofState typeof_state,
1176 Label* slow,
1177 Label* done) {
1178 // Generate fast-case code for variables that might be shadowed by
1179 // eval-introduced variables. Eval is used a lot without
1180 // introducing variables. In those cases, we do not want to
1181 // perform a runtime call for all variables in the scope
1182 // containing the eval.
1183 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1184 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1185 __ jmp(done);
1186 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001187 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001188 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1189 if (potential_slot != NULL) {
1190 // Generate fast case for locals that rewrite to slots.
1191 __ movq(rax,
1192 ContextSlotOperandCheckExtensions(potential_slot, slow));
1193 if (potential_slot->var()->mode() == Variable::CONST) {
1194 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1195 __ j(not_equal, done);
1196 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1197 }
1198 __ jmp(done);
1199 } else if (rewrite != NULL) {
1200 // Generate fast case for calls of an argument function.
1201 Property* property = rewrite->AsProperty();
1202 if (property != NULL) {
1203 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1204 Literal* key_literal = property->key()->AsLiteral();
1205 if (obj_proxy != NULL &&
1206 key_literal != NULL &&
1207 obj_proxy->IsArguments() &&
1208 key_literal->handle()->IsSmi()) {
1209 // Load arguments object if there are no eval-introduced
1210 // variables. Then load the argument from the arguments
1211 // object using keyed load.
1212 __ movq(rdx,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001213 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001214 slow));
1215 __ Move(rax, key_literal->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001216 Handle<Code> ic =
1217 isolate()->builtins()->KeyedLoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001218 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001219 __ jmp(done);
1220 }
1221 }
1222 }
1223 }
1224}
1225
1226
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001227void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1228 // Record position before possible IC call.
1229 SetSourcePosition(proxy->position());
1230 Variable* var = proxy->var();
1231
whesse@chromium.org7b260152011-06-20 15:33:18 +00001232 // Three cases: non-this global variables, lookup slots, and all other
1233 // types of slots.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001234 Slot* slot = var->AsSlot();
whesse@chromium.org7b260152011-06-20 15:33:18 +00001235 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001236
whesse@chromium.org7b260152011-06-20 15:33:18 +00001237 if (slot == NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001238 Comment cmnt(masm_, "Global variable");
1239 // Use inline caching. Variable name is passed in rcx and the global
1240 // object on the stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001241 __ Move(rcx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001242 __ movq(rax, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001243 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001244 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001245 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001246
1247 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001248 Label done, slow;
1249
1250 // Generate code for loading from variables potentially shadowed
1251 // by eval-introduced variables.
1252 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1253
1254 __ bind(&slow);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001255 Comment cmnt(masm_, "Lookup slot");
1256 __ push(rsi); // Context.
1257 __ Push(var->name());
1258 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001259 __ bind(&done);
1260
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001261 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001262
whesse@chromium.org7b260152011-06-20 15:33:18 +00001263 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001264 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1265 ? "Context slot"
1266 : "Stack slot");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001267 if (var->mode() == Variable::CONST) {
1268 // Constants may be the hole value if they have not been initialized.
1269 // Unhole them.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001270 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001271 MemOperand slot_operand = EmitSlotSearch(slot, rax);
1272 __ movq(rax, slot_operand);
1273 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001274 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001275 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1276 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001277 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001278 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001279 context()->Plug(slot);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001280 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001281 }
1282}
1283
1284
1285void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1286 Comment cmnt(masm_, "[ RegExpLiteral");
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001287 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001288 // Registers will be used as follows:
1289 // rdi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001290 // rcx = literals array.
1291 // rbx = regexp literal.
1292 // rax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001293 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001294 __ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001295 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001296 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001297 __ movq(rbx, FieldOperand(rcx, literal_offset));
1298 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
1299 __ j(not_equal, &materialized);
1300
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001301 // Create regexp literal using runtime function
1302 // Result will be in rax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001303 __ push(rcx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001304 __ Push(Smi::FromInt(expr->literal_index()));
1305 __ Push(expr->pattern());
1306 __ Push(expr->flags());
1307 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001308 __ movq(rbx, rax);
1309
1310 __ bind(&materialized);
1311 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1312 Label allocated, runtime_allocate;
1313 __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
1314 __ jmp(&allocated);
1315
1316 __ bind(&runtime_allocate);
1317 __ push(rbx);
1318 __ Push(Smi::FromInt(size));
1319 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1320 __ pop(rbx);
1321
1322 __ bind(&allocated);
1323 // Copy the content into the newly allocated memory.
1324 // (Unroll copy loop once for better throughput).
1325 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1326 __ movq(rdx, FieldOperand(rbx, i));
1327 __ movq(rcx, FieldOperand(rbx, i + kPointerSize));
1328 __ movq(FieldOperand(rax, i), rdx);
1329 __ movq(FieldOperand(rax, i + kPointerSize), rcx);
1330 }
1331 if ((size % (2 * kPointerSize)) != 0) {
1332 __ movq(rdx, FieldOperand(rbx, size - kPointerSize));
1333 __ movq(FieldOperand(rax, size - kPointerSize), rdx);
1334 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001335 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001336}
1337
1338
1339void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1340 Comment cmnt(masm_, "[ ObjectLiteral");
1341 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1342 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
1343 __ Push(Smi::FromInt(expr->literal_index()));
1344 __ Push(expr->constant_properties());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001345 int flags = expr->fast_elements()
1346 ? ObjectLiteral::kFastElements
1347 : ObjectLiteral::kNoFlags;
1348 flags |= expr->has_function()
1349 ? ObjectLiteral::kHasFunction
1350 : ObjectLiteral::kNoFlags;
1351 __ Push(Smi::FromInt(flags));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001352 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001353 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001354 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001355 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001356 }
1357
1358 // If result_saved is true the result is on top of the stack. If
1359 // result_saved is false the result is in rax.
1360 bool result_saved = false;
1361
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001362 // Mark all computed expressions that are bound to a key that
1363 // is shadowed by a later occurrence of the same key. For the
1364 // marked expressions, no store code is emitted.
1365 expr->CalculateEmitStore();
1366
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001367 for (int i = 0; i < expr->properties()->length(); i++) {
1368 ObjectLiteral::Property* property = expr->properties()->at(i);
1369 if (property->IsCompileTimeValue()) continue;
1370
1371 Literal* key = property->key();
1372 Expression* value = property->value();
1373 if (!result_saved) {
1374 __ push(rax); // Save result on the stack
1375 result_saved = true;
1376 }
1377 switch (property->kind()) {
1378 case ObjectLiteral::Property::CONSTANT:
1379 UNREACHABLE();
1380 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1381 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1382 // Fall through.
1383 case ObjectLiteral::Property::COMPUTED:
1384 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001385 if (property->emit_store()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001386 VisitForAccumulatorValue(value);
1387 __ Move(rcx, key->handle());
1388 __ movq(rdx, Operand(rsp, 0));
1389 Handle<Code> ic = is_strict_mode()
1390 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1391 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001392 __ call(ic, RelocInfo::CODE_TARGET, key->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001393 PrepareForBailoutForId(key->id(), NO_REGISTERS);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001394 } else {
1395 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001396 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001397 break;
1398 }
1399 // Fall through.
1400 case ObjectLiteral::Property::PROTOTYPE:
1401 __ push(Operand(rsp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001402 VisitForStackValue(key);
1403 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001404 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001405 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1406 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001407 } else {
1408 __ Drop(3);
1409 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001410 break;
1411 case ObjectLiteral::Property::SETTER:
1412 case ObjectLiteral::Property::GETTER:
1413 __ push(Operand(rsp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001414 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001415 __ Push(property->kind() == ObjectLiteral::Property::SETTER ?
1416 Smi::FromInt(1) :
1417 Smi::FromInt(0));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001418 VisitForStackValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001419 __ CallRuntime(Runtime::kDefineAccessor, 4);
1420 break;
1421 }
1422 }
1423
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001424 if (expr->has_function()) {
1425 ASSERT(result_saved);
1426 __ push(Operand(rsp, 0));
1427 __ CallRuntime(Runtime::kToFastProperties, 1);
1428 }
1429
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001430 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001431 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001432 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001433 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001434 }
1435}
1436
1437
1438void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1439 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001440
1441 ZoneList<Expression*>* subexprs = expr->values();
1442 int length = subexprs->length();
1443
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001444 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1445 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1446 __ Push(Smi::FromInt(expr->literal_index()));
1447 __ Push(expr->constant_elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001448 if (expr->constant_elements()->map() ==
1449 isolate()->heap()->fixed_cow_array_map()) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001450 FastCloneShallowArrayStub stub(
1451 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1452 __ CallStub(&stub);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001453 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001454 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001455 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001456 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001457 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001458 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001459 FastCloneShallowArrayStub stub(
1460 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001461 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001462 }
1463
1464 bool result_saved = false; // Is the result saved to the stack?
1465
1466 // Emit code to evaluate all the non-constant subexpressions and to store
1467 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001468 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001469 Expression* subexpr = subexprs->at(i);
1470 // If the subexpression is a literal or a simple materialized literal it
1471 // is already set in the cloned array.
1472 if (subexpr->AsLiteral() != NULL ||
1473 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1474 continue;
1475 }
1476
1477 if (!result_saved) {
1478 __ push(rax);
1479 result_saved = true;
1480 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001481 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001482
1483 // Store the subexpression value in the array's elements.
1484 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1485 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
1486 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1487 __ movq(FieldOperand(rbx, offset), result_register());
1488
1489 // Update the write barrier for the array store.
1490 __ RecordWrite(rbx, offset, result_register(), rcx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001491
1492 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001493 }
1494
1495 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001496 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001497 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001498 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001499 }
1500}
1501
1502
ager@chromium.org5c838252010-02-19 08:53:10 +00001503void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1504 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001505 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1506 // on the left-hand side.
1507 if (!expr->target()->IsValidLeftHandSide()) {
1508 VisitForEffect(expr->target());
1509 return;
1510 }
1511
ager@chromium.org5c838252010-02-19 08:53:10 +00001512 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001513 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001514 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1515 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001516 Property* property = expr->target()->AsProperty();
1517 if (property != NULL) {
1518 assign_type = (property->key()->IsPropertyName())
1519 ? NAMED_PROPERTY
1520 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001521 }
1522
1523 // Evaluate LHS expression.
1524 switch (assign_type) {
1525 case VARIABLE:
1526 // Nothing to do here.
1527 break;
1528 case NAMED_PROPERTY:
1529 if (expr->is_compound()) {
1530 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001531 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001532 __ push(result_register());
1533 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001534 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001535 }
1536 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001537 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001538 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001539 VisitForStackValue(property->obj());
1540 VisitForAccumulatorValue(property->key());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001541 __ movq(rdx, Operand(rsp, 0));
1542 __ push(rax);
1543 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001544 VisitForStackValue(property->obj());
1545 VisitForStackValue(property->key());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001546 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001547 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001548 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001549 }
1550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001551 // For compound assignments we need another deoptimization point after the
1552 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001553 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001554 { AccumulatorValueContext context(this);
1555 switch (assign_type) {
1556 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001557 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001558 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001559 break;
1560 case NAMED_PROPERTY:
1561 EmitNamedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001562 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001563 break;
1564 case KEYED_PROPERTY:
1565 EmitKeyedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001566 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001567 break;
1568 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001569 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001570
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001571 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001572 __ push(rax); // Left operand goes on the stack.
1573 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001574
ricow@chromium.org65fae842010-08-25 15:26:24 +00001575 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1576 ? OVERWRITE_RIGHT
1577 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001578 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001579 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001580 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001581 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001582 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001583 mode,
1584 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001585 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001586 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001587 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001588 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001589 // Deoptimization point in case the binary operation may have side effects.
1590 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001591 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001592 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001593 }
1594
1595 // Record source position before possible IC call.
1596 SetSourcePosition(expr->position());
1597
1598 // Store the value.
1599 switch (assign_type) {
1600 case VARIABLE:
1601 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001602 expr->op());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001603 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001604 context()->Plug(rax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001605 break;
1606 case NAMED_PROPERTY:
1607 EmitNamedPropertyAssignment(expr);
1608 break;
1609 case KEYED_PROPERTY:
1610 EmitKeyedPropertyAssignment(expr);
1611 break;
1612 }
1613}
1614
1615
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001616void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1617 SetSourcePosition(prop->position());
1618 Literal* key = prop->key()->AsLiteral();
1619 __ Move(rcx, key->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001620 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001621 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001622}
1623
1624
1625void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1626 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001627 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001628 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001629}
1630
1631
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001632void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001633 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001634 OverwriteMode mode,
1635 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001636 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001637 // Do combined smi check of the operands. Left operand is on the
1638 // stack (popped into rdx). Right operand is in rax but moved into
1639 // rcx to make the shifts easier.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001640 Label done, stub_call, smi_case;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001641 __ pop(rdx);
1642 __ movq(rcx, rax);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001643 __ or_(rax, rdx);
1644 JumpPatchSite patch_site(masm_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001645 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001646
1647 __ bind(&stub_call);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001648 __ movq(rax, rcx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001649 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001650 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1651 patch_site.EmitPatchInfo();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001652 __ jmp(&done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001653
1654 __ bind(&smi_case);
1655 switch (op) {
1656 case Token::SAR:
1657 __ SmiShiftArithmeticRight(rax, rdx, rcx);
1658 break;
1659 case Token::SHL:
1660 __ SmiShiftLeft(rax, rdx, rcx);
1661 break;
1662 case Token::SHR:
1663 __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
1664 break;
1665 case Token::ADD:
1666 __ SmiAdd(rax, rdx, rcx, &stub_call);
1667 break;
1668 case Token::SUB:
1669 __ SmiSub(rax, rdx, rcx, &stub_call);
1670 break;
1671 case Token::MUL:
1672 __ SmiMul(rax, rdx, rcx, &stub_call);
1673 break;
1674 case Token::BIT_OR:
1675 __ SmiOr(rax, rdx, rcx);
1676 break;
1677 case Token::BIT_AND:
1678 __ SmiAnd(rax, rdx, rcx);
1679 break;
1680 case Token::BIT_XOR:
1681 __ SmiXor(rax, rdx, rcx);
1682 break;
1683 default:
1684 UNREACHABLE();
1685 break;
1686 }
1687
1688 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001689 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001690}
1691
1692
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001693void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1694 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001695 OverwriteMode mode) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001696 __ pop(rdx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001697 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001698 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
1699 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1700 patch_site.EmitPatchInfo();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001701 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001702}
1703
1704
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001705void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001706 // Invalid left-hand sides are rewritten to have a 'throw
1707 // ReferenceError' on the left-hand side.
1708 if (!expr->IsValidLeftHandSide()) {
1709 VisitForEffect(expr);
1710 return;
1711 }
1712
1713 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001714 // slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001715 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1716 LhsKind assign_type = VARIABLE;
1717 Property* prop = expr->AsProperty();
1718 if (prop != NULL) {
1719 assign_type = (prop->key()->IsPropertyName())
1720 ? NAMED_PROPERTY
1721 : KEYED_PROPERTY;
1722 }
1723
1724 switch (assign_type) {
1725 case VARIABLE: {
1726 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001727 EffectContext context(this);
1728 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001729 break;
1730 }
1731 case NAMED_PROPERTY: {
1732 __ push(rax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001733 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001734 __ movq(rdx, rax);
1735 __ pop(rax); // Restore value.
1736 __ Move(rcx, prop->key()->AsLiteral()->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001737 Handle<Code> ic = is_strict_mode()
1738 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1739 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001740 __ call(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001741 break;
1742 }
1743 case KEYED_PROPERTY: {
1744 __ push(rax); // Preserve value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001745 VisitForStackValue(prop->obj());
1746 VisitForAccumulatorValue(prop->key());
1747 __ movq(rcx, rax);
1748 __ pop(rdx);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001749 __ pop(rax); // Restore value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001750 Handle<Code> ic = is_strict_mode()
1751 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1752 : isolate()->builtins()->KeyedStoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001753 __ call(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001754 break;
1755 }
1756 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001757 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001758 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001759}
1760
1761
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001762void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001763 Token::Value op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001764 ASSERT(var != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001765 ASSERT(var->is_global() || var->AsSlot() != NULL);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001766
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001767 if (var->is_global()) {
1768 ASSERT(!var->is_this());
1769 // Assignment to a global variable. Use inline caching for the
1770 // assignment. Right-hand-side value is passed in rax, variable name in
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001771 // rcx, and the global object on the stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001772 __ Move(rcx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001773 __ movq(rdx, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001774 Handle<Code> ic = is_strict_mode()
1775 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1776 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001777 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001778
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001779 } else if (op == Token::INIT_CONST) {
1780 // Like var declarations, const declarations are hoisted to function
1781 // scope. However, unlike var initializers, const initializers are able
1782 // to drill a hole to that function context, even from inside a 'with'
1783 // context. We thus bypass the normal static scope lookup.
1784 Slot* slot = var->AsSlot();
1785 Label skip;
1786 switch (slot->type()) {
1787 case Slot::PARAMETER:
1788 // No const parameters.
1789 UNREACHABLE();
1790 break;
1791 case Slot::LOCAL:
1792 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1793 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1794 __ j(not_equal, &skip);
1795 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1796 break;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001797 case Slot::CONTEXT:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001798 case Slot::LOOKUP:
1799 __ push(rax);
1800 __ push(rsi);
1801 __ Push(var->name());
1802 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1803 break;
1804 }
1805 __ bind(&skip);
1806
1807 } else if (var->mode() != Variable::CONST) {
1808 // Perform the assignment for non-const variables. Const assignments
1809 // are simply skipped.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001810 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001811 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001812 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001813 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001814 // Perform the assignment.
1815 __ movq(Operand(rbp, SlotOffset(slot)), rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001816 break;
1817
1818 case Slot::CONTEXT: {
1819 MemOperand target = EmitSlotSearch(slot, rcx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001820 // Perform the assignment and issue the write barrier.
1821 __ movq(target, rax);
1822 // The value of the assignment is in rax. RecordWrite clobbers its
1823 // register arguments.
1824 __ movq(rdx, rax);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001825 int offset = Context::SlotOffset(slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001826 __ RecordWrite(rcx, offset, rdx, rbx);
1827 break;
1828 }
1829
1830 case Slot::LOOKUP:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001831 // Call the runtime for the assignment.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001832 __ push(rax); // Value.
1833 __ push(rsi); // Context.
1834 __ Push(var->name());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001835 __ Push(Smi::FromInt(strict_mode_flag()));
1836 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001837 break;
1838 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001839 }
1840}
1841
1842
1843void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1844 // Assignment to a property, using a named store IC.
1845 Property* prop = expr->target()->AsProperty();
1846 ASSERT(prop != NULL);
1847 ASSERT(prop->key()->AsLiteral() != NULL);
1848
1849 // If the assignment starts a block of assignments to the same object,
1850 // change to slow case to avoid the quadratic behavior of repeatedly
1851 // adding fast properties.
1852 if (expr->starts_initialization_block()) {
1853 __ push(result_register());
1854 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value.
1855 __ CallRuntime(Runtime::kToSlowProperties, 1);
1856 __ pop(result_register());
1857 }
1858
1859 // Record source code position before IC call.
1860 SetSourcePosition(expr->position());
1861 __ Move(rcx, prop->key()->AsLiteral()->handle());
1862 if (expr->ends_initialization_block()) {
1863 __ movq(rdx, Operand(rsp, 0));
1864 } else {
1865 __ pop(rdx);
1866 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001867 Handle<Code> ic = is_strict_mode()
1868 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1869 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001870 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001871
1872 // If the assignment ends an initialization block, revert to fast case.
1873 if (expr->ends_initialization_block()) {
1874 __ push(rax); // Result of assignment, saved even if not needed.
1875 __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
1876 __ CallRuntime(Runtime::kToFastProperties, 1);
1877 __ pop(rax);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001878 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001879 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001880 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001881 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001882}
1883
1884
1885void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1886 // Assignment to a property, using a keyed store IC.
1887
1888 // If the assignment starts a block of assignments to the same object,
1889 // change to slow case to avoid the quadratic behavior of repeatedly
1890 // adding fast properties.
1891 if (expr->starts_initialization_block()) {
1892 __ push(result_register());
1893 // Receiver is now under the key and value.
1894 __ push(Operand(rsp, 2 * kPointerSize));
1895 __ CallRuntime(Runtime::kToSlowProperties, 1);
1896 __ pop(result_register());
1897 }
1898
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001899 __ pop(rcx);
1900 if (expr->ends_initialization_block()) {
1901 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later.
1902 } else {
1903 __ pop(rdx);
1904 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001905 // Record source code position before IC call.
1906 SetSourcePosition(expr->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001907 Handle<Code> ic = is_strict_mode()
1908 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1909 : isolate()->builtins()->KeyedStoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001910 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001911
1912 // If the assignment ends an initialization block, revert to fast case.
1913 if (expr->ends_initialization_block()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001914 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001915 __ push(rax); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001916 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001917 __ CallRuntime(Runtime::kToFastProperties, 1);
1918 __ pop(rax);
1919 }
1920
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001921 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001922 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001923}
1924
1925
1926void FullCodeGenerator::VisitProperty(Property* expr) {
1927 Comment cmnt(masm_, "[ Property");
1928 Expression* key = expr->key();
1929
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001930 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001931 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001932 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001933 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001934 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001935 VisitForStackValue(expr->obj());
1936 VisitForAccumulatorValue(expr->key());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001937 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001938 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001939 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001940 }
1941}
1942
1943
1944void FullCodeGenerator::EmitCallWithIC(Call* expr,
ager@chromium.org5c838252010-02-19 08:53:10 +00001945 Handle<Object> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001946 RelocInfo::Mode mode) {
1947 // Code common for calls using the IC.
1948 ZoneList<Expression*>* args = expr->arguments();
1949 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001950 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001951 for (int i = 0; i < arg_count; i++) {
1952 VisitForStackValue(args->at(i));
1953 }
1954 __ Move(rcx, name);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001955 }
1956 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001957 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001958 // Call the IC initialization code.
1959 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001960 Handle<Code> ic =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001961 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001962 __ call(ic, mode, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001963 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001964 // Restore context register.
1965 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001966 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001967}
1968
1969
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001970void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00001971 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001972 // Load the key.
1973 VisitForAccumulatorValue(key);
1974
1975 // Swap the name of the function and the receiver on the stack to follow
1976 // the calling convention for call ICs.
1977 __ pop(rcx);
1978 __ push(rax);
1979 __ push(rcx);
1980
1981 // Load the arguments.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001982 ZoneList<Expression*>* args = expr->arguments();
1983 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001984 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001985 for (int i = 0; i < arg_count; i++) {
1986 VisitForStackValue(args->at(i));
1987 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001988 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001989 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001990 SetSourcePosition(expr->position());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001991 // Call the IC initialization code.
1992 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001993 Handle<Code> ic =
1994 ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001995 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001996 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001997 RecordJSReturnSite(expr);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001998 // Restore context register.
1999 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002000 context()->DropAndPlug(1, rax); // Drop the key still on the stack.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002001}
2002
2003
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002004void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002005 // Code common for calls using the call stub.
2006 ZoneList<Expression*>* args = expr->arguments();
2007 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002009 for (int i = 0; i < arg_count; i++) {
2010 VisitForStackValue(args->at(i));
2011 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002012 }
2013 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002014 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002015 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002016 CallFunctionStub stub(arg_count, in_loop, flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002017 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002018 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002019 // Restore context register.
2020 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2021 // Discard the function left on TOS.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002022 context()->DropAndPlug(1, rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002023}
2024
2025
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002026void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2027 int arg_count) {
2028 // Push copy of the first argument or undefined if it doesn't exist.
2029 if (arg_count > 0) {
2030 __ push(Operand(rsp, arg_count * kPointerSize));
2031 } else {
2032 __ PushRoot(Heap::kUndefinedValueRootIndex);
2033 }
2034
2035 // Push the receiver of the enclosing function and do runtime call.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002036 __ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002037
2038 // Push the strict mode flag.
2039 __ Push(Smi::FromInt(strict_mode_flag()));
2040
2041 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2042 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2043 : Runtime::kResolvePossiblyDirectEval, 4);
2044}
2045
2046
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002047void FullCodeGenerator::VisitCall(Call* expr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002048#ifdef DEBUG
2049 // We want to verify that RecordJSReturnSite gets called on all paths
2050 // through this function. Avoid early returns.
2051 expr->return_is_recorded_ = false;
2052#endif
2053
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002054 Comment cmnt(masm_, "[ Call");
2055 Expression* fun = expr->expression();
2056 Variable* var = fun->AsVariableProxy()->AsVariable();
2057
2058 if (var != NULL && var->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002059 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2060 // resolve the function we need to call and the receiver of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002061 // call. Then we call the resolved function using the given
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002062 // arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002063 ZoneList<Expression*>* args = expr->arguments();
2064 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002065 { PreservePositionScope pos_scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002066 VisitForStackValue(fun);
2067 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002068
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002069 // Push the arguments.
2070 for (int i = 0; i < arg_count; i++) {
2071 VisitForStackValue(args->at(i));
2072 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002073
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002074 // If we know that eval can only be shadowed by eval-introduced
2075 // variables we attempt to load the global eval function directly
2076 // in generated code. If we succeed, there is no need to perform a
2077 // context lookup in the runtime system.
2078 Label done;
2079 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2080 Label slow;
2081 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2082 NOT_INSIDE_TYPEOF,
2083 &slow);
2084 // Push the function and resolve eval.
2085 __ push(rax);
2086 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2087 __ jmp(&done);
2088 __ bind(&slow);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002089 }
2090
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002091 // Push copy of the function (found below the arguments) and
2092 // resolve eval.
2093 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
2094 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2095 if (done.is_linked()) {
2096 __ bind(&done);
2097 }
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002098
2099 // The runtime call returns a pair of values in rax (function) and
2100 // rdx (receiver). Touch up the stack with the right values.
2101 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
2102 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002103 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002104 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002105 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002106 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002107 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002108 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002109 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002110 // Restore context register.
2111 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002112 context()->DropAndPlug(1, rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002113 } else if (var != NULL && !var->is_this() && var->is_global()) {
2114 // Call to a global variable.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002115 // Push global object as receiver for the call IC lookup.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002116 __ push(GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002117 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002118 } else if (var != NULL && var->AsSlot() != NULL &&
2119 var->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002120 // Call to a lookup slot (dynamically introduced variable).
2121 Label slow, done;
2122
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002123 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002124 // Generate code for loading from variables potentially shadowed
2125 // by eval-introduced variables.
2126 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
2127 NOT_INSIDE_TYPEOF,
2128 &slow,
2129 &done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002130
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002131 __ bind(&slow);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002132 }
2133 // Call the runtime to find the function to call (returned in rax)
2134 // and the object holding it (returned in rdx).
2135 __ push(context_register());
2136 __ Push(var->name());
2137 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2138 __ push(rax); // Function.
2139 __ push(rdx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002140
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002141 // If fast case code has been generated, emit code to push the
2142 // function and receiver and have the slow path jump around this
2143 // code.
2144 if (done.is_linked()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002145 Label call;
2146 __ jmp(&call, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002147 __ bind(&done);
2148 // Push function.
2149 __ push(rax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002150 // The receiver is implicitly the global receiver. Indicate this
2151 // by passing the hole to the call function stub.
2152 __ PushRoot(Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002153 __ bind(&call);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002154 }
2155
danno@chromium.org40cb8782011-05-25 07:58:50 +00002156 // The receiver is either the global receiver or an object found
2157 // by LoadContextSlot. That object could be the hole if the
2158 // receiver is implicitly the global object.
2159 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002160 } else if (fun->AsProperty() != NULL) {
2161 // Call to an object property.
2162 Property* prop = fun->AsProperty();
2163 Literal* key = prop->key()->AsLiteral();
2164 if (key != NULL && key->handle()->IsSymbol()) {
2165 // Call to a named property, use call IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002166 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002167 VisitForStackValue(prop->obj());
2168 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002169 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
2170 } else {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002171 // Call to a keyed property.
2172 // For a synthetic property use keyed load IC followed by function call,
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002173 // for a regular property use EmitKeyedCallWithIC.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002174 if (prop->is_synthetic()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002175 // Do not visit the object and key subexpressions (they are shared
2176 // by all occurrences of the same rewritten parameter).
2177 ASSERT(prop->obj()->AsVariableProxy() != NULL);
2178 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
2179 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
2180 MemOperand operand = EmitSlotSearch(slot, rdx);
2181 __ movq(rdx, operand);
2182
2183 ASSERT(prop->key()->AsLiteral() != NULL);
2184 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
2185 __ Move(rax, prop->key()->AsLiteral()->handle());
2186
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002187 // Record source code position for IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002188 SetSourcePosition(prop->position());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002189
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002190 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002191 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002192 // Push result (function).
2193 __ push(rax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002194 // Push Global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002195 __ movq(rcx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002196 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002197 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002198 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002199 { PreservePositionScope scope(masm()->positions_recorder());
2200 VisitForStackValue(prop->obj());
2201 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002202 EmitKeyedCallWithIC(expr, prop->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002203 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002204 }
2205 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002206 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002207 VisitForStackValue(fun);
2208 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002209 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002210 __ movq(rbx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002211 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
2212 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002213 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002214 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002215
2216#ifdef DEBUG
2217 // RecordJSReturnSite should have been called.
2218 ASSERT(expr->return_is_recorded_);
2219#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002220}
2221
2222
2223void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2224 Comment cmnt(masm_, "[ CallNew");
2225 // According to ECMA-262, section 11.2.2, page 44, the function
2226 // expression in new calls must be evaluated before the
2227 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002228
ricow@chromium.org65fae842010-08-25 15:26:24 +00002229 // Push constructor on the stack. If it's not a function it's used as
2230 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2231 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002232 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002233
2234 // Push the arguments ("left-to-right") on the stack.
2235 ZoneList<Expression*>* args = expr->arguments();
2236 int arg_count = args->length();
2237 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002238 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002239 }
2240
2241 // Call the construct call builtin that handles allocation and
2242 // constructor invocation.
2243 SetSourcePosition(expr->position());
2244
ricow@chromium.org65fae842010-08-25 15:26:24 +00002245 // Load function and argument count into rdi and rax.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002246 __ Set(rax, arg_count);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002247 __ movq(rdi, Operand(rsp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002248
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002249 Handle<Code> construct_builtin =
2250 isolate()->builtins()->JSConstructCall();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002251 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002252 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002253}
2254
2255
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002256void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2257 ASSERT(args->length() == 1);
2258
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002259 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002260
2261 Label materialize_true, materialize_false;
2262 Label* if_true = NULL;
2263 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002264 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002265 context()->PrepareTest(&materialize_true, &materialize_false,
2266 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002267
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002268 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002269 __ JumpIfSmi(rax, if_true);
2270 __ jmp(if_false);
2271
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002272 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002273}
2274
2275
2276void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2277 ASSERT(args->length() == 1);
2278
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002279 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002280
2281 Label materialize_true, materialize_false;
2282 Label* if_true = NULL;
2283 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002284 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002285 context()->PrepareTest(&materialize_true, &materialize_false,
2286 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002287
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002288 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00002289 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
2290 Split(non_negative_smi, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002291
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002292 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002293}
2294
2295
2296void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2297 ASSERT(args->length() == 1);
2298
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002299 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002300
2301 Label materialize_true, materialize_false;
2302 Label* if_true = NULL;
2303 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002304 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002305 context()->PrepareTest(&materialize_true, &materialize_false,
2306 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002307
2308 __ JumpIfSmi(rax, if_false);
2309 __ CompareRoot(rax, Heap::kNullValueRootIndex);
2310 __ j(equal, if_true);
2311 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2312 // Undetectable objects behave like undefined when tested with typeof.
2313 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2314 Immediate(1 << Map::kIsUndetectable));
2315 __ j(not_zero, if_false);
2316 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002317 __ cmpq(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002318 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002319 __ cmpq(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002320 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002321 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002322
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002323 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002324}
2325
2326
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002327void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2328 ASSERT(args->length() == 1);
2329
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002330 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002331
2332 Label materialize_true, materialize_false;
2333 Label* if_true = NULL;
2334 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002335 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002336 context()->PrepareTest(&materialize_true, &materialize_false,
2337 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002338
2339 __ JumpIfSmi(rax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002340 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002341 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002342 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002343
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002344 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002345}
2346
2347
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002348void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2349 ASSERT(args->length() == 1);
2350
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002351 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002352
2353 Label materialize_true, materialize_false;
2354 Label* if_true = NULL;
2355 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002356 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002357 context()->PrepareTest(&materialize_true, &materialize_false,
2358 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002359
2360 __ JumpIfSmi(rax, if_false);
2361 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2362 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2363 Immediate(1 << Map::kIsUndetectable));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002364 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002365 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002366
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002367 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002368}
2369
2370
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002371void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2372 ZoneList<Expression*>* args) {
2373 ASSERT(args->length() == 1);
2374
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002375 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002376
2377 Label materialize_true, materialize_false;
2378 Label* if_true = NULL;
2379 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002380 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002381 context()->PrepareTest(&materialize_true, &materialize_false,
2382 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002384 if (FLAG_debug_code) __ AbortIfSmi(rax);
2385
2386 // Check whether this map has already been checked to be safe for default
2387 // valueOf.
2388 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2389 __ testb(FieldOperand(rbx, Map::kBitField2Offset),
2390 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2391 __ j(not_zero, if_true);
2392
2393 // Check for fast case object. Generate false result for slow case object.
2394 __ movq(rcx, FieldOperand(rax, JSObject::kPropertiesOffset));
2395 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2396 __ CompareRoot(rcx, Heap::kHashTableMapRootIndex);
2397 __ j(equal, if_false);
2398
2399 // Look for valueOf symbol in the descriptor array, and indicate false if
2400 // found. The type is not checked, so if it is a transition it is a false
2401 // negative.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002402 __ LoadInstanceDescriptors(rbx, rbx);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002403 __ movq(rcx, FieldOperand(rbx, FixedArray::kLengthOffset));
2404 // rbx: descriptor array
2405 // rcx: length of descriptor array
2406 // Calculate the end of the descriptor array.
2407 SmiIndex index = masm_->SmiToIndex(rdx, rcx, kPointerSizeLog2);
2408 __ lea(rcx,
2409 Operand(
2410 rbx, index.reg, index.scale, FixedArray::kHeaderSize));
2411 // Calculate location of the first key name.
2412 __ addq(rbx,
2413 Immediate(FixedArray::kHeaderSize +
2414 DescriptorArray::kFirstIndex * kPointerSize));
2415 // Loop through all the keys in the descriptor array. If one of these is the
2416 // symbol valueOf the result is false.
2417 Label entry, loop;
2418 __ jmp(&entry);
2419 __ bind(&loop);
2420 __ movq(rdx, FieldOperand(rbx, 0));
2421 __ Cmp(rdx, FACTORY->value_of_symbol());
2422 __ j(equal, if_false);
2423 __ addq(rbx, Immediate(kPointerSize));
2424 __ bind(&entry);
2425 __ cmpq(rbx, rcx);
2426 __ j(not_equal, &loop);
2427
2428 // Reload map as register rbx was used as temporary above.
2429 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2430
2431 // If a valueOf property is not found on the object check that it's
2432 // prototype is the un-modified String prototype. If not result is false.
2433 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
2434 __ testq(rcx, Immediate(kSmiTagMask));
2435 __ j(zero, if_false);
2436 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2437 __ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2438 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
2439 __ cmpq(rcx,
2440 ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2441 __ j(not_equal, if_false);
2442 // Set the bit in the map to indicate that it has been checked safe for
2443 // default valueOf and set true result.
2444 __ or_(FieldOperand(rbx, Map::kBitField2Offset),
2445 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2446 __ jmp(if_true);
2447
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002448 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002449 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002450}
2451
2452
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002453void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2454 ASSERT(args->length() == 1);
2455
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002456 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002457
2458 Label materialize_true, materialize_false;
2459 Label* if_true = NULL;
2460 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002461 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002462 context()->PrepareTest(&materialize_true, &materialize_false,
2463 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002464
2465 __ JumpIfSmi(rax, if_false);
2466 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002467 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002468 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002469
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002470 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002471}
2472
2473
2474void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2475 ASSERT(args->length() == 1);
2476
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002477 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002478
2479 Label materialize_true, materialize_false;
2480 Label* if_true = NULL;
2481 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002482 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002483 context()->PrepareTest(&materialize_true, &materialize_false,
2484 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002485
2486 __ JumpIfSmi(rax, if_false);
2487 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002488 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002489 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002490
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002491 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002492}
2493
2494
2495void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2496 ASSERT(args->length() == 1);
2497
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002498 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002499
2500 Label materialize_true, materialize_false;
2501 Label* if_true = NULL;
2502 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002503 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002504 context()->PrepareTest(&materialize_true, &materialize_false,
2505 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002506
2507 __ JumpIfSmi(rax, if_false);
2508 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002509 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002510 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002511
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002512 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002513}
2514
2515
2516
2517void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2518 ASSERT(args->length() == 0);
2519
2520 Label materialize_true, materialize_false;
2521 Label* if_true = NULL;
2522 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002523 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002524 context()->PrepareTest(&materialize_true, &materialize_false,
2525 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002526
2527 // Get the frame pointer for the calling frame.
2528 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2529
2530 // Skip the arguments adaptor frame if it exists.
2531 Label check_frame_marker;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002532 __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset),
2533 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002534 __ j(not_equal, &check_frame_marker);
2535 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
2536
2537 // Check the marker in the calling frame.
2538 __ bind(&check_frame_marker);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002539 __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
2540 Smi::FromInt(StackFrame::CONSTRUCT));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002541 PrepareForBailoutBeforeSplit(TOS_REG, 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
2548void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2549 ASSERT(args->length() == 2);
2550
2551 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002552 VisitForStackValue(args->at(0));
2553 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002554
2555 Label materialize_true, materialize_false;
2556 Label* if_true = NULL;
2557 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002558 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002559 context()->PrepareTest(&materialize_true, &materialize_false,
2560 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002561
2562 __ pop(rbx);
2563 __ cmpq(rax, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002564 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002565 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002566
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002567 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002568}
2569
2570
2571void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2572 ASSERT(args->length() == 1);
2573
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002574 // ArgumentsAccessStub expects the key in rdx and the formal
2575 // parameter count in rax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002576 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002577 __ movq(rdx, rax);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002578 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002579 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2580 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002581 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002582}
2583
2584
2585void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2586 ASSERT(args->length() == 0);
2587
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002588 Label exit;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002589 // Get the number of formal parameters.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002590 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002591
2592 // Check if the calling frame is an arguments adaptor frame.
2593 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002594 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
2595 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002596 __ j(not_equal, &exit, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002597
2598 // Arguments adaptor case: Read the arguments length from the
2599 // adaptor frame.
2600 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2601
2602 __ bind(&exit);
2603 if (FLAG_debug_code) __ AbortIfNotSmi(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002604 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002605}
2606
2607
2608void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2609 ASSERT(args->length() == 1);
2610 Label done, null, function, non_function_constructor;
2611
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002612 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002613
2614 // If the object is a smi, we return null.
2615 __ JumpIfSmi(rax, &null);
2616
2617 // Check that the object is a JS object but take special care of JS
2618 // functions to make sure they have 'Function' as their class.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002619 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
2620 // Map is now in rax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002621 __ j(below, &null);
2622
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002623 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
2624 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
2625 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
2626 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
2627 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
2628 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
2629 __ CmpInstanceType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
2630 __ j(above_equal, &function);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002631
2632 // Check if the constructor in the map is a function.
2633 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
2634 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2635 __ j(not_equal, &non_function_constructor);
2636
2637 // rax now contains the constructor function. Grab the
2638 // instance class name from there.
2639 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
2640 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
2641 __ jmp(&done);
2642
2643 // Functions have class 'Function'.
2644 __ bind(&function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002645 __ Move(rax, isolate()->factory()->function_class_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002646 __ jmp(&done);
2647
2648 // Objects with a non-function constructor have class 'Object'.
2649 __ bind(&non_function_constructor);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002650 __ Move(rax, isolate()->factory()->Object_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002651 __ jmp(&done);
2652
2653 // Non-JS objects have class null.
2654 __ bind(&null);
2655 __ LoadRoot(rax, Heap::kNullValueRootIndex);
2656
2657 // All done.
2658 __ bind(&done);
2659
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002660 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002661}
2662
2663
2664void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2665 // Conditionally generate a log call.
2666 // Args:
2667 // 0 (literal string): The type of logging (corresponds to the flags).
2668 // This is used to determine whether or not to generate the log call.
2669 // 1 (string): Format string. Access the string at argument index 2
2670 // with '%2s' (see Logger::LogRuntime for all the formats).
2671 // 2 (array): Arguments to the format string.
2672 ASSERT_EQ(args->length(), 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002673 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002674 VisitForStackValue(args->at(1));
2675 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002676 __ CallRuntime(Runtime::kLog, 2);
2677 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002678 // Finally, we're expected to leave a value on the top of the stack.
2679 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002680 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002681}
2682
2683
2684void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2685 ASSERT(args->length() == 0);
2686
2687 Label slow_allocate_heapnumber;
2688 Label heapnumber_allocated;
2689
2690 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
2691 __ jmp(&heapnumber_allocated);
2692
2693 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002694 // Allocate a heap number.
2695 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002696 __ movq(rbx, rax);
2697
2698 __ bind(&heapnumber_allocated);
2699
2700 // Return a random uint32 number in rax.
2701 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002702 __ PrepareCallCFunction(1);
2703#ifdef _WIN64
2704 __ LoadAddress(rcx, ExternalReference::isolate_address());
2705#else
2706 __ LoadAddress(rdi, ExternalReference::isolate_address());
2707#endif
2708 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002709
2710 // Convert 32 random bits in rax to 0.(32 random bits) in a double
2711 // by computing:
2712 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2713 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2714 __ movd(xmm1, rcx);
2715 __ movd(xmm0, rax);
2716 __ cvtss2sd(xmm1, xmm1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002717 __ xorps(xmm0, xmm1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002718 __ subsd(xmm0, xmm1);
2719 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
2720
2721 __ movq(rax, rbx);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002722 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002723}
2724
2725
2726void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2727 // Load the arguments on the stack and call the stub.
2728 SubStringStub stub;
2729 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002730 VisitForStackValue(args->at(0));
2731 VisitForStackValue(args->at(1));
2732 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002733 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002734 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002735}
2736
2737
2738void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2739 // Load the arguments on the stack and call the stub.
2740 RegExpExecStub stub;
2741 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002742 VisitForStackValue(args->at(0));
2743 VisitForStackValue(args->at(1));
2744 VisitForStackValue(args->at(2));
2745 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002746 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002747 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002748}
2749
2750
2751void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2752 ASSERT(args->length() == 1);
2753
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002754 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002755
2756 Label done;
2757 // If the object is a smi return the object.
2758 __ JumpIfSmi(rax, &done);
2759 // If the object is not a value type, return the object.
2760 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
2761 __ j(not_equal, &done);
2762 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset));
2763
2764 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002765 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002766}
2767
2768
2769void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2770 // Load the arguments on the stack and call the runtime function.
2771 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002772 VisitForStackValue(args->at(0));
2773 VisitForStackValue(args->at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002774 MathPowStub stub;
2775 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002776 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002777}
2778
2779
2780void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2781 ASSERT(args->length() == 2);
2782
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002783 VisitForStackValue(args->at(0)); // Load the object.
2784 VisitForAccumulatorValue(args->at(1)); // Load the value.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002785 __ pop(rbx); // rax = value. rbx = object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002786
2787 Label done;
2788 // If the object is a smi, return the value.
2789 __ JumpIfSmi(rbx, &done);
2790
2791 // If the object is not a value type, return the value.
2792 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
2793 __ j(not_equal, &done);
2794
2795 // Store the value.
2796 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax);
2797 // Update the write barrier. Save the value as it will be
2798 // overwritten by the write barrier code and is needed afterward.
2799 __ movq(rdx, rax);
2800 __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx);
2801
2802 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002803 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002804}
2805
2806
2807void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2808 ASSERT_EQ(args->length(), 1);
2809
2810 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002811 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002812
2813 NumberToStringStub stub;
2814 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002815 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002816}
2817
2818
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002819void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
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));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002823
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002824 Label done;
2825 StringCharFromCodeGenerator generator(rax, rbx);
2826 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002827 __ jmp(&done);
2828
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002829 NopRuntimeCallHelper call_helper;
2830 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002831
2832 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002833 context()->Plug(rbx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002834}
2835
2836
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002837void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2838 ASSERT(args->length() == 2);
2839
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002840 VisitForStackValue(args->at(0));
2841 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002842
2843 Register object = rbx;
2844 Register index = rax;
2845 Register scratch = rcx;
2846 Register result = rdx;
2847
2848 __ pop(object);
2849
2850 Label need_conversion;
2851 Label index_out_of_range;
2852 Label done;
2853 StringCharCodeAtGenerator generator(object,
2854 index,
2855 scratch,
2856 result,
2857 &need_conversion,
2858 &need_conversion,
2859 &index_out_of_range,
2860 STRING_INDEX_IS_NUMBER);
2861 generator.GenerateFast(masm_);
2862 __ jmp(&done);
2863
2864 __ bind(&index_out_of_range);
2865 // When the index is out of range, the spec requires us to return
2866 // NaN.
2867 __ LoadRoot(result, Heap::kNanValueRootIndex);
2868 __ jmp(&done);
2869
2870 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002871 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002872 // trigger conversion.
2873 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2874 __ jmp(&done);
2875
2876 NopRuntimeCallHelper call_helper;
2877 generator.GenerateSlow(masm_, call_helper);
2878
2879 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002880 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002881}
2882
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002883
2884void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2885 ASSERT(args->length() == 2);
2886
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002887 VisitForStackValue(args->at(0));
2888 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002889
2890 Register object = rbx;
2891 Register index = rax;
2892 Register scratch1 = rcx;
2893 Register scratch2 = rdx;
2894 Register result = rax;
2895
2896 __ pop(object);
2897
2898 Label need_conversion;
2899 Label index_out_of_range;
2900 Label done;
2901 StringCharAtGenerator generator(object,
2902 index,
2903 scratch1,
2904 scratch2,
2905 result,
2906 &need_conversion,
2907 &need_conversion,
2908 &index_out_of_range,
2909 STRING_INDEX_IS_NUMBER);
2910 generator.GenerateFast(masm_);
2911 __ jmp(&done);
2912
2913 __ bind(&index_out_of_range);
2914 // When the index is out of range, the spec requires us to return
2915 // the empty string.
2916 __ LoadRoot(result, Heap::kEmptyStringRootIndex);
2917 __ jmp(&done);
2918
2919 __ bind(&need_conversion);
2920 // Move smi zero into the result register, which will trigger
2921 // conversion.
2922 __ Move(result, Smi::FromInt(0));
2923 __ jmp(&done);
2924
2925 NopRuntimeCallHelper call_helper;
2926 generator.GenerateSlow(masm_, call_helper);
2927
2928 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002929 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002930}
2931
2932
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002933void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2934 ASSERT_EQ(2, args->length());
2935
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002936 VisitForStackValue(args->at(0));
2937 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002938
2939 StringAddStub stub(NO_STRING_ADD_FLAGS);
2940 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002941 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002942}
2943
2944
2945void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2946 ASSERT_EQ(2, args->length());
2947
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002948 VisitForStackValue(args->at(0));
2949 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002950
2951 StringCompareStub stub;
2952 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002953 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002954}
2955
2956
2957void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2958 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002959 TranscendentalCacheStub stub(TranscendentalCache::SIN,
2960 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002961 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002962 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002963 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002964 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002965}
2966
2967
2968void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2969 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002970 TranscendentalCacheStub stub(TranscendentalCache::COS,
2971 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002972 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002973 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002974 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002975 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002976}
2977
2978
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002979void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
2980 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002981 TranscendentalCacheStub stub(TranscendentalCache::LOG,
2982 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002983 ASSERT(args->length() == 1);
2984 VisitForStackValue(args->at(0));
2985 __ CallStub(&stub);
2986 context()->Plug(rax);
2987}
2988
2989
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002990void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2991 // Load the argument on the stack and call the runtime function.
2992 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002993 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002994 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002995 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002996}
2997
2998
2999void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
3000 ASSERT(args->length() >= 2);
3001
danno@chromium.org160a7b02011-04-18 15:51:38 +00003002 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3003 for (int i = 0; i < arg_count + 1; i++) {
3004 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003005 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003006 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003007
danno@chromium.org160a7b02011-04-18 15:51:38 +00003008 // InvokeFunction requires the function in rdi. Move it in there.
3009 __ movq(rdi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003010 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003011 __ InvokeFunction(rdi, count, CALL_FUNCTION,
3012 NullCallWrapper(), CALL_AS_METHOD);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003013 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003014 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003015}
3016
3017
3018void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003019 RegExpConstructResultStub stub;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003020 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003021 VisitForStackValue(args->at(0));
3022 VisitForStackValue(args->at(1));
3023 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003024 __ 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
3029void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
3030 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003031 VisitForStackValue(args->at(0));
3032 VisitForStackValue(args->at(1));
3033 VisitForStackValue(args->at(2));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003034 Label done;
3035 Label slow_case;
3036 Register object = rax;
3037 Register index_1 = rbx;
3038 Register index_2 = rcx;
3039 Register elements = rdi;
3040 Register temp = rdx;
3041 __ movq(object, Operand(rsp, 2 * kPointerSize));
3042 // Fetch the map and check if array is in fast case.
3043 // Check that object doesn't require security checks and
3044 // has no indexed interceptor.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003045 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3046 __ j(not_equal, &slow_case);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003047 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
3048 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
3049 __ j(not_zero, &slow_case);
3050
3051 // Check the object's elements are in fast case and writable.
3052 __ movq(elements, FieldOperand(object, JSObject::kElementsOffset));
3053 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
3054 Heap::kFixedArrayMapRootIndex);
3055 __ j(not_equal, &slow_case);
3056
3057 // Check that both indices are smis.
3058 __ movq(index_1, Operand(rsp, 1 * kPointerSize));
3059 __ movq(index_2, Operand(rsp, 0 * kPointerSize));
3060 __ JumpIfNotBothSmi(index_1, index_2, &slow_case);
3061
3062 // Check that both indices are valid.
3063 // The JSArray length field is a smi since the array is in fast case mode.
3064 __ movq(temp, FieldOperand(object, JSArray::kLengthOffset));
3065 __ SmiCompare(temp, index_1);
3066 __ j(below_equal, &slow_case);
3067 __ SmiCompare(temp, index_2);
3068 __ j(below_equal, &slow_case);
3069
3070 __ SmiToInteger32(index_1, index_1);
3071 __ SmiToInteger32(index_2, index_2);
3072 // Bring addresses into index1 and index2.
3073 __ lea(index_1, FieldOperand(elements, index_1, times_pointer_size,
3074 FixedArray::kHeaderSize));
3075 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size,
3076 FixedArray::kHeaderSize));
3077
3078 // Swap elements. Use object and temp as scratch registers.
3079 __ movq(object, Operand(index_1, 0));
3080 __ movq(temp, Operand(index_2, 0));
3081 __ movq(Operand(index_2, 0), object);
3082 __ movq(Operand(index_1, 0), temp);
3083
3084 Label new_space;
3085 __ InNewSpace(elements, temp, equal, &new_space);
3086
3087 __ movq(object, elements);
3088 __ RecordWriteHelper(object, index_1, temp);
3089 __ RecordWriteHelper(elements, index_2, temp);
3090
3091 __ bind(&new_space);
3092 // We are done. Drop elements from the stack, and return undefined.
3093 __ addq(rsp, Immediate(3 * kPointerSize));
3094 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3095 __ jmp(&done);
3096
3097 __ bind(&slow_case);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003098 __ CallRuntime(Runtime::kSwapElements, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003099
3100 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003101 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003102}
3103
3104
3105void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3106 ASSERT_EQ(2, args->length());
3107
3108 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3109 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3110
3111 Handle<FixedArray> jsfunction_result_caches(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003112 isolate()->global_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003113 if (jsfunction_result_caches->length() <= cache_id) {
3114 __ Abort("Attempt to use undefined cache.");
3115 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003116 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003117 return;
3118 }
3119
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003120 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003121
3122 Register key = rax;
3123 Register cache = rbx;
3124 Register tmp = rcx;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003125 __ movq(cache, ContextOperand(rsi, Context::GLOBAL_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003126 __ movq(cache,
3127 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
3128 __ movq(cache,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003129 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003130 __ movq(cache,
3131 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3132
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003133 Label done, not_found;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003134 // tmp now holds finger offset as a smi.
3135 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3136 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3137 SmiIndex index =
3138 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
3139 __ cmpq(key, FieldOperand(cache,
3140 index.reg,
3141 index.scale,
3142 FixedArray::kHeaderSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003143 __ j(not_equal, &not_found, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003144 __ movq(rax, FieldOperand(cache,
3145 index.reg,
3146 index.scale,
3147 FixedArray::kHeaderSize + kPointerSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003148 __ jmp(&done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003149
3150 __ bind(&not_found);
3151 // Call runtime to perform the lookup.
3152 __ push(cache);
3153 __ push(key);
3154 __ CallRuntime(Runtime::kGetFromCache, 2);
3155
3156 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003157 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003158}
3159
3160
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003161void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3162 ASSERT_EQ(2, args->length());
3163
3164 Register right = rax;
3165 Register left = rbx;
3166 Register tmp = rcx;
3167
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003168 VisitForStackValue(args->at(0));
3169 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003170 __ pop(left);
3171
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003172 Label done, fail, ok;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003173 __ cmpq(left, right);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003174 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003175 // Fail if either is a non-HeapObject.
3176 Condition either_smi = masm()->CheckEitherSmi(left, right, tmp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003177 __ j(either_smi, &fail, Label::kNear);
3178 __ j(zero, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003179 __ movq(tmp, FieldOperand(left, HeapObject::kMapOffset));
3180 __ cmpb(FieldOperand(tmp, Map::kInstanceTypeOffset),
3181 Immediate(JS_REGEXP_TYPE));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003182 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003183 __ cmpq(tmp, FieldOperand(right, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003184 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003185 __ movq(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3186 __ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003187 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003188 __ bind(&fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003189 __ Move(rax, isolate()->factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003190 __ jmp(&done, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003191 __ bind(&ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003192 __ Move(rax, isolate()->factory()->true_value());
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003193 __ bind(&done);
3194
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003195 context()->Plug(rax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003196}
3197
3198
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003199void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
3200 ASSERT(args->length() == 1);
3201
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003202 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003203
3204 Label materialize_true, materialize_false;
3205 Label* if_true = NULL;
3206 Label* if_false = NULL;
3207 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003208 context()->PrepareTest(&materialize_true, &materialize_false,
3209 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003210
3211 __ testl(FieldOperand(rax, String::kHashFieldOffset),
3212 Immediate(String::kContainsCachedArrayIndexMask));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003213 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003214 __ j(zero, if_true);
3215 __ jmp(if_false);
3216
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003217 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003218}
3219
3220
3221void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3222 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003223 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003224
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003225 if (FLAG_debug_code) {
3226 __ AbortIfNotString(rax);
3227 }
3228
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003229 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
3230 ASSERT(String::kHashShift >= kSmiTagSize);
3231 __ IndexFromHash(rax, rax);
3232
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003233 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003234}
3235
3236
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003237void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003238 Label bailout, return_result, done, one_char_separator, long_separator,
3239 non_trivial_array, not_size_one_array, loop,
3240 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
3241 ASSERT(args->length() == 2);
3242 // We will leave the separator on the stack until the end of the function.
3243 VisitForStackValue(args->at(1));
3244 // Load this to rax (= array)
3245 VisitForAccumulatorValue(args->at(0));
3246 // All aliases of the same register have disjoint lifetimes.
3247 Register array = rax;
3248 Register elements = no_reg; // Will be rax.
3249
3250 Register index = rdx;
3251
3252 Register string_length = rcx;
3253
3254 Register string = rsi;
3255
3256 Register scratch = rbx;
3257
3258 Register array_length = rdi;
3259 Register result_pos = no_reg; // Will be rdi.
3260
3261 Operand separator_operand = Operand(rsp, 2 * kPointerSize);
3262 Operand result_operand = Operand(rsp, 1 * kPointerSize);
3263 Operand array_length_operand = Operand(rsp, 0 * kPointerSize);
3264 // Separator operand is already pushed. Make room for the two
3265 // other stack fields, and clear the direction flag in anticipation
3266 // of calling CopyBytes.
3267 __ subq(rsp, Immediate(2 * kPointerSize));
3268 __ cld();
3269 // Check that the array is a JSArray
3270 __ JumpIfSmi(array, &bailout);
3271 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3272 __ j(not_equal, &bailout);
3273
3274 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003275 __ CheckFastElements(scratch, &bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003276
3277 // Array has fast elements, so its length must be a smi.
3278 // If the array has length zero, return the empty string.
3279 __ movq(array_length, FieldOperand(array, JSArray::kLengthOffset));
3280 __ SmiCompare(array_length, Smi::FromInt(0));
3281 __ j(not_zero, &non_trivial_array);
3282 __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
3283 __ jmp(&return_result);
3284
3285 // Save the array length on the stack.
3286 __ bind(&non_trivial_array);
3287 __ SmiToInteger32(array_length, array_length);
3288 __ movl(array_length_operand, array_length);
3289
3290 // Save the FixedArray containing array's elements.
3291 // End of array's live range.
3292 elements = array;
3293 __ movq(elements, FieldOperand(array, JSArray::kElementsOffset));
3294 array = no_reg;
3295
3296
3297 // Check that all array elements are sequential ASCII strings, and
3298 // accumulate the sum of their lengths, as a smi-encoded value.
3299 __ Set(index, 0);
3300 __ Set(string_length, 0);
3301 // Loop condition: while (index < array_length).
3302 // Live loop registers: index(int32), array_length(int32), string(String*),
3303 // scratch, string_length(int32), elements(FixedArray*).
3304 if (FLAG_debug_code) {
3305 __ cmpq(index, array_length);
3306 __ Assert(below, "No empty arrays here in EmitFastAsciiArrayJoin");
3307 }
3308 __ bind(&loop);
3309 __ movq(string, FieldOperand(elements,
3310 index,
3311 times_pointer_size,
3312 FixedArray::kHeaderSize));
3313 __ JumpIfSmi(string, &bailout);
3314 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3315 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3316 __ andb(scratch, Immediate(
3317 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3318 __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
3319 __ j(not_equal, &bailout);
3320 __ AddSmiField(string_length,
3321 FieldOperand(string, SeqAsciiString::kLengthOffset));
3322 __ j(overflow, &bailout);
3323 __ incl(index);
3324 __ cmpl(index, array_length);
3325 __ j(less, &loop);
3326
3327 // Live registers:
3328 // string_length: Sum of string lengths.
3329 // elements: FixedArray of strings.
3330 // index: Array length.
3331 // array_length: Array length.
3332
3333 // If array_length is 1, return elements[0], a string.
3334 __ cmpl(array_length, Immediate(1));
3335 __ j(not_equal, &not_size_one_array);
3336 __ movq(rax, FieldOperand(elements, FixedArray::kHeaderSize));
3337 __ jmp(&return_result);
3338
3339 __ bind(&not_size_one_array);
3340
3341 // End of array_length live range.
3342 result_pos = array_length;
3343 array_length = no_reg;
3344
3345 // Live registers:
3346 // string_length: Sum of string lengths.
3347 // elements: FixedArray of strings.
3348 // index: Array length.
3349
3350 // Check that the separator is a sequential ASCII string.
3351 __ movq(string, separator_operand);
3352 __ JumpIfSmi(string, &bailout);
3353 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3354 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3355 __ andb(scratch, Immediate(
3356 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3357 __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
3358 __ j(not_equal, &bailout);
3359
3360 // Live registers:
3361 // string_length: Sum of string lengths.
3362 // elements: FixedArray of strings.
3363 // index: Array length.
3364 // string: Separator string.
3365
3366 // Add (separator length times (array_length - 1)) to string_length.
3367 __ SmiToInteger32(scratch,
3368 FieldOperand(string, SeqAsciiString::kLengthOffset));
3369 __ decl(index);
3370 __ imull(scratch, index);
3371 __ j(overflow, &bailout);
3372 __ addl(string_length, scratch);
3373 __ j(overflow, &bailout);
3374
3375 // Live registers and stack values:
3376 // string_length: Total length of result string.
3377 // elements: FixedArray of strings.
3378 __ AllocateAsciiString(result_pos, string_length, scratch,
3379 index, string, &bailout);
3380 __ movq(result_operand, result_pos);
3381 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3382
3383 __ movq(string, separator_operand);
3384 __ SmiCompare(FieldOperand(string, SeqAsciiString::kLengthOffset),
3385 Smi::FromInt(1));
3386 __ j(equal, &one_char_separator);
3387 __ j(greater, &long_separator);
3388
3389
3390 // Empty separator case:
3391 __ Set(index, 0);
3392 __ movl(scratch, array_length_operand);
3393 __ jmp(&loop_1_condition);
3394 // Loop condition: while (index < array_length).
3395 __ bind(&loop_1);
3396 // Each iteration of the loop concatenates one string to the result.
3397 // Live values in registers:
3398 // index: which element of the elements array we are adding to the result.
3399 // result_pos: the position to which we are currently copying characters.
3400 // elements: the FixedArray of strings we are joining.
3401 // scratch: array length.
3402
3403 // Get string = array[index].
3404 __ movq(string, FieldOperand(elements, index,
3405 times_pointer_size,
3406 FixedArray::kHeaderSize));
3407 __ SmiToInteger32(string_length,
3408 FieldOperand(string, String::kLengthOffset));
3409 __ lea(string,
3410 FieldOperand(string, SeqAsciiString::kHeaderSize));
3411 __ CopyBytes(result_pos, string, string_length);
3412 __ incl(index);
3413 __ bind(&loop_1_condition);
3414 __ cmpl(index, scratch);
3415 __ j(less, &loop_1); // Loop while (index < array_length).
3416 __ jmp(&done);
3417
3418 // Generic bailout code used from several places.
3419 __ bind(&bailout);
3420 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3421 __ jmp(&return_result);
3422
3423
3424 // One-character separator case
3425 __ bind(&one_char_separator);
3426 // Get the separator ascii character value.
3427 // Register "string" holds the separator.
3428 __ movzxbl(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3429 __ Set(index, 0);
3430 // Jump into the loop after the code that copies the separator, so the first
3431 // element is not preceded by a separator
3432 __ jmp(&loop_2_entry);
3433 // Loop condition: while (index < length).
3434 __ bind(&loop_2);
3435 // Each iteration of the loop concatenates one string to the result.
3436 // Live values in registers:
3437 // elements: The FixedArray of strings we are joining.
3438 // index: which element of the elements array we are adding to the result.
3439 // result_pos: the position to which we are currently copying characters.
3440 // scratch: Separator character.
3441
3442 // Copy the separator character to the result.
3443 __ movb(Operand(result_pos, 0), scratch);
3444 __ incq(result_pos);
3445
3446 __ bind(&loop_2_entry);
3447 // Get string = array[index].
3448 __ movq(string, FieldOperand(elements, index,
3449 times_pointer_size,
3450 FixedArray::kHeaderSize));
3451 __ SmiToInteger32(string_length,
3452 FieldOperand(string, String::kLengthOffset));
3453 __ lea(string,
3454 FieldOperand(string, SeqAsciiString::kHeaderSize));
3455 __ CopyBytes(result_pos, string, string_length);
3456 __ incl(index);
3457 __ cmpl(index, array_length_operand);
3458 __ j(less, &loop_2); // End while (index < length).
3459 __ jmp(&done);
3460
3461
3462 // Long separator case (separator is more than one character).
3463 __ bind(&long_separator);
3464
3465 // Make elements point to end of elements array, and index
3466 // count from -array_length to zero, so we don't need to maintain
3467 // a loop limit.
3468 __ movl(index, array_length_operand);
3469 __ lea(elements, FieldOperand(elements, index, times_pointer_size,
3470 FixedArray::kHeaderSize));
3471 __ neg(index);
3472
3473 // Replace separator string with pointer to its first character, and
3474 // make scratch be its length.
3475 __ movq(string, separator_operand);
3476 __ SmiToInteger32(scratch,
3477 FieldOperand(string, String::kLengthOffset));
3478 __ lea(string,
3479 FieldOperand(string, SeqAsciiString::kHeaderSize));
3480 __ movq(separator_operand, string);
3481
3482 // Jump into the loop after the code that copies the separator, so the first
3483 // element is not preceded by a separator
3484 __ jmp(&loop_3_entry);
3485 // Loop condition: while (index < length).
3486 __ bind(&loop_3);
3487 // Each iteration of the loop concatenates one string to the result.
3488 // Live values in registers:
3489 // index: which element of the elements array we are adding to the result.
3490 // result_pos: the position to which we are currently copying characters.
3491 // scratch: Separator length.
3492 // separator_operand (rsp[0x10]): Address of first char of separator.
3493
3494 // Copy the separator to the result.
3495 __ movq(string, separator_operand);
3496 __ movl(string_length, scratch);
3497 __ CopyBytes(result_pos, string, string_length, 2);
3498
3499 __ bind(&loop_3_entry);
3500 // Get string = array[index].
3501 __ movq(string, Operand(elements, index, times_pointer_size, 0));
3502 __ SmiToInteger32(string_length,
3503 FieldOperand(string, String::kLengthOffset));
3504 __ lea(string,
3505 FieldOperand(string, SeqAsciiString::kHeaderSize));
3506 __ CopyBytes(result_pos, string, string_length);
3507 __ incq(index);
3508 __ j(not_equal, &loop_3); // Loop while (index < 0).
3509
3510 __ bind(&done);
3511 __ movq(rax, result_operand);
3512
3513 __ bind(&return_result);
3514 // Drop temp values from the stack, and restore context register.
3515 __ addq(rsp, Immediate(3 * kPointerSize));
3516 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3517 context()->Plug(rax);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003518}
3519
3520
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003521void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) {
3522 ASSERT(args->length() == 1);
3523
3524 // Load the function into rax.
3525 VisitForAccumulatorValue(args->at(0));
3526
3527 // Prepare for the test.
3528 Label materialize_true, materialize_false;
3529 Label* if_true = NULL;
3530 Label* if_false = NULL;
3531 Label* fall_through = NULL;
3532 context()->PrepareTest(&materialize_true, &materialize_false,
3533 &if_true, &if_false, &fall_through);
3534
3535 // Test for strict mode function.
3536 __ movq(rdx, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
3537 __ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
3538 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
3539 __ j(not_equal, if_true);
3540
3541 // Test for native function.
3542 __ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset),
3543 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
3544 __ j(not_equal, if_true);
3545
3546 // Not native or strict-mode function.
3547 __ jmp(if_false);
3548
3549 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3550 context()->Plug(if_true, if_false);
3551}
3552
3553
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003554void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003555 Handle<String> name = expr->name();
3556 if (name->length() > 0 && name->Get(0) == '_') {
3557 Comment cmnt(masm_, "[ InlineRuntimeCall");
3558 EmitInlineRuntimeCall(expr);
3559 return;
3560 }
3561
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003562 Comment cmnt(masm_, "[ CallRuntime");
3563 ZoneList<Expression*>* args = expr->arguments();
3564
3565 if (expr->is_jsruntime()) {
3566 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003567 __ movq(rax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003568 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
3569 }
3570
3571 // Push the arguments ("left-to-right").
3572 int arg_count = args->length();
3573 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003574 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003575 }
3576
3577 if (expr->is_jsruntime()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003578 // Call the JS runtime function using a call IC.
3579 __ Move(rcx, expr->name());
3580 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003581 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 Handle<Code> ic =
danno@chromium.org40cb8782011-05-25 07:58:50 +00003583 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003584 __ call(ic, mode, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003585 // Restore context register.
3586 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003587 } else {
3588 __ CallRuntime(expr->function(), arg_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003589 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003590 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003591}
3592
3593
3594void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3595 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003596 case Token::DELETE: {
3597 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3598 Property* prop = expr->expression()->AsProperty();
3599 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003600
3601 if (prop != NULL) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003602 if (prop->is_synthetic()) {
3603 // Result of deleting parameters is false, even when they rewrite
3604 // to accesses on the arguments object.
3605 context()->Plug(false);
3606 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003607 VisitForStackValue(prop->obj());
3608 VisitForStackValue(prop->key());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003609 __ Push(Smi::FromInt(strict_mode_flag()));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003610 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003611 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003612 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003613 } else if (var != NULL) {
3614 // Delete of an unqualified identifier is disallowed in strict mode
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003615 // but "delete this" is.
3616 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003617 if (var->is_global()) {
3618 __ push(GlobalObjectOperand());
3619 __ Push(var->name());
3620 __ Push(Smi::FromInt(kNonStrictMode));
3621 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3622 context()->Plug(rax);
3623 } else if (var->AsSlot() != NULL &&
3624 var->AsSlot()->type() != Slot::LOOKUP) {
3625 // Result of deleting non-global, non-dynamic variables is false.
3626 // The subexpression does not have side effects.
3627 context()->Plug(false);
3628 } else {
3629 // Non-global variable. Call the runtime to try to delete from the
3630 // context where the variable was introduced.
3631 __ push(context_register());
3632 __ Push(var->name());
3633 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3634 context()->Plug(rax);
3635 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003636 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003637 // Result of deleting non-property, non-variable reference is true.
3638 // The subexpression may have side effects.
3639 VisitForEffect(expr->expression());
3640 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003641 }
3642 break;
3643 }
3644
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003645 case Token::VOID: {
3646 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3647 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003648 context()->Plug(Heap::kUndefinedValueRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003649 break;
3650 }
3651
3652 case Token::NOT: {
3653 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003654 if (context()->IsEffect()) {
3655 // Unary NOT has no side effects so it's only necessary to visit the
3656 // subexpression. Match the optimizing compiler by not branching.
3657 VisitForEffect(expr->expression());
3658 } else {
3659 Label materialize_true, materialize_false;
3660 Label* if_true = NULL;
3661 Label* if_false = NULL;
3662 Label* fall_through = NULL;
3663 // Notice that the labels are swapped.
3664 context()->PrepareTest(&materialize_true, &materialize_false,
3665 &if_false, &if_true, &fall_through);
3666 if (context()->IsTest()) ForwardBailoutToChild(expr);
3667 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3668 context()->Plug(if_false, if_true); // Labels swapped.
3669 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003670 break;
3671 }
3672
3673 case Token::TYPEOF: {
3674 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003675 { StackValueContext context(this);
3676 VisitForTypeofValue(expr->expression());
3677 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003678 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003679 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003680 break;
3681 }
3682
3683 case Token::ADD: {
3684 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003685 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003686 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003687 __ JumpIfSmi(result_register(), &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003688 ToNumberStub convert_stub;
3689 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003690 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003691 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003692 break;
3693 }
3694
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003695 case Token::SUB:
3696 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003697 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003698
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003699 case Token::BIT_NOT:
3700 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003701 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003702
3703 default:
3704 UNREACHABLE();
3705 }
3706}
3707
3708
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003709void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3710 const char* comment) {
3711 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
3712 Comment cmt(masm_, comment);
3713 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3714 UnaryOverwriteMode overwrite =
3715 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003716 UnaryOpStub stub(expr->op(), overwrite);
3717 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003718 // accumulator register rax.
3719 VisitForAccumulatorValue(expr->expression());
3720 SetSourcePosition(expr->position());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003721 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003722 context()->Plug(rax);
3723}
3724
3725
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003726void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3727 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003728 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003729
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003730 // Invalid left-hand-sides are rewritten to have a 'throw
3731 // ReferenceError' as the left-hand side.
3732 if (!expr->expression()->IsValidLeftHandSide()) {
3733 VisitForEffect(expr->expression());
3734 return;
3735 }
3736
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003737 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00003738 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003739 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3740 LhsKind assign_type = VARIABLE;
3741 Property* prop = expr->expression()->AsProperty();
3742 // In case of a property we use the uninitialized expression context
3743 // of the key to detect a named property.
3744 if (prop != NULL) {
3745 assign_type =
3746 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3747 }
3748
3749 // Evaluate expression and get value.
3750 if (assign_type == VARIABLE) {
3751 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003752 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003753 EmitVariableLoad(expr->expression()->AsVariableProxy());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003754 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003755 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003756 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003757 __ Push(Smi::FromInt(0));
3758 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003759 if (assign_type == NAMED_PROPERTY) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003760 VisitForAccumulatorValue(prop->obj());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00003761 __ push(rax); // Copy of receiver, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003762 EmitNamedPropertyLoad(prop);
3763 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003764 VisitForStackValue(prop->obj());
3765 VisitForAccumulatorValue(prop->key());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003766 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack
3767 __ push(rax); // Copy of key, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003768 EmitKeyedPropertyLoad(prop);
3769 }
3770 }
3771
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003772 // We need a second deoptimization point after loading the value
3773 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003774 if (assign_type == VARIABLE) {
3775 PrepareForBailout(expr->expression(), TOS_REG);
3776 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003777 PrepareForBailoutForId(expr->CountId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003778 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003779
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003780 // Call ToNumber only if operand is not a smi.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003781 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003782 __ JumpIfSmi(rax, &no_conversion, Label::kNear);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003783 ToNumberStub convert_stub;
3784 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003785 __ bind(&no_conversion);
3786
3787 // Save result for postfix expressions.
3788 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003789 if (!context()->IsEffect()) {
3790 // Save the result on the stack. If we have a named or keyed property
3791 // we store the result under the receiver that is currently on top
3792 // of the stack.
3793 switch (assign_type) {
3794 case VARIABLE:
3795 __ push(rax);
3796 break;
3797 case NAMED_PROPERTY:
3798 __ movq(Operand(rsp, kPointerSize), rax);
3799 break;
3800 case KEYED_PROPERTY:
3801 __ movq(Operand(rsp, 2 * kPointerSize), rax);
3802 break;
3803 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003804 }
3805 }
3806
3807 // Inline smi case if we are in a loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003808 Label done, stub_call;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003809 JumpPatchSite patch_site(masm_);
3810
ricow@chromium.org65fae842010-08-25 15:26:24 +00003811 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003812 if (expr->op() == Token::INC) {
3813 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
3814 } else {
3815 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
3816 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003817 __ j(overflow, &stub_call, Label::kNear);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003818 // We could eliminate this smi check if we split the code at
3819 // the first smi check before calling ToNumber.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003820 patch_site.EmitJumpIfSmi(rax, &done, Label::kNear);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003821
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003822 __ bind(&stub_call);
3823 // Call stub. Undo operation first.
3824 if (expr->op() == Token::INC) {
3825 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
3826 } else {
3827 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
3828 }
3829 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003830
3831 // Record position before stub call.
3832 SetSourcePosition(expr->position());
3833
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003834 // Call stub for +1/-1.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003835 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003836 if (expr->op() == Token::INC) {
3837 __ Move(rdx, Smi::FromInt(1));
3838 } else {
3839 __ movq(rdx, rax);
3840 __ Move(rax, Smi::FromInt(1));
3841 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003842 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
3843 patch_site.EmitPatchInfo();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003844 __ bind(&done);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003845
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003846 // Store the value returned in rax.
3847 switch (assign_type) {
3848 case VARIABLE:
3849 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003850 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003851 { EffectContext context(this);
3852 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3853 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003854 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003855 context.Plug(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003856 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003857 // For all contexts except kEffect: We have the result on
3858 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003859 if (!context()->IsEffect()) {
3860 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003861 }
3862 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003863 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003864 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003865 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003866 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003867 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003868 }
3869 break;
3870 case NAMED_PROPERTY: {
3871 __ Move(rcx, prop->key()->AsLiteral()->handle());
3872 __ pop(rdx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003873 Handle<Code> ic = is_strict_mode()
3874 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3875 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003876 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003877 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003878 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003879 if (!context()->IsEffect()) {
3880 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003881 }
3882 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003883 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003884 }
3885 break;
3886 }
3887 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003888 __ pop(rcx);
3889 __ pop(rdx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003890 Handle<Code> ic = is_strict_mode()
3891 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3892 : isolate()->builtins()->KeyedStoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003893 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003894 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003895 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003896 if (!context()->IsEffect()) {
3897 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003898 }
3899 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003900 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003901 }
3902 break;
3903 }
3904 }
3905}
3906
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003907
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003908void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003909 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003910 ASSERT(!context()->IsEffect());
3911 ASSERT(!context()->IsTest());
3912
ricow@chromium.org65fae842010-08-25 15:26:24 +00003913 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3914 Comment cmnt(masm_, "Global variable");
3915 __ Move(rcx, proxy->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003916 __ movq(rax, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003917 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003918 // Use a regular load, not a contextual load, to avoid a reference
3919 // error.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003920 __ call(ic);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003921 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003922 context()->Plug(rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003923 } else if (proxy != NULL &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003924 proxy->var()->AsSlot() != NULL &&
3925 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003926 Label done, slow;
3927
3928 // Generate code for loading from variables potentially shadowed
3929 // by eval-introduced variables.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003930 Slot* slot = proxy->var()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003931 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3932
3933 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003934 __ push(rsi);
3935 __ Push(proxy->name());
3936 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003937 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003938 __ bind(&done);
3939
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003940 context()->Plug(rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003941 } else {
3942 // This expression cannot throw a reference error at the top level.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003943 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003944 }
3945}
3946
3947
ager@chromium.org04921a82011-06-27 13:21:41 +00003948void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3949 Handle<String> check,
3950 Label* if_true,
3951 Label* if_false,
3952 Label* fall_through) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003953 { AccumulatorValueContext context(this);
ager@chromium.org04921a82011-06-27 13:21:41 +00003954 VisitForTypeofValue(expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003955 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003956 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003958 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003959 __ JumpIfSmi(rax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003960 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
3961 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
3962 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003963 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003964 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003965 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003966 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
3967 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003968 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003969 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003970 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003971 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003972 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
3973 __ j(equal, if_true);
3974 __ CompareRoot(rax, Heap::kFalseValueRootIndex);
3975 Split(equal, if_true, if_false, fall_through);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003976 } else if (FLAG_harmony_typeof &&
3977 check->Equals(isolate()->heap()->null_symbol())) {
3978 __ CompareRoot(rax, Heap::kNullValueRootIndex);
3979 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003980 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003981 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
3982 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003983 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003984 // Check for undetectable objects => true.
3985 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
3986 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
3987 Immediate(1 << Map::kIsUndetectable));
3988 Split(not_zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003989 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003990 __ JumpIfSmi(rax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003991 STATIC_ASSERT(LAST_CALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE);
3992 __ CmpObjectType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, rdx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003993 Split(above_equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003994 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003995 __ JumpIfSmi(rax, if_false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003996 if (!FLAG_harmony_typeof) {
3997 __ CompareRoot(rax, Heap::kNullValueRootIndex);
3998 __ j(equal, if_true);
3999 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004000 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004001 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004002 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4003 __ j(above, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004004 // Check for undetectable objects => false.
4005 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4006 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004007 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004008 } else {
4009 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004010 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004011}
ricow@chromium.org65fae842010-08-25 15:26:24 +00004012
ager@chromium.org04921a82011-06-27 13:21:41 +00004013
4014void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
4015 Label* if_true,
4016 Label* if_false,
4017 Label* fall_through) {
4018 VisitForAccumulatorValue(expr);
4019 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4020
4021 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4022 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004023}
4024
4025
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004026void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4027 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004028 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004029
4030 // Always perform the comparison for its control flow. Pack the result
4031 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004032 Label materialize_true, materialize_false;
4033 Label* if_true = NULL;
4034 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004035 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004036 context()->PrepareTest(&materialize_true, &materialize_false,
4037 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004038
4039 // First we try a fast inlined version of the compare when one of
4040 // the operands is a literal.
ager@chromium.org04921a82011-06-27 13:21:41 +00004041 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004042 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004043 return;
4044 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004045
ager@chromium.org04921a82011-06-27 13:21:41 +00004046 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004047 VisitForStackValue(expr->left());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004048 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004049 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004050 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004051 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004052 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004053 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004054 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004055 break;
4056
4057 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004058 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004059 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004060 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004061 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004062 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004063 // The stub returns 0 for true.
4064 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004065 break;
4066 }
4067
4068 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004069 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004070 Condition cc = no_condition;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004071 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004072 case Token::EQ_STRICT:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004073 // Fall through.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004074 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004075 cc = equal;
4076 __ pop(rdx);
4077 break;
4078 case Token::LT:
4079 cc = less;
4080 __ pop(rdx);
4081 break;
4082 case Token::GT:
4083 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4084 cc = less;
4085 __ movq(rdx, result_register());
4086 __ pop(rax);
4087 break;
4088 case Token::LTE:
4089 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4090 cc = greater_equal;
4091 __ movq(rdx, result_register());
4092 __ pop(rax);
4093 break;
4094 case Token::GTE:
4095 cc = greater_equal;
4096 __ pop(rdx);
4097 break;
4098 case Token::IN:
4099 case Token::INSTANCEOF:
4100 default:
4101 UNREACHABLE();
4102 }
4103
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004104 bool inline_smi_code = ShouldInlineSmiCase(op);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004105 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004106 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004107 Label slow_case;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004108 __ movq(rcx, rdx);
4109 __ or_(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004110 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004111 __ cmpq(rdx, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004112 Split(cc, if_true, if_false, NULL);
4113 __ bind(&slow_case);
4114 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004115
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004116 // Record position and call the compare IC.
4117 SetSourcePosition(expr->position());
4118 Handle<Code> ic = CompareIC::GetUninitialized(op);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004119 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
4120 patch_site.EmitPatchInfo();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004121
4122 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004123 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004124 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004125 }
4126 }
4127
4128 // Convert the result of the comparison into one expected for this
4129 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004130 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004131}
4132
4133
ricow@chromium.org65fae842010-08-25 15:26:24 +00004134void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4135 Comment cmnt(masm_, "[ CompareToNull");
4136 Label materialize_true, materialize_false;
4137 Label* if_true = NULL;
4138 Label* if_false = NULL;
4139 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004140 context()->PrepareTest(&materialize_true, &materialize_false,
4141 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004142
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004143 VisitForAccumulatorValue(expr->expression());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004144 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004145 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4146 if (expr->is_strict()) {
4147 Split(equal, if_true, if_false, fall_through);
4148 } else {
4149 __ j(equal, if_true);
4150 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4151 __ j(equal, if_true);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004152 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004153 // It can be an undetectable object.
4154 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
4155 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4156 Immediate(1 << Map::kIsUndetectable));
4157 Split(not_zero, if_true, if_false, fall_through);
4158 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004159 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004160}
4161
4162
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004163void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4164 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004165 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004166}
4167
4168
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004169Register FullCodeGenerator::result_register() {
4170 return rax;
4171}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004172
4173
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004174Register FullCodeGenerator::context_register() {
4175 return rsi;
4176}
4177
4178
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004179void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4180 ASSERT(IsAligned(frame_offset, kPointerSize));
4181 __ movq(Operand(rbp, frame_offset), value);
4182}
4183
4184
4185void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004186 __ movq(dst, ContextOperand(rsi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004187}
4188
4189
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004190void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004191 Scope* declaration_scope = scope()->DeclarationScope();
4192 if (declaration_scope->is_global_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004193 // Contexts nested in the global context have a canonical empty function
4194 // as their closure, not the anonymous closure containing the global
4195 // code. Pass a smi sentinel and let the runtime look up the empty
4196 // function.
4197 __ Push(Smi::FromInt(0));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004198 } else if (declaration_scope->is_eval_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004199 // Contexts created by a call to eval have the same closure as the
4200 // context calling eval, not the anonymous closure containing the eval
4201 // code. Fetch it from the context.
4202 __ push(ContextOperand(rsi, Context::CLOSURE_INDEX));
4203 } else {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004204 ASSERT(declaration_scope->is_function_scope());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004205 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
4206 }
4207}
4208
4209
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004210// ----------------------------------------------------------------------------
4211// Non-local control flow support.
4212
4213
4214void FullCodeGenerator::EnterFinallyBlock() {
4215 ASSERT(!result_register().is(rdx));
4216 ASSERT(!result_register().is(rcx));
4217 // Cook return address on top of stack (smi encoded Code* delta)
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004218 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004219 __ Move(rcx, masm_->CodeObject());
4220 __ subq(rdx, rcx);
4221 __ Integer32ToSmi(rdx, rdx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004222 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004223 // Store result register while executing finally block.
4224 __ push(result_register());
4225}
4226
4227
4228void FullCodeGenerator::ExitFinallyBlock() {
4229 ASSERT(!result_register().is(rdx));
4230 ASSERT(!result_register().is(rcx));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004231 __ pop(result_register());
4232 // Uncook return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004233 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004234 __ SmiToInteger32(rdx, rdx);
4235 __ Move(rcx, masm_->CodeObject());
4236 __ addq(rdx, rcx);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004237 __ jmp(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004238}
4239
4240
4241#undef __
4242
4243
4244} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004245
4246#endif // V8_TARGET_ARCH_X64