blob: 3ef867802cc9b978d3528907b397ca8aa1edc289 [file] [log] [blame]
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// 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
30#include "codegen-inl.h"
ager@chromium.orgc4c92722009-11-18 14:12:51 +000031#include "compiler.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000032#include "debug.h"
33#include "fast-codegen.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000034#include "parser.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000035
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm_)
40
41// Generate code for a JS function. On entry to the function the receiver
42// and arguments have been pushed on the stack left to right, with the
43// return address on top of them. The actual argument count matches the
44// formal parameter count expected by the function.
45//
46// The live registers are:
47// o rdi: the JS function object being called (ie, ourselves)
48// o rsi: our context
49// o rbp: our caller's frame pointer
50// o rsp: stack pointer (pointing to return address)
51//
52// The function builds a JS frame. Please see JavaScriptFrameConstants in
53// frames-x64.h for its layout.
54void FastCodeGenerator::Generate(FunctionLiteral* fun) {
55 function_ = fun;
56 SetFunctionPosition(fun);
57
58 __ push(rbp); // Caller's frame pointer.
59 __ movq(rbp, rsp);
60 __ push(rsi); // Callee's context.
61 __ push(rdi); // Callee's JS Function.
62
63 { Comment cmnt(masm_, "[ Allocate locals");
64 int locals_count = fun->scope()->num_stack_slots();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000065 if (locals_count <= 1) {
66 if (locals_count > 0) {
67 __ PushRoot(Heap::kUndefinedValueRootIndex);
68 }
69 } else {
70 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
71 for (int i = 0; i < locals_count; i++) {
72 __ push(rdx);
73 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000074 }
75 }
76
ager@chromium.orgc4c92722009-11-18 14:12:51 +000077 bool function_in_register = true;
78
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000079 // Possibly allocate a local context.
80 if (fun->scope()->num_heap_slots() > 0) {
81 Comment cmnt(masm_, "[ Allocate local context");
82 // Argument to NewContext is the function, which is still in rdi.
83 __ push(rdi);
84 __ CallRuntime(Runtime::kNewContext, 1);
85 function_in_register = false;
86 // Context is returned in both rax and rsi. It replaces the context
87 // passed to us. It's saved in the stack and kept live in rsi.
88 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
89
90 // Copy any necessary parameters into the context.
91 int num_parameters = fun->scope()->num_parameters();
92 for (int i = 0; i < num_parameters; i++) {
93 Slot* slot = fun->scope()->parameter(i)->slot();
94 if (slot != NULL && slot->type() == Slot::CONTEXT) {
95 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
96 (num_parameters - 1 - i) * kPointerSize;
97 // Load parameter from stack.
98 __ movq(rax, Operand(rbp, parameter_offset));
99 // Store it in the context
100 __ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax);
101 }
102 }
103 }
104
105 // Possibly allocate an arguments object.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000106 Variable* arguments = fun->scope()->arguments()->AsVariable();
107 if (arguments != NULL) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000108 // Arguments object must be allocated after the context object, in
109 // case the "arguments" or ".arguments" variables are in the context.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000110 Comment cmnt(masm_, "[ Allocate arguments object");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000111 if (function_in_register) {
112 __ push(rdi);
113 } else {
114 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
115 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000116 // The receiver is just before the parameters on the caller's stack.
117 __ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
118 fun->num_parameters() * kPointerSize));
119 __ push(rdx);
120 __ Push(Smi::FromInt(fun->num_parameters()));
121 // Arguments to ArgumentsAccessStub:
122 // function, receiver address, parameter count.
123 // The stub will rewrite receiver and parameter count if the previous
124 // stack frame was an arguments adapter frame.
125 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
126 __ CallStub(&stub);
127 // Store new arguments object in both "arguments" and ".arguments" slots.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000128 __ movq(rcx, rax);
129 Move(arguments->slot(), rax, rbx, rdx);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000130 Slot* dot_arguments_slot =
131 fun->scope()->arguments_shadow()->AsVariable()->slot();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000132 Move(dot_arguments_slot, rcx, rbx, rdx);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000133 }
134
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000135 { Comment cmnt(masm_, "[ Stack check");
136 Label ok;
137 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
138 __ j(above_equal, &ok);
139 StackCheckStub stub;
140 __ CallStub(&stub);
141 __ bind(&ok);
142 }
143
ager@chromium.org3811b432009-10-28 14:53:37 +0000144 { Comment cmnt(masm_, "[ Declarations");
145 VisitDeclarations(fun->scope()->declarations());
146 }
147
148 if (FLAG_trace) {
149 __ CallRuntime(Runtime::kTraceEnter, 0);
150 }
151
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000152 { Comment cmnt(masm_, "[ Body");
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000153 ASSERT(loop_depth() == 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000154 VisitStatements(fun->body());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000155 ASSERT(loop_depth() == 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000156 }
157
158 { Comment cmnt(masm_, "[ return <undefined>;");
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000159 // Emit a 'return undefined' in case control fell off the end of the body.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000160 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000161 EmitReturnSequence(function_->end_position());
162 }
163}
164
165
166void FastCodeGenerator::EmitReturnSequence(int position) {
167 Comment cmnt(masm_, "[ Return sequence");
168 if (return_label_.is_bound()) {
169 __ jmp(&return_label_);
170 } else {
171 __ bind(&return_label_);
ager@chromium.org3811b432009-10-28 14:53:37 +0000172 if (FLAG_trace) {
173 __ push(rax);
174 __ CallRuntime(Runtime::kTraceExit, 1);
175 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000176#ifdef DEBUG
177 // Add a label for checking the size of the code used for returning.
178 Label check_exit_codesize;
179 masm_->bind(&check_exit_codesize);
180#endif
181 CodeGenerator::RecordPositions(masm_, position);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000182 __ RecordJSReturn();
183 // Do not use the leave instruction here because it is too short to
184 // patch with the code required by the debugger.
185 __ movq(rsp, rbp);
186 __ pop(rbp);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000187 __ ret((function_->scope()->num_parameters() + 1) * kPointerSize);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000188#ifdef ENABLE_DEBUGGER_SUPPORT
189 // Add padding that will be overwritten by a debugger breakpoint. We
190 // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7
191 // (3 + 1 + 3).
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000192 const int kPadding = Assembler::kJSReturnSequenceLength - 7;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000193 for (int i = 0; i < kPadding; ++i) {
194 masm_->int3();
195 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000196 // Check that the size of the code used for returning matches what is
197 // expected by the debugger.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000198 ASSERT_EQ(Assembler::kJSReturnSequenceLength,
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000199 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000200#endif
201 }
202}
203
204
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000205void FastCodeGenerator::Apply(Expression::Context context,
206 Slot* slot,
207 Register scratch) {
208 switch (context) {
209 case Expression::kUninitialized:
210 UNREACHABLE();
211 case Expression::kEffect:
212 break;
213 case Expression::kValue: {
214 MemOperand location = EmitSlotSearch(slot, scratch);
215 __ push(location);
216 break;
217 }
218 case Expression::kTest:
219 case Expression::kValueTest:
220 case Expression::kTestValue:
221 Move(scratch, slot);
222 Apply(context, scratch);
223 break;
224 }
225}
226
227
228void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000229 switch (context) {
230 case Expression::kUninitialized:
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +0000231 UNREACHABLE();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000232 case Expression::kEffect:
ager@chromium.org3811b432009-10-28 14:53:37 +0000233 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000234 case Expression::kValue:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000235 __ Push(lit->handle());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000236 break;
237 case Expression::kTest:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000238 case Expression::kValueTest:
239 case Expression::kTestValue:
240 __ Move(rax, lit->handle());
241 Apply(context, rax);
242 break;
243 }
244}
245
246
247void FastCodeGenerator::ApplyTOS(Expression::Context context) {
248 switch (context) {
249 case Expression::kUninitialized:
250 UNREACHABLE();
251 case Expression::kEffect:
252 __ Drop(1);
253 break;
254 case Expression::kValue:
255 break;
256 case Expression::kTest:
257 __ pop(rax);
258 TestAndBranch(rax, true_label_, false_label_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000259 break;
260 case Expression::kValueTest: {
261 Label discard;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000262 __ movq(rax, Operand(rsp, 0));
263 TestAndBranch(rax, true_label_, &discard);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000264 __ bind(&discard);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000265 __ Drop(1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000266 __ jmp(false_label_);
267 break;
268 }
269 case Expression::kTestValue: {
270 Label discard;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000271 __ movq(rax, Operand(rsp, 0));
272 TestAndBranch(rax, &discard, false_label_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000273 __ bind(&discard);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000274 __ Drop(1);
275 __ jmp(true_label_);
276 }
277 }
278}
279
280
281void FastCodeGenerator::DropAndApply(int count,
282 Expression::Context context,
283 Register reg) {
284 ASSERT(count > 0);
285 ASSERT(!reg.is(rsp));
286 switch (context) {
287 case Expression::kUninitialized:
288 UNREACHABLE();
289 case Expression::kEffect:
290 __ Drop(count);
291 break;
292 case Expression::kValue:
293 if (count > 1) __ Drop(count - 1);
294 __ movq(Operand(rsp, 0), reg);
295 break;
296 case Expression::kTest:
297 __ Drop(count);
298 TestAndBranch(reg, true_label_, false_label_);
299 break;
300 case Expression::kValueTest: {
301 Label discard;
302 if (count > 1) __ Drop(count - 1);
303 __ movq(Operand(rsp, 0), reg);
304 TestAndBranch(reg, true_label_, &discard);
305 __ bind(&discard);
306 __ Drop(1);
307 __ jmp(false_label_);
308 break;
309 }
310 case Expression::kTestValue: {
311 Label discard;
312 if (count > 1) __ Drop(count - 1);
313 __ movq(Operand(rsp, 0), reg);
314 TestAndBranch(reg, &discard, false_label_);
315 __ bind(&discard);
316 __ Drop(1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000317 __ jmp(true_label_);
318 break;
319 }
320 }
321}
322
323
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000324MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
325 switch (slot->type()) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000326 case Slot::PARAMETER:
327 case Slot::LOCAL:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000328 return Operand(rbp, SlotOffset(slot));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000329 case Slot::CONTEXT: {
330 int context_chain_length =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000331 function_->scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000332 __ LoadContext(scratch, context_chain_length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000333 return CodeGenerator::ContextOperand(scratch, slot->index());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000334 }
335 case Slot::LOOKUP:
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000336 UNREACHABLE();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000337 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000338 UNREACHABLE();
339 return Operand(rax, 0);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000340}
341
342
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000343void FastCodeGenerator::Move(Register destination, Slot* source) {
344 MemOperand location = EmitSlotSearch(source, destination);
345 __ movq(destination, location);
ager@chromium.org3811b432009-10-28 14:53:37 +0000346}
347
348
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000349void FastCodeGenerator::Move(Slot* dst,
350 Register src,
351 Register scratch1,
352 Register scratch2) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000353 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
354 ASSERT(!scratch1.is(src) && !scratch2.is(src));
355 MemOperand location = EmitSlotSearch(dst, scratch1);
356 __ movq(location, src);
357 // Emit the write barrier code if the location is in the heap.
358 if (dst->type() == Slot::CONTEXT) {
359 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
360 __ RecordWrite(scratch1, offset, src, scratch2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000361 }
362}
363
364
365void FastCodeGenerator::TestAndBranch(Register source,
366 Label* true_label,
367 Label* false_label) {
368 ASSERT_NE(NULL, true_label);
369 ASSERT_NE(NULL, false_label);
370 // Use the shared ToBoolean stub to compile the value in the register into
371 // control flow to the code generator's true and false labels. Perform
372 // the fast checks assumed by the stub.
373
374 // The undefined value is false.
375 __ CompareRoot(source, Heap::kUndefinedValueRootIndex);
376 __ j(equal, false_label);
377 __ CompareRoot(source, Heap::kTrueValueRootIndex); // True is true.
378 __ j(equal, true_label);
379 __ CompareRoot(source, Heap::kFalseValueRootIndex); // False is false.
380 __ j(equal, false_label);
381 ASSERT_EQ(0, kSmiTag);
382 __ SmiCompare(source, Smi::FromInt(0)); // The smi zero is false.
383 __ j(equal, false_label);
384 Condition is_smi = masm_->CheckSmi(source); // All other smis are true.
385 __ j(is_smi, true_label);
386
387 // Call the stub for all other cases.
388 __ push(source);
389 ToBooleanStub stub;
390 __ CallStub(&stub);
391 __ testq(rax, rax); // The stub returns nonzero for true.
392 __ j(not_zero, true_label);
393 __ jmp(false_label);
394}
395
396
397void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
398 Comment cmnt(masm_, "[ Declaration");
399 Variable* var = decl->proxy()->var();
400 ASSERT(var != NULL); // Must have been resolved.
401 Slot* slot = var->slot();
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000402 Property* prop = var->AsProperty();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000403
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000404 if (slot != NULL) {
405 switch (slot->type()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000406 case Slot::PARAMETER:
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000407 case Slot::LOCAL:
408 if (decl->mode() == Variable::CONST) {
409 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000410 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000411 } else if (decl->fun() != NULL) {
412 Visit(decl->fun());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000413 __ pop(Operand(rbp, SlotOffset(slot)));
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000414 }
415 break;
416
417 case Slot::CONTEXT:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000418 // We bypass the general EmitSlotSearch because we know more about
419 // this specific context.
420
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000421 // The variable in the decl always resides in the current context.
422 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope()));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000423 if (FLAG_debug_code) {
424 // Check if we have the correct context pointer.
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000425 __ movq(rbx,
426 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000427 __ cmpq(rbx, rsi);
428 __ Check(equal, "Unexpected declaration in current context.");
429 }
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000430 if (decl->mode() == Variable::CONST) {
431 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
432 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
433 kScratchRegister);
434 // No write barrier since the hole value is in old space.
435 } else if (decl->fun() != NULL) {
436 Visit(decl->fun());
437 __ pop(rax);
438 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
439 int offset = Context::SlotOffset(slot->index());
440 __ RecordWrite(rsi, offset, rax, rcx);
441 }
442 break;
443
444 case Slot::LOOKUP: {
445 __ push(rsi);
446 __ Push(var->name());
447 // Declaration nodes are always introduced in one of two modes.
448 ASSERT(decl->mode() == Variable::VAR ||
449 decl->mode() == Variable::CONST);
450 PropertyAttributes attr =
451 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
452 __ Push(Smi::FromInt(attr));
453 // Push initial value, if any.
454 // Note: For variables we must not push an initial value (such as
455 // 'undefined') because we may have a (legal) redeclaration and we
456 // must not destroy the current value.
457 if (decl->mode() == Variable::CONST) {
458 __ PushRoot(Heap::kTheHoleValueRootIndex);
459 } else if (decl->fun() != NULL) {
460 Visit(decl->fun());
461 } else {
462 __ Push(Smi::FromInt(0)); // no initial value!
463 }
464 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
465 break;
466 }
467 }
468
469 } else if (prop != NULL) {
470 if (decl->fun() != NULL || decl->mode() == Variable::CONST) {
471 // We are declaring a function or constant that rewrites to a
472 // property. Use (keyed) IC to set the initial value.
473 ASSERT_EQ(Expression::kValue, prop->obj()->context());
474 Visit(prop->obj());
475 ASSERT_EQ(Expression::kValue, prop->key()->context());
476 Visit(prop->key());
477
478 if (decl->fun() != NULL) {
479 ASSERT_EQ(Expression::kValue, decl->fun()->context());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000480 Visit(decl->fun());
481 __ pop(rax);
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000482 } else {
483 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000484 }
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000485
486 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
487 __ call(ic, RelocInfo::CODE_TARGET);
488
489 // Absence of a test rax instruction following the call
490 // indicates that none of the load was inlined.
491
492 // Value in rax is ignored (declarations are statements). Receiver
493 // and key on stack are discarded.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000494 __ Drop(2);
ager@chromium.org7e3d1e62009-12-07 16:58:37 +0000495 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000496 }
497}
498
499
500void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
501 // Call the runtime to declare the globals.
502 __ push(rsi); // The context is the first argument.
503 __ Push(pairs);
504 __ Push(Smi::FromInt(is_eval_ ? 1 : 0));
505 __ CallRuntime(Runtime::kDeclareGlobals, 3);
506 // Return value is ignored.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000507}
508
509
ager@chromium.org3811b432009-10-28 14:53:37 +0000510void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
511 Comment cmnt(masm_, "[ FunctionLiteral");
512
513 // Build the function boilerplate and instantiate it.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000514 Handle<JSFunction> boilerplate =
515 Compiler::BuildBoilerplate(expr, script_, this);
ager@chromium.org3811b432009-10-28 14:53:37 +0000516 if (HasStackOverflow()) return;
517
518 ASSERT(boilerplate->IsBoilerplate());
519
520 // Create a new closure.
521 __ push(rsi);
522 __ Push(boilerplate);
523 __ CallRuntime(Runtime::kNewClosure, 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000524 Apply(expr->context(), rax);
ager@chromium.org3811b432009-10-28 14:53:37 +0000525}
526
527
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000528void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
529 Comment cmnt(masm_, "[ VariableProxy");
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000530 EmitVariableLoad(expr->var(), expr->context());
531}
532
533
534void FastCodeGenerator::EmitVariableLoad(Variable* var,
535 Expression::Context context) {
536 Expression* rewrite = var->rewrite();
ager@chromium.org3811b432009-10-28 14:53:37 +0000537 if (rewrite == NULL) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000538 ASSERT(var->is_global());
ager@chromium.org3811b432009-10-28 14:53:37 +0000539 Comment cmnt(masm_, "Global variable");
540 // Use inline caching. Variable name is passed in rcx and the global
541 // object on the stack.
542 __ push(CodeGenerator::GlobalObject());
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000543 __ Move(rcx, var->name());
ager@chromium.org3811b432009-10-28 14:53:37 +0000544 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
545 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
ager@chromium.org3811b432009-10-28 14:53:37 +0000546 // A test rax instruction following the call is used by the IC to
547 // indicate that the inobject property case was inlined. Ensure there
548 // is no test rax instruction here.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000549 __ nop();
550
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000551 DropAndApply(1, context, rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000552 } else if (rewrite->AsSlot() != NULL) {
553 Slot* slot = rewrite->AsSlot();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000554 if (FLAG_debug_code) {
555 switch (slot->type()) {
556 case Slot::LOCAL:
557 case Slot::PARAMETER: {
558 Comment cmnt(masm_, "Stack slot");
559 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000560 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000561 case Slot::CONTEXT: {
562 Comment cmnt(masm_, "Context slot");
563 break;
564 }
565 case Slot::LOOKUP:
566 UNIMPLEMENTED();
567 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000568 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000569 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000570 Apply(context, slot, rax);
ager@chromium.org3811b432009-10-28 14:53:37 +0000571 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000572 Comment cmnt(masm_, "Variable rewritten to property");
573 // A variable has been rewritten into an explicit access to an object
574 // property.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000575 Property* property = rewrite->AsProperty();
576 ASSERT_NOT_NULL(property);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000577
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000578 // The only property expressions that can occur are of the form
579 // "slot[literal]".
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000580
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000581 // Assert that the object is in a slot.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000582 Variable* object = property->obj()->AsVariableProxy()->AsVariable();
583 ASSERT_NOT_NULL(object);
584 Slot* object_slot = object->slot();
585 ASSERT_NOT_NULL(object_slot);
586
587 // Load the object.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000588 MemOperand object_loc = EmitSlotSearch(object_slot, rax);
589 __ push(object_loc);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000590
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000591 // Assert that the key is a smi.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000592 Literal* key_literal = property->key()->AsLiteral();
593 ASSERT_NOT_NULL(key_literal);
594 ASSERT(key_literal->handle()->IsSmi());
595
596 // Load the key.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000597 __ Push(key_literal->handle());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000598
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000599 // Do a keyed property load.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000600 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
601 __ call(ic, RelocInfo::CODE_TARGET);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000602 // Notice: We must not have a "test rax, ..." instruction after the
603 // call. It is treated specially by the LoadIC code.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000604
605 // Drop key and object left on the stack by IC, and push the result.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000606 DropAndApply(2, context, rax);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000607 }
608}
609
610
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +0000611void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000612 Comment cmnt(masm_, "[ RegExpLiteral");
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +0000613 Label done;
614 // Registers will be used as follows:
615 // rdi = JS function.
616 // rbx = literals array.
617 // rax = regexp literal.
618 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
619 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
620 int literal_offset =
621 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
622 __ movq(rax, FieldOperand(rbx, literal_offset));
623 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
624 __ j(not_equal, &done);
625 // Create regexp literal using runtime function
626 // Result will be in rax.
627 __ push(rbx);
628 __ Push(Smi::FromInt(expr->literal_index()));
629 __ Push(expr->pattern());
630 __ Push(expr->flags());
631 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
632 // Label done:
633 __ bind(&done);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000634 Apply(expr->context(), rax);
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +0000635}
636
637
ager@chromium.org3811b432009-10-28 14:53:37 +0000638void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
639 Comment cmnt(masm_, "[ ObjectLiteral");
ager@chromium.org3811b432009-10-28 14:53:37 +0000640 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
ager@chromium.org3811b432009-10-28 14:53:37 +0000642 __ Push(Smi::FromInt(expr->literal_index()));
ager@chromium.org3811b432009-10-28 14:53:37 +0000643 __ Push(expr->constant_properties());
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000644 if (expr->depth() > 1) {
645 __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000646 } else {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000647 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
ager@chromium.org3811b432009-10-28 14:53:37 +0000648 }
649
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000650 // If result_saved == true: The result is saved on top of the
651 // stack and in rax.
652 // If result_saved == false: The result not on the stack, just in rax.
ager@chromium.org3811b432009-10-28 14:53:37 +0000653 bool result_saved = false;
654
655 for (int i = 0; i < expr->properties()->length(); i++) {
656 ObjectLiteral::Property* property = expr->properties()->at(i);
657 if (property->IsCompileTimeValue()) continue;
658
659 Literal* key = property->key();
660 Expression* value = property->value();
661 if (!result_saved) {
662 __ push(rax); // Save result on the stack
663 result_saved = true;
664 }
665 switch (property->kind()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000666 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
ager@chromium.org3811b432009-10-28 14:53:37 +0000667 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
668 case ObjectLiteral::Property::COMPUTED:
669 if (key->handle()->IsSymbol()) {
670 Visit(value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000671 ASSERT_EQ(Expression::kValue, value->context());
ager@chromium.org3811b432009-10-28 14:53:37 +0000672 __ pop(rax);
673 __ Move(rcx, key->handle());
674 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
675 __ call(ic, RelocInfo::CODE_TARGET);
676 // StoreIC leaves the receiver on the stack.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000677 __ movq(rax, Operand(rsp, 0)); // Restore result back into rax.
ager@chromium.org3811b432009-10-28 14:53:37 +0000678 break;
679 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000680 // Fall through.
ager@chromium.org3811b432009-10-28 14:53:37 +0000681 case ObjectLiteral::Property::PROTOTYPE:
682 __ push(rax);
683 Visit(key);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000684 ASSERT_EQ(Expression::kValue, key->context());
ager@chromium.org3811b432009-10-28 14:53:37 +0000685 Visit(value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000686 ASSERT_EQ(Expression::kValue, value->context());
ager@chromium.org3811b432009-10-28 14:53:37 +0000687 __ CallRuntime(Runtime::kSetProperty, 3);
688 __ movq(rax, Operand(rsp, 0)); // Restore result into rax.
689 break;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000690 case ObjectLiteral::Property::SETTER:
ager@chromium.org3811b432009-10-28 14:53:37 +0000691 case ObjectLiteral::Property::GETTER:
692 __ push(rax);
693 Visit(key);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000694 ASSERT_EQ(Expression::kValue, key->context());
ager@chromium.org3811b432009-10-28 14:53:37 +0000695 __ Push(property->kind() == ObjectLiteral::Property::SETTER ?
696 Smi::FromInt(1) :
697 Smi::FromInt(0));
698 Visit(value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000699 ASSERT_EQ(Expression::kValue, value->context());
ager@chromium.org3811b432009-10-28 14:53:37 +0000700 __ CallRuntime(Runtime::kDefineAccessor, 4);
701 __ movq(rax, Operand(rsp, 0)); // Restore result into rax.
702 break;
703 default: UNREACHABLE();
704 }
705 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000706 switch (expr->context()) {
707 case Expression::kUninitialized:
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +0000708 UNREACHABLE();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000709 case Expression::kEffect:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000710 if (result_saved) __ Drop(1);
ager@chromium.org3811b432009-10-28 14:53:37 +0000711 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000712 case Expression::kValue:
ager@chromium.org3811b432009-10-28 14:53:37 +0000713 if (!result_saved) __ push(rax);
714 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000715 case Expression::kTest:
716 if (result_saved) __ pop(rax);
717 TestAndBranch(rax, true_label_, false_label_);
718 break;
719 case Expression::kValueTest: {
720 Label discard;
721 if (!result_saved) __ push(rax);
722 TestAndBranch(rax, true_label_, &discard);
723 __ bind(&discard);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000724 __ Drop(1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000725 __ jmp(false_label_);
726 break;
727 }
728 case Expression::kTestValue: {
729 Label discard;
730 if (!result_saved) __ push(rax);
731 TestAndBranch(rax, &discard, false_label_);
732 __ bind(&discard);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000733 __ Drop(1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000734 __ jmp(true_label_);
735 break;
736 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000737 }
738}
739
740
ager@chromium.org3811b432009-10-28 14:53:37 +0000741void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
742 Comment cmnt(masm_, "[ ArrayLiteral");
ager@chromium.org3811b432009-10-28 14:53:37 +0000743 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000744 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
ager@chromium.org3811b432009-10-28 14:53:37 +0000745 __ Push(Smi::FromInt(expr->literal_index()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000746 __ Push(expr->constant_elements());
ager@chromium.org3811b432009-10-28 14:53:37 +0000747 if (expr->depth() > 1) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000748 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ager@chromium.org3811b432009-10-28 14:53:37 +0000749 } else {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000750 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
ager@chromium.org3811b432009-10-28 14:53:37 +0000751 }
752
753 bool result_saved = false; // Is the result saved to the stack?
754
755 // Emit code to evaluate all the non-constant subexpressions and to store
756 // them into the newly cloned array.
757 ZoneList<Expression*>* subexprs = expr->values();
758 for (int i = 0, len = subexprs->length(); i < len; i++) {
759 Expression* subexpr = subexprs->at(i);
760 // If the subexpression is a literal or a simple materialized literal it
761 // is already set in the cloned array.
762 if (subexpr->AsLiteral() != NULL ||
763 CompileTimeValue::IsCompileTimeValue(subexpr)) {
764 continue;
765 }
766
767 if (!result_saved) {
768 __ push(rax);
769 result_saved = true;
770 }
771 Visit(subexpr);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000772 ASSERT_EQ(Expression::kValue, subexpr->context());
ager@chromium.org3811b432009-10-28 14:53:37 +0000773
774 // Store the subexpression value in the array's elements.
775 __ pop(rax); // Subexpression value.
776 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
777 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
778 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
779 __ movq(FieldOperand(rbx, offset), rax);
780
781 // Update the write barrier for the array store.
782 __ RecordWrite(rbx, offset, rax, rcx);
783 }
784
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000785 switch (expr->context()) {
786 case Expression::kUninitialized:
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +0000787 UNREACHABLE();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000788 case Expression::kEffect:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000789 if (result_saved) __ Drop(1);
ager@chromium.org3811b432009-10-28 14:53:37 +0000790 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000791 case Expression::kValue:
ager@chromium.org3811b432009-10-28 14:53:37 +0000792 if (!result_saved) __ push(rax);
793 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000794 case Expression::kTest:
795 if (result_saved) __ pop(rax);
796 TestAndBranch(rax, true_label_, false_label_);
797 break;
798 case Expression::kValueTest: {
799 Label discard;
800 if (!result_saved) __ push(rax);
801 TestAndBranch(rax, true_label_, &discard);
802 __ bind(&discard);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000803 __ Drop(1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000804 __ jmp(false_label_);
805 break;
806 }
807 case Expression::kTestValue: {
808 Label discard;
809 if (!result_saved) __ push(rax);
810 TestAndBranch(rax, &discard, false_label_);
811 __ bind(&discard);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000812 __ Drop(1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000813 __ jmp(true_label_);
814 break;
815 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000816 }
817}
818
819
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000820void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
821 Expression::Context context) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000822 SetSourcePosition(prop->position());
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000823 Literal* key = prop->key()->AsLiteral();
824 __ Move(rcx, key->handle());
825 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
826 __ Call(ic, RelocInfo::CODE_TARGET);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000827 Apply(context, rax);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000828}
829
830
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000831void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
832 Expression::Context context) {
833 SetSourcePosition(prop->position());
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000834 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
835 __ Call(ic, RelocInfo::CODE_TARGET);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000836 Apply(context, rax);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000837}
838
839
840void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
841 Expression::Context context) {
842 GenericBinaryOpStub stub(op,
843 NO_OVERWRITE,
844 NO_GENERIC_BINARY_FLAGS);
845 __ CallStub(&stub);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000846 Apply(context, rax);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000847}
848
849
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000850void FastCodeGenerator::EmitVariableAssignment(Variable* var,
851 Expression::Context context) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000852 ASSERT(var != NULL);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000853 ASSERT(var->is_global() || var->slot() != NULL);
ager@chromium.org3811b432009-10-28 14:53:37 +0000854 if (var->is_global()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000855 // Assignment to a global variable. Use inline caching for the
856 // assignment. Right-hand-side value is passed in rax, variable name in
857 // rcx, and the global object on the stack.
858 __ pop(rax);
ager@chromium.org3811b432009-10-28 14:53:37 +0000859 __ Move(rcx, var->name());
860 __ push(CodeGenerator::GlobalObject());
861 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
862 __ Call(ic, RelocInfo::CODE_TARGET);
863 // Overwrite the global object on the stack with the result if needed.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000864 DropAndApply(1, context, rax);
ager@chromium.org3811b432009-10-28 14:53:37 +0000865
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000866 } else if (var->slot() != NULL) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000867 Slot* slot = var->slot();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000868 switch (slot->type()) {
869 case Slot::LOCAL:
870 case Slot::PARAMETER: {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000871 Operand target = Operand(rbp, SlotOffset(slot));
872 switch (context) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000873 case Expression::kUninitialized:
874 UNREACHABLE();
875 case Expression::kEffect:
876 // Perform assignment and discard value.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000877 __ pop(target);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000878 break;
879 case Expression::kValue:
880 // Perform assignment and preserve value.
881 __ movq(rax, Operand(rsp, 0));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000882 __ movq(target, rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000883 break;
884 case Expression::kTest:
885 // Perform assignment and test (and discard) value.
886 __ pop(rax);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000887 __ movq(target, rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000888 TestAndBranch(rax, true_label_, false_label_);
889 break;
890 case Expression::kValueTest: {
891 Label discard;
892 __ movq(rax, Operand(rsp, 0));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000893 __ movq(target, rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000894 TestAndBranch(rax, true_label_, &discard);
895 __ bind(&discard);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000896 __ Drop(1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000897 __ jmp(false_label_);
898 break;
899 }
900 case Expression::kTestValue: {
901 Label discard;
902 __ movq(rax, Operand(rsp, 0));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000903 __ movq(target, rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000904 TestAndBranch(rax, &discard, false_label_);
905 __ bind(&discard);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000906 __ Drop(1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000907 __ jmp(true_label_);
908 break;
909 }
910 }
911 break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000912 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000913
914 case Slot::CONTEXT: {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000915 MemOperand target = EmitSlotSearch(slot, rcx);
916 __ pop(rax);
917 __ movq(target, rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000918
919 // RecordWrite may destroy all its register arguments.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000920 if (context == Expression::kValue) {
921 __ push(rax);
922 } else if (context != Expression::kEffect) {
923 __ movq(rdx, rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000924 }
925 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000926 __ RecordWrite(rcx, offset, rax, rbx);
927 if (context != Expression::kEffect && context != Expression::kValue) {
928 Apply(context, rdx);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000929 }
930 break;
931 }
932
933 case Slot::LOOKUP:
934 UNREACHABLE();
935 break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000936 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000937 } else {
938 // Variables rewritten as properties are not treated as variables in
939 // assignments.
940 UNREACHABLE();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000941 }
942}
943
944
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000945void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
946 // Assignment to a property, using a named store IC.
947 Property* prop = expr->target()->AsProperty();
948 ASSERT(prop != NULL);
949 ASSERT(prop->key()->AsLiteral() != NULL);
950
951 // If the assignment starts a block of assignments to the same object,
952 // change to slow case to avoid the quadratic behavior of repeatedly
953 // adding fast properties.
954 if (expr->starts_initialization_block()) {
955 __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
956 __ CallRuntime(Runtime::kToSlowProperties, 1);
957 }
958
959 __ pop(rax);
960 __ Move(rcx, prop->key()->AsLiteral()->handle());
961 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
962 __ Call(ic, RelocInfo::CODE_TARGET);
963
964 // If the assignment ends an initialization block, revert to fast case.
965 if (expr->ends_initialization_block()) {
966 __ push(rax); // Result of assignment, saved even if not needed.
967 __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
968 __ CallRuntime(Runtime::kToFastProperties, 1);
969 __ pop(rax);
970 }
971
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000972 DropAndApply(1, expr->context(), rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000973}
974
975
976void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
977 // Assignment to a property, using a keyed store IC.
978
979 // If the assignment starts a block of assignments to the same object,
980 // change to slow case to avoid the quadratic behavior of repeatedly
981 // adding fast properties.
982 if (expr->starts_initialization_block()) {
983 // Reciever is under the key and value.
984 __ push(Operand(rsp, 2 * kPointerSize));
985 __ CallRuntime(Runtime::kToSlowProperties, 1);
986 }
987
988 __ pop(rax);
989 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
990 __ Call(ic, RelocInfo::CODE_TARGET);
991 // This nop signals to the IC that there is no inlined code at the call
992 // site for it to patch.
993 __ nop();
994
995 // If the assignment ends an initialization block, revert to fast case.
996 if (expr->ends_initialization_block()) {
997 __ push(rax); // Result of assignment, saved even if not needed.
998 // Reciever is under the key and value.
999 __ push(Operand(rsp, 2 * kPointerSize));
1000 __ CallRuntime(Runtime::kToFastProperties, 1);
1001 __ pop(rax);
1002 }
1003
1004 // Receiver and key are still on stack.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001005 DropAndApply(2, expr->context(), rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001006}
1007
1008
ager@chromium.org3811b432009-10-28 14:53:37 +00001009void FastCodeGenerator::VisitProperty(Property* expr) {
1010 Comment cmnt(masm_, "[ Property");
1011 Expression* key = expr->key();
ager@chromium.org3811b432009-10-28 14:53:37 +00001012
1013 // Record the source position for the property load.
1014 SetSourcePosition(expr->position());
1015
1016 // Evaluate receiver.
1017 Visit(expr->obj());
1018
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001019 if (key->IsPropertyName()) {
1020 // Do a named property load. The IC expects the property name in rcx
1021 // and the receiver on the stack.
ager@chromium.org3811b432009-10-28 14:53:37 +00001022 __ Move(rcx, key->AsLiteral()->handle());
1023 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1024 __ call(ic, RelocInfo::CODE_TARGET);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001025 // By emitting a nop we make sure that we do not have a "test rax,..."
ager@chromium.org3811b432009-10-28 14:53:37 +00001026 // instruction after the call it is treated specially by the LoadIC code.
1027 __ nop();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001028 DropAndApply(1, expr->context(), rax);
ager@chromium.org3811b432009-10-28 14:53:37 +00001029 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001030 // Do a keyed property load.
ager@chromium.org3811b432009-10-28 14:53:37 +00001031 Visit(expr->key());
1032 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1033 __ call(ic, RelocInfo::CODE_TARGET);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001034 // Notice: We must not have a "test rax, ..." instruction after the
1035 // call. It is treated specially by the LoadIC code.
1036 __ nop();
1037 // Drop key and receiver left on the stack by IC.
1038 DropAndApply(2, expr->context(), rax);
ager@chromium.org3811b432009-10-28 14:53:37 +00001039 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001040}
1041
1042
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001043void FastCodeGenerator::EmitCallWithIC(Call* expr,
1044 Handle<Object> ignored,
1045 RelocInfo::Mode mode) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001046 // Code common for calls using the IC.
ager@chromium.org3811b432009-10-28 14:53:37 +00001047 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.org3811b432009-10-28 14:53:37 +00001048 int arg_count = args->length();
1049 for (int i = 0; i < arg_count; i++) {
1050 Visit(args->at(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001051 ASSERT_EQ(Expression::kValue, args->at(i)->context());
ager@chromium.org3811b432009-10-28 14:53:37 +00001052 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001053 // Record source position for debugger.
ager@chromium.org3811b432009-10-28 14:53:37 +00001054 SetSourcePosition(expr->position());
1055 // Call the IC initialization code.
1056 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
1057 NOT_IN_LOOP);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001058 __ call(ic, mode);
ager@chromium.org3811b432009-10-28 14:53:37 +00001059 // Restore context register.
1060 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1061 // Discard the function left on TOS.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001062 DropAndApply(1, expr->context(), rax);
ager@chromium.org3811b432009-10-28 14:53:37 +00001063}
1064
1065
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001066void FastCodeGenerator::EmitCallWithStub(Call* expr) {
1067 // Code common for calls using the call stub.
1068 ZoneList<Expression*>* args = expr->arguments();
1069 int arg_count = args->length();
1070 for (int i = 0; i < arg_count; i++) {
1071 Visit(args->at(i));
1072 }
1073 // Record source position for debugger.
1074 SetSourcePosition(expr->position());
1075 CallFunctionStub stub(arg_count, NOT_IN_LOOP);
1076 __ CallStub(&stub);
1077 // Restore context register.
1078 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1079 // Discard the function left on TOS.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001080 DropAndApply(1, expr->context(), rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001081}
1082
1083
1084void FastCodeGenerator::VisitCall(Call* expr) {
1085 Comment cmnt(masm_, "[ Call");
1086 Expression* fun = expr->expression();
1087 Variable* var = fun->AsVariableProxy()->AsVariable();
1088
1089 if (var != NULL && var->is_possibly_eval()) {
1090 // Call to the identifier 'eval'.
1091 UNREACHABLE();
1092 } else if (var != NULL && !var->is_this() && var->is_global()) {
1093 // Call to a global variable.
1094 __ Push(var->name());
1095 // Push global object as receiver for the call IC lookup.
1096 __ push(CodeGenerator::GlobalObject());
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001097 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001098 } else if (var != NULL && var->slot() != NULL &&
1099 var->slot()->type() == Slot::LOOKUP) {
1100 // Call to a lookup slot.
1101 UNREACHABLE();
1102 } else if (fun->AsProperty() != NULL) {
1103 // Call to an object property.
1104 Property* prop = fun->AsProperty();
1105 Literal* key = prop->key()->AsLiteral();
1106 if (key != NULL && key->handle()->IsSymbol()) {
1107 // Call to a named property, use call IC.
1108 __ Push(key->handle());
1109 Visit(prop->obj());
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001110 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001111 } else {
1112 // Call to a keyed property, use keyed load IC followed by function
1113 // call.
1114 Visit(prop->obj());
1115 Visit(prop->key());
1116 // Record source code position for IC call.
1117 SetSourcePosition(prop->position());
1118 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1119 __ call(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001120 // By emitting a nop we make sure that we do not have a "test rax,..."
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001121 // instruction after the call it is treated specially by the LoadIC code.
1122 __ nop();
1123 // Drop key left on the stack by IC.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001124 __ Drop(1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001125 // Pop receiver.
1126 __ pop(rbx);
1127 // Push result (function).
1128 __ push(rax);
1129 // Push receiver object on stack.
1130 if (prop->is_synthetic()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001131 __ movq(rcx, CodeGenerator::GlobalObject());
1132 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001133 } else {
1134 __ push(rbx);
1135 }
1136 EmitCallWithStub(expr);
1137 }
1138 } else {
1139 // Call to some other expression. If the expression is an anonymous
1140 // function literal not called in a loop, mark it as one that should
1141 // also use the fast code generator.
1142 FunctionLiteral* lit = fun->AsFunctionLiteral();
1143 if (lit != NULL &&
1144 lit->name()->Equals(Heap::empty_string()) &&
1145 loop_depth() == 0) {
1146 lit->set_try_fast_codegen(true);
1147 }
1148 Visit(fun);
1149 // Load global receiver object.
1150 __ movq(rbx, CodeGenerator::GlobalObject());
1151 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
1152 // Emit function call.
1153 EmitCallWithStub(expr);
1154 }
1155}
1156
1157
1158void FastCodeGenerator::VisitCallNew(CallNew* expr) {
ager@chromium.org3811b432009-10-28 14:53:37 +00001159 Comment cmnt(masm_, "[ CallNew");
1160 // According to ECMA-262, section 11.2.2, page 44, the function
1161 // expression in new calls must be evaluated before the
1162 // arguments.
1163 // Push function on the stack.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001164 Visit(expr->expression());
1165 ASSERT_EQ(Expression::kValue, expr->expression()->context());
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +00001166 // If location is value, already on the stack,
ager@chromium.org3811b432009-10-28 14:53:37 +00001167
1168 // Push global object (receiver).
1169 __ push(CodeGenerator::GlobalObject());
1170
1171 // Push the arguments ("left-to-right") on the stack.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001172 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.org3811b432009-10-28 14:53:37 +00001173 int arg_count = args->length();
1174 for (int i = 0; i < arg_count; i++) {
1175 Visit(args->at(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001176 ASSERT_EQ(Expression::kValue, args->at(i)->context());
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +00001177 // If location is value, it is already on the stack,
ager@chromium.org3811b432009-10-28 14:53:37 +00001178 // so nothing to do here.
1179 }
1180
1181 // Call the construct call builtin that handles allocation and
1182 // constructor invocation.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001183 SetSourcePosition(expr->position());
ager@chromium.org3811b432009-10-28 14:53:37 +00001184
1185 // Load function, arg_count into rdi and rax.
1186 __ Set(rax, arg_count);
1187 // Function is in rsp[arg_count + 1].
1188 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize));
1189
1190 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1191 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
1192
1193 // Replace function on TOS with result in rax, or pop it.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001194 DropAndApply(1, expr->context(), rax);
ager@chromium.org3811b432009-10-28 14:53:37 +00001195}
1196
1197
1198void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
1199 Comment cmnt(masm_, "[ CallRuntime");
1200 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.org3811b432009-10-28 14:53:37 +00001201
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001202 if (expr->is_jsruntime()) {
1203 // Prepare for calling JS runtime function.
1204 __ Push(expr->name());
1205 __ movq(rax, CodeGenerator::GlobalObject());
1206 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
1207 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001208
1209 // Push the arguments ("left-to-right").
1210 int arg_count = args->length();
1211 for (int i = 0; i < arg_count; i++) {
1212 Visit(args->at(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001213 ASSERT_EQ(Expression::kValue, args->at(i)->context());
ager@chromium.org3811b432009-10-28 14:53:37 +00001214 }
1215
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001216 if (expr->is_jsruntime()) {
1217 // Call the JS runtime function.
1218 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
1219 NOT_IN_LOOP);
1220 __ call(ic, RelocInfo::CODE_TARGET);
1221 // Restore context register.
1222 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1223 // Discard the function left on TOS.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001224 DropAndApply(1, expr->context(), rax);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001225 } else {
1226 __ CallRuntime(expr->function(), arg_count);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001227 Apply(expr->context(), rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001228 }
1229}
1230
1231
1232void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
1233 switch (expr->op()) {
1234 case Token::VOID: {
1235 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
1236 Visit(expr->expression());
1237 ASSERT_EQ(Expression::kEffect, expr->expression()->context());
1238 switch (expr->context()) {
1239 case Expression::kUninitialized:
1240 UNREACHABLE();
1241 break;
1242 case Expression::kEffect:
1243 break;
1244 case Expression::kValue:
1245 __ PushRoot(Heap::kUndefinedValueRootIndex);
1246 break;
1247 case Expression::kTestValue:
1248 // Value is false so it's needed.
1249 __ PushRoot(Heap::kUndefinedValueRootIndex);
1250 // Fall through.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001251 case Expression::kTest:
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001252 case Expression::kValueTest:
1253 __ jmp(false_label_);
1254 break;
1255 }
1256 break;
1257 }
1258
1259 case Token::NOT: {
1260 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
1261 ASSERT_EQ(Expression::kTest, expr->expression()->context());
1262
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001263 Label push_true, push_false, done;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001264 switch (expr->context()) {
1265 case Expression::kUninitialized:
1266 UNREACHABLE();
1267 break;
1268
1269 case Expression::kValue:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001270 VisitForControl(expr->expression(), &push_false, &push_true);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001271 __ bind(&push_true);
1272 __ PushRoot(Heap::kTrueValueRootIndex);
1273 __ jmp(&done);
1274 __ bind(&push_false);
1275 __ PushRoot(Heap::kFalseValueRootIndex);
1276 __ bind(&done);
1277 break;
1278
1279 case Expression::kEffect:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001280 VisitForControl(expr->expression(), &done, &done);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001281 __ bind(&done);
1282 break;
1283
1284 case Expression::kTest:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001285 VisitForControl(expr->expression(), false_label_, true_label_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001286 break;
1287
1288 case Expression::kValueTest:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001289 VisitForControl(expr->expression(), false_label_, &push_true);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001290 __ bind(&push_true);
1291 __ PushRoot(Heap::kTrueValueRootIndex);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001292 __ jmp(true_label_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001293 break;
1294
1295 case Expression::kTestValue:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001296 VisitForControl(expr->expression(), &push_false, true_label_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001297 __ bind(&push_false);
1298 __ PushRoot(Heap::kFalseValueRootIndex);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001299 __ jmp(false_label_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001300 break;
1301 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001302 break;
1303 }
1304
1305 case Token::TYPEOF: {
1306 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
1307 ASSERT_EQ(Expression::kValue, expr->expression()->context());
1308
1309 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1310 if (proxy != NULL &&
1311 !proxy->var()->is_this() &&
1312 proxy->var()->is_global()) {
1313 Comment cmnt(masm_, "Global variable");
1314 __ push(CodeGenerator::GlobalObject());
1315 __ Move(rcx, proxy->name());
1316 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1317 // Use a regular load, not a contextual load, to avoid a reference
1318 // error.
1319 __ Call(ic, RelocInfo::CODE_TARGET);
1320 __ movq(Operand(rsp, 0), rax);
1321 } else if (proxy != NULL &&
1322 proxy->var()->slot() != NULL &&
1323 proxy->var()->slot()->type() == Slot::LOOKUP) {
1324 __ push(rsi);
1325 __ Push(proxy->name());
1326 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
1327 __ push(rax);
1328 } else {
1329 // This expression cannot throw a reference error at the top level.
1330 Visit(expr->expression());
1331 }
1332
1333 __ CallRuntime(Runtime::kTypeof, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001334 Apply(expr->context(), rax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001335 break;
1336 }
1337
1338 default:
1339 UNREACHABLE();
1340 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001341}
1342
1343
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001344void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
1345 Comment cmnt(masm_, "[ CountOperation");
1346
1347 // Expression can only be a property, a global or a (parameter or local)
1348 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1349 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1350 LhsKind assign_type = VARIABLE;
1351 Property* prop = expr->expression()->AsProperty();
1352 // In case of a property we use the uninitialized expression context
1353 // of the key to detect a named property.
1354 if (prop != NULL) {
1355 assign_type = (prop->key()->context() == Expression::kUninitialized)
1356 ? NAMED_PROPERTY
1357 : KEYED_PROPERTY;
1358 }
1359
1360 // Evaluate expression and get value.
1361 if (assign_type == VARIABLE) {
1362 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
1363 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
1364 Expression::kValue);
1365 } else {
1366 // Reserve space for result of postfix operation.
1367 if (expr->is_postfix() && expr->context() != Expression::kEffect) {
1368 ASSERT(expr->context() != Expression::kUninitialized);
1369 __ Push(Smi::FromInt(0));
1370 }
1371 Visit(prop->obj());
1372 ASSERT_EQ(Expression::kValue, prop->obj()->context());
1373 if (assign_type == NAMED_PROPERTY) {
1374 EmitNamedPropertyLoad(prop, Expression::kValue);
1375 } else {
1376 Visit(prop->key());
1377 ASSERT_EQ(Expression::kValue, prop->key()->context());
1378 EmitKeyedPropertyLoad(prop, Expression::kValue);
1379 }
1380 }
1381
1382 // Convert to number.
1383 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
1384
1385 // Save result for postfix expressions.
1386 if (expr->is_postfix()) {
1387 switch (expr->context()) {
1388 case Expression::kUninitialized:
1389 UNREACHABLE();
1390 case Expression::kEffect:
1391 // Do not save result.
1392 break;
1393 case Expression::kValue: // Fall through
1394 case Expression::kTest: // Fall through
1395 case Expression::kTestValue: // Fall through
1396 case Expression::kValueTest:
1397 // Save the result on the stack. If we have a named or keyed property
1398 // we store the result under the receiver that is currently on top
1399 // of the stack.
1400 switch (assign_type) {
1401 case VARIABLE:
1402 __ push(rax);
1403 break;
1404 case NAMED_PROPERTY:
1405 __ movq(Operand(rsp, kPointerSize), rax);
1406 break;
1407 case KEYED_PROPERTY:
1408 __ movq(Operand(rsp, 2 * kPointerSize), rax);
1409 break;
1410 }
1411 break;
1412 }
1413 }
1414
1415 // Call runtime for +1/-1.
1416 __ push(rax);
1417 __ Push(Smi::FromInt(1));
1418 if (expr->op() == Token::INC) {
1419 __ CallRuntime(Runtime::kNumberAdd, 2);
1420 } else {
1421 __ CallRuntime(Runtime::kNumberSub, 2);
1422 }
1423
1424 // Store the value returned in rax.
1425 switch (assign_type) {
1426 case VARIABLE:
1427 __ push(rax);
1428 if (expr->is_postfix()) {
1429 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
1430 Expression::kEffect);
1431 // For all contexts except kEffect: We have the result on
1432 // top of the stack.
1433 if (expr->context() != Expression::kEffect) {
1434 ApplyTOS(expr->context());
1435 }
1436 } else {
1437 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
1438 expr->context());
1439 }
1440 break;
1441 case NAMED_PROPERTY: {
1442 __ Move(rcx, prop->key()->AsLiteral()->handle());
1443 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1444 __ call(ic, RelocInfo::CODE_TARGET);
1445 // This nop signals to the IC that there is no inlined code at the call
1446 // site for it to patch.
1447 __ nop();
1448 if (expr->is_postfix()) {
1449 __ Drop(1); // Result is on the stack under the receiver.
1450 if (expr->context() != Expression::kEffect) {
1451 ApplyTOS(expr->context());
1452 }
1453 } else {
1454 DropAndApply(1, expr->context(), rax);
1455 }
1456 break;
1457 }
1458 case KEYED_PROPERTY: {
1459 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1460 __ call(ic, RelocInfo::CODE_TARGET);
1461 // This nop signals to the IC that there is no inlined code at the call
1462 // site for it to patch.
1463 __ nop();
1464 if (expr->is_postfix()) {
1465 __ Drop(2); // Result is on the stack under the key and the receiver.
1466 if (expr->context() != Expression::kEffect) {
1467 ApplyTOS(expr->context());
1468 }
1469 } else {
1470 DropAndApply(2, expr->context(), rax);
1471 }
1472 break;
1473 }
1474 }
1475}
1476
ager@chromium.org3811b432009-10-28 14:53:37 +00001477void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001478 Comment cmnt(masm_, "[ BinaryOperation");
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +00001479 switch (expr->op()) {
1480 case Token::COMMA:
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001481 ASSERT_EQ(Expression::kEffect, expr->left()->context());
1482 ASSERT_EQ(expr->context(), expr->right()->context());
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +00001483 Visit(expr->left());
1484 Visit(expr->right());
1485 break;
1486
1487 case Token::OR:
1488 case Token::AND:
1489 EmitLogicalOperation(expr);
1490 break;
1491
1492 case Token::ADD:
1493 case Token::SUB:
1494 case Token::DIV:
1495 case Token::MOD:
1496 case Token::MUL:
1497 case Token::BIT_OR:
1498 case Token::BIT_AND:
1499 case Token::BIT_XOR:
1500 case Token::SHL:
1501 case Token::SHR:
1502 case Token::SAR: {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001503 ASSERT_EQ(Expression::kValue, expr->left()->context());
1504 ASSERT_EQ(Expression::kValue, expr->right()->context());
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +00001505
1506 Visit(expr->left());
1507 Visit(expr->right());
1508 GenericBinaryOpStub stub(expr->op(),
1509 NO_OVERWRITE,
1510 NO_GENERIC_BINARY_FLAGS);
1511 __ CallStub(&stub);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001512 Apply(expr->context(), rax);
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +00001513
1514 break;
1515 }
1516 default:
1517 UNREACHABLE();
1518 }
1519}
1520
1521
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001522void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
1523 Comment cmnt(masm_, "[ CompareOperation");
1524 ASSERT_EQ(Expression::kValue, expr->left()->context());
1525 ASSERT_EQ(Expression::kValue, expr->right()->context());
1526 Visit(expr->left());
1527 Visit(expr->right());
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +00001528
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001529 // Always perform the comparison for its control flow. Pack the result
1530 // into the expression's context after the comparison is performed.
1531 Label push_true, push_false, done;
1532 // Initially assume we are in a test context.
1533 Label* if_true = true_label_;
1534 Label* if_false = false_label_;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001535 switch (expr->context()) {
1536 case Expression::kUninitialized:
1537 UNREACHABLE();
1538 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001539 case Expression::kValue:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001540 if_true = &push_true;
1541 if_false = &push_false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001542 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001543 case Expression::kEffect:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001544 if_true = &done;
1545 if_false = &done;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001546 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001547 case Expression::kTest:
1548 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001549 case Expression::kValueTest:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001550 if_true = &push_true;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001551 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001552 case Expression::kTestValue:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001553 if_false = &push_false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001554 break;
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +00001555 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001556
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001557 switch (expr->op()) {
1558 case Token::IN: {
1559 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
1560 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001561 __ j(equal, if_true);
1562 __ jmp(if_false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001563 break;
1564 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001565
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001566 case Token::INSTANCEOF: {
1567 InstanceofStub stub;
1568 __ CallStub(&stub);
1569 __ testq(rax, rax);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001570 __ j(zero, if_true); // The stub returns 0 for true.
1571 __ jmp(if_false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001572 break;
1573 }
1574
1575 default: {
1576 Condition cc = no_condition;
1577 bool strict = false;
1578 switch (expr->op()) {
1579 case Token::EQ_STRICT:
1580 strict = true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001581 // Fall through.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001582 case Token::EQ:
1583 cc = equal;
1584 __ pop(rax);
1585 __ pop(rdx);
1586 break;
1587 case Token::LT:
1588 cc = less;
1589 __ pop(rax);
1590 __ pop(rdx);
1591 break;
1592 case Token::GT:
1593 // Reverse left and right sizes to obtain ECMA-262 conversion order.
1594 cc = less;
1595 __ pop(rdx);
1596 __ pop(rax);
1597 break;
1598 case Token::LTE:
1599 // Reverse left and right sizes to obtain ECMA-262 conversion order.
1600 cc = greater_equal;
1601 __ pop(rdx);
1602 __ pop(rax);
1603 break;
1604 case Token::GTE:
1605 cc = greater_equal;
1606 __ pop(rax);
1607 __ pop(rdx);
1608 break;
1609 case Token::IN:
1610 case Token::INSTANCEOF:
1611 default:
1612 UNREACHABLE();
1613 }
1614
1615 // The comparison stub expects the smi vs. smi case to be handled
1616 // before it is called.
1617 Label slow_case;
1618 __ JumpIfNotBothSmi(rax, rdx, &slow_case);
1619 __ SmiCompare(rdx, rax);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001620 __ j(cc, if_true);
1621 __ jmp(if_false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001622
1623 __ bind(&slow_case);
1624 CompareStub stub(cc, strict);
1625 __ CallStub(&stub);
1626 __ testq(rax, rax);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001627 __ j(cc, if_true);
1628 __ jmp(if_false);
ager@chromium.org3811b432009-10-28 14:53:37 +00001629 }
1630 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001631
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001632 // Convert the result of the comparison into one expected for this
1633 // expression's context.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001634 switch (expr->context()) {
1635 case Expression::kUninitialized:
1636 UNREACHABLE();
1637 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001638
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001639 case Expression::kEffect:
1640 __ bind(&done);
1641 break;
1642
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001643 case Expression::kValue:
1644 __ bind(&push_true);
1645 __ PushRoot(Heap::kTrueValueRootIndex);
1646 __ jmp(&done);
1647 __ bind(&push_false);
1648 __ PushRoot(Heap::kFalseValueRootIndex);
1649 __ bind(&done);
1650 break;
1651
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001652 case Expression::kTest:
1653 break;
1654
1655 case Expression::kValueTest:
1656 __ bind(&push_true);
1657 __ PushRoot(Heap::kTrueValueRootIndex);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001658 __ jmp(true_label_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001659 break;
1660
1661 case Expression::kTestValue:
1662 __ bind(&push_false);
1663 __ PushRoot(Heap::kFalseValueRootIndex);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001664 __ jmp(false_label_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001665 break;
sgjesse@chromium.orgf1e73132009-10-29 14:46:49 +00001666 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001667}
1668
1669
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001670void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
1671 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001672 Apply(expr->context(), rax);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001673}
1674
1675
1676Register FastCodeGenerator::result_register() { return rax; }
1677
1678
1679Register FastCodeGenerator::context_register() { return rsi; }
1680
1681
1682void FastCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
kasperl@chromium.org8cbbcc32009-12-28 10:25:11 +00001683 ASSERT(IsAligned(frame_offset, kPointerSize));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001684 __ movq(Operand(rbp, frame_offset), value);
1685}
1686
1687
1688void FastCodeGenerator::LoadContextField(Register dst, int context_index) {
1689 __ movq(dst, CodeGenerator::ContextOperand(rsi, context_index));
1690}
1691
1692
1693// ----------------------------------------------------------------------------
1694// Non-local control flow support.
1695
1696
1697void FastCodeGenerator::EnterFinallyBlock() {
1698 ASSERT(!result_register().is(rdx));
1699 ASSERT(!result_register().is(rcx));
1700 // Cook return address on top of stack (smi encoded Code* delta)
1701 __ movq(rdx, Operand(rsp, 0));
1702 __ Move(rcx, masm_->CodeObject());
1703 __ subq(rdx, rcx);
1704 __ Integer32ToSmi(rdx, rdx);
1705 __ movq(Operand(rsp, 0), rdx);
1706 // Store result register while executing finally block.
1707 __ push(result_register());
1708}
1709
1710
1711void FastCodeGenerator::ExitFinallyBlock() {
1712 ASSERT(!result_register().is(rdx));
1713 ASSERT(!result_register().is(rcx));
1714 // Restore result register from stack.
1715 __ pop(result_register());
1716 // Uncook return address.
1717 __ movq(rdx, Operand(rsp, 0));
1718 __ SmiToInteger32(rdx, rdx);
1719 __ Move(rcx, masm_->CodeObject());
1720 __ addq(rdx, rcx);
1721 __ movq(Operand(rsp, 0), rdx);
1722 // And return.
1723 __ ret(0);
1724}
1725
1726
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001727#undef __
1728
1729
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001730} } // namespace v8::internal