blob: 6c2aa3e05c01a50e3d8d67baebe279c3c859032a [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() {
81 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
82 ASSERT(is_int8(delta_to_patch_site));
83 __ testl(rax, Immediate(delta_to_patch_site));
84#ifdef DEBUG
85 info_emitted_ = true;
86#endif
87 }
88
89 bool is_bound() const { return patch_site_.is_bound(); }
90
91 private:
92 // jc will be patched with jz, jnc will become jnz.
karlklose@chromium.org83a47282011-05-11 11:54:09 +000093 void EmitJump(Condition cc, Label* target, Label::Distance near_jump) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000094 ASSERT(!patch_site_.is_bound() && !info_emitted_);
95 ASSERT(cc == carry || cc == not_carry);
96 __ bind(&patch_site_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +000097 __ j(cc, target, near_jump);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000098 }
99
100 MacroAssembler* masm_;
101 Label patch_site_;
102#ifdef DEBUG
103 bool info_emitted_;
104#endif
105};
106
107
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000108// Generate code for a JS function. On entry to the function the receiver
109// and arguments have been pushed on the stack left to right, with the
110// return address on top of them. The actual argument count matches the
111// formal parameter count expected by the function.
112//
113// The live registers are:
114// o rdi: the JS function object being called (ie, ourselves)
115// o rsi: our context
116// o rbp: our caller's frame pointer
117// o rsp: stack pointer (pointing to return address)
118//
119// The function builds a JS frame. Please see JavaScriptFrameConstants in
120// frames-x64.h for its layout.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000121void FullCodeGenerator::Generate(CompilationInfo* info) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000122 ASSERT(info_ == NULL);
123 info_ = info;
124 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000125 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126
vegorov@chromium.org42841962010-10-18 11:18:59 +0000127#ifdef DEBUG
128 if (strlen(FLAG_stop_at) > 0 &&
129 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
130 __ int3();
131 }
132#endif
danno@chromium.org40cb8782011-05-25 07:58:50 +0000133
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000134 // Strict mode functions and builtins need to replace the receiver
135 // with undefined when called as functions (without an explicit
136 // receiver object). rcx is zero for method calls and non-zero for
137 // function calls.
138 if (info->is_strict_mode() || info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000139 Label ok;
140 __ testq(rcx, rcx);
141 __ j(zero, &ok, Label::kNear);
142 // +1 for return address.
143 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
144 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
145 __ movq(Operand(rsp, receiver_offset), kScratchRegister);
146 __ bind(&ok);
147 }
148
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000149 __ push(rbp); // Caller's frame pointer.
150 __ movq(rbp, rsp);
151 __ push(rsi); // Callee's context.
152 __ push(rdi); // Callee's JS Function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000154 { Comment cmnt(masm_, "[ Allocate locals");
155 int locals_count = scope()->num_stack_slots();
156 if (locals_count == 1) {
157 __ PushRoot(Heap::kUndefinedValueRootIndex);
158 } else if (locals_count > 1) {
159 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
160 for (int i = 0; i < locals_count; i++) {
161 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000162 }
163 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000164 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000165
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000166 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000167
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000168 // Possibly allocate a local context.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000169 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000170 if (heap_slots > 0) {
171 Comment cmnt(masm_, "[ Allocate local context");
172 // Argument to NewContext is the function, which is still in rdi.
173 __ push(rdi);
174 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
175 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000176 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000177 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000178 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000179 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000180 function_in_register = false;
181 // Context is returned in both rax and rsi. It replaces the context
182 // passed to us. It's saved in the stack and kept live in rsi.
183 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
184
185 // Copy any necessary parameters into the context.
186 int num_parameters = scope()->num_parameters();
187 for (int i = 0; i < num_parameters; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000188 Slot* slot = scope()->parameter(i)->AsSlot();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000189 if (slot != NULL && slot->type() == Slot::CONTEXT) {
190 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
191 (num_parameters - 1 - i) * kPointerSize;
192 // Load parameter from stack.
193 __ movq(rax, Operand(rbp, parameter_offset));
194 // Store it in the context.
195 int context_offset = Context::SlotOffset(slot->index());
196 __ movq(Operand(rsi, context_offset), rax);
197 // Update the write barrier. This clobbers all involved
198 // registers, so we have use a third register to avoid
199 // clobbering rsi.
200 __ movq(rcx, rsi);
201 __ RecordWrite(rcx, context_offset, rax, rbx);
202 }
203 }
204 }
205
206 // Possibly allocate an arguments object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000207 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000208 if (arguments != NULL) {
209 // Arguments object must be allocated after the context object, in
210 // case the "arguments" or ".arguments" variables are in the context.
211 Comment cmnt(masm_, "[ Allocate arguments object");
212 if (function_in_register) {
213 __ push(rdi);
214 } else {
215 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
216 }
217 // The receiver is just before the parameters on the caller's stack.
218 int offset = scope()->num_parameters() * kPointerSize;
219 __ lea(rdx,
220 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
221 __ push(rdx);
222 __ Push(Smi::FromInt(scope()->num_parameters()));
223 // Arguments to ArgumentsAccessStub:
224 // function, receiver address, parameter count.
225 // The stub will rewrite receiver and parameter count if the previous
226 // stack frame was an arguments adapter frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000227 ArgumentsAccessStub stub(
228 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
229 : ArgumentsAccessStub::NEW_NON_STRICT);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000230 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000231
232 Variable* arguments_shadow = scope()->arguments_shadow();
233 if (arguments_shadow != NULL) {
234 // Store new arguments object in both "arguments" and ".arguments" slots.
235 __ movq(rcx, rax);
236 Move(arguments_shadow->AsSlot(), rcx, rbx, rdx);
237 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000238 Move(arguments->AsSlot(), rax, rbx, rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000239 }
240
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000241 if (FLAG_trace) {
242 __ CallRuntime(Runtime::kTraceEnter, 0);
243 }
244
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000245 // Visit the declarations and body unless there is an illegal
246 // redeclaration.
247 if (scope()->HasIllegalRedeclaration()) {
248 Comment cmnt(masm_, "[ Declarations");
249 scope()->VisitIllegalRedeclaration(this);
250 } else {
251 { Comment cmnt(masm_, "[ Declarations");
252 // For named function expressions, declare the function name as a
253 // constant.
254 if (scope()->is_function_scope() && scope()->function() != NULL) {
255 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
256 }
257 VisitDeclarations(scope()->declarations());
258 }
259
260 { Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000261 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000262 Label ok;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000263 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000264 __ j(above_equal, &ok, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000265 StackCheckStub stub;
266 __ CallStub(&stub);
267 __ bind(&ok);
268 }
269
270 { Comment cmnt(masm_, "[ Body");
271 ASSERT(loop_depth() == 0);
272 VisitStatements(function()->body());
273 ASSERT(loop_depth() == 0);
274 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000275 }
276
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000277 // Always emit a 'return undefined' in case control fell off the end of
278 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000279 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000280 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000281 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000282 }
283}
284
285
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000286void FullCodeGenerator::ClearAccumulator() {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000287 __ Set(rax, 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000288}
289
290
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000291void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
292 Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000293 Label ok;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000294 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000295 __ j(above_equal, &ok, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000296 StackCheckStub stub;
297 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000298 // Record a mapping of this PC offset to the OSR id. This is used to find
299 // the AST id from the unoptimized code in order to use it as a key into
300 // the deoptimization input data found in the optimized code.
301 RecordStackCheck(stmt->OsrEntryId());
302
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000303 // Loop stack checks can be patched to perform on-stack replacement. In
304 // order to decide whether or not to perform OSR we embed the loop depth
305 // in a test instruction after the call so we can extract it from the OSR
306 // builtin.
307 ASSERT(loop_depth() > 0);
308 __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
309
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000310 __ bind(&ok);
311 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000312 // Record a mapping of the OSR id to this PC. This is used if the OSR
313 // entry becomes the target of a bailout. We don't expect it to be, but
314 // we want it to work if it is.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000315 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000316}
317
318
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000319void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000320 Comment cmnt(masm_, "[ Return sequence");
321 if (return_label_.is_bound()) {
322 __ jmp(&return_label_);
323 } else {
324 __ bind(&return_label_);
325 if (FLAG_trace) {
326 __ push(rax);
327 __ CallRuntime(Runtime::kTraceExit, 1);
328 }
329#ifdef DEBUG
330 // Add a label for checking the size of the code used for returning.
331 Label check_exit_codesize;
332 masm_->bind(&check_exit_codesize);
333#endif
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000334 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000335 __ RecordJSReturn();
336 // Do not use the leave instruction here because it is too short to
337 // patch with the code required by the debugger.
338 __ movq(rsp, rbp);
339 __ pop(rbp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000340
341 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize;
342 __ Ret(arguments_bytes, rcx);
343
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000344#ifdef ENABLE_DEBUGGER_SUPPORT
345 // Add padding that will be overwritten by a debugger breakpoint. We
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000346 // have just generated at least 7 bytes: "movq rsp, rbp; pop rbp; ret k"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000347 // (3 + 1 + 3).
348 const int kPadding = Assembler::kJSReturnSequenceLength - 7;
349 for (int i = 0; i < kPadding; ++i) {
350 masm_->int3();
351 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000352 // Check that the size of the code used for returning is large enough
353 // for the debugger's requirements.
354 ASSERT(Assembler::kJSReturnSequenceLength <=
355 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000356#endif
357 }
358}
359
360
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000361void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
362}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000363
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000364
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000365void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
366 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
367 __ movq(result_register(), slot_operand);
368}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000369
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000370
371void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
372 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
373 __ push(slot_operand);
374}
375
376
377void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
378 codegen()->Move(result_register(), slot);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000379 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000380 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000381}
382
383
384void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
385}
386
387
388void FullCodeGenerator::AccumulatorValueContext::Plug(
389 Heap::RootListIndex index) const {
390 __ LoadRoot(result_register(), index);
391}
392
393
394void FullCodeGenerator::StackValueContext::Plug(
395 Heap::RootListIndex index) const {
396 __ PushRoot(index);
397}
398
399
400void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000401 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
402 true,
403 true_label_,
404 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000405 if (index == Heap::kUndefinedValueRootIndex ||
406 index == Heap::kNullValueRootIndex ||
407 index == Heap::kFalseValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000408 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000409 } else if (index == Heap::kTrueValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000410 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000411 } else {
412 __ LoadRoot(result_register(), index);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000413 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000414 }
415}
416
417
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000418void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
419}
420
421
422void FullCodeGenerator::AccumulatorValueContext::Plug(
423 Handle<Object> lit) const {
424 __ Move(result_register(), lit);
425}
426
427
428void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
429 __ Push(lit);
430}
431
432
433void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000434 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
435 true,
436 true_label_,
437 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000438 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
439 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000440 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000441 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000442 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000443 } else if (lit->IsString()) {
444 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000445 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000446 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000447 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000448 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000449 } else if (lit->IsSmi()) {
450 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000451 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000452 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000453 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000454 }
455 } else {
456 // For simplicity we always test the accumulator register.
457 __ Move(result_register(), lit);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000458 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000459 }
460}
461
462
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000463void FullCodeGenerator::EffectContext::DropAndPlug(int count,
464 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000465 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000466 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000467}
468
469
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000470void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
471 int count,
472 Register reg) const {
473 ASSERT(count > 0);
474 __ Drop(count);
475 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000476}
477
478
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000479void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
480 Register reg) const {
481 ASSERT(count > 0);
482 if (count > 1) __ Drop(count - 1);
483 __ movq(Operand(rsp, 0), reg);
484}
485
486
487void FullCodeGenerator::TestContext::DropAndPlug(int count,
488 Register reg) const {
489 ASSERT(count > 0);
490 // For simplicity we always test the accumulator register.
491 __ Drop(count);
492 __ Move(result_register(), reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000493 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000494 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000495}
496
497
498void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
499 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000500 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000501 __ bind(materialize_true);
502}
503
504
505void FullCodeGenerator::AccumulatorValueContext::Plug(
506 Label* materialize_true,
507 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000508 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000509 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000510 __ Move(result_register(), isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000511 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000512 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 __ Move(result_register(), isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000514 __ bind(&done);
515}
516
517
518void FullCodeGenerator::StackValueContext::Plug(
519 Label* materialize_true,
520 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000521 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000522 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 __ Push(isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000524 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000525 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000526 __ Push(isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000527 __ bind(&done);
528}
529
530
531void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
532 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000533 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000534 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000535}
536
537
538void FullCodeGenerator::EffectContext::Plug(bool flag) const {
539}
540
541
542void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
543 Heap::RootListIndex value_root_index =
544 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
545 __ LoadRoot(result_register(), value_root_index);
546}
547
548
549void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
550 Heap::RootListIndex value_root_index =
551 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
552 __ PushRoot(value_root_index);
553}
554
555
556void FullCodeGenerator::TestContext::Plug(bool flag) const {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000557 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
558 true,
559 true_label_,
560 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000561 if (flag) {
562 if (true_label_ != fall_through_) __ jmp(true_label_);
563 } else {
564 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000565 }
566}
567
568
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000569void FullCodeGenerator::DoTest(Expression* condition,
570 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000571 Label* if_false,
572 Label* fall_through) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000573 ToBooleanStub stub;
574 __ push(result_register());
575 __ CallStub(&stub);
576 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000577 // The stub returns nonzero for true.
578 Split(not_zero, if_true, if_false, fall_through);
579}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000580
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000581
ricow@chromium.org65fae842010-08-25 15:26:24 +0000582void FullCodeGenerator::Split(Condition cc,
583 Label* if_true,
584 Label* if_false,
585 Label* fall_through) {
586 if (if_false == fall_through) {
587 __ j(cc, if_true);
588 } else if (if_true == fall_through) {
589 __ j(NegateCondition(cc), if_false);
590 } else {
591 __ j(cc, if_true);
592 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000593 }
594}
595
596
597MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
598 switch (slot->type()) {
599 case Slot::PARAMETER:
600 case Slot::LOCAL:
601 return Operand(rbp, SlotOffset(slot));
602 case Slot::CONTEXT: {
603 int context_chain_length =
ager@chromium.org5c838252010-02-19 08:53:10 +0000604 scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000605 __ LoadContext(scratch, context_chain_length);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000606 return ContextOperand(scratch, slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000607 }
608 case Slot::LOOKUP:
609 UNREACHABLE();
610 }
611 UNREACHABLE();
612 return Operand(rax, 0);
613}
614
615
616void FullCodeGenerator::Move(Register destination, Slot* source) {
617 MemOperand location = EmitSlotSearch(source, destination);
618 __ movq(destination, location);
619}
620
621
622void FullCodeGenerator::Move(Slot* dst,
623 Register src,
624 Register scratch1,
625 Register scratch2) {
626 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
627 ASSERT(!scratch1.is(src) && !scratch2.is(src));
628 MemOperand location = EmitSlotSearch(dst, scratch1);
629 __ movq(location, src);
630 // Emit the write barrier code if the location is in the heap.
631 if (dst->type() == Slot::CONTEXT) {
632 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
633 __ RecordWrite(scratch1, offset, src, scratch2);
634 }
635}
636
637
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000638void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
639 bool should_normalize,
640 Label* if_true,
641 Label* if_false) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000642 // Only prepare for bailouts before splits if we're in a test
643 // context. Otherwise, we let the Visit function deal with the
644 // preparation to avoid preparing with the same AST id twice.
645 if (!context()->IsTest() || !info_->IsOptimizable()) return;
646
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000647 Label skip;
648 if (should_normalize) __ jmp(&skip, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000649
650 ForwardBailoutStack* current = forward_bailout_stack_;
651 while (current != NULL) {
652 PrepareForBailout(current->expr(), state);
653 current = current->parent();
654 }
655
656 if (should_normalize) {
657 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
658 Split(equal, if_true, if_false, NULL);
659 __ bind(&skip);
660 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000661}
662
663
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000664void FullCodeGenerator::EmitDeclaration(Variable* variable,
665 Variable::Mode mode,
666 FunctionLiteral* function) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000667 Comment cmnt(masm_, "[ Declaration");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000668 ASSERT(variable != NULL); // Must have been resolved.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000669 Slot* slot = variable->AsSlot();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000670 Property* prop = variable->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000671
672 if (slot != NULL) {
673 switch (slot->type()) {
674 case Slot::PARAMETER:
675 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000676 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000677 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
678 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000679 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000680 VisitForAccumulatorValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000681 __ movq(Operand(rbp, SlotOffset(slot)), result_register());
682 }
683 break;
684
685 case Slot::CONTEXT:
686 // We bypass the general EmitSlotSearch because we know more about
687 // this specific context.
688
689 // The variable in the decl always resides in the current context.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000690 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000691 if (FLAG_debug_code) {
692 // Check if we have the correct context pointer.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000693 __ movq(rbx, ContextOperand(rsi, Context::FCONTEXT_INDEX));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000694 __ cmpq(rbx, rsi);
695 __ Check(equal, "Unexpected declaration in current context.");
696 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000697 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000698 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000699 __ movq(ContextOperand(rsi, slot->index()), kScratchRegister);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000700 // No write barrier since the hole value is in old space.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000701 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000702 VisitForAccumulatorValue(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000703 __ movq(ContextOperand(rsi, slot->index()), result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000704 int offset = Context::SlotOffset(slot->index());
705 __ movq(rbx, rsi);
706 __ RecordWrite(rbx, offset, result_register(), rcx);
707 }
708 break;
709
710 case Slot::LOOKUP: {
711 __ push(rsi);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000712 __ Push(variable->name());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000713 // Declaration nodes are always introduced in one of two modes.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000714 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
715 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000716 __ Push(Smi::FromInt(attr));
717 // Push initial value, if any.
718 // Note: For variables we must not push an initial value (such as
719 // 'undefined') because we may have a (legal) redeclaration and we
720 // must not destroy the current value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000721 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000722 __ PushRoot(Heap::kTheHoleValueRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000723 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000724 VisitForStackValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000725 } else {
726 __ Push(Smi::FromInt(0)); // no initial value!
727 }
728 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
729 break;
730 }
731 }
732
733 } else if (prop != NULL) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000734 // A const declaration aliasing a parameter is an illegal redeclaration.
735 ASSERT(mode != Variable::CONST);
736 if (function != NULL) {
737 // We are declaring a function that rewrites to a property.
738 // Use (keyed) IC to set the initial value. We cannot visit the
739 // rewrite because it's shared and we risk recording duplicate AST
740 // IDs for bailouts from optimized code.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000741 ASSERT(prop->obj()->AsVariableProxy() != NULL);
742 { AccumulatorValueContext for_object(this);
743 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000744 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000745 __ push(rax);
746 VisitForAccumulatorValue(function);
747 __ pop(rdx);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000748 ASSERT(prop->key()->AsLiteral() != NULL &&
749 prop->key()->AsLiteral()->handle()->IsSmi());
750 __ Move(rcx, prop->key()->AsLiteral()->handle());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000751
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000752 Handle<Code> ic = is_strict_mode()
753 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
754 : isolate()->builtins()->KeyedStoreIC_Initialize();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000755 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000756 }
757 }
758}
759
760
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000761void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
762 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
763}
764
765
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000766void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
767 // Call the runtime to declare the globals.
768 __ push(rsi); // The context is the first argument.
769 __ Push(pairs);
ager@chromium.org5c838252010-02-19 08:53:10 +0000770 __ Push(Smi::FromInt(is_eval() ? 1 : 0));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000771 __ Push(Smi::FromInt(strict_mode_flag()));
772 __ CallRuntime(Runtime::kDeclareGlobals, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000773 // Return value is ignored.
774}
775
776
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000777void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
778 Comment cmnt(masm_, "[ SwitchStatement");
779 Breakable nested_statement(this, stmt);
780 SetStatementPosition(stmt);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000781
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000782 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000783 VisitForStackValue(stmt->tag());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000784 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000785
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000786 ZoneList<CaseClause*>* clauses = stmt->cases();
787 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000788
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000789 Label next_test; // Recycled for each test.
790 // Compile all the tests with branches to their bodies.
791 for (int i = 0; i < clauses->length(); i++) {
792 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000793 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000794
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000795 // The default is not a test, but remember it as final fall through.
796 if (clause->is_default()) {
797 default_clause = clause;
798 continue;
799 }
800
801 Comment cmnt(masm_, "[ Case comparison");
802 __ bind(&next_test);
803 next_test.Unuse();
804
805 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000806 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000807
ricow@chromium.org65fae842010-08-25 15:26:24 +0000808 // Perform the comparison as if via '==='.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000809 __ movq(rdx, Operand(rsp, 0)); // Switch value.
810 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000811 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000812 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000813 Label slow_case;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000814 __ movq(rcx, rdx);
815 __ or_(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000816 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000817
818 __ cmpq(rdx, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000819 __ j(not_equal, &next_test);
820 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000821 __ jmp(clause->body_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000822 __ bind(&slow_case);
823 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000824
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000825 // Record position before stub call for type feedback.
826 SetSourcePosition(clause->position());
827 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000828 EmitCallIC(ic, &patch_site, clause->CompareId());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000829
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000830 __ testq(rax, rax);
831 __ j(not_equal, &next_test);
832 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000833 __ jmp(clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000834 }
835
836 // Discard the test value and jump to the default if present, otherwise to
837 // the end of the statement.
838 __ bind(&next_test);
839 __ Drop(1); // Switch value is no longer needed.
840 if (default_clause == NULL) {
841 __ jmp(nested_statement.break_target());
842 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000843 __ jmp(default_clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000844 }
845
846 // Compile all the case bodies.
847 for (int i = 0; i < clauses->length(); i++) {
848 Comment cmnt(masm_, "[ Case body");
849 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000850 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000851 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000852 VisitStatements(clause->statements());
853 }
854
855 __ bind(nested_statement.break_target());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000856 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000857}
858
859
860void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
861 Comment cmnt(masm_, "[ ForInStatement");
862 SetStatementPosition(stmt);
863
864 Label loop, exit;
865 ForIn loop_statement(this, stmt);
866 increment_loop_depth();
867
868 // Get the object to enumerate over. Both SpiderMonkey and JSC
869 // ignore null and undefined in contrast to the specification; see
870 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000871 VisitForAccumulatorValue(stmt->enumerable());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000872 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
873 __ j(equal, &exit);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000874 Register null_value = rdi;
875 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
876 __ cmpq(rax, null_value);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000877 __ j(equal, &exit);
878
879 // Convert the object to a JS object.
880 Label convert, done_convert;
881 __ JumpIfSmi(rax, &convert);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000882 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000883 __ j(above_equal, &done_convert);
884 __ bind(&convert);
885 __ push(rax);
886 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
887 __ bind(&done_convert);
888 __ push(rax);
889
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000890 // Check cache validity in generated code. This is a fast case for
891 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
892 // guarantee cache validity, call the runtime system to check cache
893 // validity or get the property names in a fixed array.
894 Label next, call_runtime;
895 Register empty_fixed_array_value = r8;
896 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
897 Register empty_descriptor_array_value = r9;
898 __ LoadRoot(empty_descriptor_array_value,
899 Heap::kEmptyDescriptorArrayRootIndex);
900 __ movq(rcx, rax);
901 __ bind(&next);
902
903 // Check that there are no elements. Register rcx contains the
904 // current JS object we've reached through the prototype chain.
905 __ cmpq(empty_fixed_array_value,
906 FieldOperand(rcx, JSObject::kElementsOffset));
907 __ j(not_equal, &call_runtime);
908
909 // Check that instance descriptors are not empty so that we can
910 // check for an enum cache. Leave the map in rbx for the subsequent
911 // prototype load.
912 __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000913 __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOrBitField3Offset));
914 __ JumpIfSmi(rdx, &call_runtime);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000915
916 // Check that there is an enum cache in the non-empty instance
917 // descriptors (rdx). This is the case if the next enumeration
918 // index field does not contain a smi.
919 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
920 __ JumpIfSmi(rdx, &call_runtime);
921
922 // For all objects but the receiver, check that the cache is empty.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000923 Label check_prototype;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000924 __ cmpq(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000925 __ j(equal, &check_prototype, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000926 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
927 __ cmpq(rdx, empty_fixed_array_value);
928 __ j(not_equal, &call_runtime);
929
930 // Load the prototype from the map and loop if non-null.
931 __ bind(&check_prototype);
932 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
933 __ cmpq(rcx, null_value);
934 __ j(not_equal, &next);
935
936 // The enum cache is valid. Load the map of the object being
937 // iterated over and use the cache for the iteration.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000938 Label use_cache;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000939 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000940 __ jmp(&use_cache, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000941
942 // Get the set of properties to enumerate.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000943 __ bind(&call_runtime);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000944 __ push(rax); // Duplicate the enumerable object on the stack.
945 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
946
947 // If we got a map from the runtime call, we can do a fast
948 // modification check. Otherwise, we got a fixed array, and we have
949 // to do a slow check.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000950 Label fixed_array;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000951 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
952 Heap::kMetaMapRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000953 __ j(not_equal, &fixed_array, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000954
955 // We got a map in register rax. Get the enumeration cache from it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000956 __ bind(&use_cache);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000957 __ LoadInstanceDescriptors(rax, rcx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000958 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
959 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
960
961 // Setup the four remaining stack slots.
962 __ push(rax); // Map.
963 __ push(rdx); // Enumeration cache.
964 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000965 __ push(rax); // Enumeration cache length (as smi).
966 __ Push(Smi::FromInt(0)); // Initial index.
967 __ jmp(&loop);
968
969 // We got a fixed array in register rax. Iterate through that.
970 __ bind(&fixed_array);
971 __ Push(Smi::FromInt(0)); // Map (0) - force slow check.
972 __ push(rax);
973 __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000974 __ push(rax); // Fixed array length (as smi).
975 __ Push(Smi::FromInt(0)); // Initial index.
976
977 // Generate code for doing the condition check.
978 __ bind(&loop);
979 __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
980 __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
981 __ j(above_equal, loop_statement.break_target());
982
983 // Get the current entry of the array into register rbx.
984 __ movq(rbx, Operand(rsp, 2 * kPointerSize));
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000985 SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000986 __ movq(rbx, FieldOperand(rbx,
987 index.reg,
988 index.scale,
989 FixedArray::kHeaderSize));
990
991 // Get the expected map from the stack or a zero map in the
992 // permanent slow case into register rdx.
993 __ movq(rdx, Operand(rsp, 3 * kPointerSize));
994
995 // Check if the expected map still matches that of the enumerable.
996 // If not, we have to filter the key.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000997 Label update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000998 __ movq(rcx, Operand(rsp, 4 * kPointerSize));
999 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001000 __ j(equal, &update_each, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001001
1002 // Convert the entry to a string or null if it isn't a property
1003 // anymore. If the property has been removed while iterating, we
1004 // just skip it.
1005 __ push(rcx); // Enumerable.
1006 __ push(rbx); // Current entry.
1007 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001008 __ Cmp(rax, Smi::FromInt(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001009 __ j(equal, loop_statement.continue_target());
1010 __ movq(rbx, rax);
1011
1012 // Update the 'each' property or variable from the possibly filtered
1013 // entry in register rbx.
1014 __ bind(&update_each);
1015 __ movq(result_register(), rbx);
1016 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001017 { EffectContext context(this);
1018 EmitAssignment(stmt->each(), stmt->AssignmentId());
1019 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001020
1021 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001022 Visit(stmt->body());
1023
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001024 // Generate code for going to the next element by incrementing the
1025 // index (smi) stored on top of the stack.
1026 __ bind(loop_statement.continue_target());
1027 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001028
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001029 EmitStackCheck(stmt);
1030 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001031
1032 // Remove the pointers stored on the stack.
1033 __ bind(loop_statement.break_target());
1034 __ addq(rsp, Immediate(5 * kPointerSize));
1035
1036 // Exit and decrement the loop depth.
1037 __ bind(&exit);
1038 decrement_loop_depth();
1039}
1040
1041
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001042void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1043 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001044 // Use the fast case closure allocation code that allocates in new
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001045 // space for nested functions that don't need literals cloning. If
1046 // we're running with the --always-opt or the --prepare-always-opt
1047 // flag, we need to use the runtime function so that the new function
1048 // we are creating here gets a chance to have its code optimized and
1049 // doesn't just get a copy of the existing unoptimized code.
1050 if (!FLAG_always_opt &&
1051 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052 !pretenure &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001053 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001054 info->num_literals() == 0) {
1055 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001056 __ Push(info);
1057 __ CallStub(&stub);
1058 } else {
1059 __ push(rsi);
1060 __ Push(info);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 __ Push(pretenure
1062 ? isolate()->factory()->true_value()
1063 : isolate()->factory()->false_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001064 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001065 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001066 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001067}
1068
1069
1070void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1071 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001072 EmitVariableLoad(expr->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001073}
1074
1075
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001076void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
1077 Slot* slot,
1078 TypeofState typeof_state,
1079 Label* slow) {
1080 Register context = rsi;
1081 Register temp = rdx;
1082
1083 Scope* s = scope();
1084 while (s != NULL) {
1085 if (s->num_heap_slots() > 0) {
1086 if (s->calls_eval()) {
1087 // Check that extension is NULL.
1088 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1089 Immediate(0));
1090 __ j(not_equal, slow);
1091 }
1092 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001093 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001094 // Walk the rest of the chain without clobbering rsi.
1095 context = temp;
1096 }
1097 // If no outer scope calls eval, we do not need to check more
1098 // context extensions. If we have reached an eval scope, we check
1099 // all extensions from this point.
1100 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1101 s = s->outer_scope();
1102 }
1103
1104 if (s != NULL && s->is_eval_scope()) {
1105 // Loop up the context chain. There is no frame effect so it is
1106 // safe to use raw labels here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001107 Label next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001108 if (!context.is(temp)) {
1109 __ movq(temp, context);
1110 }
1111 // Load map for comparison into register, outside loop.
1112 __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex);
1113 __ bind(&next);
1114 // Terminate at global context.
1115 __ cmpq(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001116 __ j(equal, &fast, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001117 // Check that extension is NULL.
1118 __ cmpq(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1119 __ j(not_equal, slow);
1120 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001121 __ movq(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001122 __ jmp(&next);
1123 __ bind(&fast);
1124 }
1125
1126 // All extension objects were empty and it is safe to use a global
1127 // load IC call.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001128 __ movq(rax, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001129 __ Move(rcx, slot->var()->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001130 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001131 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1132 ? RelocInfo::CODE_TARGET
1133 : RelocInfo::CODE_TARGET_CONTEXT;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001134 EmitCallIC(ic, mode, AstNode::kNoNumber);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001135}
1136
1137
1138MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1139 Slot* slot,
1140 Label* slow) {
1141 ASSERT(slot->type() == Slot::CONTEXT);
1142 Register context = rsi;
1143 Register temp = rbx;
1144
1145 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1146 if (s->num_heap_slots() > 0) {
1147 if (s->calls_eval()) {
1148 // Check that extension is NULL.
1149 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1150 Immediate(0));
1151 __ j(not_equal, slow);
1152 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001153 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001154 // Walk the rest of the chain without clobbering rsi.
1155 context = temp;
1156 }
1157 }
1158 // Check that last extension is NULL.
1159 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1160 __ j(not_equal, slow);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001161
1162 // This function is used only for loads, not stores, so it's safe to
1163 // return an rsi-based operand (the write barrier cannot be allowed to
1164 // destroy the rsi register).
1165 return ContextOperand(context, slot->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001166}
1167
1168
1169void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1170 Slot* slot,
1171 TypeofState typeof_state,
1172 Label* slow,
1173 Label* done) {
1174 // Generate fast-case code for variables that might be shadowed by
1175 // eval-introduced variables. Eval is used a lot without
1176 // introducing variables. In those cases, we do not want to
1177 // perform a runtime call for all variables in the scope
1178 // containing the eval.
1179 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1180 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1181 __ jmp(done);
1182 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001183 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001184 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1185 if (potential_slot != NULL) {
1186 // Generate fast case for locals that rewrite to slots.
1187 __ movq(rax,
1188 ContextSlotOperandCheckExtensions(potential_slot, slow));
1189 if (potential_slot->var()->mode() == Variable::CONST) {
1190 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1191 __ j(not_equal, done);
1192 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1193 }
1194 __ jmp(done);
1195 } else if (rewrite != NULL) {
1196 // Generate fast case for calls of an argument function.
1197 Property* property = rewrite->AsProperty();
1198 if (property != NULL) {
1199 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1200 Literal* key_literal = property->key()->AsLiteral();
1201 if (obj_proxy != NULL &&
1202 key_literal != NULL &&
1203 obj_proxy->IsArguments() &&
1204 key_literal->handle()->IsSmi()) {
1205 // Load arguments object if there are no eval-introduced
1206 // variables. Then load the argument from the arguments
1207 // object using keyed load.
1208 __ movq(rdx,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001209 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001210 slow));
1211 __ Move(rax, key_literal->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001212 Handle<Code> ic =
1213 isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001214 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001215 __ jmp(done);
1216 }
1217 }
1218 }
1219 }
1220}
1221
1222
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001223void FullCodeGenerator::EmitVariableLoad(Variable* var) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001224 // Four cases: non-this global variables, lookup slots, all other
1225 // types of slots, and parameters that rewrite to explicit property
1226 // accesses on the arguments object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001227 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001228 Property* property = var->AsProperty();
1229
1230 if (var->is_global() && !var->is_this()) {
1231 Comment cmnt(masm_, "Global variable");
1232 // Use inline caching. Variable name is passed in rcx and the global
1233 // object on the stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001234 __ Move(rcx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001235 __ movq(rax, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001236 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001237 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001238 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001239
1240 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001241 Label done, slow;
1242
1243 // Generate code for loading from variables potentially shadowed
1244 // by eval-introduced variables.
1245 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1246
1247 __ bind(&slow);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001248 Comment cmnt(masm_, "Lookup slot");
1249 __ push(rsi); // Context.
1250 __ Push(var->name());
1251 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001252 __ bind(&done);
1253
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001254 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001255
1256 } else if (slot != NULL) {
1257 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1258 ? "Context slot"
1259 : "Stack slot");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001260 if (var->mode() == Variable::CONST) {
1261 // Constants may be the hole value if they have not been initialized.
1262 // Unhole them.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001263 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001264 MemOperand slot_operand = EmitSlotSearch(slot, rax);
1265 __ movq(rax, slot_operand);
1266 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001267 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001268 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1269 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001270 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001271 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001272 context()->Plug(slot);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001273 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001274
1275 } else {
1276 Comment cmnt(masm_, "Rewritten parameter");
1277 ASSERT_NOT_NULL(property);
1278 // Rewritten parameter accesses are of the form "slot[literal]".
1279
1280 // Assert that the object is in a slot.
1281 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1282 ASSERT_NOT_NULL(object_var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001283 Slot* object_slot = object_var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001284 ASSERT_NOT_NULL(object_slot);
1285
1286 // Load the object.
1287 MemOperand object_loc = EmitSlotSearch(object_slot, rax);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001288 __ movq(rdx, object_loc);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001289
1290 // Assert that the key is a smi.
1291 Literal* key_literal = property->key()->AsLiteral();
1292 ASSERT_NOT_NULL(key_literal);
1293 ASSERT(key_literal->handle()->IsSmi());
1294
1295 // Load the key.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001296 __ Move(rax, key_literal->handle());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001297
1298 // Do a keyed property load.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001299 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001300 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001301 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001302 }
1303}
1304
1305
1306void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1307 Comment cmnt(masm_, "[ RegExpLiteral");
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001308 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001309 // Registers will be used as follows:
1310 // rdi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001311 // rcx = literals array.
1312 // rbx = regexp literal.
1313 // rax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001314 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001315 __ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001316 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001317 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001318 __ movq(rbx, FieldOperand(rcx, literal_offset));
1319 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
1320 __ j(not_equal, &materialized);
1321
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001322 // Create regexp literal using runtime function
1323 // Result will be in rax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001324 __ push(rcx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001325 __ Push(Smi::FromInt(expr->literal_index()));
1326 __ Push(expr->pattern());
1327 __ Push(expr->flags());
1328 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001329 __ movq(rbx, rax);
1330
1331 __ bind(&materialized);
1332 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1333 Label allocated, runtime_allocate;
1334 __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
1335 __ jmp(&allocated);
1336
1337 __ bind(&runtime_allocate);
1338 __ push(rbx);
1339 __ Push(Smi::FromInt(size));
1340 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1341 __ pop(rbx);
1342
1343 __ bind(&allocated);
1344 // Copy the content into the newly allocated memory.
1345 // (Unroll copy loop once for better throughput).
1346 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1347 __ movq(rdx, FieldOperand(rbx, i));
1348 __ movq(rcx, FieldOperand(rbx, i + kPointerSize));
1349 __ movq(FieldOperand(rax, i), rdx);
1350 __ movq(FieldOperand(rax, i + kPointerSize), rcx);
1351 }
1352 if ((size % (2 * kPointerSize)) != 0) {
1353 __ movq(rdx, FieldOperand(rbx, size - kPointerSize));
1354 __ movq(FieldOperand(rax, size - kPointerSize), rdx);
1355 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001356 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001357}
1358
1359
1360void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1361 Comment cmnt(masm_, "[ ObjectLiteral");
1362 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1363 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
1364 __ Push(Smi::FromInt(expr->literal_index()));
1365 __ Push(expr->constant_properties());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001366 int flags = expr->fast_elements()
1367 ? ObjectLiteral::kFastElements
1368 : ObjectLiteral::kNoFlags;
1369 flags |= expr->has_function()
1370 ? ObjectLiteral::kHasFunction
1371 : ObjectLiteral::kNoFlags;
1372 __ Push(Smi::FromInt(flags));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001373 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001374 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001375 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001376 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001377 }
1378
1379 // If result_saved is true the result is on top of the stack. If
1380 // result_saved is false the result is in rax.
1381 bool result_saved = false;
1382
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001383 // Mark all computed expressions that are bound to a key that
1384 // is shadowed by a later occurrence of the same key. For the
1385 // marked expressions, no store code is emitted.
1386 expr->CalculateEmitStore();
1387
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001388 for (int i = 0; i < expr->properties()->length(); i++) {
1389 ObjectLiteral::Property* property = expr->properties()->at(i);
1390 if (property->IsCompileTimeValue()) continue;
1391
1392 Literal* key = property->key();
1393 Expression* value = property->value();
1394 if (!result_saved) {
1395 __ push(rax); // Save result on the stack
1396 result_saved = true;
1397 }
1398 switch (property->kind()) {
1399 case ObjectLiteral::Property::CONSTANT:
1400 UNREACHABLE();
1401 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1402 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1403 // Fall through.
1404 case ObjectLiteral::Property::COMPUTED:
1405 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001406 if (property->emit_store()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001407 VisitForAccumulatorValue(value);
1408 __ Move(rcx, key->handle());
1409 __ movq(rdx, Operand(rsp, 0));
1410 Handle<Code> ic = is_strict_mode()
1411 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1412 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001413 EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001414 PrepareForBailoutForId(key->id(), NO_REGISTERS);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001415 } else {
1416 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001417 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001418 break;
1419 }
1420 // Fall through.
1421 case ObjectLiteral::Property::PROTOTYPE:
1422 __ push(Operand(rsp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001423 VisitForStackValue(key);
1424 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001425 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001426 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1427 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001428 } else {
1429 __ Drop(3);
1430 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001431 break;
1432 case ObjectLiteral::Property::SETTER:
1433 case ObjectLiteral::Property::GETTER:
1434 __ push(Operand(rsp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001435 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001436 __ Push(property->kind() == ObjectLiteral::Property::SETTER ?
1437 Smi::FromInt(1) :
1438 Smi::FromInt(0));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001439 VisitForStackValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001440 __ CallRuntime(Runtime::kDefineAccessor, 4);
1441 break;
1442 }
1443 }
1444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 if (expr->has_function()) {
1446 ASSERT(result_saved);
1447 __ push(Operand(rsp, 0));
1448 __ CallRuntime(Runtime::kToFastProperties, 1);
1449 }
1450
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001451 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001452 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001453 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001454 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001455 }
1456}
1457
1458
1459void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1460 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001461
1462 ZoneList<Expression*>* subexprs = expr->values();
1463 int length = subexprs->length();
1464
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001465 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1466 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1467 __ Push(Smi::FromInt(expr->literal_index()));
1468 __ Push(expr->constant_elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001469 if (expr->constant_elements()->map() ==
1470 isolate()->heap()->fixed_cow_array_map()) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001471 FastCloneShallowArrayStub stub(
1472 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1473 __ CallStub(&stub);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001475 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001476 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001477 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001478 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001479 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001480 FastCloneShallowArrayStub stub(
1481 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001482 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001483 }
1484
1485 bool result_saved = false; // Is the result saved to the stack?
1486
1487 // Emit code to evaluate all the non-constant subexpressions and to store
1488 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001489 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001490 Expression* subexpr = subexprs->at(i);
1491 // If the subexpression is a literal or a simple materialized literal it
1492 // is already set in the cloned array.
1493 if (subexpr->AsLiteral() != NULL ||
1494 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1495 continue;
1496 }
1497
1498 if (!result_saved) {
1499 __ push(rax);
1500 result_saved = true;
1501 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001502 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001503
1504 // Store the subexpression value in the array's elements.
1505 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1506 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
1507 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1508 __ movq(FieldOperand(rbx, offset), result_register());
1509
1510 // Update the write barrier for the array store.
1511 __ RecordWrite(rbx, offset, result_register(), rcx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001512
1513 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001514 }
1515
1516 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001517 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001518 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001519 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001520 }
1521}
1522
1523
ager@chromium.org5c838252010-02-19 08:53:10 +00001524void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1525 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001526 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1527 // on the left-hand side.
1528 if (!expr->target()->IsValidLeftHandSide()) {
1529 VisitForEffect(expr->target());
1530 return;
1531 }
1532
ager@chromium.org5c838252010-02-19 08:53:10 +00001533 // Left-hand side can only be a property, a global or a (parameter or local)
1534 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1535 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1536 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001537 Property* property = expr->target()->AsProperty();
1538 if (property != NULL) {
1539 assign_type = (property->key()->IsPropertyName())
1540 ? NAMED_PROPERTY
1541 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001542 }
1543
1544 // Evaluate LHS expression.
1545 switch (assign_type) {
1546 case VARIABLE:
1547 // Nothing to do here.
1548 break;
1549 case NAMED_PROPERTY:
1550 if (expr->is_compound()) {
1551 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001552 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001553 __ push(result_register());
1554 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001555 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001556 }
1557 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001558 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001559 if (expr->is_compound()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001560 if (property->is_arguments_access()) {
1561 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1562 MemOperand slot_operand =
1563 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx);
1564 __ push(slot_operand);
1565 __ Move(rax, property->key()->AsLiteral()->handle());
1566 } else {
1567 VisitForStackValue(property->obj());
1568 VisitForAccumulatorValue(property->key());
1569 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001570 __ movq(rdx, Operand(rsp, 0));
1571 __ push(rax);
1572 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001573 if (property->is_arguments_access()) {
1574 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1575 MemOperand slot_operand =
1576 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx);
1577 __ push(slot_operand);
1578 __ Push(property->key()->AsLiteral()->handle());
1579 } else {
1580 VisitForStackValue(property->obj());
1581 VisitForStackValue(property->key());
1582 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001583 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001584 break;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001585 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001586 }
1587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001588 // For compound assignments we need another deoptimization point after the
1589 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001590 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001591 { AccumulatorValueContext context(this);
1592 switch (assign_type) {
1593 case VARIABLE:
1594 EmitVariableLoad(expr->target()->AsVariableProxy()->var());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001595 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001596 break;
1597 case NAMED_PROPERTY:
1598 EmitNamedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001599 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001600 break;
1601 case KEYED_PROPERTY:
1602 EmitKeyedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001603 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001604 break;
1605 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001606 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001607
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001608 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001609 __ push(rax); // Left operand goes on the stack.
1610 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001611
ricow@chromium.org65fae842010-08-25 15:26:24 +00001612 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1613 ? OVERWRITE_RIGHT
1614 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001615 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001616 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001617 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001618 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001619 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001620 mode,
1621 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001622 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001623 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001624 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001625 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001626 // Deoptimization point in case the binary operation may have side effects.
1627 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001628 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001629 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001630 }
1631
1632 // Record source position before possible IC call.
1633 SetSourcePosition(expr->position());
1634
1635 // Store the value.
1636 switch (assign_type) {
1637 case VARIABLE:
1638 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001639 expr->op());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001640 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001641 context()->Plug(rax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001642 break;
1643 case NAMED_PROPERTY:
1644 EmitNamedPropertyAssignment(expr);
1645 break;
1646 case KEYED_PROPERTY:
1647 EmitKeyedPropertyAssignment(expr);
1648 break;
1649 }
1650}
1651
1652
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001653void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1654 SetSourcePosition(prop->position());
1655 Literal* key = prop->key()->AsLiteral();
1656 __ Move(rcx, key->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001657 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001658 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001659}
1660
1661
1662void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1663 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001664 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001665 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001666}
1667
1668
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001669void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001670 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001671 OverwriteMode mode,
1672 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001673 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001674 // Do combined smi check of the operands. Left operand is on the
1675 // stack (popped into rdx). Right operand is in rax but moved into
1676 // rcx to make the shifts easier.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001677 Label done, stub_call, smi_case;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001678 __ pop(rdx);
1679 __ movq(rcx, rax);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001680 __ or_(rax, rdx);
1681 JumpPatchSite patch_site(masm_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001682 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001683
1684 __ bind(&stub_call);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001685 __ movq(rax, rcx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001686 BinaryOpStub stub(op, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001687 EmitCallIC(stub.GetCode(), &patch_site, expr->id());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001688 __ jmp(&done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001689
1690 __ bind(&smi_case);
1691 switch (op) {
1692 case Token::SAR:
1693 __ SmiShiftArithmeticRight(rax, rdx, rcx);
1694 break;
1695 case Token::SHL:
1696 __ SmiShiftLeft(rax, rdx, rcx);
1697 break;
1698 case Token::SHR:
1699 __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
1700 break;
1701 case Token::ADD:
1702 __ SmiAdd(rax, rdx, rcx, &stub_call);
1703 break;
1704 case Token::SUB:
1705 __ SmiSub(rax, rdx, rcx, &stub_call);
1706 break;
1707 case Token::MUL:
1708 __ SmiMul(rax, rdx, rcx, &stub_call);
1709 break;
1710 case Token::BIT_OR:
1711 __ SmiOr(rax, rdx, rcx);
1712 break;
1713 case Token::BIT_AND:
1714 __ SmiAnd(rax, rdx, rcx);
1715 break;
1716 case Token::BIT_XOR:
1717 __ SmiXor(rax, rdx, rcx);
1718 break;
1719 default:
1720 UNREACHABLE();
1721 break;
1722 }
1723
1724 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001725 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001726}
1727
1728
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001729void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1730 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001731 OverwriteMode mode) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001732 __ pop(rdx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001733 BinaryOpStub stub(op, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001734 // NULL signals no inlined smi code.
1735 EmitCallIC(stub.GetCode(), NULL, expr->id());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001736 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001737}
1738
1739
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001740void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001741 // Invalid left-hand sides are rewritten to have a 'throw
1742 // ReferenceError' on the left-hand side.
1743 if (!expr->IsValidLeftHandSide()) {
1744 VisitForEffect(expr);
1745 return;
1746 }
1747
1748 // Left-hand side can only be a property, a global or a (parameter or local)
1749 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1750 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1751 LhsKind assign_type = VARIABLE;
1752 Property* prop = expr->AsProperty();
1753 if (prop != NULL) {
1754 assign_type = (prop->key()->IsPropertyName())
1755 ? NAMED_PROPERTY
1756 : KEYED_PROPERTY;
1757 }
1758
1759 switch (assign_type) {
1760 case VARIABLE: {
1761 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001762 EffectContext context(this);
1763 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001764 break;
1765 }
1766 case NAMED_PROPERTY: {
1767 __ push(rax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001768 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001769 __ movq(rdx, rax);
1770 __ pop(rax); // Restore value.
1771 __ Move(rcx, prop->key()->AsLiteral()->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001772 Handle<Code> ic = is_strict_mode()
1773 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1774 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001775 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001776 break;
1777 }
1778 case KEYED_PROPERTY: {
1779 __ push(rax); // Preserve value.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001780 if (prop->is_synthetic()) {
1781 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1782 ASSERT(prop->key()->AsLiteral() != NULL);
1783 { AccumulatorValueContext for_object(this);
1784 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1785 }
1786 __ movq(rdx, rax);
1787 __ Move(rcx, prop->key()->AsLiteral()->handle());
1788 } else {
1789 VisitForStackValue(prop->obj());
1790 VisitForAccumulatorValue(prop->key());
1791 __ movq(rcx, rax);
1792 __ pop(rdx);
1793 }
1794 __ pop(rax); // Restore value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001795 Handle<Code> ic = is_strict_mode()
1796 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1797 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001798 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001799 break;
1800 }
1801 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001802 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001803 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001804}
1805
1806
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001807void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001808 Token::Value op) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001809 // Left-hand sides that rewrite to explicit property accesses do not reach
1810 // here.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001811 ASSERT(var != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001812 ASSERT(var->is_global() || var->AsSlot() != NULL);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001813
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001814 if (var->is_global()) {
1815 ASSERT(!var->is_this());
1816 // Assignment to a global variable. Use inline caching for the
1817 // assignment. Right-hand-side value is passed in rax, variable name in
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001818 // rcx, and the global object on the stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001819 __ Move(rcx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001820 __ movq(rdx, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001821 Handle<Code> ic = is_strict_mode()
1822 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1823 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001824 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001825
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001826 } else if (op == Token::INIT_CONST) {
1827 // Like var declarations, const declarations are hoisted to function
1828 // scope. However, unlike var initializers, const initializers are able
1829 // to drill a hole to that function context, even from inside a 'with'
1830 // context. We thus bypass the normal static scope lookup.
1831 Slot* slot = var->AsSlot();
1832 Label skip;
1833 switch (slot->type()) {
1834 case Slot::PARAMETER:
1835 // No const parameters.
1836 UNREACHABLE();
1837 break;
1838 case Slot::LOCAL:
1839 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1840 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1841 __ j(not_equal, &skip);
1842 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1843 break;
1844 case Slot::CONTEXT: {
1845 __ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX));
1846 __ movq(rdx, ContextOperand(rcx, slot->index()));
1847 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1848 __ j(not_equal, &skip);
1849 __ movq(ContextOperand(rcx, slot->index()), rax);
1850 int offset = Context::SlotOffset(slot->index());
1851 __ movq(rdx, rax); // Preserve the stored value in eax.
1852 __ RecordWrite(rcx, offset, rdx, rbx);
1853 break;
1854 }
1855 case Slot::LOOKUP:
1856 __ push(rax);
1857 __ push(rsi);
1858 __ Push(var->name());
1859 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1860 break;
1861 }
1862 __ bind(&skip);
1863
1864 } else if (var->mode() != Variable::CONST) {
1865 // Perform the assignment for non-const variables. Const assignments
1866 // are simply skipped.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001867 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001868 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001869 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001870 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001871 // Perform the assignment.
1872 __ movq(Operand(rbp, SlotOffset(slot)), rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001873 break;
1874
1875 case Slot::CONTEXT: {
1876 MemOperand target = EmitSlotSearch(slot, rcx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001877 // Perform the assignment and issue the write barrier.
1878 __ movq(target, rax);
1879 // The value of the assignment is in rax. RecordWrite clobbers its
1880 // register arguments.
1881 __ movq(rdx, rax);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001882 int offset = Context::SlotOffset(slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001883 __ RecordWrite(rcx, offset, rdx, rbx);
1884 break;
1885 }
1886
1887 case Slot::LOOKUP:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001888 // Call the runtime for the assignment.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001889 __ push(rax); // Value.
1890 __ push(rsi); // Context.
1891 __ Push(var->name());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001892 __ Push(Smi::FromInt(strict_mode_flag()));
1893 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001894 break;
1895 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001896 }
1897}
1898
1899
1900void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1901 // Assignment to a property, using a named store IC.
1902 Property* prop = expr->target()->AsProperty();
1903 ASSERT(prop != NULL);
1904 ASSERT(prop->key()->AsLiteral() != NULL);
1905
1906 // If the assignment starts a block of assignments to the same object,
1907 // change to slow case to avoid the quadratic behavior of repeatedly
1908 // adding fast properties.
1909 if (expr->starts_initialization_block()) {
1910 __ push(result_register());
1911 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value.
1912 __ CallRuntime(Runtime::kToSlowProperties, 1);
1913 __ pop(result_register());
1914 }
1915
1916 // Record source code position before IC call.
1917 SetSourcePosition(expr->position());
1918 __ Move(rcx, prop->key()->AsLiteral()->handle());
1919 if (expr->ends_initialization_block()) {
1920 __ movq(rdx, Operand(rsp, 0));
1921 } else {
1922 __ pop(rdx);
1923 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001924 Handle<Code> ic = is_strict_mode()
1925 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1926 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001927 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001928
1929 // If the assignment ends an initialization block, revert to fast case.
1930 if (expr->ends_initialization_block()) {
1931 __ push(rax); // Result of assignment, saved even if not needed.
1932 __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
1933 __ CallRuntime(Runtime::kToFastProperties, 1);
1934 __ pop(rax);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001935 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001936 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001937 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001938 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001939}
1940
1941
1942void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1943 // Assignment to a property, using a keyed store IC.
1944
1945 // If the assignment starts a block of assignments to the same object,
1946 // change to slow case to avoid the quadratic behavior of repeatedly
1947 // adding fast properties.
1948 if (expr->starts_initialization_block()) {
1949 __ push(result_register());
1950 // Receiver is now under the key and value.
1951 __ push(Operand(rsp, 2 * kPointerSize));
1952 __ CallRuntime(Runtime::kToSlowProperties, 1);
1953 __ pop(result_register());
1954 }
1955
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001956 __ pop(rcx);
1957 if (expr->ends_initialization_block()) {
1958 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later.
1959 } else {
1960 __ pop(rdx);
1961 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001962 // Record source code position before IC call.
1963 SetSourcePosition(expr->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001964 Handle<Code> ic = is_strict_mode()
1965 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1966 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001967 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001968
1969 // If the assignment ends an initialization block, revert to fast case.
1970 if (expr->ends_initialization_block()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001971 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001972 __ push(rax); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001973 __ push(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001974 __ CallRuntime(Runtime::kToFastProperties, 1);
1975 __ pop(rax);
1976 }
1977
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001978 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001979 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001980}
1981
1982
1983void FullCodeGenerator::VisitProperty(Property* expr) {
1984 Comment cmnt(masm_, "[ Property");
1985 Expression* key = expr->key();
1986
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001987 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001988 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001989 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001990 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001991 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001992 VisitForStackValue(expr->obj());
1993 VisitForAccumulatorValue(expr->key());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001994 __ pop(rdx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001995 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001996 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001997 }
1998}
1999
2000
2001void FullCodeGenerator::EmitCallWithIC(Call* expr,
ager@chromium.org5c838252010-02-19 08:53:10 +00002002 Handle<Object> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002003 RelocInfo::Mode mode) {
2004 // Code common for calls using the IC.
2005 ZoneList<Expression*>* args = expr->arguments();
2006 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002007 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002008 for (int i = 0; i < arg_count; i++) {
2009 VisitForStackValue(args->at(i));
2010 }
2011 __ Move(rcx, name);
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());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002015 // Call the IC initialization code.
2016 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002017 Handle<Code> ic =
danno@chromium.org40cb8782011-05-25 07:58:50 +00002018 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002019 EmitCallIC(ic, mode, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002020 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002021 // Restore context register.
2022 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002023 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002024}
2025
2026
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002027void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002028 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002029 // Load the key.
2030 VisitForAccumulatorValue(key);
2031
2032 // Swap the name of the function and the receiver on the stack to follow
2033 // the calling convention for call ICs.
2034 __ pop(rcx);
2035 __ push(rax);
2036 __ push(rcx);
2037
2038 // Load the arguments.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002039 ZoneList<Expression*>* args = expr->arguments();
2040 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002041 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002042 for (int i = 0; i < arg_count; i++) {
2043 VisitForStackValue(args->at(i));
2044 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002045 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002046 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002047 SetSourcePosition(expr->position());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002048 // Call the IC initialization code.
2049 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 Handle<Code> ic =
2051 ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002052 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002053 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002054 RecordJSReturnSite(expr);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002055 // Restore context register.
2056 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002057 context()->DropAndPlug(1, rax); // Drop the key still on the stack.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002058}
2059
2060
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002061void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002062 // Code common for calls using the call stub.
2063 ZoneList<Expression*>* args = expr->arguments();
2064 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002065 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002066 for (int i = 0; i < arg_count; i++) {
2067 VisitForStackValue(args->at(i));
2068 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002069 }
2070 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002071 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002072 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002073 CallFunctionStub stub(arg_count, in_loop, flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002074 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002075 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002076 // Restore context register.
2077 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2078 // Discard the function left on TOS.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002079 context()->DropAndPlug(1, rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002080}
2081
2082
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002083void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2084 int arg_count) {
2085 // Push copy of the first argument or undefined if it doesn't exist.
2086 if (arg_count > 0) {
2087 __ push(Operand(rsp, arg_count * kPointerSize));
2088 } else {
2089 __ PushRoot(Heap::kUndefinedValueRootIndex);
2090 }
2091
2092 // Push the receiver of the enclosing function and do runtime call.
2093 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
2094
2095 // Push the strict mode flag.
2096 __ Push(Smi::FromInt(strict_mode_flag()));
2097
2098 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2099 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2100 : Runtime::kResolvePossiblyDirectEval, 4);
2101}
2102
2103
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002104void FullCodeGenerator::VisitCall(Call* expr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002105#ifdef DEBUG
2106 // We want to verify that RecordJSReturnSite gets called on all paths
2107 // through this function. Avoid early returns.
2108 expr->return_is_recorded_ = false;
2109#endif
2110
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002111 Comment cmnt(masm_, "[ Call");
2112 Expression* fun = expr->expression();
2113 Variable* var = fun->AsVariableProxy()->AsVariable();
2114
2115 if (var != NULL && var->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002116 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2117 // resolve the function we need to call and the receiver of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002118 // call. Then we call the resolved function using the given
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002119 // arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002120 ZoneList<Expression*>* args = expr->arguments();
2121 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002122 { PreservePositionScope pos_scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002123 VisitForStackValue(fun);
2124 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002125
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002126 // Push the arguments.
2127 for (int i = 0; i < arg_count; i++) {
2128 VisitForStackValue(args->at(i));
2129 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002130
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002131 // If we know that eval can only be shadowed by eval-introduced
2132 // variables we attempt to load the global eval function directly
2133 // in generated code. If we succeed, there is no need to perform a
2134 // context lookup in the runtime system.
2135 Label done;
2136 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2137 Label slow;
2138 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2139 NOT_INSIDE_TYPEOF,
2140 &slow);
2141 // Push the function and resolve eval.
2142 __ push(rax);
2143 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2144 __ jmp(&done);
2145 __ bind(&slow);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002146 }
2147
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002148 // Push copy of the function (found below the arguments) and
2149 // resolve eval.
2150 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
2151 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2152 if (done.is_linked()) {
2153 __ bind(&done);
2154 }
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002155
2156 // The runtime call returns a pair of values in rax (function) and
2157 // rdx (receiver). Touch up the stack with the right values.
2158 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
2159 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002160 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002161 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002162 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002163 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002164 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002165 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002166 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002167 // Restore context register.
2168 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002169 context()->DropAndPlug(1, rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002170 } else if (var != NULL && !var->is_this() && var->is_global()) {
2171 // Call to a global variable.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002172 // Push global object as receiver for the call IC lookup.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002173 __ push(GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002174 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002175 } else if (var != NULL && var->AsSlot() != NULL &&
2176 var->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002177 // Call to a lookup slot (dynamically introduced variable).
2178 Label slow, done;
2179
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002180 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002181 // Generate code for loading from variables potentially shadowed
2182 // by eval-introduced variables.
2183 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
2184 NOT_INSIDE_TYPEOF,
2185 &slow,
2186 &done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002187
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002188 __ bind(&slow);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002189 }
2190 // Call the runtime to find the function to call (returned in rax)
2191 // and the object holding it (returned in rdx).
2192 __ push(context_register());
2193 __ Push(var->name());
2194 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2195 __ push(rax); // Function.
2196 __ push(rdx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002197
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002198 // If fast case code has been generated, emit code to push the
2199 // function and receiver and have the slow path jump around this
2200 // code.
2201 if (done.is_linked()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002202 Label call;
2203 __ jmp(&call, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002204 __ bind(&done);
2205 // Push function.
2206 __ push(rax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002207 // The receiver is implicitly the global receiver. Indicate this
2208 // by passing the hole to the call function stub.
2209 __ PushRoot(Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002210 __ bind(&call);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002211 }
2212
danno@chromium.org40cb8782011-05-25 07:58:50 +00002213 // The receiver is either the global receiver or an object found
2214 // by LoadContextSlot. That object could be the hole if the
2215 // receiver is implicitly the global object.
2216 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002217 } else if (fun->AsProperty() != NULL) {
2218 // Call to an object property.
2219 Property* prop = fun->AsProperty();
2220 Literal* key = prop->key()->AsLiteral();
2221 if (key != NULL && key->handle()->IsSymbol()) {
2222 // Call to a named property, use call IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002223 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002224 VisitForStackValue(prop->obj());
2225 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002226 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
2227 } else {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002228 // Call to a keyed property.
2229 // For a synthetic property use keyed load IC followed by function call,
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002230 // for a regular property use keyed EmitCallIC.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002231 if (prop->is_synthetic()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002232 // Do not visit the object and key subexpressions (they are shared
2233 // by all occurrences of the same rewritten parameter).
2234 ASSERT(prop->obj()->AsVariableProxy() != NULL);
2235 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
2236 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
2237 MemOperand operand = EmitSlotSearch(slot, rdx);
2238 __ movq(rdx, operand);
2239
2240 ASSERT(prop->key()->AsLiteral() != NULL);
2241 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
2242 __ Move(rax, prop->key()->AsLiteral()->handle());
2243
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002244 // Record source code position for IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002245 SetSourcePosition(prop->position());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002246
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002247 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002248 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002249 // Push result (function).
2250 __ push(rax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002251 // Push Global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002252 __ movq(rcx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002253 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002254 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002255 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002256 { PreservePositionScope scope(masm()->positions_recorder());
2257 VisitForStackValue(prop->obj());
2258 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002259 EmitKeyedCallWithIC(expr, prop->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002260 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002261 }
2262 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002263 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002264 VisitForStackValue(fun);
2265 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002266 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002267 __ movq(rbx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002268 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
2269 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002270 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002271 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002272
2273#ifdef DEBUG
2274 // RecordJSReturnSite should have been called.
2275 ASSERT(expr->return_is_recorded_);
2276#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002277}
2278
2279
2280void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2281 Comment cmnt(masm_, "[ CallNew");
2282 // According to ECMA-262, section 11.2.2, page 44, the function
2283 // expression in new calls must be evaluated before the
2284 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002285
ricow@chromium.org65fae842010-08-25 15:26:24 +00002286 // Push constructor on the stack. If it's not a function it's used as
2287 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2288 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002289 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002290
2291 // Push the arguments ("left-to-right") on the stack.
2292 ZoneList<Expression*>* args = expr->arguments();
2293 int arg_count = args->length();
2294 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002295 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002296 }
2297
2298 // Call the construct call builtin that handles allocation and
2299 // constructor invocation.
2300 SetSourcePosition(expr->position());
2301
ricow@chromium.org65fae842010-08-25 15:26:24 +00002302 // Load function and argument count into rdi and rax.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002303 __ Set(rax, arg_count);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002304 __ movq(rdi, Operand(rsp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002305
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002306 Handle<Code> construct_builtin =
2307 isolate()->builtins()->JSConstructCall();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002308 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002309 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002310}
2311
2312
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002313void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2314 ASSERT(args->length() == 1);
2315
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002316 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002317
2318 Label materialize_true, materialize_false;
2319 Label* if_true = NULL;
2320 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002321 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002322 context()->PrepareTest(&materialize_true, &materialize_false,
2323 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002324
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002325 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002326 __ JumpIfSmi(rax, if_true);
2327 __ jmp(if_false);
2328
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002329 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002330}
2331
2332
2333void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2334 ASSERT(args->length() == 1);
2335
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002336 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002337
2338 Label materialize_true, materialize_false;
2339 Label* if_true = NULL;
2340 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002341 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002342 context()->PrepareTest(&materialize_true, &materialize_false,
2343 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002344
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002345 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00002346 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
2347 Split(non_negative_smi, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002348
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002349 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002350}
2351
2352
2353void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2354 ASSERT(args->length() == 1);
2355
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002356 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002357
2358 Label materialize_true, materialize_false;
2359 Label* if_true = NULL;
2360 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002361 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002362 context()->PrepareTest(&materialize_true, &materialize_false,
2363 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002364
2365 __ JumpIfSmi(rax, if_false);
2366 __ CompareRoot(rax, Heap::kNullValueRootIndex);
2367 __ j(equal, if_true);
2368 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2369 // Undetectable objects behave like undefined when tested with typeof.
2370 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2371 Immediate(1 << Map::kIsUndetectable));
2372 __ j(not_zero, if_false);
2373 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002374 __ cmpq(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002375 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002376 __ cmpq(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002377 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002378 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002379
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002380 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002381}
2382
2383
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002384void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2385 ASSERT(args->length() == 1);
2386
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002387 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002388
2389 Label materialize_true, materialize_false;
2390 Label* if_true = NULL;
2391 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002392 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002393 context()->PrepareTest(&materialize_true, &materialize_false,
2394 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002395
2396 __ JumpIfSmi(rax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002397 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002398 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002399 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002400
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002401 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002402}
2403
2404
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002405void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2406 ASSERT(args->length() == 1);
2407
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002408 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002409
2410 Label materialize_true, materialize_false;
2411 Label* if_true = NULL;
2412 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002413 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002414 context()->PrepareTest(&materialize_true, &materialize_false,
2415 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002416
2417 __ JumpIfSmi(rax, if_false);
2418 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2419 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2420 Immediate(1 << Map::kIsUndetectable));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002421 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002422 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002423
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002424 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002425}
2426
2427
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002428void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2429 ZoneList<Expression*>* args) {
2430 ASSERT(args->length() == 1);
2431
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002432 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002433
2434 Label materialize_true, materialize_false;
2435 Label* if_true = NULL;
2436 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002437 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002438 context()->PrepareTest(&materialize_true, &materialize_false,
2439 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002441 if (FLAG_debug_code) __ AbortIfSmi(rax);
2442
2443 // Check whether this map has already been checked to be safe for default
2444 // valueOf.
2445 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2446 __ testb(FieldOperand(rbx, Map::kBitField2Offset),
2447 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2448 __ j(not_zero, if_true);
2449
2450 // Check for fast case object. Generate false result for slow case object.
2451 __ movq(rcx, FieldOperand(rax, JSObject::kPropertiesOffset));
2452 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2453 __ CompareRoot(rcx, Heap::kHashTableMapRootIndex);
2454 __ j(equal, if_false);
2455
2456 // Look for valueOf symbol in the descriptor array, and indicate false if
2457 // found. The type is not checked, so if it is a transition it is a false
2458 // negative.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002459 __ LoadInstanceDescriptors(rbx, rbx);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002460 __ movq(rcx, FieldOperand(rbx, FixedArray::kLengthOffset));
2461 // rbx: descriptor array
2462 // rcx: length of descriptor array
2463 // Calculate the end of the descriptor array.
2464 SmiIndex index = masm_->SmiToIndex(rdx, rcx, kPointerSizeLog2);
2465 __ lea(rcx,
2466 Operand(
2467 rbx, index.reg, index.scale, FixedArray::kHeaderSize));
2468 // Calculate location of the first key name.
2469 __ addq(rbx,
2470 Immediate(FixedArray::kHeaderSize +
2471 DescriptorArray::kFirstIndex * kPointerSize));
2472 // Loop through all the keys in the descriptor array. If one of these is the
2473 // symbol valueOf the result is false.
2474 Label entry, loop;
2475 __ jmp(&entry);
2476 __ bind(&loop);
2477 __ movq(rdx, FieldOperand(rbx, 0));
2478 __ Cmp(rdx, FACTORY->value_of_symbol());
2479 __ j(equal, if_false);
2480 __ addq(rbx, Immediate(kPointerSize));
2481 __ bind(&entry);
2482 __ cmpq(rbx, rcx);
2483 __ j(not_equal, &loop);
2484
2485 // Reload map as register rbx was used as temporary above.
2486 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2487
2488 // If a valueOf property is not found on the object check that it's
2489 // prototype is the un-modified String prototype. If not result is false.
2490 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
2491 __ testq(rcx, Immediate(kSmiTagMask));
2492 __ j(zero, if_false);
2493 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2494 __ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2495 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
2496 __ cmpq(rcx,
2497 ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2498 __ j(not_equal, if_false);
2499 // Set the bit in the map to indicate that it has been checked safe for
2500 // default valueOf and set true result.
2501 __ or_(FieldOperand(rbx, Map::kBitField2Offset),
2502 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2503 __ jmp(if_true);
2504
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002505 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002506 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002507}
2508
2509
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002510void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2511 ASSERT(args->length() == 1);
2512
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002513 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002514
2515 Label materialize_true, materialize_false;
2516 Label* if_true = NULL;
2517 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002518 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002519 context()->PrepareTest(&materialize_true, &materialize_false,
2520 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002521
2522 __ JumpIfSmi(rax, if_false);
2523 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002524 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002525 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002526
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002527 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002528}
2529
2530
2531void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2532 ASSERT(args->length() == 1);
2533
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002534 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002535
2536 Label materialize_true, materialize_false;
2537 Label* if_true = NULL;
2538 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002539 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002540 context()->PrepareTest(&materialize_true, &materialize_false,
2541 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002542
2543 __ JumpIfSmi(rax, if_false);
2544 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002545 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002546 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002547
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002548 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002549}
2550
2551
2552void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2553 ASSERT(args->length() == 1);
2554
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002555 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002556
2557 Label materialize_true, materialize_false;
2558 Label* if_true = NULL;
2559 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002560 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002561 context()->PrepareTest(&materialize_true, &materialize_false,
2562 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002563
2564 __ JumpIfSmi(rax, if_false);
2565 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002566 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002567 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002568
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002569 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002570}
2571
2572
2573
2574void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2575 ASSERT(args->length() == 0);
2576
2577 Label materialize_true, materialize_false;
2578 Label* if_true = NULL;
2579 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002580 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002581 context()->PrepareTest(&materialize_true, &materialize_false,
2582 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002583
2584 // Get the frame pointer for the calling frame.
2585 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2586
2587 // Skip the arguments adaptor frame if it exists.
2588 Label check_frame_marker;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002589 __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset),
2590 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002591 __ j(not_equal, &check_frame_marker);
2592 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
2593
2594 // Check the marker in the calling frame.
2595 __ bind(&check_frame_marker);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002596 __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
2597 Smi::FromInt(StackFrame::CONSTRUCT));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002598 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002599 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002600
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002601 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002602}
2603
2604
2605void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2606 ASSERT(args->length() == 2);
2607
2608 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002609 VisitForStackValue(args->at(0));
2610 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002611
2612 Label materialize_true, materialize_false;
2613 Label* if_true = NULL;
2614 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002615 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002616 context()->PrepareTest(&materialize_true, &materialize_false,
2617 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002618
2619 __ pop(rbx);
2620 __ cmpq(rax, rbx);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002621 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002622 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002623
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002624 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002625}
2626
2627
2628void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2629 ASSERT(args->length() == 1);
2630
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002631 // ArgumentsAccessStub expects the key in rdx and the formal
2632 // parameter count in rax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002633 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002634 __ movq(rdx, rax);
2635 __ Move(rax, Smi::FromInt(scope()->num_parameters()));
2636 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2637 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002638 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002639}
2640
2641
2642void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2643 ASSERT(args->length() == 0);
2644
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002645 Label exit;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002646 // Get the number of formal parameters.
2647 __ Move(rax, Smi::FromInt(scope()->num_parameters()));
2648
2649 // Check if the calling frame is an arguments adaptor frame.
2650 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002651 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
2652 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002653 __ j(not_equal, &exit, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002654
2655 // Arguments adaptor case: Read the arguments length from the
2656 // adaptor frame.
2657 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2658
2659 __ bind(&exit);
2660 if (FLAG_debug_code) __ AbortIfNotSmi(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002661 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002662}
2663
2664
2665void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2666 ASSERT(args->length() == 1);
2667 Label done, null, function, non_function_constructor;
2668
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002669 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002670
2671 // If the object is a smi, we return null.
2672 __ JumpIfSmi(rax, &null);
2673
2674 // Check that the object is a JS object but take special care of JS
2675 // functions to make sure they have 'Function' as their class.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002676 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
2677 // Map is now in rax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002678 __ j(below, &null);
2679
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002680 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
2681 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
2682 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
2683 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
2684 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
2685 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
2686 __ CmpInstanceType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
2687 __ j(above_equal, &function);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002688
2689 // Check if the constructor in the map is a function.
2690 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
2691 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2692 __ j(not_equal, &non_function_constructor);
2693
2694 // rax now contains the constructor function. Grab the
2695 // instance class name from there.
2696 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
2697 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
2698 __ jmp(&done);
2699
2700 // Functions have class 'Function'.
2701 __ bind(&function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002702 __ Move(rax, isolate()->factory()->function_class_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002703 __ jmp(&done);
2704
2705 // Objects with a non-function constructor have class 'Object'.
2706 __ bind(&non_function_constructor);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002707 __ Move(rax, isolate()->factory()->Object_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002708 __ jmp(&done);
2709
2710 // Non-JS objects have class null.
2711 __ bind(&null);
2712 __ LoadRoot(rax, Heap::kNullValueRootIndex);
2713
2714 // All done.
2715 __ bind(&done);
2716
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002717 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002718}
2719
2720
2721void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2722 // Conditionally generate a log call.
2723 // Args:
2724 // 0 (literal string): The type of logging (corresponds to the flags).
2725 // This is used to determine whether or not to generate the log call.
2726 // 1 (string): Format string. Access the string at argument index 2
2727 // with '%2s' (see Logger::LogRuntime for all the formats).
2728 // 2 (array): Arguments to the format string.
2729 ASSERT_EQ(args->length(), 3);
2730#ifdef ENABLE_LOGGING_AND_PROFILING
2731 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002732 VisitForStackValue(args->at(1));
2733 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002734 __ CallRuntime(Runtime::kLog, 2);
2735 }
2736#endif
2737 // Finally, we're expected to leave a value on the top of the stack.
2738 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002739 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002740}
2741
2742
2743void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2744 ASSERT(args->length() == 0);
2745
2746 Label slow_allocate_heapnumber;
2747 Label heapnumber_allocated;
2748
2749 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
2750 __ jmp(&heapnumber_allocated);
2751
2752 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002753 // Allocate a heap number.
2754 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002755 __ movq(rbx, rax);
2756
2757 __ bind(&heapnumber_allocated);
2758
2759 // Return a random uint32 number in rax.
2760 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002761 __ PrepareCallCFunction(1);
2762#ifdef _WIN64
2763 __ LoadAddress(rcx, ExternalReference::isolate_address());
2764#else
2765 __ LoadAddress(rdi, ExternalReference::isolate_address());
2766#endif
2767 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002768
2769 // Convert 32 random bits in rax to 0.(32 random bits) in a double
2770 // by computing:
2771 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2772 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2773 __ movd(xmm1, rcx);
2774 __ movd(xmm0, rax);
2775 __ cvtss2sd(xmm1, xmm1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002776 __ xorps(xmm0, xmm1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002777 __ subsd(xmm0, xmm1);
2778 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
2779
2780 __ movq(rax, rbx);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002781 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002782}
2783
2784
2785void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2786 // Load the arguments on the stack and call the stub.
2787 SubStringStub stub;
2788 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002789 VisitForStackValue(args->at(0));
2790 VisitForStackValue(args->at(1));
2791 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002792 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002793 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002794}
2795
2796
2797void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2798 // Load the arguments on the stack and call the stub.
2799 RegExpExecStub stub;
2800 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002801 VisitForStackValue(args->at(0));
2802 VisitForStackValue(args->at(1));
2803 VisitForStackValue(args->at(2));
2804 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002805 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002806 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002807}
2808
2809
2810void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2811 ASSERT(args->length() == 1);
2812
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002813 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002814
2815 Label done;
2816 // If the object is a smi return the object.
2817 __ JumpIfSmi(rax, &done);
2818 // If the object is not a value type, return the object.
2819 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
2820 __ j(not_equal, &done);
2821 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset));
2822
2823 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002824 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002825}
2826
2827
2828void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2829 // Load the arguments on the stack and call the runtime function.
2830 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002831 VisitForStackValue(args->at(0));
2832 VisitForStackValue(args->at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002833 MathPowStub stub;
2834 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002835 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002836}
2837
2838
2839void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2840 ASSERT(args->length() == 2);
2841
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002842 VisitForStackValue(args->at(0)); // Load the object.
2843 VisitForAccumulatorValue(args->at(1)); // Load the value.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002844 __ pop(rbx); // rax = value. rbx = object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002845
2846 Label done;
2847 // If the object is a smi, return the value.
2848 __ JumpIfSmi(rbx, &done);
2849
2850 // If the object is not a value type, return the value.
2851 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
2852 __ j(not_equal, &done);
2853
2854 // Store the value.
2855 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax);
2856 // Update the write barrier. Save the value as it will be
2857 // overwritten by the write barrier code and is needed afterward.
2858 __ movq(rdx, rax);
2859 __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx);
2860
2861 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002862 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002863}
2864
2865
2866void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2867 ASSERT_EQ(args->length(), 1);
2868
2869 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002870 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002871
2872 NumberToStringStub stub;
2873 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002874 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002875}
2876
2877
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002878void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002879 ASSERT(args->length() == 1);
2880
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002881 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002882
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002883 Label done;
2884 StringCharFromCodeGenerator generator(rax, rbx);
2885 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002886 __ jmp(&done);
2887
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002888 NopRuntimeCallHelper call_helper;
2889 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002890
2891 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002892 context()->Plug(rbx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002893}
2894
2895
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002896void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2897 ASSERT(args->length() == 2);
2898
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002899 VisitForStackValue(args->at(0));
2900 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002901
2902 Register object = rbx;
2903 Register index = rax;
2904 Register scratch = rcx;
2905 Register result = rdx;
2906
2907 __ pop(object);
2908
2909 Label need_conversion;
2910 Label index_out_of_range;
2911 Label done;
2912 StringCharCodeAtGenerator generator(object,
2913 index,
2914 scratch,
2915 result,
2916 &need_conversion,
2917 &need_conversion,
2918 &index_out_of_range,
2919 STRING_INDEX_IS_NUMBER);
2920 generator.GenerateFast(masm_);
2921 __ jmp(&done);
2922
2923 __ bind(&index_out_of_range);
2924 // When the index is out of range, the spec requires us to return
2925 // NaN.
2926 __ LoadRoot(result, Heap::kNanValueRootIndex);
2927 __ jmp(&done);
2928
2929 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002930 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002931 // trigger conversion.
2932 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2933 __ jmp(&done);
2934
2935 NopRuntimeCallHelper call_helper;
2936 generator.GenerateSlow(masm_, call_helper);
2937
2938 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002939 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002940}
2941
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002942
2943void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2944 ASSERT(args->length() == 2);
2945
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002946 VisitForStackValue(args->at(0));
2947 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002948
2949 Register object = rbx;
2950 Register index = rax;
2951 Register scratch1 = rcx;
2952 Register scratch2 = rdx;
2953 Register result = rax;
2954
2955 __ pop(object);
2956
2957 Label need_conversion;
2958 Label index_out_of_range;
2959 Label done;
2960 StringCharAtGenerator generator(object,
2961 index,
2962 scratch1,
2963 scratch2,
2964 result,
2965 &need_conversion,
2966 &need_conversion,
2967 &index_out_of_range,
2968 STRING_INDEX_IS_NUMBER);
2969 generator.GenerateFast(masm_);
2970 __ jmp(&done);
2971
2972 __ bind(&index_out_of_range);
2973 // When the index is out of range, the spec requires us to return
2974 // the empty string.
2975 __ LoadRoot(result, Heap::kEmptyStringRootIndex);
2976 __ jmp(&done);
2977
2978 __ bind(&need_conversion);
2979 // Move smi zero into the result register, which will trigger
2980 // conversion.
2981 __ Move(result, Smi::FromInt(0));
2982 __ jmp(&done);
2983
2984 NopRuntimeCallHelper call_helper;
2985 generator.GenerateSlow(masm_, call_helper);
2986
2987 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002988 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002989}
2990
2991
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002992void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2993 ASSERT_EQ(2, args->length());
2994
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002995 VisitForStackValue(args->at(0));
2996 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002997
2998 StringAddStub stub(NO_STRING_ADD_FLAGS);
2999 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003000 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003001}
3002
3003
3004void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
3005 ASSERT_EQ(2, args->length());
3006
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003007 VisitForStackValue(args->at(0));
3008 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003009
3010 StringCompareStub stub;
3011 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003012 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003013}
3014
3015
3016void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
3017 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003018 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3019 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003020 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003021 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003022 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003023 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003024}
3025
3026
3027void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
3028 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003029 TranscendentalCacheStub stub(TranscendentalCache::COS,
3030 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003031 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003032 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003033 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003034 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003035}
3036
3037
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003038void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3039 // Load the argument on the stack and call the stub.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003040 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3041 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003042 ASSERT(args->length() == 1);
3043 VisitForStackValue(args->at(0));
3044 __ CallStub(&stub);
3045 context()->Plug(rax);
3046}
3047
3048
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003049void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
3050 // Load the argument on the stack and call the runtime function.
3051 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003052 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003053 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003054 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003055}
3056
3057
3058void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
3059 ASSERT(args->length() >= 2);
3060
danno@chromium.org160a7b02011-04-18 15:51:38 +00003061 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3062 for (int i = 0; i < arg_count + 1; i++) {
3063 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003064 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003065 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003066
danno@chromium.org160a7b02011-04-18 15:51:38 +00003067 // InvokeFunction requires the function in rdi. Move it in there.
3068 __ movq(rdi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003069 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003070 __ InvokeFunction(rdi, count, CALL_FUNCTION,
3071 NullCallWrapper(), CALL_AS_METHOD);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003072 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003073 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003074}
3075
3076
3077void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003078 RegExpConstructResultStub stub;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003079 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003080 VisitForStackValue(args->at(0));
3081 VisitForStackValue(args->at(1));
3082 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003083 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003084 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003085}
3086
3087
3088void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
3089 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003090 VisitForStackValue(args->at(0));
3091 VisitForStackValue(args->at(1));
3092 VisitForStackValue(args->at(2));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003093 Label done;
3094 Label slow_case;
3095 Register object = rax;
3096 Register index_1 = rbx;
3097 Register index_2 = rcx;
3098 Register elements = rdi;
3099 Register temp = rdx;
3100 __ movq(object, Operand(rsp, 2 * kPointerSize));
3101 // Fetch the map and check if array is in fast case.
3102 // Check that object doesn't require security checks and
3103 // has no indexed interceptor.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003104 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3105 __ j(not_equal, &slow_case);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003106 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
3107 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
3108 __ j(not_zero, &slow_case);
3109
3110 // Check the object's elements are in fast case and writable.
3111 __ movq(elements, FieldOperand(object, JSObject::kElementsOffset));
3112 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
3113 Heap::kFixedArrayMapRootIndex);
3114 __ j(not_equal, &slow_case);
3115
3116 // Check that both indices are smis.
3117 __ movq(index_1, Operand(rsp, 1 * kPointerSize));
3118 __ movq(index_2, Operand(rsp, 0 * kPointerSize));
3119 __ JumpIfNotBothSmi(index_1, index_2, &slow_case);
3120
3121 // Check that both indices are valid.
3122 // The JSArray length field is a smi since the array is in fast case mode.
3123 __ movq(temp, FieldOperand(object, JSArray::kLengthOffset));
3124 __ SmiCompare(temp, index_1);
3125 __ j(below_equal, &slow_case);
3126 __ SmiCompare(temp, index_2);
3127 __ j(below_equal, &slow_case);
3128
3129 __ SmiToInteger32(index_1, index_1);
3130 __ SmiToInteger32(index_2, index_2);
3131 // Bring addresses into index1 and index2.
3132 __ lea(index_1, FieldOperand(elements, index_1, times_pointer_size,
3133 FixedArray::kHeaderSize));
3134 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size,
3135 FixedArray::kHeaderSize));
3136
3137 // Swap elements. Use object and temp as scratch registers.
3138 __ movq(object, Operand(index_1, 0));
3139 __ movq(temp, Operand(index_2, 0));
3140 __ movq(Operand(index_2, 0), object);
3141 __ movq(Operand(index_1, 0), temp);
3142
3143 Label new_space;
3144 __ InNewSpace(elements, temp, equal, &new_space);
3145
3146 __ movq(object, elements);
3147 __ RecordWriteHelper(object, index_1, temp);
3148 __ RecordWriteHelper(elements, index_2, temp);
3149
3150 __ bind(&new_space);
3151 // We are done. Drop elements from the stack, and return undefined.
3152 __ addq(rsp, Immediate(3 * kPointerSize));
3153 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3154 __ jmp(&done);
3155
3156 __ bind(&slow_case);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003157 __ CallRuntime(Runtime::kSwapElements, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003158
3159 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003160 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003161}
3162
3163
3164void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3165 ASSERT_EQ(2, args->length());
3166
3167 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3168 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3169
3170 Handle<FixedArray> jsfunction_result_caches(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003171 isolate()->global_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003172 if (jsfunction_result_caches->length() <= cache_id) {
3173 __ Abort("Attempt to use undefined cache.");
3174 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003175 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003176 return;
3177 }
3178
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003179 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003180
3181 Register key = rax;
3182 Register cache = rbx;
3183 Register tmp = rcx;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003184 __ movq(cache, ContextOperand(rsi, Context::GLOBAL_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003185 __ movq(cache,
3186 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
3187 __ movq(cache,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003188 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003189 __ movq(cache,
3190 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3191
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003192 Label done, not_found;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003193 // tmp now holds finger offset as a smi.
3194 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3195 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3196 SmiIndex index =
3197 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
3198 __ cmpq(key, FieldOperand(cache,
3199 index.reg,
3200 index.scale,
3201 FixedArray::kHeaderSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003202 __ j(not_equal, &not_found, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003203 __ movq(rax, FieldOperand(cache,
3204 index.reg,
3205 index.scale,
3206 FixedArray::kHeaderSize + kPointerSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003207 __ jmp(&done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003208
3209 __ bind(&not_found);
3210 // Call runtime to perform the lookup.
3211 __ push(cache);
3212 __ push(key);
3213 __ CallRuntime(Runtime::kGetFromCache, 2);
3214
3215 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003216 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003217}
3218
3219
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003220void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3221 ASSERT_EQ(2, args->length());
3222
3223 Register right = rax;
3224 Register left = rbx;
3225 Register tmp = rcx;
3226
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003227 VisitForStackValue(args->at(0));
3228 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003229 __ pop(left);
3230
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003231 Label done, fail, ok;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003232 __ cmpq(left, right);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003233 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003234 // Fail if either is a non-HeapObject.
3235 Condition either_smi = masm()->CheckEitherSmi(left, right, tmp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003236 __ j(either_smi, &fail, Label::kNear);
3237 __ j(zero, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003238 __ movq(tmp, FieldOperand(left, HeapObject::kMapOffset));
3239 __ cmpb(FieldOperand(tmp, Map::kInstanceTypeOffset),
3240 Immediate(JS_REGEXP_TYPE));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003241 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003242 __ cmpq(tmp, FieldOperand(right, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003243 __ j(not_equal, &fail, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003244 __ movq(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3245 __ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003246 __ j(equal, &ok, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003247 __ bind(&fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003248 __ Move(rax, isolate()->factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003249 __ jmp(&done, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003250 __ bind(&ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003251 __ Move(rax, isolate()->factory()->true_value());
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003252 __ bind(&done);
3253
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003254 context()->Plug(rax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003255}
3256
3257
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003258void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
3259 ASSERT(args->length() == 1);
3260
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003261 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003262
3263 Label materialize_true, materialize_false;
3264 Label* if_true = NULL;
3265 Label* if_false = NULL;
3266 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003267 context()->PrepareTest(&materialize_true, &materialize_false,
3268 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003269
3270 __ testl(FieldOperand(rax, String::kHashFieldOffset),
3271 Immediate(String::kContainsCachedArrayIndexMask));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003272 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003273 __ j(zero, if_true);
3274 __ jmp(if_false);
3275
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003276 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003277}
3278
3279
3280void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3281 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003282 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003283
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003284 if (FLAG_debug_code) {
3285 __ AbortIfNotString(rax);
3286 }
3287
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003288 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
3289 ASSERT(String::kHashShift >= kSmiTagSize);
3290 __ IndexFromHash(rax, rax);
3291
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003292 context()->Plug(rax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003293}
3294
3295
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003296void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003297 Label bailout, return_result, done, one_char_separator, long_separator,
3298 non_trivial_array, not_size_one_array, loop,
3299 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
3300 ASSERT(args->length() == 2);
3301 // We will leave the separator on the stack until the end of the function.
3302 VisitForStackValue(args->at(1));
3303 // Load this to rax (= array)
3304 VisitForAccumulatorValue(args->at(0));
3305 // All aliases of the same register have disjoint lifetimes.
3306 Register array = rax;
3307 Register elements = no_reg; // Will be rax.
3308
3309 Register index = rdx;
3310
3311 Register string_length = rcx;
3312
3313 Register string = rsi;
3314
3315 Register scratch = rbx;
3316
3317 Register array_length = rdi;
3318 Register result_pos = no_reg; // Will be rdi.
3319
3320 Operand separator_operand = Operand(rsp, 2 * kPointerSize);
3321 Operand result_operand = Operand(rsp, 1 * kPointerSize);
3322 Operand array_length_operand = Operand(rsp, 0 * kPointerSize);
3323 // Separator operand is already pushed. Make room for the two
3324 // other stack fields, and clear the direction flag in anticipation
3325 // of calling CopyBytes.
3326 __ subq(rsp, Immediate(2 * kPointerSize));
3327 __ cld();
3328 // Check that the array is a JSArray
3329 __ JumpIfSmi(array, &bailout);
3330 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3331 __ j(not_equal, &bailout);
3332
3333 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003334 __ CheckFastElements(scratch, &bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003335
3336 // Array has fast elements, so its length must be a smi.
3337 // If the array has length zero, return the empty string.
3338 __ movq(array_length, FieldOperand(array, JSArray::kLengthOffset));
3339 __ SmiCompare(array_length, Smi::FromInt(0));
3340 __ j(not_zero, &non_trivial_array);
3341 __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
3342 __ jmp(&return_result);
3343
3344 // Save the array length on the stack.
3345 __ bind(&non_trivial_array);
3346 __ SmiToInteger32(array_length, array_length);
3347 __ movl(array_length_operand, array_length);
3348
3349 // Save the FixedArray containing array's elements.
3350 // End of array's live range.
3351 elements = array;
3352 __ movq(elements, FieldOperand(array, JSArray::kElementsOffset));
3353 array = no_reg;
3354
3355
3356 // Check that all array elements are sequential ASCII strings, and
3357 // accumulate the sum of their lengths, as a smi-encoded value.
3358 __ Set(index, 0);
3359 __ Set(string_length, 0);
3360 // Loop condition: while (index < array_length).
3361 // Live loop registers: index(int32), array_length(int32), string(String*),
3362 // scratch, string_length(int32), elements(FixedArray*).
3363 if (FLAG_debug_code) {
3364 __ cmpq(index, array_length);
3365 __ Assert(below, "No empty arrays here in EmitFastAsciiArrayJoin");
3366 }
3367 __ bind(&loop);
3368 __ movq(string, FieldOperand(elements,
3369 index,
3370 times_pointer_size,
3371 FixedArray::kHeaderSize));
3372 __ JumpIfSmi(string, &bailout);
3373 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3374 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3375 __ andb(scratch, Immediate(
3376 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3377 __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
3378 __ j(not_equal, &bailout);
3379 __ AddSmiField(string_length,
3380 FieldOperand(string, SeqAsciiString::kLengthOffset));
3381 __ j(overflow, &bailout);
3382 __ incl(index);
3383 __ cmpl(index, array_length);
3384 __ j(less, &loop);
3385
3386 // Live registers:
3387 // string_length: Sum of string lengths.
3388 // elements: FixedArray of strings.
3389 // index: Array length.
3390 // array_length: Array length.
3391
3392 // If array_length is 1, return elements[0], a string.
3393 __ cmpl(array_length, Immediate(1));
3394 __ j(not_equal, &not_size_one_array);
3395 __ movq(rax, FieldOperand(elements, FixedArray::kHeaderSize));
3396 __ jmp(&return_result);
3397
3398 __ bind(&not_size_one_array);
3399
3400 // End of array_length live range.
3401 result_pos = array_length;
3402 array_length = no_reg;
3403
3404 // Live registers:
3405 // string_length: Sum of string lengths.
3406 // elements: FixedArray of strings.
3407 // index: Array length.
3408
3409 // Check that the separator is a sequential ASCII string.
3410 __ movq(string, separator_operand);
3411 __ JumpIfSmi(string, &bailout);
3412 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
3413 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3414 __ andb(scratch, Immediate(
3415 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3416 __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
3417 __ j(not_equal, &bailout);
3418
3419 // Live registers:
3420 // string_length: Sum of string lengths.
3421 // elements: FixedArray of strings.
3422 // index: Array length.
3423 // string: Separator string.
3424
3425 // Add (separator length times (array_length - 1)) to string_length.
3426 __ SmiToInteger32(scratch,
3427 FieldOperand(string, SeqAsciiString::kLengthOffset));
3428 __ decl(index);
3429 __ imull(scratch, index);
3430 __ j(overflow, &bailout);
3431 __ addl(string_length, scratch);
3432 __ j(overflow, &bailout);
3433
3434 // Live registers and stack values:
3435 // string_length: Total length of result string.
3436 // elements: FixedArray of strings.
3437 __ AllocateAsciiString(result_pos, string_length, scratch,
3438 index, string, &bailout);
3439 __ movq(result_operand, result_pos);
3440 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3441
3442 __ movq(string, separator_operand);
3443 __ SmiCompare(FieldOperand(string, SeqAsciiString::kLengthOffset),
3444 Smi::FromInt(1));
3445 __ j(equal, &one_char_separator);
3446 __ j(greater, &long_separator);
3447
3448
3449 // Empty separator case:
3450 __ Set(index, 0);
3451 __ movl(scratch, array_length_operand);
3452 __ jmp(&loop_1_condition);
3453 // Loop condition: while (index < array_length).
3454 __ bind(&loop_1);
3455 // Each iteration of the loop concatenates one string to the result.
3456 // Live values in registers:
3457 // index: which element of the elements array we are adding to the result.
3458 // result_pos: the position to which we are currently copying characters.
3459 // elements: the FixedArray of strings we are joining.
3460 // scratch: array length.
3461
3462 // Get string = array[index].
3463 __ movq(string, FieldOperand(elements, index,
3464 times_pointer_size,
3465 FixedArray::kHeaderSize));
3466 __ SmiToInteger32(string_length,
3467 FieldOperand(string, String::kLengthOffset));
3468 __ lea(string,
3469 FieldOperand(string, SeqAsciiString::kHeaderSize));
3470 __ CopyBytes(result_pos, string, string_length);
3471 __ incl(index);
3472 __ bind(&loop_1_condition);
3473 __ cmpl(index, scratch);
3474 __ j(less, &loop_1); // Loop while (index < array_length).
3475 __ jmp(&done);
3476
3477 // Generic bailout code used from several places.
3478 __ bind(&bailout);
3479 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3480 __ jmp(&return_result);
3481
3482
3483 // One-character separator case
3484 __ bind(&one_char_separator);
3485 // Get the separator ascii character value.
3486 // Register "string" holds the separator.
3487 __ movzxbl(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3488 __ Set(index, 0);
3489 // Jump into the loop after the code that copies the separator, so the first
3490 // element is not preceded by a separator
3491 __ jmp(&loop_2_entry);
3492 // Loop condition: while (index < length).
3493 __ bind(&loop_2);
3494 // Each iteration of the loop concatenates one string to the result.
3495 // Live values in registers:
3496 // elements: The FixedArray of strings we are joining.
3497 // index: which element of the elements array we are adding to the result.
3498 // result_pos: the position to which we are currently copying characters.
3499 // scratch: Separator character.
3500
3501 // Copy the separator character to the result.
3502 __ movb(Operand(result_pos, 0), scratch);
3503 __ incq(result_pos);
3504
3505 __ bind(&loop_2_entry);
3506 // Get string = array[index].
3507 __ movq(string, FieldOperand(elements, index,
3508 times_pointer_size,
3509 FixedArray::kHeaderSize));
3510 __ SmiToInteger32(string_length,
3511 FieldOperand(string, String::kLengthOffset));
3512 __ lea(string,
3513 FieldOperand(string, SeqAsciiString::kHeaderSize));
3514 __ CopyBytes(result_pos, string, string_length);
3515 __ incl(index);
3516 __ cmpl(index, array_length_operand);
3517 __ j(less, &loop_2); // End while (index < length).
3518 __ jmp(&done);
3519
3520
3521 // Long separator case (separator is more than one character).
3522 __ bind(&long_separator);
3523
3524 // Make elements point to end of elements array, and index
3525 // count from -array_length to zero, so we don't need to maintain
3526 // a loop limit.
3527 __ movl(index, array_length_operand);
3528 __ lea(elements, FieldOperand(elements, index, times_pointer_size,
3529 FixedArray::kHeaderSize));
3530 __ neg(index);
3531
3532 // Replace separator string with pointer to its first character, and
3533 // make scratch be its length.
3534 __ movq(string, separator_operand);
3535 __ SmiToInteger32(scratch,
3536 FieldOperand(string, String::kLengthOffset));
3537 __ lea(string,
3538 FieldOperand(string, SeqAsciiString::kHeaderSize));
3539 __ movq(separator_operand, string);
3540
3541 // Jump into the loop after the code that copies the separator, so the first
3542 // element is not preceded by a separator
3543 __ jmp(&loop_3_entry);
3544 // Loop condition: while (index < length).
3545 __ bind(&loop_3);
3546 // Each iteration of the loop concatenates one string to the result.
3547 // Live values in registers:
3548 // index: which element of the elements array we are adding to the result.
3549 // result_pos: the position to which we are currently copying characters.
3550 // scratch: Separator length.
3551 // separator_operand (rsp[0x10]): Address of first char of separator.
3552
3553 // Copy the separator to the result.
3554 __ movq(string, separator_operand);
3555 __ movl(string_length, scratch);
3556 __ CopyBytes(result_pos, string, string_length, 2);
3557
3558 __ bind(&loop_3_entry);
3559 // Get string = array[index].
3560 __ movq(string, Operand(elements, index, times_pointer_size, 0));
3561 __ SmiToInteger32(string_length,
3562 FieldOperand(string, String::kLengthOffset));
3563 __ lea(string,
3564 FieldOperand(string, SeqAsciiString::kHeaderSize));
3565 __ CopyBytes(result_pos, string, string_length);
3566 __ incq(index);
3567 __ j(not_equal, &loop_3); // Loop while (index < 0).
3568
3569 __ bind(&done);
3570 __ movq(rax, result_operand);
3571
3572 __ bind(&return_result);
3573 // Drop temp values from the stack, and restore context register.
3574 __ addq(rsp, Immediate(3 * kPointerSize));
3575 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3576 context()->Plug(rax);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003577}
3578
3579
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003580void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003581 Handle<String> name = expr->name();
3582 if (name->length() > 0 && name->Get(0) == '_') {
3583 Comment cmnt(masm_, "[ InlineRuntimeCall");
3584 EmitInlineRuntimeCall(expr);
3585 return;
3586 }
3587
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003588 Comment cmnt(masm_, "[ CallRuntime");
3589 ZoneList<Expression*>* args = expr->arguments();
3590
3591 if (expr->is_jsruntime()) {
3592 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003593 __ movq(rax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003594 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
3595 }
3596
3597 // Push the arguments ("left-to-right").
3598 int arg_count = args->length();
3599 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003600 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003601 }
3602
3603 if (expr->is_jsruntime()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003604 // Call the JS runtime function using a call IC.
3605 __ Move(rcx, expr->name());
3606 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003607 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003608 Handle<Code> ic =
danno@chromium.org40cb8782011-05-25 07:58:50 +00003609 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
3610 EmitCallIC(ic, mode, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003611 // Restore context register.
3612 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003613 } else {
3614 __ CallRuntime(expr->function(), arg_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003615 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003616 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003617}
3618
3619
3620void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3621 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003622 case Token::DELETE: {
3623 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3624 Property* prop = expr->expression()->AsProperty();
3625 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003626
3627 if (prop != NULL) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003628 if (prop->is_synthetic()) {
3629 // Result of deleting parameters is false, even when they rewrite
3630 // to accesses on the arguments object.
3631 context()->Plug(false);
3632 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003633 VisitForStackValue(prop->obj());
3634 VisitForStackValue(prop->key());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003635 __ Push(Smi::FromInt(strict_mode_flag()));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003636 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003637 context()->Plug(rax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003638 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003639 } else if (var != NULL) {
3640 // Delete of an unqualified identifier is disallowed in strict mode
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003641 // but "delete this" is.
3642 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003643 if (var->is_global()) {
3644 __ push(GlobalObjectOperand());
3645 __ Push(var->name());
3646 __ Push(Smi::FromInt(kNonStrictMode));
3647 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3648 context()->Plug(rax);
3649 } else if (var->AsSlot() != NULL &&
3650 var->AsSlot()->type() != Slot::LOOKUP) {
3651 // Result of deleting non-global, non-dynamic variables is false.
3652 // The subexpression does not have side effects.
3653 context()->Plug(false);
3654 } else {
3655 // Non-global variable. Call the runtime to try to delete from the
3656 // context where the variable was introduced.
3657 __ push(context_register());
3658 __ Push(var->name());
3659 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3660 context()->Plug(rax);
3661 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003662 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003663 // Result of deleting non-property, non-variable reference is true.
3664 // The subexpression may have side effects.
3665 VisitForEffect(expr->expression());
3666 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003667 }
3668 break;
3669 }
3670
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003671 case Token::VOID: {
3672 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3673 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003674 context()->Plug(Heap::kUndefinedValueRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003675 break;
3676 }
3677
3678 case Token::NOT: {
3679 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003680 if (context()->IsEffect()) {
3681 // Unary NOT has no side effects so it's only necessary to visit the
3682 // subexpression. Match the optimizing compiler by not branching.
3683 VisitForEffect(expr->expression());
3684 } else {
3685 Label materialize_true, materialize_false;
3686 Label* if_true = NULL;
3687 Label* if_false = NULL;
3688 Label* fall_through = NULL;
3689 // Notice that the labels are swapped.
3690 context()->PrepareTest(&materialize_true, &materialize_false,
3691 &if_false, &if_true, &fall_through);
3692 if (context()->IsTest()) ForwardBailoutToChild(expr);
3693 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3694 context()->Plug(if_false, if_true); // Labels swapped.
3695 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003696 break;
3697 }
3698
3699 case Token::TYPEOF: {
3700 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003701 { StackValueContext context(this);
3702 VisitForTypeofValue(expr->expression());
3703 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003704 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003705 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003706 break;
3707 }
3708
3709 case Token::ADD: {
3710 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003711 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003712 Label no_conversion;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003713 Condition is_smi = masm_->CheckSmi(result_register());
3714 __ j(is_smi, &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003715 ToNumberStub convert_stub;
3716 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003717 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003718 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003719 break;
3720 }
3721
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003722 case Token::SUB:
3723 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003724 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003725
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003726 case Token::BIT_NOT:
3727 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003728 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003729
3730 default:
3731 UNREACHABLE();
3732 }
3733}
3734
3735
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003736void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3737 const char* comment) {
3738 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
3739 Comment cmt(masm_, comment);
3740 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3741 UnaryOverwriteMode overwrite =
3742 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003743 UnaryOpStub stub(expr->op(), overwrite);
3744 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003745 // accumulator register rax.
3746 VisitForAccumulatorValue(expr->expression());
3747 SetSourcePosition(expr->position());
3748 EmitCallIC(stub.GetCode(), NULL, expr->id());
3749 context()->Plug(rax);
3750}
3751
3752
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003753void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3754 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003755 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003756
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003757 // Invalid left-hand-sides are rewritten to have a 'throw
3758 // ReferenceError' as the left-hand side.
3759 if (!expr->expression()->IsValidLeftHandSide()) {
3760 VisitForEffect(expr->expression());
3761 return;
3762 }
3763
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003764 // Expression can only be a property, a global or a (parameter or local)
3765 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
3766 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3767 LhsKind assign_type = VARIABLE;
3768 Property* prop = expr->expression()->AsProperty();
3769 // In case of a property we use the uninitialized expression context
3770 // of the key to detect a named property.
3771 if (prop != NULL) {
3772 assign_type =
3773 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3774 }
3775
3776 // Evaluate expression and get value.
3777 if (assign_type == VARIABLE) {
3778 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003779 AccumulatorValueContext context(this);
3780 EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003781 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003782 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003783 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003784 __ Push(Smi::FromInt(0));
3785 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003786 if (assign_type == NAMED_PROPERTY) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003787 VisitForAccumulatorValue(prop->obj());
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00003788 __ push(rax); // Copy of receiver, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003789 EmitNamedPropertyLoad(prop);
3790 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003791 if (prop->is_arguments_access()) {
3792 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy();
3793 MemOperand slot_operand =
3794 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx);
3795 __ push(slot_operand);
3796 __ Move(rax, prop->key()->AsLiteral()->handle());
3797 } else {
3798 VisitForStackValue(prop->obj());
3799 VisitForAccumulatorValue(prop->key());
3800 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003801 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack
3802 __ push(rax); // Copy of key, needed for later store.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003803 EmitKeyedPropertyLoad(prop);
3804 }
3805 }
3806
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003807 // We need a second deoptimization point after loading the value
3808 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003809 if (assign_type == VARIABLE) {
3810 PrepareForBailout(expr->expression(), TOS_REG);
3811 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003812 PrepareForBailoutForId(expr->CountId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003813 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003814
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003815 // Call ToNumber only if operand is not a smi.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003816 Label no_conversion;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003817 Condition is_smi;
3818 is_smi = masm_->CheckSmi(rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003819 __ j(is_smi, &no_conversion, Label::kNear);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003820 ToNumberStub convert_stub;
3821 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003822 __ bind(&no_conversion);
3823
3824 // Save result for postfix expressions.
3825 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003826 if (!context()->IsEffect()) {
3827 // Save the result on the stack. If we have a named or keyed property
3828 // we store the result under the receiver that is currently on top
3829 // of the stack.
3830 switch (assign_type) {
3831 case VARIABLE:
3832 __ push(rax);
3833 break;
3834 case NAMED_PROPERTY:
3835 __ movq(Operand(rsp, kPointerSize), rax);
3836 break;
3837 case KEYED_PROPERTY:
3838 __ movq(Operand(rsp, 2 * kPointerSize), rax);
3839 break;
3840 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003841 }
3842 }
3843
3844 // Inline smi case if we are in a loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003845 Label done, stub_call;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003846 JumpPatchSite patch_site(masm_);
3847
ricow@chromium.org65fae842010-08-25 15:26:24 +00003848 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003849 if (expr->op() == Token::INC) {
3850 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
3851 } else {
3852 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
3853 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003854 __ j(overflow, &stub_call, Label::kNear);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003855 // We could eliminate this smi check if we split the code at
3856 // the first smi check before calling ToNumber.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003857 patch_site.EmitJumpIfSmi(rax, &done, Label::kNear);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003858
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003859 __ bind(&stub_call);
3860 // Call stub. Undo operation first.
3861 if (expr->op() == Token::INC) {
3862 __ SmiSubConstant(rax, rax, Smi::FromInt(1));
3863 } else {
3864 __ SmiAddConstant(rax, rax, Smi::FromInt(1));
3865 }
3866 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003867
3868 // Record position before stub call.
3869 SetSourcePosition(expr->position());
3870
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003871 // Call stub for +1/-1.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003872 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003873 if (expr->op() == Token::INC) {
3874 __ Move(rdx, Smi::FromInt(1));
3875 } else {
3876 __ movq(rdx, rax);
3877 __ Move(rax, Smi::FromInt(1));
3878 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003879 EmitCallIC(stub.GetCode(), &patch_site, expr->CountId());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003880 __ bind(&done);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003881
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003882 // Store the value returned in rax.
3883 switch (assign_type) {
3884 case VARIABLE:
3885 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003886 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003887 { EffectContext context(this);
3888 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3889 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003890 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003891 context.Plug(rax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003892 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003893 // For all contexts except kEffect: We have the result on
3894 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003895 if (!context()->IsEffect()) {
3896 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003897 }
3898 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003899 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003900 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003901 Token::ASSIGN);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003902 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003903 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003904 }
3905 break;
3906 case NAMED_PROPERTY: {
3907 __ Move(rcx, prop->key()->AsLiteral()->handle());
3908 __ pop(rdx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003909 Handle<Code> ic = is_strict_mode()
3910 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3911 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003912 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003913 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003914 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003915 if (!context()->IsEffect()) {
3916 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003917 }
3918 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003919 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003920 }
3921 break;
3922 }
3923 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003924 __ pop(rcx);
3925 __ pop(rdx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003926 Handle<Code> ic = is_strict_mode()
3927 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3928 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003929 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003930 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003931 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003932 if (!context()->IsEffect()) {
3933 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003934 }
3935 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003936 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003937 }
3938 break;
3939 }
3940 }
3941}
3942
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003943
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003944void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003945 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003946 ASSERT(!context()->IsEffect());
3947 ASSERT(!context()->IsTest());
3948
ricow@chromium.org65fae842010-08-25 15:26:24 +00003949 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3950 Comment cmnt(masm_, "Global variable");
3951 __ Move(rcx, proxy->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003952 __ movq(rax, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003953 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003954 // Use a regular load, not a contextual load, to avoid a reference
3955 // error.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003956 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003957 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003958 context()->Plug(rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003959 } else if (proxy != NULL &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003960 proxy->var()->AsSlot() != NULL &&
3961 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003962 Label done, slow;
3963
3964 // Generate code for loading from variables potentially shadowed
3965 // by eval-introduced variables.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003966 Slot* slot = proxy->var()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003967 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3968
3969 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003970 __ push(rsi);
3971 __ Push(proxy->name());
3972 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003973 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003974 __ bind(&done);
3975
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003976 context()->Plug(rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003977 } else {
3978 // This expression cannot throw a reference error at the top level.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003979 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003980 }
3981}
3982
3983
ricow@chromium.org65fae842010-08-25 15:26:24 +00003984bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
3985 Expression* left,
3986 Expression* right,
3987 Label* if_true,
3988 Label* if_false,
3989 Label* fall_through) {
3990 if (op != Token::EQ && op != Token::EQ_STRICT) return false;
3991
3992 // Check for the pattern: typeof <expression> == <string literal>.
3993 Literal* right_literal = right->AsLiteral();
3994 if (right_literal == NULL) return false;
3995 Handle<Object> right_literal_value = right_literal->handle();
3996 if (!right_literal_value->IsString()) return false;
3997 UnaryOperation* left_unary = left->AsUnaryOperation();
3998 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
3999 Handle<String> check = Handle<String>::cast(right_literal_value);
4000
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004001 { AccumulatorValueContext context(this);
4002 VisitForTypeofValue(left_unary->expression());
4003 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004004 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004005
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004007 __ JumpIfSmi(rax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004008 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
4009 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
4010 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004011 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004012 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004013 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004014 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
4015 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004016 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004017 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004018 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004019 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004020 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
4021 __ j(equal, if_true);
4022 __ CompareRoot(rax, Heap::kFalseValueRootIndex);
4023 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004024 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004025 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4026 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004027 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004028 // Check for undetectable objects => true.
4029 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
4030 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4031 Immediate(1 << Map::kIsUndetectable));
4032 Split(not_zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004033 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004034 __ JumpIfSmi(rax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004035 STATIC_ASSERT(LAST_CALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE);
4036 __ CmpObjectType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, rdx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004037 Split(above_equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004039 __ JumpIfSmi(rax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004040 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4041 __ j(equal, if_true);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004042 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004043 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004044 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4045 __ j(above, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004046 // Check for undetectable objects => false.
4047 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4048 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004049 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004050 } else {
4051 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004052 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004053
4054 return true;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004055}
4056
4057
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004058void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4059 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004060 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004061
4062 // Always perform the comparison for its control flow. Pack the result
4063 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004064 Label materialize_true, materialize_false;
4065 Label* if_true = NULL;
4066 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004067 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004068 context()->PrepareTest(&materialize_true, &materialize_false,
4069 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004070
4071 // First we try a fast inlined version of the compare when one of
4072 // the operands is a literal.
4073 Token::Value op = expr->op();
4074 Expression* left = expr->left();
4075 Expression* right = expr->right();
4076 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004077 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004078 return;
4079 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004080
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004081 VisitForStackValue(expr->left());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004082 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004083 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004084 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004085 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004086 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004087 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004088 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004089 break;
4090
4091 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004092 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004093 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004094 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004095 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004096 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004097 // The stub returns 0 for true.
4098 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004099 break;
4100 }
4101
4102 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004103 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004104 Condition cc = no_condition;
4105 bool strict = false;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004106 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004107 case Token::EQ_STRICT:
4108 strict = true;
4109 // Fall through.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004110 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004111 cc = equal;
4112 __ pop(rdx);
4113 break;
4114 case Token::LT:
4115 cc = less;
4116 __ pop(rdx);
4117 break;
4118 case Token::GT:
4119 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4120 cc = less;
4121 __ movq(rdx, result_register());
4122 __ pop(rax);
4123 break;
4124 case Token::LTE:
4125 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4126 cc = greater_equal;
4127 __ movq(rdx, result_register());
4128 __ pop(rax);
4129 break;
4130 case Token::GTE:
4131 cc = greater_equal;
4132 __ pop(rdx);
4133 break;
4134 case Token::IN:
4135 case Token::INSTANCEOF:
4136 default:
4137 UNREACHABLE();
4138 }
4139
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004140 bool inline_smi_code = ShouldInlineSmiCase(op);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004141 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004142 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004143 Label slow_case;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004144 __ movq(rcx, rdx);
4145 __ or_(rcx, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004146 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004147 __ cmpq(rdx, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004148 Split(cc, if_true, if_false, NULL);
4149 __ bind(&slow_case);
4150 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004151
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004152 // Record position and call the compare IC.
4153 SetSourcePosition(expr->position());
4154 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004155 EmitCallIC(ic, &patch_site, expr->id());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004156
4157 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004158 __ testq(rax, rax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004159 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004160 }
4161 }
4162
4163 // Convert the result of the comparison into one expected for this
4164 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004165 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004166}
4167
4168
ricow@chromium.org65fae842010-08-25 15:26:24 +00004169void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4170 Comment cmnt(masm_, "[ CompareToNull");
4171 Label materialize_true, materialize_false;
4172 Label* if_true = NULL;
4173 Label* if_false = NULL;
4174 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004175 context()->PrepareTest(&materialize_true, &materialize_false,
4176 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004177
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004178 VisitForAccumulatorValue(expr->expression());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004179 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004180 __ CompareRoot(rax, Heap::kNullValueRootIndex);
4181 if (expr->is_strict()) {
4182 Split(equal, if_true, if_false, fall_through);
4183 } else {
4184 __ j(equal, if_true);
4185 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4186 __ j(equal, if_true);
4187 Condition is_smi = masm_->CheckSmi(rax);
4188 __ j(is_smi, if_false);
4189 // It can be an undetectable object.
4190 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
4191 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
4192 Immediate(1 << Map::kIsUndetectable));
4193 Split(not_zero, if_true, if_false, fall_through);
4194 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004195 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004196}
4197
4198
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004199void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4200 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004201 context()->Plug(rax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004202}
4203
4204
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004205Register FullCodeGenerator::result_register() {
4206 return rax;
4207}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004208
4209
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004210Register FullCodeGenerator::context_register() {
4211 return rsi;
4212}
4213
4214
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004215void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
4216 RelocInfo::Mode mode,
4217 unsigned ast_id) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004218 ASSERT(mode == RelocInfo::CODE_TARGET ||
4219 mode == RelocInfo::CODE_TARGET_CONTEXT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004220 Counters* counters = isolate()->counters();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004221 switch (ic->kind()) {
4222 case Code::LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004223 __ IncrementCounter(counters->named_load_full(), 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004224 break;
4225 case Code::KEYED_LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004226 __ IncrementCounter(counters->keyed_load_full(), 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004227 break;
4228 case Code::STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004229 __ IncrementCounter(counters->named_store_full(), 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004230 break;
4231 case Code::KEYED_STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004232 __ IncrementCounter(counters->keyed_store_full(), 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004233 default:
4234 break;
4235 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004236 __ call(ic, mode, ast_id);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004237}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004238
4239
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004240void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
4241 JumpPatchSite* patch_site,
4242 unsigned ast_id) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004243 Counters* counters = isolate()->counters();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004244 switch (ic->kind()) {
4245 case Code::LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004246 __ IncrementCounter(counters->named_load_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004247 break;
4248 case Code::KEYED_LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004249 __ IncrementCounter(counters->keyed_load_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004250 break;
4251 case Code::STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004252 __ IncrementCounter(counters->named_store_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004253 break;
4254 case Code::KEYED_STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004255 __ IncrementCounter(counters->keyed_store_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004256 default:
4257 break;
4258 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004259 __ call(ic, RelocInfo::CODE_TARGET, ast_id);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004260 if (patch_site != NULL && patch_site->is_bound()) {
4261 patch_site->EmitPatchInfo();
4262 } else {
4263 __ nop(); // Signals no inlined code.
4264 }
4265}
4266
4267
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004268void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4269 ASSERT(IsAligned(frame_offset, kPointerSize));
4270 __ movq(Operand(rbp, frame_offset), value);
4271}
4272
4273
4274void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004275 __ movq(dst, ContextOperand(rsi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004276}
4277
4278
4279// ----------------------------------------------------------------------------
4280// Non-local control flow support.
4281
4282
4283void FullCodeGenerator::EnterFinallyBlock() {
4284 ASSERT(!result_register().is(rdx));
4285 ASSERT(!result_register().is(rcx));
4286 // Cook return address on top of stack (smi encoded Code* delta)
4287 __ movq(rdx, Operand(rsp, 0));
4288 __ Move(rcx, masm_->CodeObject());
4289 __ subq(rdx, rcx);
4290 __ Integer32ToSmi(rdx, rdx);
4291 __ movq(Operand(rsp, 0), rdx);
4292 // Store result register while executing finally block.
4293 __ push(result_register());
4294}
4295
4296
4297void FullCodeGenerator::ExitFinallyBlock() {
4298 ASSERT(!result_register().is(rdx));
4299 ASSERT(!result_register().is(rcx));
4300 // Restore result register from stack.
4301 __ pop(result_register());
4302 // Uncook return address.
4303 __ movq(rdx, Operand(rsp, 0));
4304 __ SmiToInteger32(rdx, rdx);
4305 __ Move(rcx, masm_->CodeObject());
4306 __ addq(rdx, rcx);
4307 __ movq(Operand(rsp, 0), rdx);
4308 // And return.
4309 __ ret(0);
4310}
4311
4312
4313#undef __
4314
4315
4316} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004317
4318#endif // V8_TARGET_ARCH_X64