blob: b042a3eca36cdf64d27c538519e300951852944e [file] [log] [blame]
lrn@chromium.org7516f052011-03-30 08:52:27 +00001// Copyright 2011 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +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_MIPS)
31
lrn@chromium.org7516f052011-03-30 08:52:27 +000032// Note on Mips implementation:
33//
34// The result_register() for mips is the 'v0' register, which is defined
35// by the ABI to contain function return values. However, the first
36// parameter to a function is defined to be 'a0'. So there are many
37// places where we have to move a previous result in v0 to a0 for the
38// next call: mov(a0, v0). This is not needed on the other architectures.
39
40#include "code-stubs.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000041#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000042#include "compiler.h"
43#include "debug.h"
44#include "full-codegen.h"
45#include "parser.h"
lrn@chromium.org7516f052011-03-30 08:52:27 +000046#include "scopes.h"
47#include "stub-cache.h"
48
49#include "mips/code-stubs-mips.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000050
51namespace v8 {
52namespace internal {
53
54#define __ ACCESS_MASM(masm_)
55
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000056
danno@chromium.org40cb8782011-05-25 07:58:50 +000057static unsigned GetPropertyId(Property* property) {
danno@chromium.org40cb8782011-05-25 07:58:50 +000058 return property->id();
59}
60
61
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000062// A patch site is a location in the code which it is possible to patch. This
63// class has a number of methods to emit the code which is patchable and the
64// method EmitPatchInfo to record a marker back to the patchable code. This
65// marker is a andi at, rx, #yyy instruction, and x * 0x0000ffff + yyy (raw 16
66// bit immediate value is used) is the delta from the pc to the first
67// instruction of the patchable code.
68class JumpPatchSite BASE_EMBEDDED {
69 public:
70 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
71#ifdef DEBUG
72 info_emitted_ = false;
73#endif
74 }
75
76 ~JumpPatchSite() {
77 ASSERT(patch_site_.is_bound() == info_emitted_);
78 }
79
80 // When initially emitting this ensure that a jump is always generated to skip
81 // the inlined smi code.
82 void EmitJumpIfNotSmi(Register reg, Label* target) {
83 ASSERT(!patch_site_.is_bound() && !info_emitted_);
84 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
85 __ bind(&patch_site_);
86 __ andi(at, reg, 0);
87 // Always taken before patched.
88 __ Branch(target, eq, at, Operand(zero_reg));
89 }
90
91 // When initially emitting this ensure that a jump is never generated to skip
92 // the inlined smi code.
93 void EmitJumpIfSmi(Register reg, Label* target) {
94 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
95 ASSERT(!patch_site_.is_bound() && !info_emitted_);
96 __ bind(&patch_site_);
97 __ andi(at, reg, 0);
98 // Never taken before patched.
99 __ Branch(target, ne, at, Operand(zero_reg));
100 }
101
102 void EmitPatchInfo() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000103 if (patch_site_.is_bound()) {
104 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
105 Register reg = Register::from_code(delta_to_patch_site / kImm16Mask);
106 __ andi(at, reg, delta_to_patch_site % kImm16Mask);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000107#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000108 info_emitted_ = true;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000109#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000110 } else {
111 __ nop(); // Signals no inlined code.
112 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000113 }
114
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000115 private:
116 MacroAssembler* masm_;
117 Label patch_site_;
118#ifdef DEBUG
119 bool info_emitted_;
120#endif
121};
122
123
lrn@chromium.org7516f052011-03-30 08:52:27 +0000124// Generate code for a JS function. On entry to the function the receiver
125// and arguments have been pushed on the stack left to right. The actual
126// argument count matches the formal parameter count expected by the
127// function.
128//
129// The live registers are:
130// o a1: the JS function object being called (ie, ourselves)
131// o cp: our context
132// o fp: our caller's frame pointer
133// o sp: stack pointer
134// o ra: return address
135//
136// The function builds a JS frame. Please see JavaScriptFrameConstants in
137// frames-mips.h for its layout.
138void FullCodeGenerator::Generate(CompilationInfo* info) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000139 ASSERT(info_ == NULL);
140 info_ = info;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000141 scope_ = info->scope();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000142 SetFunctionPosition(function());
143 Comment cmnt(masm_, "[ function compiled by full code generator");
144
145#ifdef DEBUG
146 if (strlen(FLAG_stop_at) > 0 &&
147 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
148 __ stop("stop-at");
149 }
150#endif
151
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000152 // Strict mode functions and builtins need to replace the receiver
153 // with undefined when called as functions (without an explicit
154 // receiver object). t1 is zero for method calls and non-zero for
155 // function calls.
156 if (info->is_strict_mode() || info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000157 Label ok;
158 __ Branch(&ok, eq, t1, Operand(zero_reg));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000159 int receiver_offset = info->scope()->num_parameters() * kPointerSize;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000160 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
161 __ sw(a2, MemOperand(sp, receiver_offset));
162 __ bind(&ok);
163 }
164
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000165 int locals_count = info->scope()->num_stack_slots();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000166
167 __ Push(ra, fp, cp, a1);
168 if (locals_count > 0) {
169 // Load undefined value here, so the value is ready for the loop
170 // below.
171 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
172 }
173 // Adjust fp to point to caller's fp.
174 __ Addu(fp, sp, Operand(2 * kPointerSize));
175
176 { Comment cmnt(masm_, "[ Allocate locals");
177 for (int i = 0; i < locals_count; i++) {
178 __ push(at);
179 }
180 }
181
182 bool function_in_register = true;
183
184 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000185 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000186 if (heap_slots > 0) {
187 Comment cmnt(masm_, "[ Allocate local context");
188 // Argument to NewContext is the function, which is in a1.
189 __ push(a1);
190 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
191 FastNewContextStub stub(heap_slots);
192 __ CallStub(&stub);
193 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000194 __ CallRuntime(Runtime::kNewFunctionContext, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000195 }
196 function_in_register = false;
197 // Context is returned in both v0 and cp. It replaces the context
198 // passed to us. It's saved in the stack and kept live in cp.
199 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
200 // Copy any necessary parameters into the context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000201 int num_parameters = info->scope()->num_parameters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000202 for (int i = 0; i < num_parameters; i++) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000203 Variable* var = scope()->parameter(i);
204 if (var->IsContextSlot()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000205 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
206 (num_parameters - 1 - i) * kPointerSize;
207 // Load parameter from stack.
208 __ lw(a0, MemOperand(fp, parameter_offset));
209 // Store it in the context.
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000210 __ li(a1, Operand(Context::SlotOffset(var->index())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000211 __ addu(a2, cp, a1);
212 __ sw(a0, MemOperand(a2, 0));
213 // Update the write barrier. This clobbers all involved
214 // registers, so we have to use two more registers to avoid
215 // clobbering cp.
216 __ mov(a2, cp);
217 __ RecordWrite(a2, a1, a3);
218 }
219 }
220 }
221
222 Variable* arguments = scope()->arguments();
223 if (arguments != NULL) {
224 // Function uses arguments object.
225 Comment cmnt(masm_, "[ Allocate arguments object");
226 if (!function_in_register) {
227 // Load this again, if it's used by the local context below.
228 __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
229 } else {
230 __ mov(a3, a1);
231 }
232 // Receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000233 int num_parameters = info->scope()->num_parameters();
234 int offset = num_parameters * kPointerSize;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000235 __ Addu(a2, fp,
236 Operand(StandardFrameConstants::kCallerSPOffset + offset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000237 __ li(a1, Operand(Smi::FromInt(num_parameters)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000238 __ Push(a3, a2, a1);
239
240 // Arguments to ArgumentsAccessStub:
241 // function, receiver address, parameter count.
242 // The stub will rewrite receiever and parameter count if the previous
243 // stack frame was an arguments adapter frame.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000244 ArgumentsAccessStub::Type type;
245 if (is_strict_mode()) {
246 type = ArgumentsAccessStub::NEW_STRICT;
247 } else if (function()->has_duplicate_parameters()) {
248 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
249 } else {
250 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
251 }
252 ArgumentsAccessStub stub(type);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000253 __ CallStub(&stub);
254
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000255 SetVar(arguments, v0, a1, a2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000256 }
257
258 if (FLAG_trace) {
259 __ CallRuntime(Runtime::kTraceEnter, 0);
260 }
261
262 // Visit the declarations and body unless there is an illegal
263 // redeclaration.
264 if (scope()->HasIllegalRedeclaration()) {
265 Comment cmnt(masm_, "[ Declarations");
266 scope()->VisitIllegalRedeclaration(this);
267
268 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000269 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000270 { Comment cmnt(masm_, "[ Declarations");
271 // For named function expressions, declare the function name as a
272 // constant.
273 if (scope()->is_function_scope() && scope()->function() != NULL) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000274 int ignored = 0;
275 EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000276 }
277 VisitDeclarations(scope()->declarations());
278 }
279
280 { Comment cmnt(masm_, "[ Stack check");
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000281 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000282 Label ok;
283 __ LoadRoot(t0, Heap::kStackLimitRootIndex);
284 __ Branch(&ok, hs, sp, Operand(t0));
285 StackCheckStub stub;
286 __ CallStub(&stub);
287 __ bind(&ok);
288 }
289
290 { Comment cmnt(masm_, "[ Body");
291 ASSERT(loop_depth() == 0);
292 VisitStatements(function()->body());
293 ASSERT(loop_depth() == 0);
294 }
295 }
296
297 // Always emit a 'return undefined' in case control fell off the end of
298 // the body.
299 { Comment cmnt(masm_, "[ return <undefined>;");
300 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
301 }
302 EmitReturnSequence();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000303}
304
305
306void FullCodeGenerator::ClearAccumulator() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000307 ASSERT(Smi::FromInt(0) == 0);
308 __ mov(v0, zero_reg);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000309}
310
311
312void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000313 Comment cmnt(masm_, "[ Stack check");
314 Label ok;
315 __ LoadRoot(t0, Heap::kStackLimitRootIndex);
316 __ Branch(&ok, hs, sp, Operand(t0));
317 StackCheckStub stub;
318 // Record a mapping of this PC offset to the OSR id. This is used to find
319 // the AST id from the unoptimized code in order to use it as a key into
320 // the deoptimization input data found in the optimized code.
321 RecordStackCheck(stmt->OsrEntryId());
322
323 __ CallStub(&stub);
324 __ bind(&ok);
325 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
326 // Record a mapping of the OSR id to this PC. This is used if the OSR
327 // entry becomes the target of a bailout. We don't expect it to be, but
328 // we want it to work if it is.
329 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
ager@chromium.org5c838252010-02-19 08:53:10 +0000330}
331
332
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000333void FullCodeGenerator::EmitReturnSequence() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000334 Comment cmnt(masm_, "[ Return sequence");
335 if (return_label_.is_bound()) {
336 __ Branch(&return_label_);
337 } else {
338 __ bind(&return_label_);
339 if (FLAG_trace) {
340 // Push the return value on the stack as the parameter.
341 // Runtime::TraceExit returns its parameter in v0.
342 __ push(v0);
343 __ CallRuntime(Runtime::kTraceExit, 1);
344 }
345
346#ifdef DEBUG
347 // Add a label for checking the size of the code used for returning.
348 Label check_exit_codesize;
349 masm_->bind(&check_exit_codesize);
350#endif
351 // Make sure that the constant pool is not emitted inside of the return
352 // sequence.
353 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
354 // Here we use masm_-> instead of the __ macro to avoid the code coverage
355 // tool from instrumenting as we rely on the code size here.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000356 int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000357 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
358 __ RecordJSReturn();
359 masm_->mov(sp, fp);
360 masm_->MultiPop(static_cast<RegList>(fp.bit() | ra.bit()));
361 masm_->Addu(sp, sp, Operand(sp_delta));
362 masm_->Jump(ra);
363 }
364
365#ifdef DEBUG
366 // Check that the size of the code used for returning is large enough
367 // for the debugger's requirements.
368 ASSERT(Assembler::kJSReturnSequenceInstructions <=
369 masm_->InstructionsGeneratedSince(&check_exit_codesize));
370#endif
371 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000372}
373
374
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000375void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
376 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
ager@chromium.org5c838252010-02-19 08:53:10 +0000377}
378
379
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000380void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
381 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
382 codegen()->GetVar(result_register(), var);
ager@chromium.org5c838252010-02-19 08:53:10 +0000383}
384
385
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000386void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
387 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
388 codegen()->GetVar(result_register(), var);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000389 __ push(result_register());
ager@chromium.org5c838252010-02-19 08:53:10 +0000390}
391
392
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000393void FullCodeGenerator::TestContext::Plug(Variable* var) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000394 // For simplicity we always test the accumulator register.
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000395 codegen()->GetVar(result_register(), var);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000396 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000397 codegen()->DoTest(this);
ager@chromium.org5c838252010-02-19 08:53:10 +0000398}
399
400
lrn@chromium.org7516f052011-03-30 08:52:27 +0000401void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
ager@chromium.org5c838252010-02-19 08:53:10 +0000402}
403
404
lrn@chromium.org7516f052011-03-30 08:52:27 +0000405void FullCodeGenerator::AccumulatorValueContext::Plug(
406 Heap::RootListIndex index) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000407 __ LoadRoot(result_register(), index);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000408}
409
410
411void FullCodeGenerator::StackValueContext::Plug(
412 Heap::RootListIndex index) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000413 __ LoadRoot(result_register(), index);
414 __ push(result_register());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000415}
416
417
418void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000419 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
420 true,
421 true_label_,
422 false_label_);
423 if (index == Heap::kUndefinedValueRootIndex ||
424 index == Heap::kNullValueRootIndex ||
425 index == Heap::kFalseValueRootIndex) {
426 if (false_label_ != fall_through_) __ Branch(false_label_);
427 } else if (index == Heap::kTrueValueRootIndex) {
428 if (true_label_ != fall_through_) __ Branch(true_label_);
429 } else {
430 __ LoadRoot(result_register(), index);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000431 codegen()->DoTest(this);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000432 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000433}
434
435
436void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000437}
438
439
440void FullCodeGenerator::AccumulatorValueContext::Plug(
441 Handle<Object> lit) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000442 __ li(result_register(), Operand(lit));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000443}
444
445
446void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000447 // Immediates cannot be pushed directly.
448 __ li(result_register(), Operand(lit));
449 __ push(result_register());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000450}
451
452
453void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000454 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
455 true,
456 true_label_,
457 false_label_);
458 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
459 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
460 if (false_label_ != fall_through_) __ Branch(false_label_);
461 } else if (lit->IsTrue() || lit->IsJSObject()) {
462 if (true_label_ != fall_through_) __ Branch(true_label_);
463 } else if (lit->IsString()) {
464 if (String::cast(*lit)->length() == 0) {
465 if (false_label_ != fall_through_) __ Branch(false_label_);
466 } else {
467 if (true_label_ != fall_through_) __ Branch(true_label_);
468 }
469 } else if (lit->IsSmi()) {
470 if (Smi::cast(*lit)->value() == 0) {
471 if (false_label_ != fall_through_) __ Branch(false_label_);
472 } else {
473 if (true_label_ != fall_through_) __ Branch(true_label_);
474 }
475 } else {
476 // For simplicity we always test the accumulator register.
477 __ li(result_register(), Operand(lit));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000478 codegen()->DoTest(this);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000479 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000480}
481
482
483void FullCodeGenerator::EffectContext::DropAndPlug(int count,
484 Register reg) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000485 ASSERT(count > 0);
486 __ Drop(count);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000487}
488
489
490void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
491 int count,
492 Register reg) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000493 ASSERT(count > 0);
494 __ Drop(count);
495 __ Move(result_register(), reg);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000496}
497
498
499void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
500 Register reg) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000501 ASSERT(count > 0);
502 if (count > 1) __ Drop(count - 1);
503 __ sw(reg, MemOperand(sp, 0));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000504}
505
506
507void FullCodeGenerator::TestContext::DropAndPlug(int count,
508 Register reg) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000509 ASSERT(count > 0);
510 // For simplicity we always test the accumulator register.
511 __ Drop(count);
512 __ Move(result_register(), reg);
513 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000514 codegen()->DoTest(this);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000515}
516
517
518void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
519 Label* materialize_false) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000520 ASSERT(materialize_true == materialize_false);
521 __ bind(materialize_true);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000522}
523
524
525void FullCodeGenerator::AccumulatorValueContext::Plug(
526 Label* materialize_true,
527 Label* materialize_false) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000528 Label done;
529 __ bind(materialize_true);
530 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
531 __ Branch(&done);
532 __ bind(materialize_false);
533 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
534 __ bind(&done);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000535}
536
537
538void FullCodeGenerator::StackValueContext::Plug(
539 Label* materialize_true,
540 Label* materialize_false) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000541 Label done;
542 __ bind(materialize_true);
543 __ LoadRoot(at, Heap::kTrueValueRootIndex);
544 __ push(at);
545 __ Branch(&done);
546 __ bind(materialize_false);
547 __ LoadRoot(at, Heap::kFalseValueRootIndex);
548 __ push(at);
549 __ bind(&done);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000550}
551
552
553void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
554 Label* materialize_false) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000555 ASSERT(materialize_true == true_label_);
556 ASSERT(materialize_false == false_label_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000557}
558
559
560void FullCodeGenerator::EffectContext::Plug(bool flag) const {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000561}
562
563
564void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000565 Heap::RootListIndex value_root_index =
566 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
567 __ LoadRoot(result_register(), value_root_index);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000568}
569
570
571void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000572 Heap::RootListIndex value_root_index =
573 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
574 __ LoadRoot(at, value_root_index);
575 __ push(at);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000576}
577
578
579void FullCodeGenerator::TestContext::Plug(bool flag) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000580 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
581 true,
582 true_label_,
583 false_label_);
584 if (flag) {
585 if (true_label_ != fall_through_) __ Branch(true_label_);
586 } else {
587 if (false_label_ != fall_through_) __ Branch(false_label_);
588 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000589}
590
591
whesse@chromium.org7b260152011-06-20 15:33:18 +0000592void FullCodeGenerator::DoTest(Expression* condition,
593 Label* if_true,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000594 Label* if_false,
595 Label* fall_through) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000596 if (CpuFeatures::IsSupported(FPU)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000597 ToBooleanStub stub(result_register());
598 __ CallStub(&stub);
599 __ mov(at, zero_reg);
600 } else {
601 // Call the runtime to find the boolean value of the source and then
602 // translate it into control flow to the pair of labels.
603 __ push(result_register());
604 __ CallRuntime(Runtime::kToBool, 1);
605 __ LoadRoot(at, Heap::kFalseValueRootIndex);
606 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000607 Split(ne, v0, Operand(at), if_true, if_false, fall_through);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000608}
609
610
lrn@chromium.org7516f052011-03-30 08:52:27 +0000611void FullCodeGenerator::Split(Condition cc,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000612 Register lhs,
613 const Operand& rhs,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000614 Label* if_true,
615 Label* if_false,
616 Label* fall_through) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000617 if (if_false == fall_through) {
618 __ Branch(if_true, cc, lhs, rhs);
619 } else if (if_true == fall_through) {
620 __ Branch(if_false, NegateCondition(cc), lhs, rhs);
621 } else {
622 __ Branch(if_true, cc, lhs, rhs);
623 __ Branch(if_false);
624 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000625}
626
627
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000628MemOperand FullCodeGenerator::StackOperand(Variable* var) {
629 ASSERT(var->IsStackAllocated());
630 // Offset is negative because higher indexes are at lower addresses.
631 int offset = -var->index() * kPointerSize;
632 // Adjust by a (parameter or local) base offset.
633 if (var->IsParameter()) {
634 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
635 } else {
636 offset += JavaScriptFrameConstants::kLocal0Offset;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000637 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000638 return MemOperand(fp, offset);
ager@chromium.org5c838252010-02-19 08:53:10 +0000639}
640
641
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000642MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
643 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
644 if (var->IsContextSlot()) {
645 int context_chain_length = scope()->ContextChainLength(var->scope());
646 __ LoadContext(scratch, context_chain_length);
647 return ContextOperand(scratch, var->index());
648 } else {
649 return StackOperand(var);
650 }
651}
652
653
654void FullCodeGenerator::GetVar(Register dest, Variable* var) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000655 // Use destination as scratch.
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000656 MemOperand location = VarOperand(var, dest);
657 __ lw(dest, location);
658}
659
660
661void FullCodeGenerator::SetVar(Variable* var,
662 Register src,
663 Register scratch0,
664 Register scratch1) {
665 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
666 ASSERT(!scratch0.is(src));
667 ASSERT(!scratch0.is(scratch1));
668 ASSERT(!scratch1.is(src));
669 MemOperand location = VarOperand(var, scratch0);
670 __ sw(src, location);
671 // Emit the write barrier code if the location is in the heap.
672 if (var->IsContextSlot()) {
673 __ RecordWrite(scratch0,
674 Operand(Context::SlotOffset(var->index())),
675 scratch1,
676 src);
677 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000678}
679
680
lrn@chromium.org7516f052011-03-30 08:52:27 +0000681void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
682 bool should_normalize,
683 Label* if_true,
684 Label* if_false) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000685 // Only prepare for bailouts before splits if we're in a test
686 // context. Otherwise, we let the Visit function deal with the
687 // preparation to avoid preparing with the same AST id twice.
688 if (!context()->IsTest() || !info_->IsOptimizable()) return;
689
690 Label skip;
691 if (should_normalize) __ Branch(&skip);
692
693 ForwardBailoutStack* current = forward_bailout_stack_;
694 while (current != NULL) {
695 PrepareForBailout(current->expr(), state);
696 current = current->parent();
697 }
698
699 if (should_normalize) {
700 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
701 Split(eq, a0, Operand(t0), if_true, if_false, NULL);
702 __ bind(&skip);
703 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000704}
705
706
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000707void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000708 Variable::Mode mode,
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000709 FunctionLiteral* function,
710 int* global_count) {
711 // If it was not possible to allocate the variable at compile time, we
712 // need to "declare" it at runtime to make sure it actually exists in the
713 // local context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000714 Variable* variable = proxy->var();
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000715 switch (variable->location()) {
716 case Variable::UNALLOCATED:
717 ++(*global_count);
718 break;
719
720 case Variable::PARAMETER:
721 case Variable::LOCAL:
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000722 if (function != NULL) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000723 Comment cmnt(masm_, "[ Declaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000724 VisitForAccumulatorValue(function);
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000725 __ sw(result_register(), StackOperand(variable));
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000726 } else if (mode == Variable::CONST || mode == Variable::LET) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000727 Comment cmnt(masm_, "[ Declaration");
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000728 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000729 __ sw(t0, StackOperand(variable));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000730 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000731 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000732
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000733 case Variable::CONTEXT:
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000734 // The variable in the decl always resides in the current function
735 // context.
736 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
737 if (FLAG_debug_code) {
738 // Check that we're not inside a with or catch context.
739 __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
740 __ LoadRoot(t0, Heap::kWithContextMapRootIndex);
741 __ Check(ne, "Declaration in with context.",
742 a1, Operand(t0));
743 __ LoadRoot(t0, Heap::kCatchContextMapRootIndex);
744 __ Check(ne, "Declaration in catch context.",
745 a1, Operand(t0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000746 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000747 if (function != NULL) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000748 Comment cmnt(masm_, "[ Declaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000749 VisitForAccumulatorValue(function);
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000750 __ sw(result_register(), ContextOperand(cp, variable->index()));
751 int offset = Context::SlotOffset(variable->index());
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000752 // We know that we have written a function, which is not a smi.
753 __ mov(a1, cp);
754 __ RecordWrite(a1, Operand(offset), a2, result_register());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000755 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000756 } else if (mode == Variable::CONST || mode == Variable::LET) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000757 Comment cmnt(masm_, "[ Declaration");
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000758 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000759 __ sw(at, ContextOperand(cp, variable->index()));
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000760 // No write barrier since the_hole_value is in old space.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000761 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000762 }
763 break;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000764
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000765 case Variable::LOOKUP: {
766 Comment cmnt(masm_, "[ Declaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000767 __ li(a2, Operand(variable->name()));
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000768 // Declaration nodes are always introduced in one of three modes.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000769 ASSERT(mode == Variable::VAR ||
770 mode == Variable::CONST ||
771 mode == Variable::LET);
772 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
773 __ li(a1, Operand(Smi::FromInt(attr)));
774 // Push initial value, if any.
775 // Note: For variables we must not push an initial value (such as
776 // 'undefined') because we may have a (legal) redeclaration and we
777 // must not destroy the current value.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000778 if (function != NULL) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000779 __ Push(cp, a2, a1);
780 // Push initial value for function declaration.
781 VisitForStackValue(function);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000782 } else if (mode == Variable::CONST || mode == Variable::LET) {
783 __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
784 __ Push(cp, a2, a1, a0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000785 } else {
786 ASSERT(Smi::FromInt(0) == 0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000787 __ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000788 __ Push(cp, a2, a1, a0);
789 }
790 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
791 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000792 }
793 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000794}
795
796
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000797void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
ager@chromium.org5c838252010-02-19 08:53:10 +0000798
799
800void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000801 // Call the runtime to declare the globals.
802 // The context is the first argument.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000803 __ li(a1, Operand(pairs));
804 __ li(a0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
805 __ Push(cp, a1, a0);
806 __ CallRuntime(Runtime::kDeclareGlobals, 3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000807 // Return value is ignored.
ager@chromium.org5c838252010-02-19 08:53:10 +0000808}
809
810
lrn@chromium.org7516f052011-03-30 08:52:27 +0000811void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000812 Comment cmnt(masm_, "[ SwitchStatement");
813 Breakable nested_statement(this, stmt);
814 SetStatementPosition(stmt);
815
816 // Keep the switch value on the stack until a case matches.
817 VisitForStackValue(stmt->tag());
818 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
819
820 ZoneList<CaseClause*>* clauses = stmt->cases();
821 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
822
823 Label next_test; // Recycled for each test.
824 // Compile all the tests with branches to their bodies.
825 for (int i = 0; i < clauses->length(); i++) {
826 CaseClause* clause = clauses->at(i);
827 clause->body_target()->Unuse();
828
829 // The default is not a test, but remember it as final fall through.
830 if (clause->is_default()) {
831 default_clause = clause;
832 continue;
833 }
834
835 Comment cmnt(masm_, "[ Case comparison");
836 __ bind(&next_test);
837 next_test.Unuse();
838
839 // Compile the label expression.
840 VisitForAccumulatorValue(clause->label());
841 __ mov(a0, result_register()); // CompareStub requires args in a0, a1.
842
843 // Perform the comparison as if via '==='.
844 __ lw(a1, MemOperand(sp, 0)); // Switch value.
845 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
846 JumpPatchSite patch_site(masm_);
847 if (inline_smi_code) {
848 Label slow_case;
849 __ or_(a2, a1, a0);
850 patch_site.EmitJumpIfNotSmi(a2, &slow_case);
851
852 __ Branch(&next_test, ne, a1, Operand(a0));
853 __ Drop(1); // Switch value is no longer needed.
854 __ Branch(clause->body_target());
855
856 __ bind(&slow_case);
857 }
858
859 // Record position before stub call for type feedback.
860 SetSourcePosition(clause->position());
861 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000862 __ Call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000863 patch_site.EmitPatchInfo();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000864
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000865 __ Branch(&next_test, ne, v0, Operand(zero_reg));
866 __ Drop(1); // Switch value is no longer needed.
867 __ Branch(clause->body_target());
868 }
869
870 // Discard the test value and jump to the default if present, otherwise to
871 // the end of the statement.
872 __ bind(&next_test);
873 __ Drop(1); // Switch value is no longer needed.
874 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000875 __ Branch(nested_statement.break_label());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000876 } else {
877 __ Branch(default_clause->body_target());
878 }
879
880 // Compile all the case bodies.
881 for (int i = 0; i < clauses->length(); i++) {
882 Comment cmnt(masm_, "[ Case body");
883 CaseClause* clause = clauses->at(i);
884 __ bind(clause->body_target());
885 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
886 VisitStatements(clause->statements());
887 }
888
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000889 __ bind(nested_statement.break_label());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000890 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000891}
892
893
894void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000895 Comment cmnt(masm_, "[ ForInStatement");
896 SetStatementPosition(stmt);
897
898 Label loop, exit;
899 ForIn loop_statement(this, stmt);
900 increment_loop_depth();
901
902 // Get the object to enumerate over. Both SpiderMonkey and JSC
903 // ignore null and undefined in contrast to the specification; see
904 // ECMA-262 section 12.6.4.
905 VisitForAccumulatorValue(stmt->enumerable());
906 __ mov(a0, result_register()); // Result as param to InvokeBuiltin below.
907 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
908 __ Branch(&exit, eq, a0, Operand(at));
909 Register null_value = t1;
910 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
911 __ Branch(&exit, eq, a0, Operand(null_value));
912
913 // Convert the object to a JS object.
914 Label convert, done_convert;
915 __ JumpIfSmi(a0, &convert);
916 __ GetObjectType(a0, a1, a1);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000917 __ Branch(&done_convert, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000918 __ bind(&convert);
919 __ push(a0);
920 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
921 __ mov(a0, v0);
922 __ bind(&done_convert);
923 __ push(a0);
924
925 // Check cache validity in generated code. This is a fast case for
926 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
927 // guarantee cache validity, call the runtime system to check cache
928 // validity or get the property names in a fixed array.
929 Label next, call_runtime;
930 // Preload a couple of values used in the loop.
931 Register empty_fixed_array_value = t2;
932 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
933 Register empty_descriptor_array_value = t3;
934 __ LoadRoot(empty_descriptor_array_value,
935 Heap::kEmptyDescriptorArrayRootIndex);
936 __ mov(a1, a0);
937 __ bind(&next);
938
939 // Check that there are no elements. Register a1 contains the
940 // current JS object we've reached through the prototype chain.
941 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
942 __ Branch(&call_runtime, ne, a2, Operand(empty_fixed_array_value));
943
944 // Check that instance descriptors are not empty so that we can
945 // check for an enum cache. Leave the map in a2 for the subsequent
946 // prototype load.
947 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000948 __ lw(a3, FieldMemOperand(a2, Map::kInstanceDescriptorsOrBitField3Offset));
949 __ JumpIfSmi(a3, &call_runtime);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000950
951 // Check that there is an enum cache in the non-empty instance
952 // descriptors (a3). This is the case if the next enumeration
953 // index field does not contain a smi.
954 __ lw(a3, FieldMemOperand(a3, DescriptorArray::kEnumerationIndexOffset));
955 __ JumpIfSmi(a3, &call_runtime);
956
957 // For all objects but the receiver, check that the cache is empty.
958 Label check_prototype;
959 __ Branch(&check_prototype, eq, a1, Operand(a0));
960 __ lw(a3, FieldMemOperand(a3, DescriptorArray::kEnumCacheBridgeCacheOffset));
961 __ Branch(&call_runtime, ne, a3, Operand(empty_fixed_array_value));
962
963 // Load the prototype from the map and loop if non-null.
964 __ bind(&check_prototype);
965 __ lw(a1, FieldMemOperand(a2, Map::kPrototypeOffset));
966 __ Branch(&next, ne, a1, Operand(null_value));
967
968 // The enum cache is valid. Load the map of the object being
969 // iterated over and use the cache for the iteration.
970 Label use_cache;
971 __ lw(v0, FieldMemOperand(a0, HeapObject::kMapOffset));
972 __ Branch(&use_cache);
973
974 // Get the set of properties to enumerate.
975 __ bind(&call_runtime);
976 __ push(a0); // Duplicate the enumerable object on the stack.
977 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
978
979 // If we got a map from the runtime call, we can do a fast
980 // modification check. Otherwise, we got a fixed array, and we have
981 // to do a slow check.
982 Label fixed_array;
983 __ mov(a2, v0);
984 __ lw(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
985 __ LoadRoot(at, Heap::kMetaMapRootIndex);
986 __ Branch(&fixed_array, ne, a1, Operand(at));
987
988 // We got a map in register v0. Get the enumeration cache from it.
989 __ bind(&use_cache);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000990 __ LoadInstanceDescriptors(v0, a1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000991 __ lw(a1, FieldMemOperand(a1, DescriptorArray::kEnumerationIndexOffset));
992 __ lw(a2, FieldMemOperand(a1, DescriptorArray::kEnumCacheBridgeCacheOffset));
993
994 // Setup the four remaining stack slots.
995 __ push(v0); // Map.
996 __ lw(a1, FieldMemOperand(a2, FixedArray::kLengthOffset));
997 __ li(a0, Operand(Smi::FromInt(0)));
998 // Push enumeration cache, enumeration cache length (as smi) and zero.
999 __ Push(a2, a1, a0);
1000 __ jmp(&loop);
1001
1002 // We got a fixed array in register v0. Iterate through that.
1003 __ bind(&fixed_array);
1004 __ li(a1, Operand(Smi::FromInt(0))); // Map (0) - force slow check.
1005 __ Push(a1, v0);
1006 __ lw(a1, FieldMemOperand(v0, FixedArray::kLengthOffset));
1007 __ li(a0, Operand(Smi::FromInt(0)));
1008 __ Push(a1, a0); // Fixed array length (as smi) and initial index.
1009
1010 // Generate code for doing the condition check.
1011 __ bind(&loop);
1012 // Load the current count to a0, load the length to a1.
1013 __ lw(a0, MemOperand(sp, 0 * kPointerSize));
1014 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001015 __ Branch(loop_statement.break_label(), hs, a0, Operand(a1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001016
1017 // Get the current entry of the array into register a3.
1018 __ lw(a2, MemOperand(sp, 2 * kPointerSize));
1019 __ Addu(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1020 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
1021 __ addu(t0, a2, t0); // Array base + scaled (smi) index.
1022 __ lw(a3, MemOperand(t0)); // Current entry.
1023
1024 // Get the expected map from the stack or a zero map in the
1025 // permanent slow case into register a2.
1026 __ lw(a2, MemOperand(sp, 3 * kPointerSize));
1027
1028 // Check if the expected map still matches that of the enumerable.
1029 // If not, we have to filter the key.
1030 Label update_each;
1031 __ lw(a1, MemOperand(sp, 4 * kPointerSize));
1032 __ lw(t0, FieldMemOperand(a1, HeapObject::kMapOffset));
1033 __ Branch(&update_each, eq, t0, Operand(a2));
1034
1035 // Convert the entry to a string or (smi) 0 if it isn't a property
1036 // any more. If the property has been removed while iterating, we
1037 // just skip it.
1038 __ push(a1); // Enumerable.
1039 __ push(a3); // Current entry.
1040 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
1041 __ mov(a3, result_register());
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001042 __ Branch(loop_statement.continue_label(), eq, a3, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001043
1044 // Update the 'each' property or variable from the possibly filtered
1045 // entry in register a3.
1046 __ bind(&update_each);
1047 __ mov(result_register(), a3);
1048 // Perform the assignment as if via '='.
1049 { EffectContext context(this);
1050 EmitAssignment(stmt->each(), stmt->AssignmentId());
1051 }
1052
1053 // Generate code for the body of the loop.
1054 Visit(stmt->body());
1055
1056 // Generate code for the going to the next element by incrementing
1057 // the index (smi) stored on top of the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001058 __ bind(loop_statement.continue_label());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001059 __ pop(a0);
1060 __ Addu(a0, a0, Operand(Smi::FromInt(1)));
1061 __ push(a0);
1062
1063 EmitStackCheck(stmt);
1064 __ Branch(&loop);
1065
1066 // Remove the pointers stored on the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001067 __ bind(loop_statement.break_label());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001068 __ Drop(5);
1069
1070 // Exit and decrement the loop depth.
1071 __ bind(&exit);
1072 decrement_loop_depth();
lrn@chromium.org7516f052011-03-30 08:52:27 +00001073}
1074
1075
1076void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1077 bool pretenure) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001078 // Use the fast case closure allocation code that allocates in new
1079 // space for nested functions that don't need literals cloning. If
1080 // we're running with the --always-opt or the --prepare-always-opt
1081 // flag, we need to use the runtime function so that the new function
1082 // we are creating here gets a chance to have its code optimized and
1083 // doesn't just get a copy of the existing unoptimized code.
1084 if (!FLAG_always_opt &&
1085 !FLAG_prepare_always_opt &&
1086 !pretenure &&
1087 scope()->is_function_scope() &&
1088 info->num_literals() == 0) {
1089 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
1090 __ li(a0, Operand(info));
1091 __ push(a0);
1092 __ CallStub(&stub);
1093 } else {
1094 __ li(a0, Operand(info));
1095 __ LoadRoot(a1, pretenure ? Heap::kTrueValueRootIndex
1096 : Heap::kFalseValueRootIndex);
1097 __ Push(cp, a0, a1);
1098 __ CallRuntime(Runtime::kNewClosure, 3);
1099 }
1100 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001101}
1102
1103
1104void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001105 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001106 EmitVariableLoad(expr);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001107}
1108
1109
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001110void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1111 TypeofState typeof_state,
1112 Label* slow) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001113 Register current = cp;
1114 Register next = a1;
1115 Register temp = a2;
1116
1117 Scope* s = scope();
1118 while (s != NULL) {
1119 if (s->num_heap_slots() > 0) {
1120 if (s->calls_eval()) {
1121 // Check that extension is NULL.
1122 __ lw(temp, ContextOperand(current, Context::EXTENSION_INDEX));
1123 __ Branch(slow, ne, temp, Operand(zero_reg));
1124 }
1125 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001126 __ lw(next, ContextOperand(current, Context::PREVIOUS_INDEX));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001127 // Walk the rest of the chain without clobbering cp.
1128 current = next;
1129 }
1130 // If no outer scope calls eval, we do not need to check more
1131 // context extensions.
1132 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1133 s = s->outer_scope();
1134 }
1135
1136 if (s->is_eval_scope()) {
1137 Label loop, fast;
1138 if (!current.is(next)) {
1139 __ Move(next, current);
1140 }
1141 __ bind(&loop);
1142 // Terminate at global context.
1143 __ lw(temp, FieldMemOperand(next, HeapObject::kMapOffset));
1144 __ LoadRoot(t0, Heap::kGlobalContextMapRootIndex);
1145 __ Branch(&fast, eq, temp, Operand(t0));
1146 // Check that extension is NULL.
1147 __ lw(temp, ContextOperand(next, Context::EXTENSION_INDEX));
1148 __ Branch(slow, ne, temp, Operand(zero_reg));
1149 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001150 __ lw(next, ContextOperand(next, Context::PREVIOUS_INDEX));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001151 __ Branch(&loop);
1152 __ bind(&fast);
1153 }
1154
1155 __ lw(a0, GlobalObjectOperand());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001156 __ li(a2, Operand(var->name()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001157 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1158 ? RelocInfo::CODE_TARGET
1159 : RelocInfo::CODE_TARGET_CONTEXT;
1160 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001161 __ Call(ic, mode);
ager@chromium.org5c838252010-02-19 08:53:10 +00001162}
1163
1164
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001165MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1166 Label* slow) {
1167 ASSERT(var->IsContextSlot());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001168 Register context = cp;
1169 Register next = a3;
1170 Register temp = t0;
1171
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001172 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001173 if (s->num_heap_slots() > 0) {
1174 if (s->calls_eval()) {
1175 // Check that extension is NULL.
1176 __ lw(temp, ContextOperand(context, Context::EXTENSION_INDEX));
1177 __ Branch(slow, ne, temp, Operand(zero_reg));
1178 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001179 __ lw(next, ContextOperand(context, Context::PREVIOUS_INDEX));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001180 // Walk the rest of the chain without clobbering cp.
1181 context = next;
1182 }
1183 }
1184 // Check that last extension is NULL.
1185 __ lw(temp, ContextOperand(context, Context::EXTENSION_INDEX));
1186 __ Branch(slow, ne, temp, Operand(zero_reg));
1187
1188 // This function is used only for loads, not stores, so it's safe to
1189 // return an cp-based operand (the write barrier cannot be allowed to
1190 // destroy the cp register).
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001191 return ContextOperand(context, var->index());
lrn@chromium.org7516f052011-03-30 08:52:27 +00001192}
1193
1194
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001195void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1196 TypeofState typeof_state,
1197 Label* slow,
1198 Label* done) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001199 // Generate fast-case code for variables that might be shadowed by
1200 // eval-introduced variables. Eval is used a lot without
1201 // introducing variables. In those cases, we do not want to
1202 // perform a runtime call for all variables in the scope
1203 // containing the eval.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001204 if (var->mode() == Variable::DYNAMIC_GLOBAL) {
1205 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001206 __ Branch(done);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001207 } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
1208 Variable* local = var->local_if_not_shadowed();
1209 __ lw(v0, ContextSlotOperandCheckExtensions(local, slow));
1210 if (local->mode() == Variable::CONST) {
1211 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
1212 __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
1213 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
1214 __ movz(v0, a0, at); // Conditional move: return Undefined if TheHole.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001215 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001216 __ Branch(done);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001217 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001218}
1219
1220
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001221void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1222 // Record position before possible IC call.
1223 SetSourcePosition(proxy->position());
1224 Variable* var = proxy->var();
1225
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001226 // Three cases: global variables, lookup variables, and all other types of
1227 // variables.
1228 switch (var->location()) {
1229 case Variable::UNALLOCATED: {
1230 Comment cmnt(masm_, "Global variable");
1231 // Use inline caching. Variable name is passed in a2 and the global
1232 // object (receiver) in a0.
1233 __ lw(a0, GlobalObjectOperand());
1234 __ li(a2, Operand(var->name()));
1235 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
1236 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
1237 context()->Plug(v0);
1238 break;
1239 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001240
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001241 case Variable::PARAMETER:
1242 case Variable::LOCAL:
1243 case Variable::CONTEXT: {
1244 Comment cmnt(masm_, var->IsContextSlot()
1245 ? "Context variable"
1246 : "Stack variable");
1247 if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
1248 context()->Plug(var);
1249 } else {
1250 // Let and const need a read barrier.
1251 GetVar(v0, var);
1252 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
1253 __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
1254 if (var->mode() == Variable::LET) {
1255 Label done;
1256 __ Branch(&done, ne, at, Operand(zero_reg));
1257 __ li(a0, Operand(var->name()));
1258 __ push(a0);
1259 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1260 __ bind(&done);
1261 } else {
1262 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
1263 __ movz(v0, a0, at); // Conditional move: Undefined if TheHole.
1264 }
1265 context()->Plug(v0);
1266 }
1267 break;
1268 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001269
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001270 case Variable::LOOKUP: {
1271 Label done, slow;
1272 // Generate code for loading from variables potentially shadowed
1273 // by eval-introduced variables.
1274 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1275 __ bind(&slow);
1276 Comment cmnt(masm_, "Lookup variable");
1277 __ li(a1, Operand(var->name()));
1278 __ Push(cp, a1); // Context and name.
1279 __ CallRuntime(Runtime::kLoadContextSlot, 2);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001280 __ bind(&done);
1281 context()->Plug(v0);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001282 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001283 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001284}
1285
1286
1287void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001288 Comment cmnt(masm_, "[ RegExpLiteral");
1289 Label materialized;
1290 // Registers will be used as follows:
1291 // t1 = materialized value (RegExp literal)
1292 // t0 = JS function, literals array
1293 // a3 = literal index
1294 // a2 = RegExp pattern
1295 // a1 = RegExp flags
1296 // a0 = RegExp literal clone
1297 __ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1298 __ lw(t0, FieldMemOperand(a0, JSFunction::kLiteralsOffset));
1299 int literal_offset =
1300 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
1301 __ lw(t1, FieldMemOperand(t0, literal_offset));
1302 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
1303 __ Branch(&materialized, ne, t1, Operand(at));
1304
1305 // Create regexp literal using runtime function.
1306 // Result will be in v0.
1307 __ li(a3, Operand(Smi::FromInt(expr->literal_index())));
1308 __ li(a2, Operand(expr->pattern()));
1309 __ li(a1, Operand(expr->flags()));
1310 __ Push(t0, a3, a2, a1);
1311 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
1312 __ mov(t1, v0);
1313
1314 __ bind(&materialized);
1315 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1316 Label allocated, runtime_allocate;
1317 __ AllocateInNewSpace(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT);
1318 __ jmp(&allocated);
1319
1320 __ bind(&runtime_allocate);
1321 __ push(t1);
1322 __ li(a0, Operand(Smi::FromInt(size)));
1323 __ push(a0);
1324 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1325 __ pop(t1);
1326
1327 __ bind(&allocated);
1328
1329 // After this, registers are used as follows:
1330 // v0: Newly allocated regexp.
1331 // t1: Materialized regexp.
1332 // a2: temp.
1333 __ CopyFields(v0, t1, a2.bit(), size / kPointerSize);
1334 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001335}
1336
1337
1338void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001339 Comment cmnt(masm_, "[ ObjectLiteral");
1340 __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1341 __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
1342 __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
1343 __ li(a1, Operand(expr->constant_properties()));
1344 int flags = expr->fast_elements()
1345 ? ObjectLiteral::kFastElements
1346 : ObjectLiteral::kNoFlags;
1347 flags |= expr->has_function()
1348 ? ObjectLiteral::kHasFunction
1349 : ObjectLiteral::kNoFlags;
1350 __ li(a0, Operand(Smi::FromInt(flags)));
1351 __ Push(a3, a2, a1, a0);
1352 if (expr->depth() > 1) {
1353 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
1354 } else {
1355 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
1356 }
1357
1358 // If result_saved is true the result is on top of the stack. If
1359 // result_saved is false the result is in v0.
1360 bool result_saved = false;
1361
1362 // Mark all computed expressions that are bound to a key that
1363 // is shadowed by a later occurrence of the same key. For the
1364 // marked expressions, no store code is emitted.
1365 expr->CalculateEmitStore();
1366
1367 for (int i = 0; i < expr->properties()->length(); i++) {
1368 ObjectLiteral::Property* property = expr->properties()->at(i);
1369 if (property->IsCompileTimeValue()) continue;
1370
1371 Literal* key = property->key();
1372 Expression* value = property->value();
1373 if (!result_saved) {
1374 __ push(v0); // Save result on stack.
1375 result_saved = true;
1376 }
1377 switch (property->kind()) {
1378 case ObjectLiteral::Property::CONSTANT:
1379 UNREACHABLE();
1380 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1381 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
1382 // Fall through.
1383 case ObjectLiteral::Property::COMPUTED:
1384 if (key->handle()->IsSymbol()) {
1385 if (property->emit_store()) {
1386 VisitForAccumulatorValue(value);
1387 __ mov(a0, result_register());
1388 __ li(a2, Operand(key->handle()));
1389 __ lw(a1, MemOperand(sp));
1390 Handle<Code> ic = is_strict_mode()
1391 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1392 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001393 __ Call(ic, RelocInfo::CODE_TARGET, key->id());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001394 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1395 } else {
1396 VisitForEffect(value);
1397 }
1398 break;
1399 }
1400 // Fall through.
1401 case ObjectLiteral::Property::PROTOTYPE:
1402 // Duplicate receiver on stack.
1403 __ lw(a0, MemOperand(sp));
1404 __ push(a0);
1405 VisitForStackValue(key);
1406 VisitForStackValue(value);
1407 if (property->emit_store()) {
1408 __ li(a0, Operand(Smi::FromInt(NONE))); // PropertyAttributes.
1409 __ push(a0);
1410 __ CallRuntime(Runtime::kSetProperty, 4);
1411 } else {
1412 __ Drop(3);
1413 }
1414 break;
1415 case ObjectLiteral::Property::GETTER:
1416 case ObjectLiteral::Property::SETTER:
1417 // Duplicate receiver on stack.
1418 __ lw(a0, MemOperand(sp));
1419 __ push(a0);
1420 VisitForStackValue(key);
1421 __ li(a1, Operand(property->kind() == ObjectLiteral::Property::SETTER ?
1422 Smi::FromInt(1) :
1423 Smi::FromInt(0)));
1424 __ push(a1);
1425 VisitForStackValue(value);
1426 __ CallRuntime(Runtime::kDefineAccessor, 4);
1427 break;
1428 }
1429 }
1430
1431 if (expr->has_function()) {
1432 ASSERT(result_saved);
1433 __ lw(a0, MemOperand(sp));
1434 __ push(a0);
1435 __ CallRuntime(Runtime::kToFastProperties, 1);
1436 }
1437
1438 if (result_saved) {
1439 context()->PlugTOS();
1440 } else {
1441 context()->Plug(v0);
1442 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001443}
1444
1445
1446void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001447 Comment cmnt(masm_, "[ ArrayLiteral");
1448
1449 ZoneList<Expression*>* subexprs = expr->values();
1450 int length = subexprs->length();
1451 __ mov(a0, result_register());
1452 __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1453 __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
1454 __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
1455 __ li(a1, Operand(expr->constant_elements()));
1456 __ Push(a3, a2, a1);
1457 if (expr->constant_elements()->map() ==
1458 isolate()->heap()->fixed_cow_array_map()) {
1459 FastCloneShallowArrayStub stub(
1460 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1461 __ CallStub(&stub);
1462 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(),
1463 1, a1, a2);
1464 } else if (expr->depth() > 1) {
1465 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
1466 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
1467 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
1468 } else {
1469 FastCloneShallowArrayStub stub(
1470 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
1471 __ CallStub(&stub);
1472 }
1473
1474 bool result_saved = false; // Is the result saved to the stack?
1475
1476 // Emit code to evaluate all the non-constant subexpressions and to store
1477 // them into the newly cloned array.
1478 for (int i = 0; i < length; i++) {
1479 Expression* subexpr = subexprs->at(i);
1480 // If the subexpression is a literal or a simple materialized literal it
1481 // is already set in the cloned array.
1482 if (subexpr->AsLiteral() != NULL ||
1483 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1484 continue;
1485 }
1486
1487 if (!result_saved) {
1488 __ push(v0);
1489 result_saved = true;
1490 }
1491 VisitForAccumulatorValue(subexpr);
1492
1493 // Store the subexpression value in the array's elements.
1494 __ lw(a1, MemOperand(sp)); // Copy of array literal.
1495 __ lw(a1, FieldMemOperand(a1, JSObject::kElementsOffset));
1496 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1497 __ sw(result_register(), FieldMemOperand(a1, offset));
1498
1499 // Update the write barrier for the array store with v0 as the scratch
1500 // register.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001501 __ RecordWrite(a1, Operand(offset), a2, result_register());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001502
1503 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
1504 }
1505
1506 if (result_saved) {
1507 context()->PlugTOS();
1508 } else {
1509 context()->Plug(v0);
1510 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001511}
1512
1513
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001514void FullCodeGenerator::VisitAssignment(Assignment* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001515 Comment cmnt(masm_, "[ Assignment");
1516 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1517 // on the left-hand side.
1518 if (!expr->target()->IsValidLeftHandSide()) {
1519 VisitForEffect(expr->target());
1520 return;
1521 }
1522
1523 // Left-hand side can only be a property, a global or a (parameter or local)
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001524 // slot.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001525 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1526 LhsKind assign_type = VARIABLE;
1527 Property* property = expr->target()->AsProperty();
1528 if (property != NULL) {
1529 assign_type = (property->key()->IsPropertyName())
1530 ? NAMED_PROPERTY
1531 : KEYED_PROPERTY;
1532 }
1533
1534 // Evaluate LHS expression.
1535 switch (assign_type) {
1536 case VARIABLE:
1537 // Nothing to do here.
1538 break;
1539 case NAMED_PROPERTY:
1540 if (expr->is_compound()) {
1541 // We need the receiver both on the stack and in the accumulator.
1542 VisitForAccumulatorValue(property->obj());
1543 __ push(result_register());
1544 } else {
1545 VisitForStackValue(property->obj());
1546 }
1547 break;
1548 case KEYED_PROPERTY:
1549 // We need the key and receiver on both the stack and in v0 and a1.
1550 if (expr->is_compound()) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001551 VisitForStackValue(property->obj());
1552 VisitForAccumulatorValue(property->key());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001553 __ lw(a1, MemOperand(sp, 0));
1554 __ push(v0);
1555 } else {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001556 VisitForStackValue(property->obj());
1557 VisitForStackValue(property->key());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001558 }
1559 break;
1560 }
1561
1562 // For compound assignments we need another deoptimization point after the
1563 // variable/property load.
1564 if (expr->is_compound()) {
1565 { AccumulatorValueContext context(this);
1566 switch (assign_type) {
1567 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001568 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001569 PrepareForBailout(expr->target(), TOS_REG);
1570 break;
1571 case NAMED_PROPERTY:
1572 EmitNamedPropertyLoad(property);
1573 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
1574 break;
1575 case KEYED_PROPERTY:
1576 EmitKeyedPropertyLoad(property);
1577 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
1578 break;
1579 }
1580 }
1581
1582 Token::Value op = expr->binary_op();
1583 __ push(v0); // Left operand goes on the stack.
1584 VisitForAccumulatorValue(expr->value());
1585
1586 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1587 ? OVERWRITE_RIGHT
1588 : NO_OVERWRITE;
1589 SetSourcePosition(expr->position() + 1);
1590 AccumulatorValueContext context(this);
1591 if (ShouldInlineSmiCase(op)) {
1592 EmitInlineSmiBinaryOp(expr->binary_operation(),
1593 op,
1594 mode,
1595 expr->target(),
1596 expr->value());
1597 } else {
1598 EmitBinaryOp(expr->binary_operation(), op, mode);
1599 }
1600
1601 // Deoptimization point in case the binary operation may have side effects.
1602 PrepareForBailout(expr->binary_operation(), TOS_REG);
1603 } else {
1604 VisitForAccumulatorValue(expr->value());
1605 }
1606
1607 // Record source position before possible IC call.
1608 SetSourcePosition(expr->position());
1609
1610 // Store the value.
1611 switch (assign_type) {
1612 case VARIABLE:
1613 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1614 expr->op());
1615 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1616 context()->Plug(v0);
1617 break;
1618 case NAMED_PROPERTY:
1619 EmitNamedPropertyAssignment(expr);
1620 break;
1621 case KEYED_PROPERTY:
1622 EmitKeyedPropertyAssignment(expr);
1623 break;
1624 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001625}
1626
1627
ager@chromium.org5c838252010-02-19 08:53:10 +00001628void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001629 SetSourcePosition(prop->position());
1630 Literal* key = prop->key()->AsLiteral();
1631 __ mov(a0, result_register());
1632 __ li(a2, Operand(key->handle()));
1633 // Call load IC. It has arguments receiver and property name a0 and a2.
1634 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001635 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
ager@chromium.org5c838252010-02-19 08:53:10 +00001636}
1637
1638
1639void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001640 SetSourcePosition(prop->position());
1641 __ mov(a0, result_register());
1642 // Call keyed load IC. It has arguments key and receiver in a0 and a1.
1643 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001644 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
ager@chromium.org5c838252010-02-19 08:53:10 +00001645}
1646
1647
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001648void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001649 Token::Value op,
1650 OverwriteMode mode,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001651 Expression* left_expr,
1652 Expression* right_expr) {
1653 Label done, smi_case, stub_call;
1654
1655 Register scratch1 = a2;
1656 Register scratch2 = a3;
1657
1658 // Get the arguments.
1659 Register left = a1;
1660 Register right = a0;
1661 __ pop(left);
1662 __ mov(a0, result_register());
1663
1664 // Perform combined smi check on both operands.
1665 __ Or(scratch1, left, Operand(right));
1666 STATIC_ASSERT(kSmiTag == 0);
1667 JumpPatchSite patch_site(masm_);
1668 patch_site.EmitJumpIfSmi(scratch1, &smi_case);
1669
1670 __ bind(&stub_call);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001671 BinaryOpStub stub(op, mode);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001672 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001673 patch_site.EmitPatchInfo();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001674 __ jmp(&done);
1675
1676 __ bind(&smi_case);
1677 // Smi case. This code works the same way as the smi-smi case in the type
1678 // recording binary operation stub, see
danno@chromium.org40cb8782011-05-25 07:58:50 +00001679 // BinaryOpStub::GenerateSmiSmiOperation for comments.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001680 switch (op) {
1681 case Token::SAR:
1682 __ Branch(&stub_call);
1683 __ GetLeastBitsFromSmi(scratch1, right, 5);
1684 __ srav(right, left, scratch1);
1685 __ And(v0, right, Operand(~kSmiTagMask));
1686 break;
1687 case Token::SHL: {
1688 __ Branch(&stub_call);
1689 __ SmiUntag(scratch1, left);
1690 __ GetLeastBitsFromSmi(scratch2, right, 5);
1691 __ sllv(scratch1, scratch1, scratch2);
1692 __ Addu(scratch2, scratch1, Operand(0x40000000));
1693 __ Branch(&stub_call, lt, scratch2, Operand(zero_reg));
1694 __ SmiTag(v0, scratch1);
1695 break;
1696 }
1697 case Token::SHR: {
1698 __ Branch(&stub_call);
1699 __ SmiUntag(scratch1, left);
1700 __ GetLeastBitsFromSmi(scratch2, right, 5);
1701 __ srlv(scratch1, scratch1, scratch2);
1702 __ And(scratch2, scratch1, 0xc0000000);
1703 __ Branch(&stub_call, ne, scratch2, Operand(zero_reg));
1704 __ SmiTag(v0, scratch1);
1705 break;
1706 }
1707 case Token::ADD:
1708 __ AdduAndCheckForOverflow(v0, left, right, scratch1);
1709 __ BranchOnOverflow(&stub_call, scratch1);
1710 break;
1711 case Token::SUB:
1712 __ SubuAndCheckForOverflow(v0, left, right, scratch1);
1713 __ BranchOnOverflow(&stub_call, scratch1);
1714 break;
1715 case Token::MUL: {
1716 __ SmiUntag(scratch1, right);
1717 __ Mult(left, scratch1);
1718 __ mflo(scratch1);
1719 __ mfhi(scratch2);
1720 __ sra(scratch1, scratch1, 31);
1721 __ Branch(&stub_call, ne, scratch1, Operand(scratch2));
1722 __ mflo(v0);
1723 __ Branch(&done, ne, v0, Operand(zero_reg));
1724 __ Addu(scratch2, right, left);
1725 __ Branch(&stub_call, lt, scratch2, Operand(zero_reg));
1726 ASSERT(Smi::FromInt(0) == 0);
1727 __ mov(v0, zero_reg);
1728 break;
1729 }
1730 case Token::BIT_OR:
1731 __ Or(v0, left, Operand(right));
1732 break;
1733 case Token::BIT_AND:
1734 __ And(v0, left, Operand(right));
1735 break;
1736 case Token::BIT_XOR:
1737 __ Xor(v0, left, Operand(right));
1738 break;
1739 default:
1740 UNREACHABLE();
1741 }
1742
1743 __ bind(&done);
1744 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001745}
1746
1747
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001748void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1749 Token::Value op,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001750 OverwriteMode mode) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001751 __ mov(a0, result_register());
1752 __ pop(a1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001753 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001754 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001755 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001756 patch_site.EmitPatchInfo();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001757 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001758}
1759
1760
1761void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001762 // Invalid left-hand sides are rewritten to have a 'throw
1763 // ReferenceError' on the left-hand side.
1764 if (!expr->IsValidLeftHandSide()) {
1765 VisitForEffect(expr);
1766 return;
1767 }
1768
1769 // Left-hand side can only be a property, a global or a (parameter or local)
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001770 // slot.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001771 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1772 LhsKind assign_type = VARIABLE;
1773 Property* prop = expr->AsProperty();
1774 if (prop != NULL) {
1775 assign_type = (prop->key()->IsPropertyName())
1776 ? NAMED_PROPERTY
1777 : KEYED_PROPERTY;
1778 }
1779
1780 switch (assign_type) {
1781 case VARIABLE: {
1782 Variable* var = expr->AsVariableProxy()->var();
1783 EffectContext context(this);
1784 EmitVariableAssignment(var, Token::ASSIGN);
1785 break;
1786 }
1787 case NAMED_PROPERTY: {
1788 __ push(result_register()); // Preserve value.
1789 VisitForAccumulatorValue(prop->obj());
1790 __ mov(a1, result_register());
1791 __ pop(a0); // Restore value.
1792 __ li(a2, Operand(prop->key()->AsLiteral()->handle()));
1793 Handle<Code> ic = is_strict_mode()
1794 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1795 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001796 __ Call(ic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001797 break;
1798 }
1799 case KEYED_PROPERTY: {
1800 __ push(result_register()); // Preserve value.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001801 VisitForStackValue(prop->obj());
1802 VisitForAccumulatorValue(prop->key());
1803 __ mov(a1, result_register());
1804 __ pop(a2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001805 __ pop(a0); // Restore value.
1806 Handle<Code> ic = is_strict_mode()
1807 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1808 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001809 __ Call(ic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001810 break;
1811 }
1812 }
1813 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1814 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001815}
1816
1817
1818void FullCodeGenerator::EmitVariableAssignment(Variable* var,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001819 Token::Value op) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001820 if (var->IsUnallocated()) {
1821 // Global var, const, or let.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001822 __ mov(a0, result_register());
1823 __ li(a2, Operand(var->name()));
1824 __ lw(a1, GlobalObjectOperand());
1825 Handle<Code> ic = is_strict_mode()
1826 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1827 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001828 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001829
1830 } else if (op == Token::INIT_CONST) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001831 // Const initializers need a write barrier.
1832 ASSERT(!var->IsParameter()); // No const parameters.
1833 if (var->IsStackLocal()) {
1834 Label skip;
1835 __ lw(a1, StackOperand(var));
1836 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
1837 __ Branch(&skip, ne, a1, Operand(t0));
1838 __ sw(result_register(), StackOperand(var));
1839 __ bind(&skip);
1840 } else {
1841 ASSERT(var->IsContextSlot() || var->IsLookupSlot());
1842 // Like var declarations, const declarations are hoisted to function
1843 // scope. However, unlike var initializers, const initializers are
1844 // able to drill a hole to that function context, even from inside a
1845 // 'with' context. We thus bypass the normal static scope lookup for
1846 // var->IsContextSlot().
1847 __ push(v0);
1848 __ li(a0, Operand(var->name()));
1849 __ Push(cp, a0); // Context and name.
1850 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001851 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001852
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001853 } else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001854 // Non-initializing assignment to let variable needs a write barrier.
1855 if (var->IsLookupSlot()) {
1856 __ push(v0); // Value.
1857 __ li(a1, Operand(var->name()));
1858 __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
1859 __ Push(cp, a1, a0); // Context, name, strict mode.
1860 __ CallRuntime(Runtime::kStoreContextSlot, 4);
1861 } else {
1862 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
1863 Label assign;
1864 MemOperand location = VarOperand(var, a1);
1865 __ lw(a3, location);
1866 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
1867 __ Branch(&assign, ne, a3, Operand(t0));
1868 __ li(a3, Operand(var->name()));
1869 __ push(a3);
1870 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1871 // Perform the assignment.
1872 __ bind(&assign);
1873 __ sw(result_register(), location);
1874 if (var->IsContextSlot()) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001875 // RecordWrite may destroy all its register arguments.
1876 __ mov(a3, result_register());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001877 int offset = Context::SlotOffset(var->index());
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001878 __ RecordWrite(a1, Operand(offset), a2, a3);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001879 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001880 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001881
1882 } else if (var->mode() != Variable::CONST) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001883 // Assignment to var or initializing assignment to let.
1884 if (var->IsStackAllocated() || var->IsContextSlot()) {
1885 MemOperand location = VarOperand(var, a1);
1886 if (FLAG_debug_code && op == Token::INIT_LET) {
1887 // Check for an uninitialized let binding.
1888 __ lw(a2, location);
1889 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
1890 __ Check(eq, "Let binding re-initialization.", a2, Operand(t0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001891 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001892 // Perform the assignment.
1893 __ sw(v0, location);
1894 if (var->IsContextSlot()) {
1895 __ mov(a3, v0);
1896 __ RecordWrite(a1, Operand(Context::SlotOffset(var->index())), a2, a3);
1897 }
1898 } else {
1899 ASSERT(var->IsLookupSlot());
1900 __ push(v0); // Value.
1901 __ li(a1, Operand(var->name()));
1902 __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
1903 __ Push(cp, a1, a0); // Context, name, strict mode.
1904 __ CallRuntime(Runtime::kStoreContextSlot, 4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001905 }
1906 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001907 // Non-initializing assignments to consts are ignored.
ager@chromium.org5c838252010-02-19 08:53:10 +00001908}
1909
1910
1911void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001912 // Assignment to a property, using a named store IC.
1913 Property* prop = expr->target()->AsProperty();
1914 ASSERT(prop != NULL);
1915 ASSERT(prop->key()->AsLiteral() != NULL);
1916
1917 // If the assignment starts a block of assignments to the same object,
1918 // change to slow case to avoid the quadratic behavior of repeatedly
1919 // adding fast properties.
1920 if (expr->starts_initialization_block()) {
1921 __ push(result_register());
1922 __ lw(t0, MemOperand(sp, kPointerSize)); // Receiver is now under value.
1923 __ push(t0);
1924 __ CallRuntime(Runtime::kToSlowProperties, 1);
1925 __ pop(result_register());
1926 }
1927
1928 // Record source code position before IC call.
1929 SetSourcePosition(expr->position());
1930 __ mov(a0, result_register()); // Load the value.
1931 __ li(a2, Operand(prop->key()->AsLiteral()->handle()));
1932 // Load receiver to a1. Leave a copy in the stack if needed for turning the
1933 // receiver into fast case.
1934 if (expr->ends_initialization_block()) {
1935 __ lw(a1, MemOperand(sp));
1936 } else {
1937 __ pop(a1);
1938 }
1939
1940 Handle<Code> ic = is_strict_mode()
1941 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1942 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001943 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001944
1945 // If the assignment ends an initialization block, revert to fast case.
1946 if (expr->ends_initialization_block()) {
1947 __ push(v0); // Result of assignment, saved even if not needed.
1948 // Receiver is under the result value.
1949 __ lw(t0, MemOperand(sp, kPointerSize));
1950 __ push(t0);
1951 __ CallRuntime(Runtime::kToFastProperties, 1);
1952 __ pop(v0);
1953 __ Drop(1);
1954 }
1955 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1956 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001957}
1958
1959
1960void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001961 // Assignment to a property, using a keyed store IC.
1962
1963 // If the assignment starts a block of assignments to the same object,
1964 // change to slow case to avoid the quadratic behavior of repeatedly
1965 // adding fast properties.
1966 if (expr->starts_initialization_block()) {
1967 __ push(result_register());
1968 // Receiver is now under the key and value.
1969 __ lw(t0, MemOperand(sp, 2 * kPointerSize));
1970 __ push(t0);
1971 __ CallRuntime(Runtime::kToSlowProperties, 1);
1972 __ pop(result_register());
1973 }
1974
1975 // Record source code position before IC call.
1976 SetSourcePosition(expr->position());
1977 // Call keyed store IC.
1978 // The arguments are:
1979 // - a0 is the value,
1980 // - a1 is the key,
1981 // - a2 is the receiver.
1982 __ mov(a0, result_register());
1983 __ pop(a1); // Key.
1984 // Load receiver to a2. Leave a copy in the stack if needed for turning the
1985 // receiver into fast case.
1986 if (expr->ends_initialization_block()) {
1987 __ lw(a2, MemOperand(sp));
1988 } else {
1989 __ pop(a2);
1990 }
1991
1992 Handle<Code> ic = is_strict_mode()
1993 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1994 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001995 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001996
1997 // If the assignment ends an initialization block, revert to fast case.
1998 if (expr->ends_initialization_block()) {
1999 __ push(v0); // Result of assignment, saved even if not needed.
2000 // Receiver is under the result value.
2001 __ lw(t0, MemOperand(sp, kPointerSize));
2002 __ push(t0);
2003 __ CallRuntime(Runtime::kToFastProperties, 1);
2004 __ pop(v0);
2005 __ Drop(1);
2006 }
2007 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2008 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00002009}
2010
2011
2012void FullCodeGenerator::VisitProperty(Property* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002013 Comment cmnt(masm_, "[ Property");
2014 Expression* key = expr->key();
2015
2016 if (key->IsPropertyName()) {
2017 VisitForAccumulatorValue(expr->obj());
2018 EmitNamedPropertyLoad(expr);
2019 context()->Plug(v0);
2020 } else {
2021 VisitForStackValue(expr->obj());
2022 VisitForAccumulatorValue(expr->key());
2023 __ pop(a1);
2024 EmitKeyedPropertyLoad(expr);
2025 context()->Plug(v0);
2026 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002027}
2028
lrn@chromium.org7516f052011-03-30 08:52:27 +00002029
ager@chromium.org5c838252010-02-19 08:53:10 +00002030void FullCodeGenerator::EmitCallWithIC(Call* expr,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002031 Handle<Object> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00002032 RelocInfo::Mode mode) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002033 // Code common for calls using the IC.
2034 ZoneList<Expression*>* args = expr->arguments();
2035 int arg_count = args->length();
2036 { PreservePositionScope scope(masm()->positions_recorder());
2037 for (int i = 0; i < arg_count; i++) {
2038 VisitForStackValue(args->at(i));
2039 }
2040 __ li(a2, Operand(name));
2041 }
2042 // Record source position for debugger.
2043 SetSourcePosition(expr->position());
2044 // Call the IC initialization code.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002045 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002046 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002047 __ Call(ic, mode, expr->id());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002048 RecordJSReturnSite(expr);
2049 // Restore context register.
2050 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2051 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00002052}
2053
2054
lrn@chromium.org7516f052011-03-30 08:52:27 +00002055void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002056 Expression* key) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002057 // Load the key.
2058 VisitForAccumulatorValue(key);
2059
2060 // Swap the name of the function and the receiver on the stack to follow
2061 // the calling convention for call ICs.
2062 __ pop(a1);
2063 __ push(v0);
2064 __ push(a1);
2065
2066 // Code common for calls using the IC.
2067 ZoneList<Expression*>* args = expr->arguments();
2068 int arg_count = args->length();
2069 { PreservePositionScope scope(masm()->positions_recorder());
2070 for (int i = 0; i < arg_count; i++) {
2071 VisitForStackValue(args->at(i));
2072 }
2073 }
2074 // Record source position for debugger.
2075 SetSourcePosition(expr->position());
2076 // Call the IC initialization code.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002077 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002078 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002079 __ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002080 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002081 RecordJSReturnSite(expr);
2082 // Restore context register.
2083 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2084 context()->DropAndPlug(1, v0); // Drop the key still on the stack.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002085}
2086
2087
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002088void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002089 // Code common for calls using the call stub.
2090 ZoneList<Expression*>* args = expr->arguments();
2091 int arg_count = args->length();
2092 { PreservePositionScope scope(masm()->positions_recorder());
2093 for (int i = 0; i < arg_count; i++) {
2094 VisitForStackValue(args->at(i));
2095 }
2096 }
2097 // Record source position for debugger.
2098 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002099 CallFunctionStub stub(arg_count, flags);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002100 __ CallStub(&stub);
2101 RecordJSReturnSite(expr);
2102 // Restore context register.
2103 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2104 context()->DropAndPlug(1, v0);
2105}
2106
2107
2108void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2109 int arg_count) {
2110 // Push copy of the first argument or undefined if it doesn't exist.
2111 if (arg_count > 0) {
2112 __ lw(a1, MemOperand(sp, arg_count * kPointerSize));
2113 } else {
2114 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
2115 }
2116 __ push(a1);
2117
2118 // Push the receiver of the enclosing function and do runtime call.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002119 int receiver_offset = 2 + info_->scope()->num_parameters();
2120 __ lw(a1, MemOperand(fp, receiver_offset * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002121 __ push(a1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002122 // Push the strict mode flag. In harmony mode every eval call
2123 // is a strict mode eval call.
2124 StrictModeFlag strict_mode = strict_mode_flag();
2125 if (FLAG_harmony_block_scoping) {
2126 strict_mode = kStrictMode;
2127 }
2128 __ li(a1, Operand(Smi::FromInt(strict_mode)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002129 __ push(a1);
2130
2131 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2132 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2133 : Runtime::kResolvePossiblyDirectEval, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00002134}
2135
2136
2137void FullCodeGenerator::VisitCall(Call* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002138#ifdef DEBUG
2139 // We want to verify that RecordJSReturnSite gets called on all paths
2140 // through this function. Avoid early returns.
2141 expr->return_is_recorded_ = false;
2142#endif
2143
2144 Comment cmnt(masm_, "[ Call");
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002145 Expression* callee = expr->expression();
2146 VariableProxy* proxy = callee->AsVariableProxy();
2147 Property* property = callee->AsProperty();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002148
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002149 if (proxy != NULL && proxy->var()->is_possibly_eval()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002150 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2151 // resolve the function we need to call and the receiver of the
2152 // call. Then we call the resolved function using the given
2153 // arguments.
2154 ZoneList<Expression*>* args = expr->arguments();
2155 int arg_count = args->length();
2156
2157 { PreservePositionScope pos_scope(masm()->positions_recorder());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002158 VisitForStackValue(callee);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002159 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
2160 __ push(a2); // Reserved receiver slot.
2161
2162 // Push the arguments.
2163 for (int i = 0; i < arg_count; i++) {
2164 VisitForStackValue(args->at(i));
2165 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002166
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002167 // If we know that eval can only be shadowed by eval-introduced
2168 // variables we attempt to load the global eval function directly
2169 // in generated code. If we succeed, there is no need to perform a
2170 // context lookup in the runtime system.
2171 Label done;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002172 Variable* var = proxy->var();
2173 if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002174 Label slow;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002175 EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002176 // Push the function and resolve eval.
2177 __ push(v0);
2178 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2179 __ jmp(&done);
2180 __ bind(&slow);
2181 }
2182
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002183 // Push a copy of the function (found below the arguments) and
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002184 // resolve eval.
2185 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2186 __ push(a1);
2187 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002188 __ bind(&done);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002189
2190 // The runtime call returns a pair of values in v0 (function) and
2191 // v1 (receiver). Touch up the stack with the right values.
2192 __ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
2193 __ sw(v1, MemOperand(sp, arg_count * kPointerSize));
2194 }
2195 // Record source position for debugger.
2196 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002197 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002198 __ CallStub(&stub);
2199 RecordJSReturnSite(expr);
2200 // Restore context register.
2201 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2202 context()->DropAndPlug(1, v0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002203 } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002204 // Push global object as receiver for the call IC.
2205 __ lw(a0, GlobalObjectOperand());
2206 __ push(a0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002207 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
2208 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002209 // Call to a lookup slot (dynamically introduced variable).
2210 Label slow, done;
2211
2212 { PreservePositionScope scope(masm()->positions_recorder());
2213 // Generate code for loading from variables potentially shadowed
2214 // by eval-introduced variables.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002215 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002216 }
2217
2218 __ bind(&slow);
2219 // Call the runtime to find the function to call (returned in v0)
2220 // and the object holding it (returned in v1).
2221 __ push(context_register());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002222 __ li(a2, Operand(proxy->name()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002223 __ push(a2);
2224 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2225 __ Push(v0, v1); // Function, receiver.
2226
2227 // If fast case code has been generated, emit code to push the
2228 // function and receiver and have the slow path jump around this
2229 // code.
2230 if (done.is_linked()) {
2231 Label call;
2232 __ Branch(&call);
2233 __ bind(&done);
2234 // Push function.
2235 __ push(v0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002236 // The receiver is implicitly the global receiver. Indicate this
2237 // by passing the hole to the call function stub.
2238 __ LoadRoot(a1, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002239 __ push(a1);
2240 __ bind(&call);
2241 }
2242
danno@chromium.org40cb8782011-05-25 07:58:50 +00002243 // The receiver is either the global receiver or an object found
2244 // by LoadContextSlot. That object could be the hole if the
2245 // receiver is implicitly the global object.
2246 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002247 } else if (property != NULL) {
2248 { PreservePositionScope scope(masm()->positions_recorder());
2249 VisitForStackValue(property->obj());
2250 }
2251 if (property->key()->IsPropertyName()) {
2252 EmitCallWithIC(expr,
2253 property->key()->AsLiteral()->handle(),
2254 RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002255 } else {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002256 EmitKeyedCallWithIC(expr, property->key());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002257 }
2258 } else {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002259 // Call to an arbitrary expression not handled specially above.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002260 { PreservePositionScope scope(masm()->positions_recorder());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002261 VisitForStackValue(callee);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002262 }
2263 // Load global receiver object.
2264 __ lw(a1, GlobalObjectOperand());
2265 __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2266 __ push(a1);
2267 // Emit function call.
2268 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
2269 }
2270
2271#ifdef DEBUG
2272 // RecordJSReturnSite should have been called.
2273 ASSERT(expr->return_is_recorded_);
2274#endif
ager@chromium.org5c838252010-02-19 08:53:10 +00002275}
2276
2277
2278void FullCodeGenerator::VisitCallNew(CallNew* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002279 Comment cmnt(masm_, "[ CallNew");
2280 // According to ECMA-262, section 11.2.2, page 44, the function
2281 // expression in new calls must be evaluated before the
2282 // arguments.
2283
2284 // Push constructor on the stack. If it's not a function it's used as
2285 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2286 // ignored.
2287 VisitForStackValue(expr->expression());
2288
2289 // Push the arguments ("left-to-right") on the stack.
2290 ZoneList<Expression*>* args = expr->arguments();
2291 int arg_count = args->length();
2292 for (int i = 0; i < arg_count; i++) {
2293 VisitForStackValue(args->at(i));
2294 }
2295
2296 // Call the construct call builtin that handles allocation and
2297 // constructor invocation.
2298 SetSourcePosition(expr->position());
2299
2300 // Load function and argument count into a1 and a0.
2301 __ li(a0, Operand(arg_count));
2302 __ lw(a1, MemOperand(sp, arg_count * kPointerSize));
2303
2304 Handle<Code> construct_builtin =
2305 isolate()->builtins()->JSConstructCall();
2306 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
2307 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00002308}
2309
2310
lrn@chromium.org7516f052011-03-30 08:52:27 +00002311void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002312 ASSERT(args->length() == 1);
2313
2314 VisitForAccumulatorValue(args->at(0));
2315
2316 Label materialize_true, materialize_false;
2317 Label* if_true = NULL;
2318 Label* if_false = NULL;
2319 Label* fall_through = NULL;
2320 context()->PrepareTest(&materialize_true, &materialize_false,
2321 &if_true, &if_false, &fall_through);
2322
2323 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2324 __ And(t0, v0, Operand(kSmiTagMask));
2325 Split(eq, t0, Operand(zero_reg), if_true, if_false, fall_through);
2326
2327 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002328}
2329
2330
2331void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002332 ASSERT(args->length() == 1);
2333
2334 VisitForAccumulatorValue(args->at(0));
2335
2336 Label materialize_true, materialize_false;
2337 Label* if_true = NULL;
2338 Label* if_false = NULL;
2339 Label* fall_through = NULL;
2340 context()->PrepareTest(&materialize_true, &materialize_false,
2341 &if_true, &if_false, &fall_through);
2342
2343 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2344 __ And(at, v0, Operand(kSmiTagMask | 0x80000000));
2345 Split(eq, at, Operand(zero_reg), if_true, if_false, fall_through);
2346
2347 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002348}
2349
2350
2351void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002352 ASSERT(args->length() == 1);
2353
2354 VisitForAccumulatorValue(args->at(0));
2355
2356 Label materialize_true, materialize_false;
2357 Label* if_true = NULL;
2358 Label* if_false = NULL;
2359 Label* fall_through = NULL;
2360 context()->PrepareTest(&materialize_true, &materialize_false,
2361 &if_true, &if_false, &fall_through);
2362
2363 __ JumpIfSmi(v0, if_false);
2364 __ LoadRoot(at, Heap::kNullValueRootIndex);
2365 __ Branch(if_true, eq, v0, Operand(at));
2366 __ lw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
2367 // Undetectable objects behave like undefined when tested with typeof.
2368 __ lbu(a1, FieldMemOperand(a2, Map::kBitFieldOffset));
2369 __ And(at, a1, Operand(1 << Map::kIsUndetectable));
2370 __ Branch(if_false, ne, at, Operand(zero_reg));
2371 __ lbu(a1, FieldMemOperand(a2, Map::kInstanceTypeOffset));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002372 __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002373 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002374 Split(le, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE),
2375 if_true, if_false, fall_through);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002376
2377 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002378}
2379
2380
2381void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002382 ASSERT(args->length() == 1);
2383
2384 VisitForAccumulatorValue(args->at(0));
2385
2386 Label materialize_true, materialize_false;
2387 Label* if_true = NULL;
2388 Label* if_false = NULL;
2389 Label* fall_through = NULL;
2390 context()->PrepareTest(&materialize_true, &materialize_false,
2391 &if_true, &if_false, &fall_through);
2392
2393 __ JumpIfSmi(v0, if_false);
2394 __ GetObjectType(v0, a1, a1);
2395 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002396 Split(ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002397 if_true, if_false, fall_through);
2398
2399 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002400}
2401
2402
2403void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002404 ASSERT(args->length() == 1);
2405
2406 VisitForAccumulatorValue(args->at(0));
2407
2408 Label materialize_true, materialize_false;
2409 Label* if_true = NULL;
2410 Label* if_false = NULL;
2411 Label* fall_through = NULL;
2412 context()->PrepareTest(&materialize_true, &materialize_false,
2413 &if_true, &if_false, &fall_through);
2414
2415 __ JumpIfSmi(v0, if_false);
2416 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
2417 __ lbu(a1, FieldMemOperand(a1, Map::kBitFieldOffset));
2418 __ And(at, a1, Operand(1 << Map::kIsUndetectable));
2419 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2420 Split(ne, at, Operand(zero_reg), if_true, if_false, fall_through);
2421
2422 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002423}
2424
2425
2426void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2427 ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002428
2429 ASSERT(args->length() == 1);
2430
2431 VisitForAccumulatorValue(args->at(0));
2432
2433 Label materialize_true, materialize_false;
2434 Label* if_true = NULL;
2435 Label* if_false = NULL;
2436 Label* fall_through = NULL;
2437 context()->PrepareTest(&materialize_true, &materialize_false,
2438 &if_true, &if_false, &fall_through);
2439
2440 if (FLAG_debug_code) __ AbortIfSmi(v0);
2441
2442 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
2443 __ lbu(t0, FieldMemOperand(a1, Map::kBitField2Offset));
2444 __ And(t0, t0, 1 << Map::kStringWrapperSafeForDefaultValueOf);
2445 __ Branch(if_true, ne, t0, Operand(zero_reg));
2446
2447 // Check for fast case object. Generate false result for slow case object.
2448 __ lw(a2, FieldMemOperand(v0, JSObject::kPropertiesOffset));
2449 __ lw(a2, FieldMemOperand(a2, HeapObject::kMapOffset));
2450 __ LoadRoot(t0, Heap::kHashTableMapRootIndex);
2451 __ Branch(if_false, eq, a2, Operand(t0));
2452
2453 // Look for valueOf symbol in the descriptor array, and indicate false if
2454 // found. The type is not checked, so if it is a transition it is a false
2455 // negative.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002456 __ LoadInstanceDescriptors(a1, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002457 __ lw(a3, FieldMemOperand(t0, FixedArray::kLengthOffset));
2458 // t0: descriptor array
2459 // a3: length of descriptor array
2460 // Calculate the end of the descriptor array.
2461 STATIC_ASSERT(kSmiTag == 0);
2462 STATIC_ASSERT(kSmiTagSize == 1);
2463 STATIC_ASSERT(kPointerSize == 4);
2464 __ Addu(a2, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
2465 __ sll(t1, a3, kPointerSizeLog2 - kSmiTagSize);
2466 __ Addu(a2, a2, t1);
2467
2468 // Calculate location of the first key name.
2469 __ Addu(t0,
2470 t0,
2471 Operand(FixedArray::kHeaderSize - kHeapObjectTag +
2472 DescriptorArray::kFirstIndex * kPointerSize));
2473 // Loop through all the keys in the descriptor array. If one of these is the
2474 // symbol valueOf the result is false.
2475 Label entry, loop;
2476 // The use of t2 to store the valueOf symbol asumes that it is not otherwise
2477 // used in the loop below.
2478 __ li(t2, Operand(FACTORY->value_of_symbol()));
2479 __ jmp(&entry);
2480 __ bind(&loop);
2481 __ lw(a3, MemOperand(t0, 0));
2482 __ Branch(if_false, eq, a3, Operand(t2));
2483 __ Addu(t0, t0, Operand(kPointerSize));
2484 __ bind(&entry);
2485 __ Branch(&loop, ne, t0, Operand(a2));
2486
2487 // If a valueOf property is not found on the object check that it's
2488 // prototype is the un-modified String prototype. If not result is false.
2489 __ lw(a2, FieldMemOperand(a1, Map::kPrototypeOffset));
2490 __ JumpIfSmi(a2, if_false);
2491 __ lw(a2, FieldMemOperand(a2, HeapObject::kMapOffset));
2492 __ lw(a3, ContextOperand(cp, Context::GLOBAL_INDEX));
2493 __ lw(a3, FieldMemOperand(a3, GlobalObject::kGlobalContextOffset));
2494 __ lw(a3, ContextOperand(a3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2495 __ Branch(if_false, ne, a2, Operand(a3));
2496
2497 // Set the bit in the map to indicate that it has been checked safe for
2498 // default valueOf and set true result.
2499 __ lbu(a2, FieldMemOperand(a1, Map::kBitField2Offset));
2500 __ Or(a2, a2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
2501 __ sb(a2, FieldMemOperand(a1, Map::kBitField2Offset));
2502 __ jmp(if_true);
2503
2504 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2505 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002506}
2507
2508
2509void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002510 ASSERT(args->length() == 1);
2511
2512 VisitForAccumulatorValue(args->at(0));
2513
2514 Label materialize_true, materialize_false;
2515 Label* if_true = NULL;
2516 Label* if_false = NULL;
2517 Label* fall_through = NULL;
2518 context()->PrepareTest(&materialize_true, &materialize_false,
2519 &if_true, &if_false, &fall_through);
2520
2521 __ JumpIfSmi(v0, if_false);
2522 __ GetObjectType(v0, a1, a2);
2523 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2524 __ Branch(if_true, eq, a2, Operand(JS_FUNCTION_TYPE));
2525 __ Branch(if_false);
2526
2527 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002528}
2529
2530
2531void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002532 ASSERT(args->length() == 1);
2533
2534 VisitForAccumulatorValue(args->at(0));
2535
2536 Label materialize_true, materialize_false;
2537 Label* if_true = NULL;
2538 Label* if_false = NULL;
2539 Label* fall_through = NULL;
2540 context()->PrepareTest(&materialize_true, &materialize_false,
2541 &if_true, &if_false, &fall_through);
2542
2543 __ JumpIfSmi(v0, if_false);
2544 __ GetObjectType(v0, a1, a1);
2545 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2546 Split(eq, a1, Operand(JS_ARRAY_TYPE),
2547 if_true, if_false, fall_through);
2548
2549 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002550}
2551
2552
2553void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002554 ASSERT(args->length() == 1);
2555
2556 VisitForAccumulatorValue(args->at(0));
2557
2558 Label materialize_true, materialize_false;
2559 Label* if_true = NULL;
2560 Label* if_false = NULL;
2561 Label* fall_through = NULL;
2562 context()->PrepareTest(&materialize_true, &materialize_false,
2563 &if_true, &if_false, &fall_through);
2564
2565 __ JumpIfSmi(v0, if_false);
2566 __ GetObjectType(v0, a1, a1);
2567 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2568 Split(eq, a1, Operand(JS_REGEXP_TYPE), if_true, if_false, fall_through);
2569
2570 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002571}
2572
2573
2574void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002575 ASSERT(args->length() == 0);
2576
2577 Label materialize_true, materialize_false;
2578 Label* if_true = NULL;
2579 Label* if_false = NULL;
2580 Label* fall_through = NULL;
2581 context()->PrepareTest(&materialize_true, &materialize_false,
2582 &if_true, &if_false, &fall_through);
2583
2584 // Get the frame pointer for the calling frame.
2585 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2586
2587 // Skip the arguments adaptor frame if it exists.
2588 Label check_frame_marker;
2589 __ lw(a1, MemOperand(a2, StandardFrameConstants::kContextOffset));
2590 __ Branch(&check_frame_marker, ne,
2591 a1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2592 __ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
2593
2594 // Check the marker in the calling frame.
2595 __ bind(&check_frame_marker);
2596 __ lw(a1, MemOperand(a2, StandardFrameConstants::kMarkerOffset));
2597 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2598 Split(eq, a1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)),
2599 if_true, if_false, fall_through);
2600
2601 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002602}
2603
2604
2605void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002606 ASSERT(args->length() == 2);
2607
2608 // Load the two objects into registers and perform the comparison.
2609 VisitForStackValue(args->at(0));
2610 VisitForAccumulatorValue(args->at(1));
2611
2612 Label materialize_true, materialize_false;
2613 Label* if_true = NULL;
2614 Label* if_false = NULL;
2615 Label* fall_through = NULL;
2616 context()->PrepareTest(&materialize_true, &materialize_false,
2617 &if_true, &if_false, &fall_through);
2618
2619 __ pop(a1);
2620 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2621 Split(eq, v0, Operand(a1), if_true, if_false, fall_through);
2622
2623 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002624}
2625
2626
2627void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002628 ASSERT(args->length() == 1);
2629
2630 // ArgumentsAccessStub expects the key in a1 and the formal
2631 // parameter count in a0.
2632 VisitForAccumulatorValue(args->at(0));
2633 __ mov(a1, v0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002634 __ li(a0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002635 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2636 __ CallStub(&stub);
2637 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002638}
2639
2640
2641void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002642 ASSERT(args->length() == 0);
2643
2644 Label exit;
2645 // Get the number of formal parameters.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002646 __ li(v0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002647
2648 // Check if the calling frame is an arguments adaptor frame.
2649 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2650 __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
2651 __ Branch(&exit, ne, a3,
2652 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2653
2654 // Arguments adaptor case: Read the arguments length from the
2655 // adaptor frame.
2656 __ lw(v0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2657
2658 __ bind(&exit);
2659 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002660}
2661
2662
2663void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002664 ASSERT(args->length() == 1);
2665 Label done, null, function, non_function_constructor;
2666
2667 VisitForAccumulatorValue(args->at(0));
2668
2669 // If the object is a smi, we return null.
2670 __ JumpIfSmi(v0, &null);
2671
2672 // Check that the object is a JS object but take special care of JS
2673 // functions to make sure they have 'Function' as their class.
2674 __ GetObjectType(v0, v0, a1); // Map is now in v0.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002675 __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002676
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002677 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
2678 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
2679 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
2680 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
2681 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
2682 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
2683 __ Branch(&function, ge, a1, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002684
2685 // Check if the constructor in the map is a function.
2686 __ lw(v0, FieldMemOperand(v0, Map::kConstructorOffset));
2687 __ GetObjectType(v0, a1, a1);
2688 __ Branch(&non_function_constructor, ne, a1, Operand(JS_FUNCTION_TYPE));
2689
2690 // v0 now contains the constructor function. Grab the
2691 // instance class name from there.
2692 __ lw(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset));
2693 __ lw(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset));
2694 __ Branch(&done);
2695
2696 // Functions have class 'Function'.
2697 __ bind(&function);
2698 __ LoadRoot(v0, Heap::kfunction_class_symbolRootIndex);
2699 __ jmp(&done);
2700
2701 // Objects with a non-function constructor have class 'Object'.
2702 __ bind(&non_function_constructor);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002703 __ LoadRoot(v0, Heap::kObject_symbolRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002704 __ jmp(&done);
2705
2706 // Non-JS objects have class null.
2707 __ bind(&null);
2708 __ LoadRoot(v0, Heap::kNullValueRootIndex);
2709
2710 // All done.
2711 __ bind(&done);
2712
2713 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002714}
2715
2716
2717void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002718 // Conditionally generate a log call.
2719 // Args:
2720 // 0 (literal string): The type of logging (corresponds to the flags).
2721 // This is used to determine whether or not to generate the log call.
2722 // 1 (string): Format string. Access the string at argument index 2
2723 // with '%2s' (see Logger::LogRuntime for all the formats).
2724 // 2 (array): Arguments to the format string.
2725 ASSERT_EQ(args->length(), 3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002726 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
2727 VisitForStackValue(args->at(1));
2728 VisitForStackValue(args->at(2));
2729 __ CallRuntime(Runtime::kLog, 2);
2730 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002731
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002732 // Finally, we're expected to leave a value on the top of the stack.
2733 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2734 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002735}
2736
2737
2738void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002739 ASSERT(args->length() == 0);
2740
2741 Label slow_allocate_heapnumber;
2742 Label heapnumber_allocated;
2743
2744 // Save the new heap number in callee-saved register s0, since
2745 // we call out to external C code below.
2746 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
2747 __ AllocateHeapNumber(s0, a1, a2, t6, &slow_allocate_heapnumber);
2748 __ jmp(&heapnumber_allocated);
2749
2750 __ bind(&slow_allocate_heapnumber);
2751
2752 // Allocate a heap number.
2753 __ CallRuntime(Runtime::kNumberAlloc, 0);
2754 __ mov(s0, v0); // Save result in s0, so it is saved thru CFunc call.
2755
2756 __ bind(&heapnumber_allocated);
2757
2758 // Convert 32 random bits in v0 to 0.(32 random bits) in a double
2759 // by computing:
2760 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2761 if (CpuFeatures::IsSupported(FPU)) {
2762 __ PrepareCallCFunction(1, a0);
2763 __ li(a0, Operand(ExternalReference::isolate_address()));
2764 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
2765
2766
2767 CpuFeatures::Scope scope(FPU);
2768 // 0x41300000 is the top half of 1.0 x 2^20 as a double.
2769 __ li(a1, Operand(0x41300000));
2770 // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002771 __ Move(f12, v0, a1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002772 // Move 0x4130000000000000 to FPU.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002773 __ Move(f14, zero_reg, a1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002774 // Subtract and store the result in the heap number.
2775 __ sub_d(f0, f12, f14);
2776 __ sdc1(f0, MemOperand(s0, HeapNumber::kValueOffset - kHeapObjectTag));
2777 __ mov(v0, s0);
2778 } else {
2779 __ PrepareCallCFunction(2, a0);
2780 __ mov(a0, s0);
2781 __ li(a1, Operand(ExternalReference::isolate_address()));
2782 __ CallCFunction(
2783 ExternalReference::fill_heap_number_with_random_function(isolate()), 2);
2784 }
2785
2786 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002787}
2788
2789
2790void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002791 // Load the arguments on the stack and call the stub.
2792 SubStringStub stub;
2793 ASSERT(args->length() == 3);
2794 VisitForStackValue(args->at(0));
2795 VisitForStackValue(args->at(1));
2796 VisitForStackValue(args->at(2));
2797 __ CallStub(&stub);
2798 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002799}
2800
2801
2802void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002803 // Load the arguments on the stack and call the stub.
2804 RegExpExecStub stub;
2805 ASSERT(args->length() == 4);
2806 VisitForStackValue(args->at(0));
2807 VisitForStackValue(args->at(1));
2808 VisitForStackValue(args->at(2));
2809 VisitForStackValue(args->at(3));
2810 __ CallStub(&stub);
2811 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002812}
2813
2814
2815void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002816 ASSERT(args->length() == 1);
2817
2818 VisitForAccumulatorValue(args->at(0)); // Load the object.
2819
2820 Label done;
2821 // If the object is a smi return the object.
2822 __ JumpIfSmi(v0, &done);
2823 // If the object is not a value type, return the object.
2824 __ GetObjectType(v0, a1, a1);
2825 __ Branch(&done, ne, a1, Operand(JS_VALUE_TYPE));
2826
2827 __ lw(v0, FieldMemOperand(v0, JSValue::kValueOffset));
2828
2829 __ bind(&done);
2830 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002831}
2832
2833
2834void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002835 // Load the arguments on the stack and call the runtime function.
2836 ASSERT(args->length() == 2);
2837 VisitForStackValue(args->at(0));
2838 VisitForStackValue(args->at(1));
2839 MathPowStub stub;
2840 __ CallStub(&stub);
2841 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002842}
2843
2844
2845void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002846 ASSERT(args->length() == 2);
2847
2848 VisitForStackValue(args->at(0)); // Load the object.
2849 VisitForAccumulatorValue(args->at(1)); // Load the value.
2850 __ pop(a1); // v0 = value. a1 = object.
2851
2852 Label done;
2853 // If the object is a smi, return the value.
2854 __ JumpIfSmi(a1, &done);
2855
2856 // If the object is not a value type, return the value.
2857 __ GetObjectType(a1, a2, a2);
2858 __ Branch(&done, ne, a2, Operand(JS_VALUE_TYPE));
2859
2860 // Store the value.
2861 __ sw(v0, FieldMemOperand(a1, JSValue::kValueOffset));
2862 // Update the write barrier. Save the value as it will be
2863 // overwritten by the write barrier code and is needed afterward.
2864 __ RecordWrite(a1, Operand(JSValue::kValueOffset - kHeapObjectTag), a2, a3);
2865
2866 __ bind(&done);
2867 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002868}
2869
2870
2871void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002872 ASSERT_EQ(args->length(), 1);
2873
2874 // Load the argument on the stack and call the stub.
2875 VisitForStackValue(args->at(0));
2876
2877 NumberToStringStub stub;
2878 __ CallStub(&stub);
2879 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002880}
2881
2882
2883void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002884 ASSERT(args->length() == 1);
2885
2886 VisitForAccumulatorValue(args->at(0));
2887
2888 Label done;
2889 StringCharFromCodeGenerator generator(v0, a1);
2890 generator.GenerateFast(masm_);
2891 __ jmp(&done);
2892
2893 NopRuntimeCallHelper call_helper;
2894 generator.GenerateSlow(masm_, call_helper);
2895
2896 __ bind(&done);
2897 context()->Plug(a1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002898}
2899
2900
2901void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002902 ASSERT(args->length() == 2);
2903
2904 VisitForStackValue(args->at(0));
2905 VisitForAccumulatorValue(args->at(1));
2906 __ mov(a0, result_register());
2907
2908 Register object = a1;
2909 Register index = a0;
2910 Register scratch = a2;
2911 Register result = v0;
2912
2913 __ pop(object);
2914
2915 Label need_conversion;
2916 Label index_out_of_range;
2917 Label done;
2918 StringCharCodeAtGenerator generator(object,
2919 index,
2920 scratch,
2921 result,
2922 &need_conversion,
2923 &need_conversion,
2924 &index_out_of_range,
2925 STRING_INDEX_IS_NUMBER);
2926 generator.GenerateFast(masm_);
2927 __ jmp(&done);
2928
2929 __ bind(&index_out_of_range);
2930 // When the index is out of range, the spec requires us to return
2931 // NaN.
2932 __ LoadRoot(result, Heap::kNanValueRootIndex);
2933 __ jmp(&done);
2934
2935 __ bind(&need_conversion);
2936 // Load the undefined value into the result register, which will
2937 // trigger conversion.
2938 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2939 __ jmp(&done);
2940
2941 NopRuntimeCallHelper call_helper;
2942 generator.GenerateSlow(masm_, call_helper);
2943
2944 __ bind(&done);
2945 context()->Plug(result);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002946}
2947
2948
2949void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002950 ASSERT(args->length() == 2);
2951
2952 VisitForStackValue(args->at(0));
2953 VisitForAccumulatorValue(args->at(1));
2954 __ mov(a0, result_register());
2955
2956 Register object = a1;
2957 Register index = a0;
2958 Register scratch1 = a2;
2959 Register scratch2 = a3;
2960 Register result = v0;
2961
2962 __ pop(object);
2963
2964 Label need_conversion;
2965 Label index_out_of_range;
2966 Label done;
2967 StringCharAtGenerator generator(object,
2968 index,
2969 scratch1,
2970 scratch2,
2971 result,
2972 &need_conversion,
2973 &need_conversion,
2974 &index_out_of_range,
2975 STRING_INDEX_IS_NUMBER);
2976 generator.GenerateFast(masm_);
2977 __ jmp(&done);
2978
2979 __ bind(&index_out_of_range);
2980 // When the index is out of range, the spec requires us to return
2981 // the empty string.
2982 __ LoadRoot(result, Heap::kEmptyStringRootIndex);
2983 __ jmp(&done);
2984
2985 __ bind(&need_conversion);
2986 // Move smi zero into the result register, which will trigger
2987 // conversion.
2988 __ li(result, Operand(Smi::FromInt(0)));
2989 __ jmp(&done);
2990
2991 NopRuntimeCallHelper call_helper;
2992 generator.GenerateSlow(masm_, call_helper);
2993
2994 __ bind(&done);
2995 context()->Plug(result);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002996}
2997
2998
2999void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003000 ASSERT_EQ(2, args->length());
3001
3002 VisitForStackValue(args->at(0));
3003 VisitForStackValue(args->at(1));
3004
3005 StringAddStub stub(NO_STRING_ADD_FLAGS);
3006 __ CallStub(&stub);
3007 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003008}
3009
3010
3011void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003012 ASSERT_EQ(2, args->length());
3013
3014 VisitForStackValue(args->at(0));
3015 VisitForStackValue(args->at(1));
3016
3017 StringCompareStub stub;
3018 __ CallStub(&stub);
3019 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003020}
3021
3022
3023void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003024 // Load the argument on the stack and call the stub.
3025 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3026 TranscendentalCacheStub::TAGGED);
3027 ASSERT(args->length() == 1);
3028 VisitForStackValue(args->at(0));
3029 __ mov(a0, result_register()); // Stub requires parameter in a0 and on tos.
3030 __ CallStub(&stub);
3031 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003032}
3033
3034
3035void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003036 // Load the argument on the stack and call the stub.
3037 TranscendentalCacheStub stub(TranscendentalCache::COS,
3038 TranscendentalCacheStub::TAGGED);
3039 ASSERT(args->length() == 1);
3040 VisitForStackValue(args->at(0));
3041 __ mov(a0, result_register()); // Stub requires parameter in a0 and on tos.
3042 __ CallStub(&stub);
3043 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003044}
3045
3046
3047void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003048 // Load the argument on the stack and call the stub.
3049 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3050 TranscendentalCacheStub::TAGGED);
3051 ASSERT(args->length() == 1);
3052 VisitForStackValue(args->at(0));
3053 __ mov(a0, result_register()); // Stub requires parameter in a0 and on tos.
3054 __ CallStub(&stub);
3055 context()->Plug(v0);
3056}
3057
3058
3059void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
3060 // Load the argument on the stack and call the runtime function.
3061 ASSERT(args->length() == 1);
3062 VisitForStackValue(args->at(0));
3063 __ CallRuntime(Runtime::kMath_sqrt, 1);
3064 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003065}
3066
3067
3068void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003069 ASSERT(args->length() >= 2);
3070
3071 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3072 for (int i = 0; i < arg_count + 1; i++) {
3073 VisitForStackValue(args->at(i));
3074 }
3075 VisitForAccumulatorValue(args->last()); // Function.
3076
3077 // InvokeFunction requires the function in a1. Move it in there.
3078 __ mov(a1, result_register());
3079 ParameterCount count(arg_count);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003080 __ InvokeFunction(a1, count, CALL_FUNCTION,
3081 NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003082 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3083 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003084}
3085
3086
3087void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003088 RegExpConstructResultStub stub;
3089 ASSERT(args->length() == 3);
3090 VisitForStackValue(args->at(0));
3091 VisitForStackValue(args->at(1));
3092 VisitForStackValue(args->at(2));
3093 __ CallStub(&stub);
3094 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003095}
3096
3097
3098void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003099 ASSERT(args->length() == 3);
3100 VisitForStackValue(args->at(0));
3101 VisitForStackValue(args->at(1));
3102 VisitForStackValue(args->at(2));
3103 Label done;
3104 Label slow_case;
3105 Register object = a0;
3106 Register index1 = a1;
3107 Register index2 = a2;
3108 Register elements = a3;
3109 Register scratch1 = t0;
3110 Register scratch2 = t1;
3111
3112 __ lw(object, MemOperand(sp, 2 * kPointerSize));
3113 // Fetch the map and check if array is in fast case.
3114 // Check that object doesn't require security checks and
3115 // has no indexed interceptor.
3116 __ GetObjectType(object, scratch1, scratch2);
3117 __ Branch(&slow_case, ne, scratch2, Operand(JS_ARRAY_TYPE));
3118 // Map is now in scratch1.
3119
3120 __ lbu(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
3121 __ And(scratch2, scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
3122 __ Branch(&slow_case, ne, scratch2, Operand(zero_reg));
3123
3124 // Check the object's elements are in fast case and writable.
3125 __ lw(elements, FieldMemOperand(object, JSObject::kElementsOffset));
3126 __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
3127 __ LoadRoot(scratch2, Heap::kFixedArrayMapRootIndex);
3128 __ Branch(&slow_case, ne, scratch1, Operand(scratch2));
3129
3130 // Check that both indices are smis.
3131 __ lw(index1, MemOperand(sp, 1 * kPointerSize));
3132 __ lw(index2, MemOperand(sp, 0));
3133 __ JumpIfNotBothSmi(index1, index2, &slow_case);
3134
3135 // Check that both indices are valid.
3136 Label not_hi;
3137 __ lw(scratch1, FieldMemOperand(object, JSArray::kLengthOffset));
3138 __ Branch(&slow_case, ls, scratch1, Operand(index1));
3139 __ Branch(&not_hi, NegateCondition(hi), scratch1, Operand(index1));
3140 __ Branch(&slow_case, ls, scratch1, Operand(index2));
3141 __ bind(&not_hi);
3142
3143 // Bring the address of the elements into index1 and index2.
3144 __ Addu(scratch1, elements,
3145 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3146 __ sll(index1, index1, kPointerSizeLog2 - kSmiTagSize);
3147 __ Addu(index1, scratch1, index1);
3148 __ sll(index2, index2, kPointerSizeLog2 - kSmiTagSize);
3149 __ Addu(index2, scratch1, index2);
3150
3151 // Swap elements.
3152 __ lw(scratch1, MemOperand(index1, 0));
3153 __ lw(scratch2, MemOperand(index2, 0));
3154 __ sw(scratch1, MemOperand(index2, 0));
3155 __ sw(scratch2, MemOperand(index1, 0));
3156
3157 Label new_space;
3158 __ InNewSpace(elements, scratch1, eq, &new_space);
3159 // Possible optimization: do a check that both values are Smis
3160 // (or them and test against Smi mask).
3161
3162 __ mov(scratch1, elements);
3163 __ RecordWriteHelper(elements, index1, scratch2);
3164 __ RecordWriteHelper(scratch1, index2, scratch2); // scratch1 holds elements.
3165
3166 __ bind(&new_space);
3167 // We are done. Drop elements from the stack, and return undefined.
3168 __ Drop(3);
3169 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
3170 __ jmp(&done);
3171
3172 __ bind(&slow_case);
3173 __ CallRuntime(Runtime::kSwapElements, 3);
3174
3175 __ bind(&done);
3176 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003177}
3178
3179
3180void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003181 ASSERT_EQ(2, args->length());
3182
3183 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3184 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3185
3186 Handle<FixedArray> jsfunction_result_caches(
3187 isolate()->global_context()->jsfunction_result_caches());
3188 if (jsfunction_result_caches->length() <= cache_id) {
3189 __ Abort("Attempt to use undefined cache.");
3190 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
3191 context()->Plug(v0);
3192 return;
3193 }
3194
3195 VisitForAccumulatorValue(args->at(1));
3196
3197 Register key = v0;
3198 Register cache = a1;
3199 __ lw(cache, ContextOperand(cp, Context::GLOBAL_INDEX));
3200 __ lw(cache, FieldMemOperand(cache, GlobalObject::kGlobalContextOffset));
3201 __ lw(cache,
3202 ContextOperand(
3203 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
3204 __ lw(cache,
3205 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3206
3207
3208 Label done, not_found;
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003209 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003210 __ lw(a2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
3211 // a2 now holds finger offset as a smi.
3212 __ Addu(a3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3213 // a3 now points to the start of fixed array elements.
3214 __ sll(at, a2, kPointerSizeLog2 - kSmiTagSize);
3215 __ addu(a3, a3, at);
3216 // a3 now points to key of indexed element of cache.
3217 __ lw(a2, MemOperand(a3));
3218 __ Branch(&not_found, ne, key, Operand(a2));
3219
3220 __ lw(v0, MemOperand(a3, kPointerSize));
3221 __ Branch(&done);
3222
3223 __ bind(&not_found);
3224 // Call runtime to perform the lookup.
3225 __ Push(cache, key);
3226 __ CallRuntime(Runtime::kGetFromCache, 2);
3227
3228 __ bind(&done);
3229 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003230}
3231
3232
3233void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003234 ASSERT_EQ(2, args->length());
3235
3236 Register right = v0;
3237 Register left = a1;
3238 Register tmp = a2;
3239 Register tmp2 = a3;
3240
3241 VisitForStackValue(args->at(0));
3242 VisitForAccumulatorValue(args->at(1)); // Result (right) in v0.
3243 __ pop(left);
3244
3245 Label done, fail, ok;
3246 __ Branch(&ok, eq, left, Operand(right));
3247 // Fail if either is a non-HeapObject.
3248 __ And(tmp, left, Operand(right));
3249 __ And(at, tmp, Operand(kSmiTagMask));
3250 __ Branch(&fail, eq, at, Operand(zero_reg));
3251 __ lw(tmp, FieldMemOperand(left, HeapObject::kMapOffset));
3252 __ lbu(tmp2, FieldMemOperand(tmp, Map::kInstanceTypeOffset));
3253 __ Branch(&fail, ne, tmp2, Operand(JS_REGEXP_TYPE));
3254 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
3255 __ Branch(&fail, ne, tmp, Operand(tmp2));
3256 __ lw(tmp, FieldMemOperand(left, JSRegExp::kDataOffset));
3257 __ lw(tmp2, FieldMemOperand(right, JSRegExp::kDataOffset));
3258 __ Branch(&ok, eq, tmp, Operand(tmp2));
3259 __ bind(&fail);
3260 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
3261 __ jmp(&done);
3262 __ bind(&ok);
3263 __ LoadRoot(v0, Heap::kTrueValueRootIndex);
3264 __ bind(&done);
3265
3266 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003267}
3268
3269
3270void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003271 VisitForAccumulatorValue(args->at(0));
3272
3273 Label materialize_true, materialize_false;
3274 Label* if_true = NULL;
3275 Label* if_false = NULL;
3276 Label* fall_through = NULL;
3277 context()->PrepareTest(&materialize_true, &materialize_false,
3278 &if_true, &if_false, &fall_through);
3279
3280 __ lw(a0, FieldMemOperand(v0, String::kHashFieldOffset));
3281 __ And(a0, a0, Operand(String::kContainsCachedArrayIndexMask));
3282
3283 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3284 Split(eq, a0, Operand(zero_reg), if_true, if_false, fall_through);
3285
3286 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003287}
3288
3289
3290void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003291 ASSERT(args->length() == 1);
3292 VisitForAccumulatorValue(args->at(0));
3293
3294 if (FLAG_debug_code) {
3295 __ AbortIfNotString(v0);
3296 }
3297
3298 __ lw(v0, FieldMemOperand(v0, String::kHashFieldOffset));
3299 __ IndexFromHash(v0, v0);
3300
3301 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003302}
3303
3304
3305void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003306 Label bailout, done, one_char_separator, long_separator,
3307 non_trivial_array, not_size_one_array, loop,
3308 empty_separator_loop, one_char_separator_loop,
3309 one_char_separator_loop_entry, long_separator_loop;
3310
3311 ASSERT(args->length() == 2);
3312 VisitForStackValue(args->at(1));
3313 VisitForAccumulatorValue(args->at(0));
3314
3315 // All aliases of the same register have disjoint lifetimes.
3316 Register array = v0;
3317 Register elements = no_reg; // Will be v0.
3318 Register result = no_reg; // Will be v0.
3319 Register separator = a1;
3320 Register array_length = a2;
3321 Register result_pos = no_reg; // Will be a2.
3322 Register string_length = a3;
3323 Register string = t0;
3324 Register element = t1;
3325 Register elements_end = t2;
3326 Register scratch1 = t3;
3327 Register scratch2 = t5;
3328 Register scratch3 = t4;
3329 Register scratch4 = v1;
3330
3331 // Separator operand is on the stack.
3332 __ pop(separator);
3333
3334 // Check that the array is a JSArray.
3335 __ JumpIfSmi(array, &bailout);
3336 __ GetObjectType(array, scratch1, scratch2);
3337 __ Branch(&bailout, ne, scratch2, Operand(JS_ARRAY_TYPE));
3338
3339 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003340 __ CheckFastElements(scratch1, scratch2, &bailout);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003341
3342 // If the array has length zero, return the empty string.
3343 __ lw(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
3344 __ SmiUntag(array_length);
3345 __ Branch(&non_trivial_array, ne, array_length, Operand(zero_reg));
3346 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
3347 __ Branch(&done);
3348
3349 __ bind(&non_trivial_array);
3350
3351 // Get the FixedArray containing array's elements.
3352 elements = array;
3353 __ lw(elements, FieldMemOperand(array, JSArray::kElementsOffset));
3354 array = no_reg; // End of array's live range.
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 __ mov(string_length, zero_reg);
3359 __ Addu(element,
3360 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3361 __ sll(elements_end, array_length, kPointerSizeLog2);
3362 __ Addu(elements_end, element, elements_end);
3363 // Loop condition: while (element < elements_end).
3364 // Live values in registers:
3365 // elements: Fixed array of strings.
3366 // array_length: Length of the fixed array of strings (not smi)
3367 // separator: Separator string
3368 // string_length: Accumulated sum of string lengths (smi).
3369 // element: Current array element.
3370 // elements_end: Array end.
3371 if (FLAG_debug_code) {
3372 __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin",
3373 array_length, Operand(zero_reg));
3374 }
3375 __ bind(&loop);
3376 __ lw(string, MemOperand(element));
3377 __ Addu(element, element, kPointerSize);
3378 __ JumpIfSmi(string, &bailout);
3379 __ lw(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
3380 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3381 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3382 __ lw(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset));
3383 __ AdduAndCheckForOverflow(string_length, string_length, scratch1, scratch3);
3384 __ BranchOnOverflow(&bailout, scratch3);
3385 __ Branch(&loop, lt, element, Operand(elements_end));
3386
3387 // If array_length is 1, return elements[0], a string.
3388 __ Branch(&not_size_one_array, ne, array_length, Operand(1));
3389 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
3390 __ Branch(&done);
3391
3392 __ bind(&not_size_one_array);
3393
3394 // Live values in registers:
3395 // separator: Separator string
3396 // array_length: Length of the array.
3397 // string_length: Sum of string lengths (smi).
3398 // elements: FixedArray of strings.
3399
3400 // Check that the separator is a flat ASCII string.
3401 __ JumpIfSmi(separator, &bailout);
3402 __ lw(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
3403 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3404 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3405
3406 // Add (separator length times array_length) - separator length to the
3407 // string_length to get the length of the result string. array_length is not
3408 // smi but the other values are, so the result is a smi.
3409 __ lw(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3410 __ Subu(string_length, string_length, Operand(scratch1));
3411 __ Mult(array_length, scratch1);
3412 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
3413 // zero.
3414 __ mfhi(scratch2);
3415 __ Branch(&bailout, ne, scratch2, Operand(zero_reg));
3416 __ mflo(scratch2);
3417 __ And(scratch3, scratch2, Operand(0x80000000));
3418 __ Branch(&bailout, ne, scratch3, Operand(zero_reg));
3419 __ AdduAndCheckForOverflow(string_length, string_length, scratch2, scratch3);
3420 __ BranchOnOverflow(&bailout, scratch3);
3421 __ SmiUntag(string_length);
3422
3423 // Get first element in the array to free up the elements register to be used
3424 // for the result.
3425 __ Addu(element,
3426 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3427 result = elements; // End of live range for elements.
3428 elements = no_reg;
3429 // Live values in registers:
3430 // element: First array element
3431 // separator: Separator string
3432 // string_length: Length of result string (not smi)
3433 // array_length: Length of the array.
3434 __ AllocateAsciiString(result,
3435 string_length,
3436 scratch1,
3437 scratch2,
3438 elements_end,
3439 &bailout);
3440 // Prepare for looping. Set up elements_end to end of the array. Set
3441 // result_pos to the position of the result where to write the first
3442 // character.
3443 __ sll(elements_end, array_length, kPointerSizeLog2);
3444 __ Addu(elements_end, element, elements_end);
3445 result_pos = array_length; // End of live range for array_length.
3446 array_length = no_reg;
3447 __ Addu(result_pos,
3448 result,
3449 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3450
3451 // Check the length of the separator.
3452 __ lw(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3453 __ li(at, Operand(Smi::FromInt(1)));
3454 __ Branch(&one_char_separator, eq, scratch1, Operand(at));
3455 __ Branch(&long_separator, gt, scratch1, Operand(at));
3456
3457 // Empty separator case.
3458 __ bind(&empty_separator_loop);
3459 // Live values in registers:
3460 // result_pos: the position to which we are currently copying characters.
3461 // element: Current array element.
3462 // elements_end: Array end.
3463
3464 // Copy next array element to the result.
3465 __ lw(string, MemOperand(element));
3466 __ Addu(element, element, kPointerSize);
3467 __ lw(string_length, FieldMemOperand(string, String::kLengthOffset));
3468 __ SmiUntag(string_length);
3469 __ Addu(string, string, SeqAsciiString::kHeaderSize - kHeapObjectTag);
3470 __ CopyBytes(string, result_pos, string_length, scratch1);
3471 // End while (element < elements_end).
3472 __ Branch(&empty_separator_loop, lt, element, Operand(elements_end));
3473 ASSERT(result.is(v0));
3474 __ Branch(&done);
3475
3476 // One-character separator case.
3477 __ bind(&one_char_separator);
3478 // Replace separator with its ascii character value.
3479 __ lbu(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize));
3480 // Jump into the loop after the code that copies the separator, so the first
3481 // element is not preceded by a separator.
3482 __ jmp(&one_char_separator_loop_entry);
3483
3484 __ bind(&one_char_separator_loop);
3485 // Live values in registers:
3486 // result_pos: the position to which we are currently copying characters.
3487 // element: Current array element.
3488 // elements_end: Array end.
3489 // separator: Single separator ascii char (in lower byte).
3490
3491 // Copy the separator character to the result.
3492 __ sb(separator, MemOperand(result_pos));
3493 __ Addu(result_pos, result_pos, 1);
3494
3495 // Copy next array element to the result.
3496 __ bind(&one_char_separator_loop_entry);
3497 __ lw(string, MemOperand(element));
3498 __ Addu(element, element, kPointerSize);
3499 __ lw(string_length, FieldMemOperand(string, String::kLengthOffset));
3500 __ SmiUntag(string_length);
3501 __ Addu(string, string, SeqAsciiString::kHeaderSize - kHeapObjectTag);
3502 __ CopyBytes(string, result_pos, string_length, scratch1);
3503 // End while (element < elements_end).
3504 __ Branch(&one_char_separator_loop, lt, element, Operand(elements_end));
3505 ASSERT(result.is(v0));
3506 __ Branch(&done);
3507
3508 // Long separator case (separator is more than one character). Entry is at the
3509 // label long_separator below.
3510 __ bind(&long_separator_loop);
3511 // Live values in registers:
3512 // result_pos: the position to which we are currently copying characters.
3513 // element: Current array element.
3514 // elements_end: Array end.
3515 // separator: Separator string.
3516
3517 // Copy the separator to the result.
3518 __ lw(string_length, FieldMemOperand(separator, String::kLengthOffset));
3519 __ SmiUntag(string_length);
3520 __ Addu(string,
3521 separator,
3522 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3523 __ CopyBytes(string, result_pos, string_length, scratch1);
3524
3525 __ bind(&long_separator);
3526 __ lw(string, MemOperand(element));
3527 __ Addu(element, element, kPointerSize);
3528 __ lw(string_length, FieldMemOperand(string, String::kLengthOffset));
3529 __ SmiUntag(string_length);
3530 __ Addu(string, string, SeqAsciiString::kHeaderSize - kHeapObjectTag);
3531 __ CopyBytes(string, result_pos, string_length, scratch1);
3532 // End while (element < elements_end).
3533 __ Branch(&long_separator_loop, lt, element, Operand(elements_end));
3534 ASSERT(result.is(v0));
3535 __ Branch(&done);
3536
3537 __ bind(&bailout);
3538 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
3539 __ bind(&done);
3540 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003541}
3542
3543
ager@chromium.org5c838252010-02-19 08:53:10 +00003544void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003545 Handle<String> name = expr->name();
3546 if (name->length() > 0 && name->Get(0) == '_') {
3547 Comment cmnt(masm_, "[ InlineRuntimeCall");
3548 EmitInlineRuntimeCall(expr);
3549 return;
3550 }
3551
3552 Comment cmnt(masm_, "[ CallRuntime");
3553 ZoneList<Expression*>* args = expr->arguments();
3554
3555 if (expr->is_jsruntime()) {
3556 // Prepare for calling JS runtime function.
3557 __ lw(a0, GlobalObjectOperand());
3558 __ lw(a0, FieldMemOperand(a0, GlobalObject::kBuiltinsOffset));
3559 __ push(a0);
3560 }
3561
3562 // Push the arguments ("left-to-right").
3563 int arg_count = args->length();
3564 for (int i = 0; i < arg_count; i++) {
3565 VisitForStackValue(args->at(i));
3566 }
3567
3568 if (expr->is_jsruntime()) {
3569 // Call the JS runtime function.
3570 __ li(a2, Operand(expr->name()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003571 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003572 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003573 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003574 __ Call(ic, mode, expr->id());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003575 // Restore context register.
3576 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3577 } else {
3578 // Call the C runtime function.
3579 __ CallRuntime(expr->function(), arg_count);
3580 }
3581 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003582}
3583
3584
3585void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003586 switch (expr->op()) {
3587 case Token::DELETE: {
3588 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003589 Property* property = expr->expression()->AsProperty();
3590 VariableProxy* proxy = expr->expression()->AsVariableProxy();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003591
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003592 if (property != NULL) {
3593 VisitForStackValue(property->obj());
3594 VisitForStackValue(property->key());
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003595 __ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
3596 __ push(a1);
3597 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3598 context()->Plug(v0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003599 } else if (proxy != NULL) {
3600 Variable* var = proxy->var();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003601 // Delete of an unqualified identifier is disallowed in strict mode
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003602 // but "delete this" is allowed.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003603 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003604 if (var->IsUnallocated()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003605 __ lw(a2, GlobalObjectOperand());
3606 __ li(a1, Operand(var->name()));
3607 __ li(a0, Operand(Smi::FromInt(kNonStrictMode)));
3608 __ Push(a2, a1, a0);
3609 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3610 context()->Plug(v0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003611 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003612 // Result of deleting non-global, non-dynamic variables is false.
3613 // The subexpression does not have side effects.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003614 context()->Plug(var->is_this());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003615 } else {
3616 // Non-global variable. Call the runtime to try to delete from the
3617 // context where the variable was introduced.
3618 __ push(context_register());
3619 __ li(a2, Operand(var->name()));
3620 __ push(a2);
3621 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3622 context()->Plug(v0);
3623 }
3624 } else {
3625 // Result of deleting non-property, non-variable reference is true.
3626 // The subexpression may have side effects.
3627 VisitForEffect(expr->expression());
3628 context()->Plug(true);
3629 }
3630 break;
3631 }
3632
3633 case Token::VOID: {
3634 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3635 VisitForEffect(expr->expression());
3636 context()->Plug(Heap::kUndefinedValueRootIndex);
3637 break;
3638 }
3639
3640 case Token::NOT: {
3641 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
3642 if (context()->IsEffect()) {
3643 // Unary NOT has no side effects so it's only necessary to visit the
3644 // subexpression. Match the optimizing compiler by not branching.
3645 VisitForEffect(expr->expression());
3646 } else {
3647 Label materialize_true, materialize_false;
3648 Label* if_true = NULL;
3649 Label* if_false = NULL;
3650 Label* fall_through = NULL;
3651
3652 // Notice that the labels are swapped.
3653 context()->PrepareTest(&materialize_true, &materialize_false,
3654 &if_false, &if_true, &fall_through);
3655 if (context()->IsTest()) ForwardBailoutToChild(expr);
3656 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3657 context()->Plug(if_false, if_true); // Labels swapped.
3658 }
3659 break;
3660 }
3661
3662 case Token::TYPEOF: {
3663 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
3664 { StackValueContext context(this);
3665 VisitForTypeofValue(expr->expression());
3666 }
3667 __ CallRuntime(Runtime::kTypeof, 1);
3668 context()->Plug(v0);
3669 break;
3670 }
3671
3672 case Token::ADD: {
3673 Comment cmt(masm_, "[ UnaryOperation (ADD)");
3674 VisitForAccumulatorValue(expr->expression());
3675 Label no_conversion;
3676 __ JumpIfSmi(result_register(), &no_conversion);
3677 __ mov(a0, result_register());
3678 ToNumberStub convert_stub;
3679 __ CallStub(&convert_stub);
3680 __ bind(&no_conversion);
3681 context()->Plug(result_register());
3682 break;
3683 }
3684
3685 case Token::SUB:
3686 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
3687 break;
3688
3689 case Token::BIT_NOT:
3690 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
3691 break;
3692
3693 default:
3694 UNREACHABLE();
3695 }
3696}
3697
3698
3699void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3700 const char* comment) {
3701 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
3702 Comment cmt(masm_, comment);
3703 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3704 UnaryOverwriteMode overwrite =
3705 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003706 UnaryOpStub stub(expr->op(), overwrite);
3707 // GenericUnaryOpStub expects the argument to be in a0.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003708 VisitForAccumulatorValue(expr->expression());
3709 SetSourcePosition(expr->position());
3710 __ mov(a0, result_register());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003711 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003712 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003713}
3714
3715
3716void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003717 Comment cmnt(masm_, "[ CountOperation");
3718 SetSourcePosition(expr->position());
3719
3720 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3721 // as the left-hand side.
3722 if (!expr->expression()->IsValidLeftHandSide()) {
3723 VisitForEffect(expr->expression());
3724 return;
3725 }
3726
3727 // Expression can only be a property, a global or a (parameter or local)
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00003728 // slot.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003729 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3730 LhsKind assign_type = VARIABLE;
3731 Property* prop = expr->expression()->AsProperty();
3732 // In case of a property we use the uninitialized expression context
3733 // of the key to detect a named property.
3734 if (prop != NULL) {
3735 assign_type =
3736 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3737 }
3738
3739 // Evaluate expression and get value.
3740 if (assign_type == VARIABLE) {
3741 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
3742 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003743 EmitVariableLoad(expr->expression()->AsVariableProxy());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003744 } else {
3745 // Reserve space for result of postfix operation.
3746 if (expr->is_postfix() && !context()->IsEffect()) {
3747 __ li(at, Operand(Smi::FromInt(0)));
3748 __ push(at);
3749 }
3750 if (assign_type == NAMED_PROPERTY) {
3751 // Put the object both on the stack and in the accumulator.
3752 VisitForAccumulatorValue(prop->obj());
3753 __ push(v0);
3754 EmitNamedPropertyLoad(prop);
3755 } else {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00003756 VisitForStackValue(prop->obj());
3757 VisitForAccumulatorValue(prop->key());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003758 __ lw(a1, MemOperand(sp, 0));
3759 __ push(v0);
3760 EmitKeyedPropertyLoad(prop);
3761 }
3762 }
3763
3764 // We need a second deoptimization point after loading the value
3765 // in case evaluating the property load my have a side effect.
3766 if (assign_type == VARIABLE) {
3767 PrepareForBailout(expr->expression(), TOS_REG);
3768 } else {
3769 PrepareForBailoutForId(expr->CountId(), TOS_REG);
3770 }
3771
3772 // Call ToNumber only if operand is not a smi.
3773 Label no_conversion;
3774 __ JumpIfSmi(v0, &no_conversion);
3775 __ mov(a0, v0);
3776 ToNumberStub convert_stub;
3777 __ CallStub(&convert_stub);
3778 __ bind(&no_conversion);
3779
3780 // Save result for postfix expressions.
3781 if (expr->is_postfix()) {
3782 if (!context()->IsEffect()) {
3783 // Save the result on the stack. If we have a named or keyed property
3784 // we store the result under the receiver that is currently on top
3785 // of the stack.
3786 switch (assign_type) {
3787 case VARIABLE:
3788 __ push(v0);
3789 break;
3790 case NAMED_PROPERTY:
3791 __ sw(v0, MemOperand(sp, kPointerSize));
3792 break;
3793 case KEYED_PROPERTY:
3794 __ sw(v0, MemOperand(sp, 2 * kPointerSize));
3795 break;
3796 }
3797 }
3798 }
3799 __ mov(a0, result_register());
3800
3801 // Inline smi case if we are in a loop.
3802 Label stub_call, done;
3803 JumpPatchSite patch_site(masm_);
3804
3805 int count_value = expr->op() == Token::INC ? 1 : -1;
3806 __ li(a1, Operand(Smi::FromInt(count_value)));
3807
3808 if (ShouldInlineSmiCase(expr->op())) {
3809 __ AdduAndCheckForOverflow(v0, a0, a1, t0);
3810 __ BranchOnOverflow(&stub_call, t0); // Do stub on overflow.
3811
3812 // We could eliminate this smi check if we split the code at
3813 // the first smi check before calling ToNumber.
3814 patch_site.EmitJumpIfSmi(v0, &done);
3815 __ bind(&stub_call);
3816 }
3817
3818 // Record position before stub call.
3819 SetSourcePosition(expr->position());
3820
danno@chromium.org40cb8782011-05-25 07:58:50 +00003821 BinaryOpStub stub(Token::ADD, NO_OVERWRITE);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003822 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003823 patch_site.EmitPatchInfo();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003824 __ bind(&done);
3825
3826 // Store the value returned in v0.
3827 switch (assign_type) {
3828 case VARIABLE:
3829 if (expr->is_postfix()) {
3830 { EffectContext context(this);
3831 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3832 Token::ASSIGN);
3833 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3834 context.Plug(v0);
3835 }
3836 // For all contexts except EffectConstant we have the result on
3837 // top of the stack.
3838 if (!context()->IsEffect()) {
3839 context()->PlugTOS();
3840 }
3841 } else {
3842 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3843 Token::ASSIGN);
3844 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3845 context()->Plug(v0);
3846 }
3847 break;
3848 case NAMED_PROPERTY: {
3849 __ mov(a0, result_register()); // Value.
3850 __ li(a2, Operand(prop->key()->AsLiteral()->handle())); // Name.
3851 __ pop(a1); // Receiver.
3852 Handle<Code> ic = is_strict_mode()
3853 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3854 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003855 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003856 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3857 if (expr->is_postfix()) {
3858 if (!context()->IsEffect()) {
3859 context()->PlugTOS();
3860 }
3861 } else {
3862 context()->Plug(v0);
3863 }
3864 break;
3865 }
3866 case KEYED_PROPERTY: {
3867 __ mov(a0, result_register()); // Value.
3868 __ pop(a1); // Key.
3869 __ pop(a2); // Receiver.
3870 Handle<Code> ic = is_strict_mode()
3871 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3872 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003873 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003874 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3875 if (expr->is_postfix()) {
3876 if (!context()->IsEffect()) {
3877 context()->PlugTOS();
3878 }
3879 } else {
3880 context()->Plug(v0);
3881 }
3882 break;
3883 }
3884 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003885}
3886
3887
lrn@chromium.org7516f052011-03-30 08:52:27 +00003888void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003889 ASSERT(!context()->IsEffect());
3890 ASSERT(!context()->IsTest());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003891 VariableProxy* proxy = expr->AsVariableProxy();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003892 if (proxy != NULL && proxy->var()->IsUnallocated()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003893 Comment cmnt(masm_, "Global variable");
3894 __ lw(a0, GlobalObjectOperand());
3895 __ li(a2, Operand(proxy->name()));
3896 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
3897 // Use a regular load, not a contextual load, to avoid a reference
3898 // error.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003899 __ Call(ic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003900 PrepareForBailout(expr, TOS_REG);
3901 context()->Plug(v0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003902 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003903 Label done, slow;
3904
3905 // Generate code for loading from variables potentially shadowed
3906 // by eval-introduced variables.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003907 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003908
3909 __ bind(&slow);
3910 __ li(a0, Operand(proxy->name()));
3911 __ Push(cp, a0);
3912 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
3913 PrepareForBailout(expr, TOS_REG);
3914 __ bind(&done);
3915
3916 context()->Plug(v0);
3917 } else {
3918 // This expression cannot throw a reference error at the top level.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003919 VisitInCurrentContext(expr);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003920 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003921}
3922
ager@chromium.org04921a82011-06-27 13:21:41 +00003923void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3924 Handle<String> check,
3925 Label* if_true,
3926 Label* if_false,
3927 Label* fall_through) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003928 { AccumulatorValueContext context(this);
ager@chromium.org04921a82011-06-27 13:21:41 +00003929 VisitForTypeofValue(expr);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003930 }
3931 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3932
3933 if (check->Equals(isolate()->heap()->number_symbol())) {
3934 __ JumpIfSmi(v0, if_true);
3935 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3936 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3937 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
3938 } else if (check->Equals(isolate()->heap()->string_symbol())) {
3939 __ JumpIfSmi(v0, if_false);
3940 // Check for undetectable objects => false.
3941 __ GetObjectType(v0, v0, a1);
3942 __ Branch(if_false, ge, a1, Operand(FIRST_NONSTRING_TYPE));
3943 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3944 __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
3945 Split(eq, a1, Operand(zero_reg),
3946 if_true, if_false, fall_through);
3947 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
3948 __ LoadRoot(at, Heap::kTrueValueRootIndex);
3949 __ Branch(if_true, eq, v0, Operand(at));
3950 __ LoadRoot(at, Heap::kFalseValueRootIndex);
3951 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003952 } else if (FLAG_harmony_typeof &&
3953 check->Equals(isolate()->heap()->null_symbol())) {
3954 __ LoadRoot(at, Heap::kNullValueRootIndex);
3955 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003956 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
3957 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
3958 __ Branch(if_true, eq, v0, Operand(at));
3959 __ JumpIfSmi(v0, if_false);
3960 // Check for undetectable objects => true.
3961 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3962 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3963 __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
3964 Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through);
3965 } else if (check->Equals(isolate()->heap()->function_symbol())) {
3966 __ JumpIfSmi(v0, if_false);
3967 __ GetObjectType(v0, a1, v0); // Leave map in a1.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003968 Split(ge, v0, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003969 if_true, if_false, fall_through);
3970
3971 } else if (check->Equals(isolate()->heap()->object_symbol())) {
3972 __ JumpIfSmi(v0, if_false);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003973 if (!FLAG_harmony_typeof) {
3974 __ LoadRoot(at, Heap::kNullValueRootIndex);
3975 __ Branch(if_true, eq, v0, Operand(at));
3976 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003977 // Check for JS objects => true.
3978 __ GetObjectType(v0, v0, a1);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003979 __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003980 __ lbu(a1, FieldMemOperand(v0, Map::kInstanceTypeOffset));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003981 __ Branch(if_false, gt, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003982 // Check for undetectable objects => false.
3983 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3984 __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
3985 Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through);
3986 } else {
3987 if (if_false != fall_through) __ jmp(if_false);
3988 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003989}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003990
ager@chromium.org04921a82011-06-27 13:21:41 +00003991
3992void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
3993 Label* if_true,
3994 Label* if_false,
3995 Label* fall_through) {
3996 VisitForAccumulatorValue(expr);
3997 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3998
3999 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4000 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004001}
4002
4003
ager@chromium.org5c838252010-02-19 08:53:10 +00004004void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004005 Comment cmnt(masm_, "[ CompareOperation");
4006 SetSourcePosition(expr->position());
4007
4008 // Always perform the comparison for its control flow. Pack the result
4009 // into the expression's context after the comparison is performed.
4010
4011 Label materialize_true, materialize_false;
4012 Label* if_true = NULL;
4013 Label* if_false = NULL;
4014 Label* fall_through = NULL;
4015 context()->PrepareTest(&materialize_true, &materialize_false,
4016 &if_true, &if_false, &fall_through);
4017
4018 // First we try a fast inlined version of the compare when one of
4019 // the operands is a literal.
ager@chromium.org04921a82011-06-27 13:21:41 +00004020 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004021 context()->Plug(if_true, if_false);
4022 return;
4023 }
4024
ager@chromium.org04921a82011-06-27 13:21:41 +00004025 Token::Value op = expr->op();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004026 VisitForStackValue(expr->left());
4027 switch (op) {
4028 case Token::IN:
4029 VisitForStackValue(expr->right());
4030 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
4031 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
4032 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
4033 Split(eq, v0, Operand(t0), if_true, if_false, fall_through);
4034 break;
4035
4036 case Token::INSTANCEOF: {
4037 VisitForStackValue(expr->right());
4038 InstanceofStub stub(InstanceofStub::kNoFlags);
4039 __ CallStub(&stub);
4040 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4041 // The stub returns 0 for true.
4042 Split(eq, v0, Operand(zero_reg), if_true, if_false, fall_through);
4043 break;
4044 }
4045
4046 default: {
4047 VisitForAccumulatorValue(expr->right());
4048 Condition cc = eq;
4049 bool strict = false;
4050 switch (op) {
4051 case Token::EQ_STRICT:
4052 strict = true;
4053 // Fall through.
4054 case Token::EQ:
4055 cc = eq;
4056 __ mov(a0, result_register());
4057 __ pop(a1);
4058 break;
4059 case Token::LT:
4060 cc = lt;
4061 __ mov(a0, result_register());
4062 __ pop(a1);
4063 break;
4064 case Token::GT:
4065 // Reverse left and right sides to obtain ECMA-262 conversion order.
4066 cc = lt;
4067 __ mov(a1, result_register());
4068 __ pop(a0);
4069 break;
4070 case Token::LTE:
4071 // Reverse left and right sides to obtain ECMA-262 conversion order.
4072 cc = ge;
4073 __ mov(a1, result_register());
4074 __ pop(a0);
4075 break;
4076 case Token::GTE:
4077 cc = ge;
4078 __ mov(a0, result_register());
4079 __ pop(a1);
4080 break;
4081 case Token::IN:
4082 case Token::INSTANCEOF:
4083 default:
4084 UNREACHABLE();
4085 }
4086
4087 bool inline_smi_code = ShouldInlineSmiCase(op);
4088 JumpPatchSite patch_site(masm_);
4089 if (inline_smi_code) {
4090 Label slow_case;
4091 __ Or(a2, a0, Operand(a1));
4092 patch_site.EmitJumpIfNotSmi(a2, &slow_case);
4093 Split(cc, a1, Operand(a0), if_true, if_false, NULL);
4094 __ bind(&slow_case);
4095 }
4096 // Record position and call the compare IC.
4097 SetSourcePosition(expr->position());
4098 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004099 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004100 patch_site.EmitPatchInfo();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004101 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4102 Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through);
4103 }
4104 }
4105
4106 // Convert the result of the comparison into one expected for this
4107 // expression's context.
4108 context()->Plug(if_true, if_false);
ager@chromium.org5c838252010-02-19 08:53:10 +00004109}
4110
4111
lrn@chromium.org7516f052011-03-30 08:52:27 +00004112void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004113 Comment cmnt(masm_, "[ CompareToNull");
4114 Label materialize_true, materialize_false;
4115 Label* if_true = NULL;
4116 Label* if_false = NULL;
4117 Label* fall_through = NULL;
4118 context()->PrepareTest(&materialize_true, &materialize_false,
4119 &if_true, &if_false, &fall_through);
4120
4121 VisitForAccumulatorValue(expr->expression());
4122 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4123 __ mov(a0, result_register());
4124 __ LoadRoot(a1, Heap::kNullValueRootIndex);
4125 if (expr->is_strict()) {
4126 Split(eq, a0, Operand(a1), if_true, if_false, fall_through);
4127 } else {
4128 __ Branch(if_true, eq, a0, Operand(a1));
4129 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
4130 __ Branch(if_true, eq, a0, Operand(a1));
4131 __ And(at, a0, Operand(kSmiTagMask));
4132 __ Branch(if_false, eq, at, Operand(zero_reg));
4133 // It can be an undetectable object.
4134 __ lw(a1, FieldMemOperand(a0, HeapObject::kMapOffset));
4135 __ lbu(a1, FieldMemOperand(a1, Map::kBitFieldOffset));
4136 __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
4137 Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through);
4138 }
4139 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004140}
4141
4142
ager@chromium.org5c838252010-02-19 08:53:10 +00004143void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004144 __ lw(v0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4145 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004146}
4147
4148
lrn@chromium.org7516f052011-03-30 08:52:27 +00004149Register FullCodeGenerator::result_register() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00004150 return v0;
4151}
ager@chromium.org5c838252010-02-19 08:53:10 +00004152
4153
lrn@chromium.org7516f052011-03-30 08:52:27 +00004154Register FullCodeGenerator::context_register() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00004155 return cp;
4156}
4157
4158
ager@chromium.org5c838252010-02-19 08:53:10 +00004159void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004160 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4161 __ sw(value, MemOperand(fp, frame_offset));
ager@chromium.org5c838252010-02-19 08:53:10 +00004162}
4163
4164
4165void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004166 __ lw(dst, ContextOperand(cp, context_index));
ager@chromium.org5c838252010-02-19 08:53:10 +00004167}
4168
4169
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004170void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
4171 Scope* declaration_scope = scope()->DeclarationScope();
4172 if (declaration_scope->is_global_scope()) {
4173 // Contexts nested in the global context have a canonical empty function
4174 // as their closure, not the anonymous closure containing the global
4175 // code. Pass a smi sentinel and let the runtime look up the empty
4176 // function.
4177 __ li(at, Operand(Smi::FromInt(0)));
4178 } else if (declaration_scope->is_eval_scope()) {
4179 // Contexts created by a call to eval have the same closure as the
4180 // context calling eval, not the anonymous closure containing the eval
4181 // code. Fetch it from the context.
4182 __ lw(at, ContextOperand(cp, Context::CLOSURE_INDEX));
4183 } else {
4184 ASSERT(declaration_scope->is_function_scope());
4185 __ lw(at, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4186 }
4187 __ push(at);
4188}
4189
4190
ager@chromium.org5c838252010-02-19 08:53:10 +00004191// ----------------------------------------------------------------------------
4192// Non-local control flow support.
4193
4194void FullCodeGenerator::EnterFinallyBlock() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004195 ASSERT(!result_register().is(a1));
4196 // Store result register while executing finally block.
4197 __ push(result_register());
4198 // Cook return address in link register to stack (smi encoded Code* delta).
4199 __ Subu(a1, ra, Operand(masm_->CodeObject()));
4200 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004201 STATIC_ASSERT(0 == kSmiTag);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004202 __ Addu(a1, a1, Operand(a1)); // Convert to smi.
4203 __ push(a1);
ager@chromium.org5c838252010-02-19 08:53:10 +00004204}
4205
4206
4207void FullCodeGenerator::ExitFinallyBlock() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004208 ASSERT(!result_register().is(a1));
4209 // Restore result register from stack.
4210 __ pop(a1);
4211 // Uncook return address and return.
4212 __ pop(result_register());
4213 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4214 __ sra(a1, a1, 1); // Un-smi-tag value.
4215 __ Addu(at, a1, Operand(masm_->CodeObject()));
4216 __ Jump(at);
ager@chromium.org5c838252010-02-19 08:53:10 +00004217}
4218
4219
4220#undef __
4221
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004222#define __ ACCESS_MASM(masm())
4223
4224FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4225 int* stack_depth,
4226 int* context_length) {
4227 // The macros used here must preserve the result register.
4228
4229 // Because the handler block contains the context of the finally
4230 // code, we can restore it directly from there for the finally code
4231 // rather than iteratively unwinding contexts via their previous
4232 // links.
4233 __ Drop(*stack_depth); // Down to the handler block.
4234 if (*context_length > 0) {
4235 // Restore the context to its dedicated register and the stack.
4236 __ lw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
4237 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
4238 }
4239 __ PopTryHandler();
4240 __ Call(finally_entry_);
4241
4242 *stack_depth = 0;
4243 *context_length = 0;
4244 return previous_;
4245}
4246
4247
4248#undef __
4249
ager@chromium.org5c838252010-02-19 08:53:10 +00004250} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004251
4252#endif // V8_TARGET_ARCH_MIPS