blob: dfbe37f6c73f8ed7921cc328fe6f0be4ccc87cd6 [file] [log] [blame]
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001// Copyright 2012 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
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_MIPS
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
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"
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000045#include "isolate-inl.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000046#include "parser.h"
lrn@chromium.org7516f052011-03-30 08:52:27 +000047#include "scopes.h"
48#include "stub-cache.h"
49
50#include "mips/code-stubs-mips.h"
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000051#include "mips/macro-assembler-mips.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000052
53namespace v8 {
54namespace internal {
55
56#define __ ACCESS_MASM(masm_)
57
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000058
59// A patch site is a location in the code which it is possible to patch. This
60// class has a number of methods to emit the code which is patchable and the
61// method EmitPatchInfo to record a marker back to the patchable code. This
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000062// marker is a andi zero_reg, rx, #yyyy instruction, and rx * 0x0000ffff + yyyy
63// (raw 16 bit immediate value is used) is the delta from the pc to the first
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000064// instruction of the patchable code.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000065// The marker instruction is effectively a NOP (dest is zero_reg) and will
66// never be emitted by normal code.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000067class JumpPatchSite BASE_EMBEDDED {
68 public:
69 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
70#ifdef DEBUG
71 info_emitted_ = false;
72#endif
73 }
74
75 ~JumpPatchSite() {
76 ASSERT(patch_site_.is_bound() == info_emitted_);
77 }
78
79 // When initially emitting this ensure that a jump is always generated to skip
80 // the inlined smi code.
81 void EmitJumpIfNotSmi(Register reg, Label* target) {
82 ASSERT(!patch_site_.is_bound() && !info_emitted_);
83 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
84 __ bind(&patch_site_);
85 __ andi(at, reg, 0);
86 // Always taken before patched.
bmeurer@chromium.org25530ce2014-02-07 09:11:16 +000087 __ BranchShort(target, eq, at, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000088 }
89
90 // When initially emitting this ensure that a jump is never generated to skip
91 // the inlined smi code.
92 void EmitJumpIfSmi(Register reg, Label* target) {
93 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
94 ASSERT(!patch_site_.is_bound() && !info_emitted_);
95 __ bind(&patch_site_);
96 __ andi(at, reg, 0);
97 // Never taken before patched.
bmeurer@chromium.org25530ce2014-02-07 09:11:16 +000098 __ BranchShort(target, ne, at, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000099 }
100
101 void EmitPatchInfo() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000102 if (patch_site_.is_bound()) {
103 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
104 Register reg = Register::from_code(delta_to_patch_site / kImm16Mask);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000105 __ andi(zero_reg, reg, delta_to_patch_site % kImm16Mask);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000106#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000107 info_emitted_ = true;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000108#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000109 } else {
110 __ nop(); // Signals no inlined code.
111 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000112 }
113
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000114 private:
115 MacroAssembler* masm_;
116 Label patch_site_;
117#ifdef DEBUG
118 bool info_emitted_;
119#endif
120};
121
122
machenbach@chromium.orga2218802014-03-25 07:30:47 +0000123static void EmitStackCheck(MacroAssembler* masm_,
124 Register stack_limit_scratch,
125 int pointers = 0,
126 Register scratch = sp) {
127 Isolate* isolate = masm_->isolate();
128 Label ok;
129 ASSERT(scratch.is(sp) == (pointers == 0));
machenbach@chromium.org63a7c9f2014-04-01 00:04:36 +0000130 Heap::RootListIndex index;
machenbach@chromium.orga2218802014-03-25 07:30:47 +0000131 if (pointers != 0) {
132 __ Subu(scratch, sp, Operand(pointers * kPointerSize));
machenbach@chromium.org63a7c9f2014-04-01 00:04:36 +0000133 index = Heap::kRealStackLimitRootIndex;
134 } else {
135 index = Heap::kStackLimitRootIndex;
machenbach@chromium.orga2218802014-03-25 07:30:47 +0000136 }
machenbach@chromium.org63a7c9f2014-04-01 00:04:36 +0000137 __ LoadRoot(stack_limit_scratch, index);
machenbach@chromium.orga2218802014-03-25 07:30:47 +0000138 __ Branch(&ok, hs, scratch, Operand(stack_limit_scratch));
139 PredictableCodeSizeScope predictable(masm_, 4 * Assembler::kInstrSize);
140 __ Call(isolate->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
141 __ bind(&ok);
142}
143
144
lrn@chromium.org7516f052011-03-30 08:52:27 +0000145// Generate code for a JS function. On entry to the function the receiver
146// and arguments have been pushed on the stack left to right. The actual
147// argument count matches the formal parameter count expected by the
148// function.
149//
150// The live registers are:
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000151// o a1: the JS function object being called (i.e. ourselves)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000152// o cp: our context
153// o fp: our caller's frame pointer
154// o sp: stack pointer
155// o ra: return address
156//
157// The function builds a JS frame. Please see JavaScriptFrameConstants in
158// frames-mips.h for its layout.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000159void FullCodeGenerator::Generate() {
160 CompilationInfo* info = info_;
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +0000161 handler_table_ =
162 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000163
machenbach@chromium.org8545d492014-03-17 09:28:03 +0000164 InitializeFeedbackVector();
165
danno@chromium.orgf95d4b92013-06-13 14:40:17 +0000166 profiling_counter_ = isolate()->factory()->NewCell(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000167 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000168 SetFunctionPosition(function());
169 Comment cmnt(masm_, "[ function compiled by full code generator");
170
danno@chromium.org129d3982012-07-25 15:01:47 +0000171 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
172
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000173#ifdef DEBUG
174 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000175 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000176 __ stop("stop-at");
177 }
178#endif
179
dslomov@chromium.org486536d2014-03-12 13:09:18 +0000180 // Sloppy mode functions and builtins need to replace the receiver with the
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000181 // global proxy when called as functions (without an explicit receiver
182 // object).
dslomov@chromium.org486536d2014-03-12 13:09:18 +0000183 if (info->strict_mode() == SLOPPY && !info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000184 Label ok;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000185 int receiver_offset = info->scope()->num_parameters() * kPointerSize;
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000186 __ lw(at, MemOperand(sp, receiver_offset));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000187 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000188 __ Branch(&ok, ne, a2, Operand(at));
189
190 __ lw(a2, GlobalObjectOperand());
191 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset));
192
danno@chromium.org40cb8782011-05-25 07:58:50 +0000193 __ sw(a2, MemOperand(sp, receiver_offset));
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000194
danno@chromium.org40cb8782011-05-25 07:58:50 +0000195 __ bind(&ok);
196 }
197
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000198 // Open a frame scope to indicate that there is a frame on the stack. The
199 // MANUAL indicates that the scope shouldn't actually generate code to set up
200 // the frame (that is done below).
201 FrameScope frame_scope(masm_, StackFrame::MANUAL);
202
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000203 info->set_prologue_offset(masm_->pc_offset());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000204 __ Prologue(BUILD_FUNCTION_FRAME);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000205 info->AddNoFrameRange(0, masm_->pc_offset());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000206
207 { Comment cmnt(masm_, "[ Allocate locals");
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000208 int locals_count = info->scope()->num_stack_slots();
209 // Generators allocate locals, if any, in context slots.
210 ASSERT(!info->function()->is_generator() || locals_count == 0);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000211 if (locals_count > 0) {
machenbach@chromium.orga2218802014-03-25 07:30:47 +0000212 if (locals_count >= 128) {
213 EmitStackCheck(masm_, a2, locals_count, t5);
214 }
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000215 __ LoadRoot(t5, Heap::kUndefinedValueRootIndex);
machenbach@chromium.orga2218802014-03-25 07:30:47 +0000216 int kMaxPushes = FLAG_optimize_for_size ? 4 : 32;
217 if (locals_count >= kMaxPushes) {
218 int loop_iterations = locals_count / kMaxPushes;
219 __ li(a2, Operand(loop_iterations));
220 Label loop_header;
221 __ bind(&loop_header);
222 // Do pushes.
223 __ Subu(sp, sp, Operand(kMaxPushes * kPointerSize));
224 for (int i = 0; i < kMaxPushes; i++) {
yangguo@chromium.org49546742013-12-23 16:17:49 +0000225 __ sw(t5, MemOperand(sp, i * kPointerSize));
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000226 }
machenbach@chromium.orga2218802014-03-25 07:30:47 +0000227 // Continue loop if not done.
228 __ Subu(a2, a2, Operand(1));
229 __ Branch(&loop_header, ne, a2, Operand(zero_reg));
230 }
231 int remaining = locals_count % kMaxPushes;
232 // Emit the remaining pushes.
233 __ Subu(sp, sp, Operand(remaining * kPointerSize));
234 for (int i = 0; i < remaining; i++) {
235 __ sw(t5, MemOperand(sp, i * kPointerSize));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000236 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000237 }
238 }
239
240 bool function_in_register = true;
241
242 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000243 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000244 if (heap_slots > 0) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000245 Comment cmnt(masm_, "[ Allocate context");
246 // Argument to NewContext is the function, which is still in a1.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000247 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000248 __ push(a1);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000249 __ Push(info->scope()->GetScopeInfo());
machenbach@chromium.org895f00d2014-03-27 01:04:43 +0000250 __ CallRuntime(Runtime::kHiddenNewGlobalContext, 2);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000251 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000252 FastNewContextStub stub(heap_slots);
253 __ CallStub(&stub);
254 } else {
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000255 __ push(a1);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +0000256 __ CallRuntime(Runtime::kHiddenNewFunctionContext, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000257 }
258 function_in_register = false;
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000259 // Context is returned in v0. It replaces the context passed to us.
260 // It's saved in the stack and kept live in cp.
261 __ mov(cp, v0);
262 __ sw(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000263 // Copy any necessary parameters into the context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000264 int num_parameters = info->scope()->num_parameters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000265 for (int i = 0; i < num_parameters; i++) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000266 Variable* var = scope()->parameter(i);
267 if (var->IsContextSlot()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000268 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
269 (num_parameters - 1 - i) * kPointerSize;
270 // Load parameter from stack.
271 __ lw(a0, MemOperand(fp, parameter_offset));
272 // Store it in the context.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000273 MemOperand target = ContextOperand(cp, var->index());
274 __ sw(a0, target);
275
276 // Update the write barrier.
277 __ RecordWriteContextSlot(
278 cp, target.offset(), a0, a3, kRAHasBeenSaved, kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000279 }
280 }
281 }
282
283 Variable* arguments = scope()->arguments();
284 if (arguments != NULL) {
285 // Function uses arguments object.
286 Comment cmnt(masm_, "[ Allocate arguments object");
287 if (!function_in_register) {
288 // Load this again, if it's used by the local context below.
289 __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
290 } else {
291 __ mov(a3, a1);
292 }
293 // Receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000294 int num_parameters = info->scope()->num_parameters();
295 int offset = num_parameters * kPointerSize;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000296 __ Addu(a2, fp,
297 Operand(StandardFrameConstants::kCallerSPOffset + offset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000298 __ li(a1, Operand(Smi::FromInt(num_parameters)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000299 __ Push(a3, a2, a1);
300
301 // Arguments to ArgumentsAccessStub:
302 // function, receiver address, parameter count.
303 // The stub will rewrite receiever and parameter count if the previous
304 // stack frame was an arguments adapter frame.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000305 ArgumentsAccessStub::Type type;
dslomov@chromium.org486536d2014-03-12 13:09:18 +0000306 if (strict_mode() == STRICT) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000307 type = ArgumentsAccessStub::NEW_STRICT;
308 } else if (function()->has_duplicate_parameters()) {
dslomov@chromium.org486536d2014-03-12 13:09:18 +0000309 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW;
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000310 } else {
dslomov@chromium.org486536d2014-03-12 13:09:18 +0000311 type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000312 }
313 ArgumentsAccessStub stub(type);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000314 __ CallStub(&stub);
315
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000316 SetVar(arguments, v0, a1, a2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000317 }
318
319 if (FLAG_trace) {
320 __ CallRuntime(Runtime::kTraceEnter, 0);
321 }
322
323 // Visit the declarations and body unless there is an illegal
324 // redeclaration.
325 if (scope()->HasIllegalRedeclaration()) {
326 Comment cmnt(masm_, "[ Declarations");
327 scope()->VisitIllegalRedeclaration(this);
328
329 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000330 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000331 { Comment cmnt(masm_, "[ Declarations");
332 // For named function expressions, declare the function name as a
333 // constant.
334 if (scope()->is_function_scope() && scope()->function() != NULL) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000335 VariableDeclaration* function = scope()->function();
336 ASSERT(function->proxy()->var()->mode() == CONST ||
dslomov@chromium.org486536d2014-03-12 13:09:18 +0000337 function->proxy()->var()->mode() == CONST_LEGACY);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000338 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
339 VisitVariableDeclaration(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000340 }
341 VisitDeclarations(scope()->declarations());
342 }
343
344 { Comment cmnt(masm_, "[ Stack check");
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000345 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
machenbach@chromium.orga2218802014-03-25 07:30:47 +0000346 EmitStackCheck(masm_, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000347 }
348
349 { Comment cmnt(masm_, "[ Body");
350 ASSERT(loop_depth() == 0);
351 VisitStatements(function()->body());
352 ASSERT(loop_depth() == 0);
353 }
354 }
355
356 // Always emit a 'return undefined' in case control fell off the end of
357 // the body.
358 { Comment cmnt(masm_, "[ return <undefined>;");
359 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
360 }
361 EmitReturnSequence();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000362}
363
364
365void FullCodeGenerator::ClearAccumulator() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000366 ASSERT(Smi::FromInt(0) == 0);
367 __ mov(v0, zero_reg);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000368}
369
370
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000371void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
372 __ li(a2, Operand(profiling_counter_));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +0000373 __ lw(a3, FieldMemOperand(a2, Cell::kValueOffset));
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000374 __ Subu(a3, a3, Operand(Smi::FromInt(delta)));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +0000375 __ sw(a3, FieldMemOperand(a2, Cell::kValueOffset));
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000376}
377
378
379void FullCodeGenerator::EmitProfilingCounterReset() {
380 int reset_value = FLAG_interrupt_budget;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000381 if (isolate()->IsDebuggerActive()) {
382 // Detect debug break requests as soon as possible.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000383 reset_value = FLAG_interrupt_budget >> 4;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000384 }
385 __ li(a2, Operand(profiling_counter_));
386 __ li(a3, Operand(Smi::FromInt(reset_value)));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +0000387 __ sw(a3, FieldMemOperand(a2, Cell::kValueOffset));
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000388}
389
390
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000391void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
392 Label* back_edge_target) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000393 // The generated code is used in Deoptimizer::PatchStackCheckCodeAt so we need
394 // to make sure it is constant. Branch may emit a skip-or-jump sequence
395 // instead of the normal Branch. It seems that the "skip" part of that
396 // sequence is about as long as this Branch would be so it is safe to ignore
397 // that.
398 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000399 Comment cmnt(masm_, "[ Back edge bookkeeping");
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000400 Label ok;
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000401 ASSERT(back_edge_target->is_bound());
402 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
403 int weight = Min(kMaxBackEdgeWeight,
404 Max(1, distance / kCodeSizeMultiplier));
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000405 EmitProfilingCounterDecrement(weight);
406 __ slt(at, a3, zero_reg);
407 __ beq(at, zero_reg, &ok);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000408 // Call will emit a li t9 first, so it is safe to use the delay slot.
409 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000410 // Record a mapping of this PC offset to the OSR id. This is used to find
411 // the AST id from the unoptimized code in order to use it as a key into
412 // the deoptimization input data found in the optimized code.
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000413 RecordBackEdge(stmt->OsrEntryId());
414 EmitProfilingCounterReset();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000415
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000416 __ bind(&ok);
417 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
418 // Record a mapping of the OSR id to this PC. This is used if the OSR
419 // entry becomes the target of a bailout. We don't expect it to be, but
420 // we want it to work if it is.
421 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
ager@chromium.org5c838252010-02-19 08:53:10 +0000422}
423
424
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000425void FullCodeGenerator::EmitReturnSequence() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000426 Comment cmnt(masm_, "[ Return sequence");
427 if (return_label_.is_bound()) {
428 __ Branch(&return_label_);
429 } else {
430 __ bind(&return_label_);
431 if (FLAG_trace) {
432 // Push the return value on the stack as the parameter.
433 // Runtime::TraceExit returns its parameter in v0.
434 __ push(v0);
435 __ CallRuntime(Runtime::kTraceExit, 1);
436 }
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000437 // Pretend that the exit is a backwards jump to the entry.
438 int weight = 1;
439 if (info_->ShouldSelfOptimize()) {
440 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
441 } else {
442 int distance = masm_->pc_offset();
443 weight = Min(kMaxBackEdgeWeight,
444 Max(1, distance / kCodeSizeMultiplier));
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000445 }
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000446 EmitProfilingCounterDecrement(weight);
447 Label ok;
448 __ Branch(&ok, ge, a3, Operand(zero_reg));
449 __ push(v0);
450 __ Call(isolate()->builtins()->InterruptCheck(),
451 RelocInfo::CODE_TARGET);
452 __ pop(v0);
453 EmitProfilingCounterReset();
454 __ bind(&ok);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000455
456#ifdef DEBUG
457 // Add a label for checking the size of the code used for returning.
458 Label check_exit_codesize;
459 masm_->bind(&check_exit_codesize);
460#endif
461 // Make sure that the constant pool is not emitted inside of the return
462 // sequence.
463 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
464 // Here we use masm_-> instead of the __ macro to avoid the code coverage
465 // tool from instrumenting as we rely on the code size here.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000466 int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000467 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
468 __ RecordJSReturn();
469 masm_->mov(sp, fp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000470 int no_frame_start = masm_->pc_offset();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000471 masm_->MultiPop(static_cast<RegList>(fp.bit() | ra.bit()));
472 masm_->Addu(sp, sp, Operand(sp_delta));
473 masm_->Jump(ra);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000474 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000475 }
476
477#ifdef DEBUG
478 // Check that the size of the code used for returning is large enough
479 // for the debugger's requirements.
480 ASSERT(Assembler::kJSReturnSequenceInstructions <=
481 masm_->InstructionsGeneratedSince(&check_exit_codesize));
482#endif
483 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000484}
485
486
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000487void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
488 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
ager@chromium.org5c838252010-02-19 08:53:10 +0000489}
490
491
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000492void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
493 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
494 codegen()->GetVar(result_register(), var);
ager@chromium.org5c838252010-02-19 08:53:10 +0000495}
496
497
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000498void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
499 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
500 codegen()->GetVar(result_register(), var);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000501 __ push(result_register());
ager@chromium.org5c838252010-02-19 08:53:10 +0000502}
503
504
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000505void FullCodeGenerator::TestContext::Plug(Variable* var) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000506 // For simplicity we always test the accumulator register.
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000507 codegen()->GetVar(result_register(), var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000508 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000509 codegen()->DoTest(this);
ager@chromium.org5c838252010-02-19 08:53:10 +0000510}
511
512
lrn@chromium.org7516f052011-03-30 08:52:27 +0000513void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
ager@chromium.org5c838252010-02-19 08:53:10 +0000514}
515
516
lrn@chromium.org7516f052011-03-30 08:52:27 +0000517void FullCodeGenerator::AccumulatorValueContext::Plug(
518 Heap::RootListIndex index) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000519 __ LoadRoot(result_register(), index);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000520}
521
522
523void FullCodeGenerator::StackValueContext::Plug(
524 Heap::RootListIndex index) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000525 __ LoadRoot(result_register(), index);
526 __ push(result_register());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000527}
528
529
530void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000531 codegen()->PrepareForBailoutBeforeSplit(condition(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000532 true,
533 true_label_,
534 false_label_);
535 if (index == Heap::kUndefinedValueRootIndex ||
536 index == Heap::kNullValueRootIndex ||
537 index == Heap::kFalseValueRootIndex) {
538 if (false_label_ != fall_through_) __ Branch(false_label_);
539 } else if (index == Heap::kTrueValueRootIndex) {
540 if (true_label_ != fall_through_) __ Branch(true_label_);
541 } else {
542 __ LoadRoot(result_register(), index);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000543 codegen()->DoTest(this);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000544 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000545}
546
547
548void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000549}
550
551
552void FullCodeGenerator::AccumulatorValueContext::Plug(
553 Handle<Object> lit) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000554 __ li(result_register(), Operand(lit));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000555}
556
557
558void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000559 // Immediates cannot be pushed directly.
560 __ li(result_register(), Operand(lit));
561 __ push(result_register());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000562}
563
564
565void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000566 codegen()->PrepareForBailoutBeforeSplit(condition(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000567 true,
568 true_label_,
569 false_label_);
570 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
571 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
572 if (false_label_ != fall_through_) __ Branch(false_label_);
573 } else if (lit->IsTrue() || lit->IsJSObject()) {
574 if (true_label_ != fall_through_) __ Branch(true_label_);
575 } else if (lit->IsString()) {
576 if (String::cast(*lit)->length() == 0) {
577 if (false_label_ != fall_through_) __ Branch(false_label_);
578 } else {
579 if (true_label_ != fall_through_) __ Branch(true_label_);
580 }
581 } else if (lit->IsSmi()) {
582 if (Smi::cast(*lit)->value() == 0) {
583 if (false_label_ != fall_through_) __ Branch(false_label_);
584 } else {
585 if (true_label_ != fall_through_) __ Branch(true_label_);
586 }
587 } else {
588 // For simplicity we always test the accumulator register.
589 __ li(result_register(), Operand(lit));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000590 codegen()->DoTest(this);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000591 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000592}
593
594
595void FullCodeGenerator::EffectContext::DropAndPlug(int count,
596 Register reg) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000597 ASSERT(count > 0);
598 __ Drop(count);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000599}
600
601
602void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
603 int count,
604 Register reg) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000605 ASSERT(count > 0);
606 __ Drop(count);
607 __ Move(result_register(), reg);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000608}
609
610
611void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
612 Register reg) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000613 ASSERT(count > 0);
614 if (count > 1) __ Drop(count - 1);
615 __ sw(reg, MemOperand(sp, 0));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000616}
617
618
619void FullCodeGenerator::TestContext::DropAndPlug(int count,
620 Register reg) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000621 ASSERT(count > 0);
622 // For simplicity we always test the accumulator register.
623 __ Drop(count);
624 __ Move(result_register(), reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000625 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000626 codegen()->DoTest(this);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000627}
628
629
630void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
631 Label* materialize_false) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000632 ASSERT(materialize_true == materialize_false);
633 __ bind(materialize_true);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000634}
635
636
637void FullCodeGenerator::AccumulatorValueContext::Plug(
638 Label* materialize_true,
639 Label* materialize_false) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000640 Label done;
641 __ bind(materialize_true);
642 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
643 __ Branch(&done);
644 __ bind(materialize_false);
645 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
646 __ bind(&done);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000647}
648
649
650void FullCodeGenerator::StackValueContext::Plug(
651 Label* materialize_true,
652 Label* materialize_false) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000653 Label done;
654 __ bind(materialize_true);
655 __ LoadRoot(at, Heap::kTrueValueRootIndex);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +0000656 // Push the value as the following branch can clobber at in long branch mode.
657 __ push(at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000658 __ Branch(&done);
659 __ bind(materialize_false);
660 __ LoadRoot(at, Heap::kFalseValueRootIndex);
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000661 __ push(at);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +0000662 __ bind(&done);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000663}
664
665
666void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
667 Label* materialize_false) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000668 ASSERT(materialize_true == true_label_);
669 ASSERT(materialize_false == false_label_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000670}
671
672
673void FullCodeGenerator::EffectContext::Plug(bool flag) const {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000674}
675
676
677void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000678 Heap::RootListIndex value_root_index =
679 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
680 __ LoadRoot(result_register(), value_root_index);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000681}
682
683
684void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000685 Heap::RootListIndex value_root_index =
686 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
687 __ LoadRoot(at, value_root_index);
688 __ push(at);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000689}
690
691
692void FullCodeGenerator::TestContext::Plug(bool flag) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 codegen()->PrepareForBailoutBeforeSplit(condition(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000694 true,
695 true_label_,
696 false_label_);
697 if (flag) {
698 if (true_label_ != fall_through_) __ Branch(true_label_);
699 } else {
700 if (false_label_ != fall_through_) __ Branch(false_label_);
701 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000702}
703
704
whesse@chromium.org7b260152011-06-20 15:33:18 +0000705void FullCodeGenerator::DoTest(Expression* condition,
706 Label* if_true,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000707 Label* if_false,
708 Label* fall_through) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000709 __ mov(a0, result_register());
710 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000711 CallIC(ic, condition->test_id());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000712 __ mov(at, zero_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000713 Split(ne, v0, Operand(at), if_true, if_false, fall_through);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000714}
715
716
lrn@chromium.org7516f052011-03-30 08:52:27 +0000717void FullCodeGenerator::Split(Condition cc,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000718 Register lhs,
719 const Operand& rhs,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000720 Label* if_true,
721 Label* if_false,
722 Label* fall_through) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000723 if (if_false == fall_through) {
724 __ Branch(if_true, cc, lhs, rhs);
725 } else if (if_true == fall_through) {
726 __ Branch(if_false, NegateCondition(cc), lhs, rhs);
727 } else {
728 __ Branch(if_true, cc, lhs, rhs);
729 __ Branch(if_false);
730 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000731}
732
733
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000734MemOperand FullCodeGenerator::StackOperand(Variable* var) {
735 ASSERT(var->IsStackAllocated());
736 // Offset is negative because higher indexes are at lower addresses.
737 int offset = -var->index() * kPointerSize;
738 // Adjust by a (parameter or local) base offset.
739 if (var->IsParameter()) {
740 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
741 } else {
742 offset += JavaScriptFrameConstants::kLocal0Offset;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000743 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000744 return MemOperand(fp, offset);
ager@chromium.org5c838252010-02-19 08:53:10 +0000745}
746
747
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000748MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
749 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
750 if (var->IsContextSlot()) {
751 int context_chain_length = scope()->ContextChainLength(var->scope());
752 __ LoadContext(scratch, context_chain_length);
753 return ContextOperand(scratch, var->index());
754 } else {
755 return StackOperand(var);
756 }
757}
758
759
760void FullCodeGenerator::GetVar(Register dest, Variable* var) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000761 // Use destination as scratch.
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000762 MemOperand location = VarOperand(var, dest);
763 __ lw(dest, location);
764}
765
766
767void FullCodeGenerator::SetVar(Variable* var,
768 Register src,
769 Register scratch0,
770 Register scratch1) {
771 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
772 ASSERT(!scratch0.is(src));
773 ASSERT(!scratch0.is(scratch1));
774 ASSERT(!scratch1.is(src));
775 MemOperand location = VarOperand(var, scratch0);
776 __ sw(src, location);
777 // Emit the write barrier code if the location is in the heap.
778 if (var->IsContextSlot()) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000779 __ RecordWriteContextSlot(scratch0,
780 location.offset(),
781 src,
782 scratch1,
783 kRAHasBeenSaved,
784 kDontSaveFPRegs);
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000785 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000786}
787
788
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000789void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000790 bool should_normalize,
791 Label* if_true,
792 Label* if_false) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000793 // Only prepare for bailouts before splits if we're in a test
794 // context. Otherwise, we let the Visit function deal with the
795 // preparation to avoid preparing with the same AST id twice.
796 if (!context()->IsTest() || !info_->IsOptimizable()) return;
797
798 Label skip;
799 if (should_normalize) __ Branch(&skip);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000800 PrepareForBailout(expr, TOS_REG);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000801 if (should_normalize) {
802 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
803 Split(eq, a0, Operand(t0), if_true, if_false, NULL);
804 __ bind(&skip);
805 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000806}
807
808
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000809void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
810 // The variable in the declaration always resides in the current function
811 // context.
812 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000813 if (generate_debug_code_) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000814 // Check that we're not inside a with or catch context.
815 __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
816 __ LoadRoot(t0, Heap::kWithContextMapRootIndex);
danno@chromium.org59400602013-08-13 17:09:37 +0000817 __ Check(ne, kDeclarationInWithContext,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000818 a1, Operand(t0));
819 __ LoadRoot(t0, Heap::kCatchContextMapRootIndex);
danno@chromium.org59400602013-08-13 17:09:37 +0000820 __ Check(ne, kDeclarationInCatchContext,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000821 a1, Operand(t0));
822 }
823}
824
825
826void FullCodeGenerator::VisitVariableDeclaration(
827 VariableDeclaration* declaration) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000828 // If it was not possible to allocate the variable at compile time, we
829 // need to "declare" it at runtime to make sure it actually exists in the
830 // local context.
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000831 VariableProxy* proxy = declaration->proxy();
832 VariableMode mode = declaration->mode();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000833 Variable* variable = proxy->var();
dslomov@chromium.org486536d2014-03-12 13:09:18 +0000834 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000835 switch (variable->location()) {
836 case Variable::UNALLOCATED:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000837 globals_->Add(variable->name(), zone());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000838 globals_->Add(variable->binding_needs_init()
839 ? isolate()->factory()->the_hole_value()
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000840 : isolate()->factory()->undefined_value(),
841 zone());
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000842 break;
843
844 case Variable::PARAMETER:
845 case Variable::LOCAL:
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000846 if (hole_init) {
847 Comment cmnt(masm_, "[ VariableDeclaration");
848 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
849 __ sw(t0, StackOperand(variable));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000850 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000851 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000852
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000853 case Variable::CONTEXT:
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000854 if (hole_init) {
855 Comment cmnt(masm_, "[ VariableDeclaration");
856 EmitDebugCheckDeclarationContext(variable);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000857 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000858 __ sw(at, ContextOperand(cp, variable->index()));
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000859 // No write barrier since the_hole_value is in old space.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000860 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000861 }
862 break;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000863
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000864 case Variable::LOOKUP: {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000865 Comment cmnt(masm_, "[ VariableDeclaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000866 __ li(a2, Operand(variable->name()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000867 // Declaration nodes are always introduced in one of four modes.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000868 ASSERT(IsDeclaredVariableMode(mode));
869 PropertyAttributes attr =
870 IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000871 __ li(a1, Operand(Smi::FromInt(attr)));
872 // Push initial value, if any.
873 // Note: For variables we must not push an initial value (such as
874 // 'undefined') because we may have a (legal) redeclaration and we
875 // must not destroy the current value.
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000876 if (hole_init) {
877 __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
878 __ Push(cp, a2, a1, a0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000879 } else {
880 ASSERT(Smi::FromInt(0) == 0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000881 __ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000882 __ Push(cp, a2, a1, a0);
883 }
machenbach@chromium.org895f00d2014-03-27 01:04:43 +0000884 __ CallRuntime(Runtime::kHiddenDeclareContextSlot, 4);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000885 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000886 }
887 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000888}
889
890
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000891void FullCodeGenerator::VisitFunctionDeclaration(
892 FunctionDeclaration* declaration) {
893 VariableProxy* proxy = declaration->proxy();
894 Variable* variable = proxy->var();
895 switch (variable->location()) {
896 case Variable::UNALLOCATED: {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000897 globals_->Add(variable->name(), zone());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000898 Handle<SharedFunctionInfo> function =
899 Compiler::BuildFunctionInfo(declaration->fun(), script());
900 // Check for stack-overflow exception.
901 if (function.is_null()) return SetStackOverflow();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000902 globals_->Add(function, zone());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000903 break;
904 }
905
906 case Variable::PARAMETER:
907 case Variable::LOCAL: {
908 Comment cmnt(masm_, "[ FunctionDeclaration");
909 VisitForAccumulatorValue(declaration->fun());
910 __ sw(result_register(), StackOperand(variable));
911 break;
912 }
913
914 case Variable::CONTEXT: {
915 Comment cmnt(masm_, "[ FunctionDeclaration");
916 EmitDebugCheckDeclarationContext(variable);
917 VisitForAccumulatorValue(declaration->fun());
918 __ sw(result_register(), ContextOperand(cp, variable->index()));
919 int offset = Context::SlotOffset(variable->index());
920 // We know that we have written a function, which is not a smi.
921 __ RecordWriteContextSlot(cp,
922 offset,
923 result_register(),
924 a2,
925 kRAHasBeenSaved,
926 kDontSaveFPRegs,
927 EMIT_REMEMBERED_SET,
928 OMIT_SMI_CHECK);
929 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
930 break;
931 }
932
933 case Variable::LOOKUP: {
934 Comment cmnt(masm_, "[ FunctionDeclaration");
935 __ li(a2, Operand(variable->name()));
936 __ li(a1, Operand(Smi::FromInt(NONE)));
937 __ Push(cp, a2, a1);
938 // Push initial value for function declaration.
939 VisitForStackValue(declaration->fun());
machenbach@chromium.org895f00d2014-03-27 01:04:43 +0000940 __ CallRuntime(Runtime::kHiddenDeclareContextSlot, 4);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000941 break;
942 }
943 }
944}
945
946
947void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000948 Variable* variable = declaration->proxy()->var();
949 ASSERT(variable->location() == Variable::CONTEXT);
950 ASSERT(variable->interface()->IsFrozen());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000951
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000952 Comment cmnt(masm_, "[ ModuleDeclaration");
953 EmitDebugCheckDeclarationContext(variable);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000954
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000955 // Load instance object.
956 __ LoadContext(a1, scope_->ContextChainLength(scope_->GlobalScope()));
957 __ lw(a1, ContextOperand(a1, variable->interface()->Index()));
958 __ lw(a1, ContextOperand(a1, Context::EXTENSION_INDEX));
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000959
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000960 // Assign it.
961 __ sw(a1, ContextOperand(cp, variable->index()));
962 // We know that we have written a module, which is not a smi.
963 __ RecordWriteContextSlot(cp,
964 Context::SlotOffset(variable->index()),
965 a1,
966 a3,
967 kRAHasBeenSaved,
968 kDontSaveFPRegs,
969 EMIT_REMEMBERED_SET,
970 OMIT_SMI_CHECK);
971 PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
972
973 // Traverse into body.
974 Visit(declaration->module());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000975}
976
977
978void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
979 VariableProxy* proxy = declaration->proxy();
980 Variable* variable = proxy->var();
981 switch (variable->location()) {
982 case Variable::UNALLOCATED:
983 // TODO(rossberg)
984 break;
985
986 case Variable::CONTEXT: {
987 Comment cmnt(masm_, "[ ImportDeclaration");
988 EmitDebugCheckDeclarationContext(variable);
989 // TODO(rossberg)
990 break;
991 }
992
993 case Variable::PARAMETER:
994 case Variable::LOCAL:
995 case Variable::LOOKUP:
996 UNREACHABLE();
997 }
998}
999
1000
1001void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
1002 // TODO(rossberg)
1003}
1004
1005
ager@chromium.org5c838252010-02-19 08:53:10 +00001006void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001007 // Call the runtime to declare the globals.
1008 // The context is the first argument.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001009 __ li(a1, Operand(pairs));
1010 __ li(a0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
1011 __ Push(cp, a1, a0);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001012 __ CallRuntime(Runtime::kHiddenDeclareGlobals, 3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001013 // Return value is ignored.
ager@chromium.org5c838252010-02-19 08:53:10 +00001014}
1015
1016
danno@chromium.org1f34ad32012-11-26 14:53:56 +00001017void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
1018 // Call the runtime to declare the modules.
1019 __ Push(descriptions);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001020 __ CallRuntime(Runtime::kHiddenDeclareModules, 1);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00001021 // Return value is ignored.
1022}
1023
1024
lrn@chromium.org7516f052011-03-30 08:52:27 +00001025void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001026 Comment cmnt(masm_, "[ SwitchStatement");
1027 Breakable nested_statement(this, stmt);
1028 SetStatementPosition(stmt);
1029
1030 // Keep the switch value on the stack until a case matches.
1031 VisitForStackValue(stmt->tag());
1032 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
1033
1034 ZoneList<CaseClause*>* clauses = stmt->cases();
1035 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
1036
1037 Label next_test; // Recycled for each test.
1038 // Compile all the tests with branches to their bodies.
1039 for (int i = 0; i < clauses->length(); i++) {
1040 CaseClause* clause = clauses->at(i);
1041 clause->body_target()->Unuse();
1042
1043 // The default is not a test, but remember it as final fall through.
1044 if (clause->is_default()) {
1045 default_clause = clause;
1046 continue;
1047 }
1048
1049 Comment cmnt(masm_, "[ Case comparison");
1050 __ bind(&next_test);
1051 next_test.Unuse();
1052
1053 // Compile the label expression.
1054 VisitForAccumulatorValue(clause->label());
1055 __ mov(a0, result_register()); // CompareStub requires args in a0, a1.
1056
1057 // Perform the comparison as if via '==='.
1058 __ lw(a1, MemOperand(sp, 0)); // Switch value.
1059 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
1060 JumpPatchSite patch_site(masm_);
1061 if (inline_smi_code) {
1062 Label slow_case;
1063 __ or_(a2, a1, a0);
1064 patch_site.EmitJumpIfNotSmi(a2, &slow_case);
1065
1066 __ Branch(&next_test, ne, a1, Operand(a0));
1067 __ Drop(1); // Switch value is no longer needed.
1068 __ Branch(clause->body_target());
1069
1070 __ bind(&slow_case);
1071 }
1072
1073 // Record position before stub call for type feedback.
1074 SetSourcePosition(clause->position());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001075 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00001076 CallIC(ic, clause->CompareId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001077 patch_site.EmitPatchInfo();
danno@chromium.org40cb8782011-05-25 07:58:50 +00001078
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00001079 Label skip;
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00001080 __ Branch(&skip);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00001081 PrepareForBailout(clause, TOS_REG);
1082 __ LoadRoot(at, Heap::kTrueValueRootIndex);
1083 __ Branch(&next_test, ne, v0, Operand(at));
1084 __ Drop(1);
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00001085 __ Branch(clause->body_target());
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00001086 __ bind(&skip);
1087
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001088 __ Branch(&next_test, ne, v0, Operand(zero_reg));
1089 __ Drop(1); // Switch value is no longer needed.
1090 __ Branch(clause->body_target());
1091 }
1092
1093 // Discard the test value and jump to the default if present, otherwise to
1094 // the end of the statement.
1095 __ bind(&next_test);
1096 __ Drop(1); // Switch value is no longer needed.
1097 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001098 __ Branch(nested_statement.break_label());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001099 } else {
1100 __ Branch(default_clause->body_target());
1101 }
1102
1103 // Compile all the case bodies.
1104 for (int i = 0; i < clauses->length(); i++) {
1105 Comment cmnt(masm_, "[ Case body");
1106 CaseClause* clause = clauses->at(i);
1107 __ bind(clause->body_target());
1108 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
1109 VisitStatements(clause->statements());
1110 }
1111
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001112 __ bind(nested_statement.break_label());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001113 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001114}
1115
1116
1117void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001118 Comment cmnt(masm_, "[ ForInStatement");
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00001119 int slot = stmt->ForInFeedbackSlot();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001120 SetStatementPosition(stmt);
1121
1122 Label loop, exit;
1123 ForIn loop_statement(this, stmt);
1124 increment_loop_depth();
1125
palfia@homejinni.com9b73b0d2013-06-08 14:05:11 +00001126 // Get the object to enumerate over. If the object is null or undefined, skip
1127 // over the loop. See ECMA-262 version 5, section 12.6.4.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001128 VisitForAccumulatorValue(stmt->enumerable());
1129 __ mov(a0, result_register()); // Result as param to InvokeBuiltin below.
1130 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
1131 __ Branch(&exit, eq, a0, Operand(at));
1132 Register null_value = t1;
1133 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
1134 __ Branch(&exit, eq, a0, Operand(null_value));
ulan@chromium.org812308e2012-02-29 15:58:45 +00001135 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1136 __ mov(a0, v0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001137 // Convert the object to a JS object.
1138 Label convert, done_convert;
1139 __ JumpIfSmi(a0, &convert);
1140 __ GetObjectType(a0, a1, a1);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001141 __ Branch(&done_convert, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001142 __ bind(&convert);
1143 __ push(a0);
1144 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1145 __ mov(a0, v0);
1146 __ bind(&done_convert);
1147 __ push(a0);
1148
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001149 // Check for proxies.
1150 Label call_runtime;
1151 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1152 __ GetObjectType(a0, a1, a1);
1153 __ Branch(&call_runtime, le, a1, Operand(LAST_JS_PROXY_TYPE));
1154
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001155 // Check cache validity in generated code. This is a fast case for
1156 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1157 // guarantee cache validity, call the runtime system to check cache
1158 // validity or get the property names in a fixed array.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001159 __ CheckEnumCache(null_value, &call_runtime);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001160
1161 // The enum cache is valid. Load the map of the object being
1162 // iterated over and use the cache for the iteration.
1163 Label use_cache;
1164 __ lw(v0, FieldMemOperand(a0, HeapObject::kMapOffset));
1165 __ Branch(&use_cache);
1166
1167 // Get the set of properties to enumerate.
1168 __ bind(&call_runtime);
1169 __ push(a0); // Duplicate the enumerable object on the stack.
1170 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1171
1172 // If we got a map from the runtime call, we can do a fast
1173 // modification check. Otherwise, we got a fixed array, and we have
1174 // to do a slow check.
1175 Label fixed_array;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001176 __ lw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001177 __ LoadRoot(at, Heap::kMetaMapRootIndex);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001178 __ Branch(&fixed_array, ne, a2, Operand(at));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001179
1180 // We got a map in register v0. Get the enumeration cache from it.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001181 Label no_descriptors;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001182 __ bind(&use_cache);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001183
1184 __ EnumLength(a1, v0);
1185 __ Branch(&no_descriptors, eq, a1, Operand(Smi::FromInt(0)));
1186
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001187 __ LoadInstanceDescriptors(v0, a2);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001188 __ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheOffset));
1189 __ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheBridgeCacheOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001190
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001191 // Set up the four remaining stack slots.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001192 __ li(a0, Operand(Smi::FromInt(0)));
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +00001193 // Push map, enumeration cache, enumeration cache length (as smi) and zero.
1194 __ Push(v0, a2, a1, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001195 __ jmp(&loop);
1196
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001197 __ bind(&no_descriptors);
1198 __ Drop(1);
1199 __ jmp(&exit);
1200
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001201 // We got a fixed array in register v0. Iterate through that.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001202 Label non_proxy;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001203 __ bind(&fixed_array);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001204
machenbach@chromium.org8545d492014-03-17 09:28:03 +00001205 Handle<Object> feedback = Handle<Object>(
1206 Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker),
1207 isolate());
1208 StoreFeedbackVectorSlot(slot, feedback);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00001209 __ li(a1, FeedbackVector());
machenbach@chromium.org8545d492014-03-17 09:28:03 +00001210 __ li(a2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker)));
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00001211 __ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(slot)));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001212
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001213 __ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check
1214 __ lw(a2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object
1215 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1216 __ GetObjectType(a2, a3, a3);
1217 __ Branch(&non_proxy, gt, a3, Operand(LAST_JS_PROXY_TYPE));
1218 __ li(a1, Operand(Smi::FromInt(0))); // Zero indicates proxy
1219 __ bind(&non_proxy);
1220 __ Push(a1, v0); // Smi and array
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001221 __ lw(a1, FieldMemOperand(v0, FixedArray::kLengthOffset));
1222 __ li(a0, Operand(Smi::FromInt(0)));
1223 __ Push(a1, a0); // Fixed array length (as smi) and initial index.
1224
1225 // Generate code for doing the condition check.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001226 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001227 __ bind(&loop);
1228 // Load the current count to a0, load the length to a1.
1229 __ lw(a0, MemOperand(sp, 0 * kPointerSize));
1230 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001231 __ Branch(loop_statement.break_label(), hs, a0, Operand(a1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001232
1233 // Get the current entry of the array into register a3.
1234 __ lw(a2, MemOperand(sp, 2 * kPointerSize));
1235 __ Addu(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1236 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
1237 __ addu(t0, a2, t0); // Array base + scaled (smi) index.
1238 __ lw(a3, MemOperand(t0)); // Current entry.
1239
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001240 // Get the expected map from the stack or a smi in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001241 // permanent slow case into register a2.
1242 __ lw(a2, MemOperand(sp, 3 * kPointerSize));
1243
1244 // Check if the expected map still matches that of the enumerable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001245 // If not, we may have to filter the key.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001246 Label update_each;
1247 __ lw(a1, MemOperand(sp, 4 * kPointerSize));
1248 __ lw(t0, FieldMemOperand(a1, HeapObject::kMapOffset));
1249 __ Branch(&update_each, eq, t0, Operand(a2));
1250
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001251 // For proxies, no filtering is done.
1252 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1253 ASSERT_EQ(Smi::FromInt(0), 0);
1254 __ Branch(&update_each, eq, a2, Operand(zero_reg));
1255
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001256 // Convert the entry to a string or (smi) 0 if it isn't a property
1257 // any more. If the property has been removed while iterating, we
1258 // just skip it.
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +00001259 __ Push(a1, a3); // Enumerable and current entry.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001260 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
1261 __ mov(a3, result_register());
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001262 __ Branch(loop_statement.continue_label(), eq, a3, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001263
1264 // Update the 'each' property or variable from the possibly filtered
1265 // entry in register a3.
1266 __ bind(&update_each);
1267 __ mov(result_register(), a3);
1268 // Perform the assignment as if via '='.
1269 { EffectContext context(this);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001270 EmitAssignment(stmt->each());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001271 }
1272
1273 // Generate code for the body of the loop.
1274 Visit(stmt->body());
1275
1276 // Generate code for the going to the next element by incrementing
1277 // the index (smi) stored on top of the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001278 __ bind(loop_statement.continue_label());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001279 __ pop(a0);
1280 __ Addu(a0, a0, Operand(Smi::FromInt(1)));
1281 __ push(a0);
1282
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001283 EmitBackEdgeBookkeeping(stmt, &loop);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001284 __ Branch(&loop);
1285
1286 // Remove the pointers stored on the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001287 __ bind(loop_statement.break_label());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001288 __ Drop(5);
1289
1290 // Exit and decrement the loop depth.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001291 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001292 __ bind(&exit);
1293 decrement_loop_depth();
lrn@chromium.org7516f052011-03-30 08:52:27 +00001294}
1295
1296
palfia@homejinni.com9b73b0d2013-06-08 14:05:11 +00001297void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1298 Comment cmnt(masm_, "[ ForOfStatement");
1299 SetStatementPosition(stmt);
1300
1301 Iteration loop_statement(this, stmt);
1302 increment_loop_depth();
1303
1304 // var iterator = iterable[@@iterator]()
1305 VisitForAccumulatorValue(stmt->assign_iterator());
1306 __ mov(a0, v0);
1307
1308 // As with for-in, skip the loop if the iterator is null or undefined.
1309 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
1310 __ Branch(loop_statement.break_label(), eq, a0, Operand(at));
1311 __ LoadRoot(at, Heap::kNullValueRootIndex);
1312 __ Branch(loop_statement.break_label(), eq, a0, Operand(at));
1313
1314 // Convert the iterator to a JS object.
1315 Label convert, done_convert;
1316 __ JumpIfSmi(a0, &convert);
1317 __ GetObjectType(a0, a1, a1);
1318 __ Branch(&done_convert, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
1319 __ bind(&convert);
1320 __ push(a0);
1321 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1322 __ mov(a0, v0);
1323 __ bind(&done_convert);
1324 __ push(a0);
1325
1326 // Loop entry.
1327 __ bind(loop_statement.continue_label());
1328
1329 // result = iterator.next()
1330 VisitForEffect(stmt->next_result());
1331
1332 // if (result.done) break;
1333 Label result_not_done;
1334 VisitForControl(stmt->result_done(),
1335 loop_statement.break_label(),
1336 &result_not_done,
1337 &result_not_done);
1338 __ bind(&result_not_done);
1339
1340 // each = result.value
1341 VisitForEffect(stmt->assign_each());
1342
1343 // Generate code for the body of the loop.
1344 Visit(stmt->body());
1345
1346 // Check stack before looping.
1347 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
1348 EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
1349 __ jmp(loop_statement.continue_label());
1350
1351 // Exit and decrement the loop depth.
1352 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1353 __ bind(loop_statement.break_label());
1354 decrement_loop_depth();
1355}
1356
1357
lrn@chromium.org7516f052011-03-30 08:52:27 +00001358void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1359 bool pretenure) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001360 // Use the fast case closure allocation code that allocates in new
1361 // space for nested functions that don't need literals cloning. If
1362 // we're running with the --always-opt or the --prepare-always-opt
1363 // flag, we need to use the runtime function so that the new function
1364 // we are creating here gets a chance to have its code optimized and
1365 // doesn't just get a copy of the existing unoptimized code.
1366 if (!FLAG_always_opt &&
1367 !FLAG_prepare_always_opt &&
1368 !pretenure &&
1369 scope()->is_function_scope() &&
1370 info->num_literals() == 0) {
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001371 FastNewClosureStub stub(info->strict_mode(), info->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001372 __ li(a2, Operand(info));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001373 __ CallStub(&stub);
1374 } else {
1375 __ li(a0, Operand(info));
1376 __ LoadRoot(a1, pretenure ? Heap::kTrueValueRootIndex
1377 : Heap::kFalseValueRootIndex);
1378 __ Push(cp, a0, a1);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001379 __ CallRuntime(Runtime::kHiddenNewClosure, 3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001380 }
1381 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001382}
1383
1384
1385void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001386 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001387 EmitVariableLoad(expr);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001388}
1389
1390
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001391void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1392 TypeofState typeof_state,
1393 Label* slow) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001394 Register current = cp;
1395 Register next = a1;
1396 Register temp = a2;
1397
1398 Scope* s = scope();
1399 while (s != NULL) {
1400 if (s->num_heap_slots() > 0) {
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001401 if (s->calls_sloppy_eval()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001402 // Check that extension is NULL.
1403 __ lw(temp, ContextOperand(current, Context::EXTENSION_INDEX));
1404 __ Branch(slow, ne, temp, Operand(zero_reg));
1405 }
1406 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001407 __ lw(next, ContextOperand(current, Context::PREVIOUS_INDEX));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001408 // Walk the rest of the chain without clobbering cp.
1409 current = next;
1410 }
1411 // If no outer scope calls eval, we do not need to check more
1412 // context extensions.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001413 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001414 s = s->outer_scope();
1415 }
1416
1417 if (s->is_eval_scope()) {
1418 Label loop, fast;
1419 if (!current.is(next)) {
1420 __ Move(next, current);
1421 }
1422 __ bind(&loop);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001423 // Terminate at native context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001424 __ lw(temp, FieldMemOperand(next, HeapObject::kMapOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001425 __ LoadRoot(t0, Heap::kNativeContextMapRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001426 __ Branch(&fast, eq, temp, Operand(t0));
1427 // Check that extension is NULL.
1428 __ lw(temp, ContextOperand(next, Context::EXTENSION_INDEX));
1429 __ Branch(slow, ne, temp, Operand(zero_reg));
1430 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001431 __ lw(next, ContextOperand(next, Context::PREVIOUS_INDEX));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001432 __ Branch(&loop);
1433 __ bind(&fast);
1434 }
1435
1436 __ lw(a0, GlobalObjectOperand());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001437 __ li(a2, Operand(var->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00001438 ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
1439 ? NOT_CONTEXTUAL
1440 : CONTEXTUAL;
1441 CallLoadIC(mode);
ager@chromium.org5c838252010-02-19 08:53:10 +00001442}
1443
1444
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001445MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1446 Label* slow) {
1447 ASSERT(var->IsContextSlot());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001448 Register context = cp;
1449 Register next = a3;
1450 Register temp = t0;
1451
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001452 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001453 if (s->num_heap_slots() > 0) {
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001454 if (s->calls_sloppy_eval()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001455 // Check that extension is NULL.
1456 __ lw(temp, ContextOperand(context, Context::EXTENSION_INDEX));
1457 __ Branch(slow, ne, temp, Operand(zero_reg));
1458 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001459 __ lw(next, ContextOperand(context, Context::PREVIOUS_INDEX));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001460 // Walk the rest of the chain without clobbering cp.
1461 context = next;
1462 }
1463 }
1464 // Check that last extension is NULL.
1465 __ lw(temp, ContextOperand(context, Context::EXTENSION_INDEX));
1466 __ Branch(slow, ne, temp, Operand(zero_reg));
1467
1468 // This function is used only for loads, not stores, so it's safe to
1469 // return an cp-based operand (the write barrier cannot be allowed to
1470 // destroy the cp register).
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001471 return ContextOperand(context, var->index());
lrn@chromium.org7516f052011-03-30 08:52:27 +00001472}
1473
1474
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001475void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1476 TypeofState typeof_state,
1477 Label* slow,
1478 Label* done) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001479 // Generate fast-case code for variables that might be shadowed by
1480 // eval-introduced variables. Eval is used a lot without
1481 // introducing variables. In those cases, we do not want to
1482 // perform a runtime call for all variables in the scope
1483 // containing the eval.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001484 if (var->mode() == DYNAMIC_GLOBAL) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001485 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001486 __ Branch(done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001487 } else if (var->mode() == DYNAMIC_LOCAL) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001488 Variable* local = var->local_if_not_shadowed();
1489 __ lw(v0, ContextSlotOperandCheckExtensions(local, slow));
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001490 if (local->mode() == LET || local->mode() == CONST ||
1491 local->mode() == CONST_LEGACY) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001492 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
1493 __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001494 if (local->mode() == CONST_LEGACY) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001495 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001496 __ Movz(v0, a0, at); // Conditional move: return Undefined if TheHole.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001497 } else { // LET || CONST
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001498 __ Branch(done, ne, at, Operand(zero_reg));
1499 __ li(a0, Operand(var->name()));
1500 __ push(a0);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001501 __ CallRuntime(Runtime::kHiddenThrowReferenceError, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001502 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001503 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001504 __ Branch(done);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001505 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001506}
1507
1508
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001509void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1510 // Record position before possible IC call.
1511 SetSourcePosition(proxy->position());
1512 Variable* var = proxy->var();
1513
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001514 // Three cases: global variables, lookup variables, and all other types of
1515 // variables.
1516 switch (var->location()) {
1517 case Variable::UNALLOCATED: {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00001518 Comment cmnt(masm_, "[ Global variable");
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001519 // Use inline caching. Variable name is passed in a2 and the global
1520 // object (receiver) in a0.
1521 __ lw(a0, GlobalObjectOperand());
1522 __ li(a2, Operand(var->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00001523 CallLoadIC(CONTEXTUAL);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001524 context()->Plug(v0);
1525 break;
1526 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001527
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001528 case Variable::PARAMETER:
1529 case Variable::LOCAL:
1530 case Variable::CONTEXT: {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00001531 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1532 : "[ Stack variable");
danno@chromium.orgc612e022011-11-10 11:38:15 +00001533 if (var->binding_needs_init()) {
1534 // var->scope() may be NULL when the proxy is located in eval code and
1535 // refers to a potential outside binding. Currently those bindings are
1536 // always looked up dynamically, i.e. in that case
1537 // var->location() == LOOKUP.
1538 // always holds.
1539 ASSERT(var->scope() != NULL);
1540
1541 // Check if the binding really needs an initialization check. The check
1542 // can be skipped in the following situation: we have a LET or CONST
1543 // binding in harmony mode, both the Variable and the VariableProxy have
1544 // the same declaration scope (i.e. they are both in global code, in the
1545 // same function or in the same eval code) and the VariableProxy is in
1546 // the source physically located after the initializer of the variable.
1547 //
1548 // We cannot skip any initialization checks for CONST in non-harmony
1549 // mode because const variables may be declared but never initialized:
1550 // if (false) { const x; }; var y = x;
1551 //
1552 // The condition on the declaration scopes is a conservative check for
1553 // nested functions that access a binding and are called before the
1554 // binding is initialized:
1555 // function() { f(); let x = 1; function f() { x = 2; } }
1556 //
1557 bool skip_init_check;
1558 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1559 skip_init_check = false;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001560 } else {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001561 // Check that we always have valid source position.
1562 ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1563 ASSERT(proxy->position() != RelocInfo::kNoPosition);
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001564 skip_init_check = var->mode() != CONST_LEGACY &&
danno@chromium.orgc612e022011-11-10 11:38:15 +00001565 var->initializer_position() < proxy->position();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001566 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001567
1568 if (!skip_init_check) {
1569 // Let and const need a read barrier.
1570 GetVar(v0, var);
1571 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
1572 __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001573 if (var->mode() == LET || var->mode() == CONST) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001574 // Throw a reference error when using an uninitialized let/const
1575 // binding in harmony mode.
1576 Label done;
1577 __ Branch(&done, ne, at, Operand(zero_reg));
1578 __ li(a0, Operand(var->name()));
1579 __ push(a0);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001580 __ CallRuntime(Runtime::kHiddenThrowReferenceError, 1);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001581 __ bind(&done);
1582 } else {
1583 // Uninitalized const bindings outside of harmony mode are unholed.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00001584 ASSERT(var->mode() == CONST_LEGACY);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001585 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001586 __ Movz(v0, a0, at); // Conditional move: Undefined if TheHole.
danno@chromium.orgc612e022011-11-10 11:38:15 +00001587 }
1588 context()->Plug(v0);
1589 break;
1590 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001591 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001592 context()->Plug(var);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001593 break;
1594 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001595
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001596 case Variable::LOOKUP: {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00001597 Comment cmnt(masm_, "[ Lookup variable");
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001598 Label done, slow;
1599 // Generate code for loading from variables potentially shadowed
1600 // by eval-introduced variables.
1601 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1602 __ bind(&slow);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001603 __ li(a1, Operand(var->name()));
1604 __ Push(cp, a1); // Context and name.
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001605 __ CallRuntime(Runtime::kHiddenLoadContextSlot, 2);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001606 __ bind(&done);
1607 context()->Plug(v0);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001608 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001609 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001610}
1611
1612
1613void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001614 Comment cmnt(masm_, "[ RegExpLiteral");
1615 Label materialized;
1616 // Registers will be used as follows:
1617 // t1 = materialized value (RegExp literal)
1618 // t0 = JS function, literals array
1619 // a3 = literal index
1620 // a2 = RegExp pattern
1621 // a1 = RegExp flags
1622 // a0 = RegExp literal clone
1623 __ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1624 __ lw(t0, FieldMemOperand(a0, JSFunction::kLiteralsOffset));
1625 int literal_offset =
1626 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
1627 __ lw(t1, FieldMemOperand(t0, literal_offset));
1628 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
1629 __ Branch(&materialized, ne, t1, Operand(at));
1630
1631 // Create regexp literal using runtime function.
1632 // Result will be in v0.
1633 __ li(a3, Operand(Smi::FromInt(expr->literal_index())));
1634 __ li(a2, Operand(expr->pattern()));
1635 __ li(a1, Operand(expr->flags()));
1636 __ Push(t0, a3, a2, a1);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001637 __ CallRuntime(Runtime::kHiddenMaterializeRegExpLiteral, 4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001638 __ mov(t1, v0);
1639
1640 __ bind(&materialized);
1641 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1642 Label allocated, runtime_allocate;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00001643 __ Allocate(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001644 __ jmp(&allocated);
1645
1646 __ bind(&runtime_allocate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001647 __ li(a0, Operand(Smi::FromInt(size)));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001648 __ Push(t1, a0);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001649 __ CallRuntime(Runtime::kHiddenAllocateInNewSpace, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001650 __ pop(t1);
1651
1652 __ bind(&allocated);
1653
1654 // After this, registers are used as follows:
1655 // v0: Newly allocated regexp.
1656 // t1: Materialized regexp.
1657 // a2: temp.
1658 __ CopyFields(v0, t1, a2.bit(), size / kPointerSize);
1659 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001660}
1661
1662
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001663void FullCodeGenerator::EmitAccessor(Expression* expression) {
1664 if (expression == NULL) {
1665 __ LoadRoot(a1, Heap::kNullValueRootIndex);
1666 __ push(a1);
1667 } else {
1668 VisitForStackValue(expression);
1669 }
1670}
1671
1672
ager@chromium.org5c838252010-02-19 08:53:10 +00001673void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001674 Comment cmnt(masm_, "[ ObjectLiteral");
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001675
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001676 expr->BuildConstantProperties(isolate());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001677 Handle<FixedArray> constant_properties = expr->constant_properties();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001678 __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001679 __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
1680 __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001681 __ li(a1, Operand(constant_properties));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001682 int flags = expr->fast_elements()
1683 ? ObjectLiteral::kFastElements
1684 : ObjectLiteral::kNoFlags;
1685 flags |= expr->has_function()
1686 ? ObjectLiteral::kHasFunction
1687 : ObjectLiteral::kNoFlags;
1688 __ li(a0, Operand(Smi::FromInt(flags)));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001689 int properties_count = constant_properties->length() / 2;
titzer@chromium.orgbc176052014-03-05 15:10:53 +00001690 if (expr->may_store_doubles() || expr->depth() > 1 || Serializer::enabled() ||
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001691 flags != ObjectLiteral::kFastElements ||
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001692 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001693 __ Push(a3, a2, a1, a0);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001694 __ CallRuntime(Runtime::kHiddenCreateObjectLiteral, 4);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001695 } else {
1696 FastCloneShallowObjectStub stub(properties_count);
1697 __ CallStub(&stub);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001698 }
1699
1700 // If result_saved is true the result is on top of the stack. If
1701 // result_saved is false the result is in v0.
1702 bool result_saved = false;
1703
1704 // Mark all computed expressions that are bound to a key that
1705 // is shadowed by a later occurrence of the same key. For the
1706 // marked expressions, no store code is emitted.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001707 expr->CalculateEmitStore(zone());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001708
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001709 AccessorTable accessor_table(zone());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001710 for (int i = 0; i < expr->properties()->length(); i++) {
1711 ObjectLiteral::Property* property = expr->properties()->at(i);
1712 if (property->IsCompileTimeValue()) continue;
1713
1714 Literal* key = property->key();
1715 Expression* value = property->value();
1716 if (!result_saved) {
1717 __ push(v0); // Save result on stack.
1718 result_saved = true;
1719 }
1720 switch (property->kind()) {
1721 case ObjectLiteral::Property::CONSTANT:
1722 UNREACHABLE();
1723 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1724 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
1725 // Fall through.
1726 case ObjectLiteral::Property::COMPUTED:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001727 if (key->value()->IsInternalizedString()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001728 if (property->emit_store()) {
1729 VisitForAccumulatorValue(value);
1730 __ mov(a0, result_register());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001731 __ li(a2, Operand(key->value()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001732 __ lw(a1, MemOperand(sp));
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00001733 CallStoreIC(key->LiteralFeedbackId());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001734 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1735 } else {
1736 VisitForEffect(value);
1737 }
1738 break;
1739 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001740 // Duplicate receiver on stack.
1741 __ lw(a0, MemOperand(sp));
1742 __ push(a0);
1743 VisitForStackValue(key);
1744 VisitForStackValue(value);
1745 if (property->emit_store()) {
1746 __ li(a0, Operand(Smi::FromInt(NONE))); // PropertyAttributes.
1747 __ push(a0);
1748 __ CallRuntime(Runtime::kSetProperty, 4);
1749 } else {
1750 __ Drop(3);
1751 }
1752 break;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001753 case ObjectLiteral::Property::PROTOTYPE:
1754 // Duplicate receiver on stack.
1755 __ lw(a0, MemOperand(sp));
1756 __ push(a0);
1757 VisitForStackValue(value);
1758 if (property->emit_store()) {
1759 __ CallRuntime(Runtime::kSetPrototype, 2);
1760 } else {
1761 __ Drop(2);
1762 }
1763 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001764 case ObjectLiteral::Property::GETTER:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001765 accessor_table.lookup(key)->second->getter = value;
1766 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001767 case ObjectLiteral::Property::SETTER:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001768 accessor_table.lookup(key)->second->setter = value;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001769 break;
1770 }
1771 }
1772
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001773 // Emit code to define accessors, using only a single call to the runtime for
1774 // each pair of corresponding getters and setters.
1775 for (AccessorTable::Iterator it = accessor_table.begin();
1776 it != accessor_table.end();
1777 ++it) {
1778 __ lw(a0, MemOperand(sp)); // Duplicate receiver.
1779 __ push(a0);
1780 VisitForStackValue(it->first);
1781 EmitAccessor(it->second->getter);
1782 EmitAccessor(it->second->setter);
1783 __ li(a0, Operand(Smi::FromInt(NONE)));
1784 __ push(a0);
1785 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
1786 }
1787
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001788 if (expr->has_function()) {
1789 ASSERT(result_saved);
1790 __ lw(a0, MemOperand(sp));
1791 __ push(a0);
1792 __ CallRuntime(Runtime::kToFastProperties, 1);
1793 }
1794
1795 if (result_saved) {
1796 context()->PlugTOS();
1797 } else {
1798 context()->Plug(v0);
1799 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001800}
1801
1802
1803void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001804 Comment cmnt(masm_, "[ ArrayLiteral");
1805
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001806 expr->BuildConstantElements(isolate());
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001807 int flags = expr->depth() == 1
1808 ? ArrayLiteral::kShallowElements
1809 : ArrayLiteral::kNoFlags;
1810
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001811 ZoneList<Expression*>* subexprs = expr->values();
1812 int length = subexprs->length();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001813
1814 Handle<FixedArray> constant_elements = expr->constant_elements();
1815 ASSERT_EQ(2, constant_elements->length());
1816 ElementsKind constant_elements_kind =
1817 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001818 bool has_fast_elements =
1819 IsFastObjectElementsKind(constant_elements_kind);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001820 Handle<FixedArrayBase> constant_elements_values(
1821 FixedArrayBase::cast(constant_elements->get(1)));
1822
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00001823 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00001824 if (has_fast_elements && !FLAG_allocation_site_pretenuring) {
1825 // If the only customer of allocation sites is transitioning, then
1826 // we can turn it off if we don't have anywhere else to transition to.
1827 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1828 }
1829
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001830 __ mov(a0, result_register());
1831 __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1832 __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
1833 __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001834 __ li(a1, Operand(constant_elements));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001835 if (has_fast_elements && constant_elements_values->map() ==
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001836 isolate()->heap()->fixed_cow_array_map()) {
1837 FastCloneShallowArrayStub stub(
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001838 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00001839 allocation_site_mode,
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001840 length);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001841 __ CallStub(&stub);
1842 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(),
1843 1, a1, a2);
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001844 } else if (expr->depth() > 1 || Serializer::enabled() ||
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001845 length > FastCloneShallowArrayStub::kMaximumClonedLength) {
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001846 __ li(a0, Operand(Smi::FromInt(flags)));
1847 __ Push(a3, a2, a1, a0);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00001848 __ CallRuntime(Runtime::kHiddenCreateArrayLiteral, 4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001849 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001850 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001851 FLAG_smi_only_arrays);
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001852 FastCloneShallowArrayStub::Mode mode =
1853 FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001854
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001855 if (has_fast_elements) {
1856 mode = FastCloneShallowArrayStub::CLONE_ELEMENTS;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001857 }
1858
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001859 FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001860 __ CallStub(&stub);
1861 }
1862
1863 bool result_saved = false; // Is the result saved to the stack?
1864
1865 // Emit code to evaluate all the non-constant subexpressions and to store
1866 // them into the newly cloned array.
1867 for (int i = 0; i < length; i++) {
1868 Expression* subexpr = subexprs->at(i);
1869 // If the subexpression is a literal or a simple materialized literal it
1870 // is already set in the cloned array.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001871 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001872
1873 if (!result_saved) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001874 __ push(v0); // array literal
1875 __ Push(Smi::FromInt(expr->literal_index()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001876 result_saved = true;
1877 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001878
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001879 VisitForAccumulatorValue(subexpr);
1880
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001881 if (IsFastObjectElementsKind(constant_elements_kind)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001882 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001883 __ lw(t2, MemOperand(sp, kPointerSize)); // Copy of array literal.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001884 __ lw(a1, FieldMemOperand(t2, JSObject::kElementsOffset));
1885 __ sw(result_register(), FieldMemOperand(a1, offset));
1886 // Update the write barrier for the array store.
1887 __ RecordWriteField(a1, offset, result_register(), a2,
1888 kRAHasBeenSaved, kDontSaveFPRegs,
1889 EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
1890 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001891 __ li(a3, Operand(Smi::FromInt(i)));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001892 __ mov(a0, result_register());
1893 StoreArrayLiteralElementStub stub;
1894 __ CallStub(&stub);
1895 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001896
1897 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
1898 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001899 if (result_saved) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001900 __ Pop(); // literal index
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001901 context()->PlugTOS();
1902 } else {
1903 context()->Plug(v0);
1904 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001905}
1906
1907
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001908void FullCodeGenerator::VisitAssignment(Assignment* expr) {
machenbach@chromium.orgda0c8282014-04-03 07:05:51 +00001909 ASSERT(expr->target()->IsValidReferenceExpression());
machenbach@chromium.org2904d1a2014-03-18 01:05:18 +00001910
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001911 Comment cmnt(masm_, "[ Assignment");
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001912
1913 // Left-hand side can only be a property, a global or a (parameter or local)
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001914 // slot.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001915 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1916 LhsKind assign_type = VARIABLE;
1917 Property* property = expr->target()->AsProperty();
1918 if (property != NULL) {
1919 assign_type = (property->key()->IsPropertyName())
1920 ? NAMED_PROPERTY
1921 : KEYED_PROPERTY;
1922 }
1923
1924 // Evaluate LHS expression.
1925 switch (assign_type) {
1926 case VARIABLE:
1927 // Nothing to do here.
1928 break;
1929 case NAMED_PROPERTY:
1930 if (expr->is_compound()) {
1931 // We need the receiver both on the stack and in the accumulator.
1932 VisitForAccumulatorValue(property->obj());
1933 __ push(result_register());
1934 } else {
1935 VisitForStackValue(property->obj());
1936 }
1937 break;
1938 case KEYED_PROPERTY:
1939 // We need the key and receiver on both the stack and in v0 and a1.
1940 if (expr->is_compound()) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001941 VisitForStackValue(property->obj());
1942 VisitForAccumulatorValue(property->key());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001943 __ lw(a1, MemOperand(sp, 0));
1944 __ push(v0);
1945 } else {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001946 VisitForStackValue(property->obj());
1947 VisitForStackValue(property->key());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001948 }
1949 break;
1950 }
1951
1952 // For compound assignments we need another deoptimization point after the
1953 // variable/property load.
1954 if (expr->is_compound()) {
1955 { AccumulatorValueContext context(this);
1956 switch (assign_type) {
1957 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001958 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001959 PrepareForBailout(expr->target(), TOS_REG);
1960 break;
1961 case NAMED_PROPERTY:
1962 EmitNamedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001963 PrepareForBailoutForId(property->LoadId(), TOS_REG);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001964 break;
1965 case KEYED_PROPERTY:
1966 EmitKeyedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001967 PrepareForBailoutForId(property->LoadId(), TOS_REG);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001968 break;
1969 }
1970 }
1971
1972 Token::Value op = expr->binary_op();
1973 __ push(v0); // Left operand goes on the stack.
1974 VisitForAccumulatorValue(expr->value());
1975
1976 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1977 ? OVERWRITE_RIGHT
1978 : NO_OVERWRITE;
1979 SetSourcePosition(expr->position() + 1);
1980 AccumulatorValueContext context(this);
1981 if (ShouldInlineSmiCase(op)) {
1982 EmitInlineSmiBinaryOp(expr->binary_operation(),
1983 op,
1984 mode,
1985 expr->target(),
1986 expr->value());
1987 } else {
1988 EmitBinaryOp(expr->binary_operation(), op, mode);
1989 }
1990
1991 // Deoptimization point in case the binary operation may have side effects.
1992 PrepareForBailout(expr->binary_operation(), TOS_REG);
1993 } else {
1994 VisitForAccumulatorValue(expr->value());
1995 }
1996
1997 // Record source position before possible IC call.
1998 SetSourcePosition(expr->position());
1999
2000 // Store the value.
2001 switch (assign_type) {
2002 case VARIABLE:
2003 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
2004 expr->op());
2005 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2006 context()->Plug(v0);
2007 break;
2008 case NAMED_PROPERTY:
2009 EmitNamedPropertyAssignment(expr);
2010 break;
2011 case KEYED_PROPERTY:
2012 EmitKeyedPropertyAssignment(expr);
2013 break;
2014 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002015}
2016
2017
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002018void FullCodeGenerator::VisitYield(Yield* expr) {
2019 Comment cmnt(masm_, "[ Yield");
2020 // Evaluate yielded value first; the initial iterator definition depends on
2021 // this. It stays on the stack while we update the iterator.
2022 VisitForStackValue(expr->expression());
2023
2024 switch (expr->yield_kind()) {
danno@chromium.org41728482013-06-12 22:31:22 +00002025 case Yield::SUSPEND:
2026 // Pop value from top-of-stack slot; box result into result register.
2027 EmitCreateIteratorResult(false);
2028 __ push(result_register());
2029 // Fall through.
2030 case Yield::INITIAL: {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002031 Label suspend, continuation, post_runtime, resume;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002032
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002033 __ jmp(&suspend);
2034
2035 __ bind(&continuation);
2036 __ jmp(&resume);
2037
2038 __ bind(&suspend);
2039 VisitForAccumulatorValue(expr->generator_object());
2040 ASSERT(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
2041 __ li(a1, Operand(Smi::FromInt(continuation.pos())));
2042 __ sw(a1, FieldMemOperand(v0, JSGeneratorObject::kContinuationOffset));
2043 __ sw(cp, FieldMemOperand(v0, JSGeneratorObject::kContextOffset));
2044 __ mov(a1, cp);
2045 __ RecordWriteField(v0, JSGeneratorObject::kContextOffset, a1, a2,
2046 kRAHasBeenSaved, kDontSaveFPRegs);
2047 __ Addu(a1, fp, Operand(StandardFrameConstants::kExpressionsOffset));
2048 __ Branch(&post_runtime, eq, sp, Operand(a1));
2049 __ push(v0); // generator object
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002050 __ CallRuntime(Runtime::kHiddenSuspendJSGeneratorObject, 1);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002051 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2052 __ bind(&post_runtime);
danno@chromium.org41728482013-06-12 22:31:22 +00002053 __ pop(result_register());
2054 EmitReturnSequence();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002055
2056 __ bind(&resume);
2057 context()->Plug(result_register());
2058 break;
2059 }
2060
2061 case Yield::FINAL: {
2062 VisitForAccumulatorValue(expr->generator_object());
2063 __ li(a1, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
2064 __ sw(a1, FieldMemOperand(result_register(),
2065 JSGeneratorObject::kContinuationOffset));
danno@chromium.org41728482013-06-12 22:31:22 +00002066 // Pop value from top-of-stack slot, box result into result register.
2067 EmitCreateIteratorResult(true);
2068 EmitUnwindBeforeReturn();
2069 EmitReturnSequence();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002070 break;
2071 }
2072
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002073 case Yield::DELEGATING: {
2074 VisitForStackValue(expr->generator_object());
2075
2076 // Initial stack layout is as follows:
2077 // [sp + 1 * kPointerSize] iter
2078 // [sp + 0 * kPointerSize] g
2079
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002080 Label l_catch, l_try, l_suspend, l_continuation, l_resume;
2081 Label l_next, l_call, l_loop;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002082 // Initial send value is undefined.
2083 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00002084 __ Branch(&l_next);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002085
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002086 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002087 __ bind(&l_catch);
2088 __ mov(a0, v0);
2089 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002090 __ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw"
2091 __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
2092 __ Push(a2, a3, a0); // "throw", iter, except
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002093 __ jmp(&l_call);
2094
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002095 // try { received = %yield result }
2096 // Shuffle the received result above a try handler and yield it without
2097 // re-boxing.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002098 __ bind(&l_try);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002099 __ pop(a0); // result
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002100 __ PushTryHandler(StackHandler::CATCH, expr->index());
2101 const int handler_size = StackHandlerConstants::kSize;
danno@chromium.org41728482013-06-12 22:31:22 +00002102 __ push(a0); // result
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002103 __ jmp(&l_suspend);
2104 __ bind(&l_continuation);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002105 __ mov(a0, v0);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002106 __ jmp(&l_resume);
2107 __ bind(&l_suspend);
2108 const int generator_object_depth = kPointerSize + handler_size;
2109 __ lw(a0, MemOperand(sp, generator_object_depth));
2110 __ push(a0); // g
2111 ASSERT(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
2112 __ li(a1, Operand(Smi::FromInt(l_continuation.pos())));
2113 __ sw(a1, FieldMemOperand(a0, JSGeneratorObject::kContinuationOffset));
2114 __ sw(cp, FieldMemOperand(a0, JSGeneratorObject::kContextOffset));
2115 __ mov(a1, cp);
2116 __ RecordWriteField(a0, JSGeneratorObject::kContextOffset, a1, a2,
2117 kRAHasBeenSaved, kDontSaveFPRegs);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002118 __ CallRuntime(Runtime::kHiddenSuspendJSGeneratorObject, 1);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002119 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002120 __ pop(v0); // result
danno@chromium.org41728482013-06-12 22:31:22 +00002121 EmitReturnSequence();
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002122 __ mov(a0, v0);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002123 __ bind(&l_resume); // received in a0
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002124 __ PopTryHandler();
2125
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002126 // receiver = iter; f = 'next'; arg = received;
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00002127 __ bind(&l_next);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002128 __ LoadRoot(a2, Heap::knext_stringRootIndex); // "next"
2129 __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
2130 __ Push(a2, a3, a0); // "next", iter, received
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002131
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002132 // result = receiver[f](arg);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002133 __ bind(&l_call);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002134 __ lw(a1, MemOperand(sp, kPointerSize));
2135 __ lw(a0, MemOperand(sp, 2 * kPointerSize));
2136 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002137 CallIC(ic, TypeFeedbackId::None());
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002138 __ mov(a0, v0);
2139 __ mov(a1, a0);
2140 __ sw(a1, MemOperand(sp, 2 * kPointerSize));
2141 CallFunctionStub stub(1, CALL_AS_METHOD);
2142 __ CallStub(&stub);
2143
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002144 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002145 __ Drop(1); // The function is still on the stack; drop it.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002146
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002147 // if (!result.done) goto l_try;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002148 __ bind(&l_loop);
2149 __ mov(a0, v0);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002150 __ push(a0); // save result
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002151 __ LoadRoot(a2, Heap::kdone_stringRootIndex); // "done"
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002152 CallLoadIC(NOT_CONTEXTUAL); // result.done in v0
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002153 __ mov(a0, v0);
2154 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
2155 CallIC(bool_ic);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002156 __ Branch(&l_try, eq, v0, Operand(zero_reg));
2157
2158 // result.value
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002159 __ pop(a0); // result
2160 __ LoadRoot(a2, Heap::kvalue_stringRootIndex); // "value"
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002161 CallLoadIC(NOT_CONTEXTUAL); // result.value in v0
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002162 context()->DropAndPlug(2, v0); // drop iter and g
2163 break;
2164 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002165 }
2166}
2167
2168
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002169void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
2170 Expression *value,
2171 JSGeneratorObject::ResumeMode resume_mode) {
2172 // The value stays in a0, and is ultimately read by the resumed generator, as
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002173 // if CallRuntime(Runtime::kHiddenSuspendJSGeneratorObject) returned it. Or it
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002174 // is read to throw the value when the resumed generator is already closed.
2175 // a1 will hold the generator object until the activation has been resumed.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002176 VisitForStackValue(generator);
2177 VisitForAccumulatorValue(value);
2178 __ pop(a1);
2179
2180 // Check generator state.
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002181 Label wrong_state, closed_state, done;
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002182 __ lw(a3, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset));
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002183 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
2184 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
2185 __ Branch(&closed_state, eq, a3, Operand(zero_reg));
2186 __ Branch(&wrong_state, lt, a3, Operand(zero_reg));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002187
2188 // Load suspended function and context.
2189 __ lw(cp, FieldMemOperand(a1, JSGeneratorObject::kContextOffset));
2190 __ lw(t0, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset));
2191
2192 // Load receiver and store as the first argument.
2193 __ lw(a2, FieldMemOperand(a1, JSGeneratorObject::kReceiverOffset));
2194 __ push(a2);
2195
2196 // Push holes for the rest of the arguments to the generator function.
2197 __ lw(a3, FieldMemOperand(t0, JSFunction::kSharedFunctionInfoOffset));
2198 __ lw(a3,
2199 FieldMemOperand(a3, SharedFunctionInfo::kFormalParameterCountOffset));
2200 __ LoadRoot(a2, Heap::kTheHoleValueRootIndex);
2201 Label push_argument_holes, push_frame;
2202 __ bind(&push_argument_holes);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002203 __ Subu(a3, a3, Operand(Smi::FromInt(1)));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002204 __ Branch(&push_frame, lt, a3, Operand(zero_reg));
2205 __ push(a2);
2206 __ jmp(&push_argument_holes);
2207
2208 // Enter a new JavaScript frame, and initialize its slots as they were when
2209 // the generator was suspended.
2210 Label resume_frame;
2211 __ bind(&push_frame);
2212 __ Call(&resume_frame);
2213 __ jmp(&done);
2214 __ bind(&resume_frame);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002215 // ra = return address.
2216 // fp = caller's frame pointer.
2217 // cp = callee's context,
2218 // t0 = callee's JS function.
2219 __ Push(ra, fp, cp, t0);
2220 // Adjust FP to point to saved FP.
2221 __ Addu(fp, sp, 2 * kPointerSize);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002222
2223 // Load the operand stack size.
2224 __ lw(a3, FieldMemOperand(a1, JSGeneratorObject::kOperandStackOffset));
2225 __ lw(a3, FieldMemOperand(a3, FixedArray::kLengthOffset));
2226 __ SmiUntag(a3);
2227
2228 // If we are sending a value and there is no operand stack, we can jump back
2229 // in directly.
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00002230 if (resume_mode == JSGeneratorObject::NEXT) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002231 Label slow_resume;
2232 __ Branch(&slow_resume, ne, a3, Operand(zero_reg));
2233 __ lw(a3, FieldMemOperand(t0, JSFunction::kCodeEntryOffset));
2234 __ lw(a2, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset));
2235 __ SmiUntag(a2);
2236 __ Addu(a3, a3, Operand(a2));
2237 __ li(a2, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
2238 __ sw(a2, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset));
2239 __ Jump(a3);
2240 __ bind(&slow_resume);
2241 }
2242
2243 // Otherwise, we push holes for the operand stack and call the runtime to fix
2244 // up the stack and the handlers.
2245 Label push_operand_holes, call_resume;
2246 __ bind(&push_operand_holes);
2247 __ Subu(a3, a3, Operand(1));
2248 __ Branch(&call_resume, lt, a3, Operand(zero_reg));
2249 __ push(a2);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002250 __ Branch(&push_operand_holes);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002251 __ bind(&call_resume);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002252 ASSERT(!result_register().is(a1));
2253 __ Push(a1, result_register());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002254 __ Push(Smi::FromInt(resume_mode));
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002255 __ CallRuntime(Runtime::kHiddenResumeJSGeneratorObject, 3);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002256 // Not reached: the runtime call returns elsewhere.
2257 __ stop("not-reached");
2258
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002259 // Reach here when generator is closed.
2260 __ bind(&closed_state);
2261 if (resume_mode == JSGeneratorObject::NEXT) {
2262 // Return completed iterator result when generator is closed.
2263 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
2264 __ push(a2);
2265 // Pop value from top-of-stack slot; box result into result register.
2266 EmitCreateIteratorResult(true);
2267 } else {
2268 // Throw the provided value.
2269 __ push(a0);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002270 __ CallRuntime(Runtime::kHiddenThrow, 1);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002271 }
2272 __ jmp(&done);
2273
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002274 // Throw error if we attempt to operate on a running generator.
2275 __ bind(&wrong_state);
2276 __ push(a1);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002277 __ CallRuntime(Runtime::kHiddenThrowGeneratorStateError, 1);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002278
2279 __ bind(&done);
2280 context()->Plug(result_register());
2281}
2282
2283
danno@chromium.org41728482013-06-12 22:31:22 +00002284void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002285 Label gc_required;
2286 Label allocated;
2287
2288 Handle<Map> map(isolate()->native_context()->generator_result_map());
2289
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002290 __ Allocate(map->instance_size(), v0, a2, a3, &gc_required, TAG_OBJECT);
danno@chromium.org41728482013-06-12 22:31:22 +00002291 __ jmp(&allocated);
2292
2293 __ bind(&gc_required);
2294 __ Push(Smi::FromInt(map->instance_size()));
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002295 __ CallRuntime(Runtime::kHiddenAllocateInNewSpace, 1);
danno@chromium.org41728482013-06-12 22:31:22 +00002296 __ lw(context_register(),
2297 MemOperand(fp, StandardFrameConstants::kContextOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002298
2299 __ bind(&allocated);
2300 __ li(a1, Operand(map));
2301 __ pop(a2);
2302 __ li(a3, Operand(isolate()->factory()->ToBoolean(done)));
2303 __ li(t0, Operand(isolate()->factory()->empty_fixed_array()));
2304 ASSERT_EQ(map->instance_size(), 5 * kPointerSize);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002305 __ sw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
2306 __ sw(t0, FieldMemOperand(v0, JSObject::kPropertiesOffset));
2307 __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002308 __ sw(a2,
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002309 FieldMemOperand(v0, JSGeneratorObject::kResultValuePropertyOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002310 __ sw(a3,
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002311 FieldMemOperand(v0, JSGeneratorObject::kResultDonePropertyOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002312
2313 // Only the value field needs a write barrier, as the other values are in the
2314 // root set.
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002315 __ RecordWriteField(v0, JSGeneratorObject::kResultValuePropertyOffset,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002316 a2, a3, kRAHasBeenSaved, kDontSaveFPRegs);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002317}
2318
2319
ager@chromium.org5c838252010-02-19 08:53:10 +00002320void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002321 SetSourcePosition(prop->position());
2322 Literal* key = prop->key()->AsLiteral();
2323 __ mov(a0, result_register());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002324 __ li(a2, Operand(key->value()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002325 // Call load IC. It has arguments receiver and property name a0 and a2.
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002326 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
ager@chromium.org5c838252010-02-19 08:53:10 +00002327}
2328
2329
2330void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002331 SetSourcePosition(prop->position());
2332 __ mov(a0, result_register());
2333 // Call keyed load IC. It has arguments key and receiver in a0 and a1.
2334 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002335 CallIC(ic, prop->PropertyFeedbackId());
ager@chromium.org5c838252010-02-19 08:53:10 +00002336}
2337
2338
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002339void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002340 Token::Value op,
2341 OverwriteMode mode,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002342 Expression* left_expr,
2343 Expression* right_expr) {
2344 Label done, smi_case, stub_call;
2345
2346 Register scratch1 = a2;
2347 Register scratch2 = a3;
2348
2349 // Get the arguments.
2350 Register left = a1;
2351 Register right = a0;
2352 __ pop(left);
2353 __ mov(a0, result_register());
2354
2355 // Perform combined smi check on both operands.
2356 __ Or(scratch1, left, Operand(right));
2357 STATIC_ASSERT(kSmiTag == 0);
2358 JumpPatchSite patch_site(masm_);
2359 patch_site.EmitJumpIfSmi(scratch1, &smi_case);
2360
2361 __ bind(&stub_call);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002362 BinaryOpICStub stub(op, mode);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002363 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002364 patch_site.EmitPatchInfo();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002365 __ jmp(&done);
2366
2367 __ bind(&smi_case);
2368 // Smi case. This code works the same way as the smi-smi case in the type
2369 // recording binary operation stub, see
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002370 switch (op) {
2371 case Token::SAR:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002372 __ GetLeastBitsFromSmi(scratch1, right, 5);
2373 __ srav(right, left, scratch1);
2374 __ And(v0, right, Operand(~kSmiTagMask));
2375 break;
2376 case Token::SHL: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002377 __ SmiUntag(scratch1, left);
2378 __ GetLeastBitsFromSmi(scratch2, right, 5);
2379 __ sllv(scratch1, scratch1, scratch2);
2380 __ Addu(scratch2, scratch1, Operand(0x40000000));
2381 __ Branch(&stub_call, lt, scratch2, Operand(zero_reg));
2382 __ SmiTag(v0, scratch1);
2383 break;
2384 }
2385 case Token::SHR: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002386 __ SmiUntag(scratch1, left);
2387 __ GetLeastBitsFromSmi(scratch2, right, 5);
2388 __ srlv(scratch1, scratch1, scratch2);
2389 __ And(scratch2, scratch1, 0xc0000000);
2390 __ Branch(&stub_call, ne, scratch2, Operand(zero_reg));
2391 __ SmiTag(v0, scratch1);
2392 break;
2393 }
2394 case Token::ADD:
2395 __ AdduAndCheckForOverflow(v0, left, right, scratch1);
2396 __ BranchOnOverflow(&stub_call, scratch1);
2397 break;
2398 case Token::SUB:
2399 __ SubuAndCheckForOverflow(v0, left, right, scratch1);
2400 __ BranchOnOverflow(&stub_call, scratch1);
2401 break;
2402 case Token::MUL: {
2403 __ SmiUntag(scratch1, right);
2404 __ Mult(left, scratch1);
2405 __ mflo(scratch1);
2406 __ mfhi(scratch2);
2407 __ sra(scratch1, scratch1, 31);
2408 __ Branch(&stub_call, ne, scratch1, Operand(scratch2));
2409 __ mflo(v0);
2410 __ Branch(&done, ne, v0, Operand(zero_reg));
2411 __ Addu(scratch2, right, left);
2412 __ Branch(&stub_call, lt, scratch2, Operand(zero_reg));
2413 ASSERT(Smi::FromInt(0) == 0);
2414 __ mov(v0, zero_reg);
2415 break;
2416 }
2417 case Token::BIT_OR:
2418 __ Or(v0, left, Operand(right));
2419 break;
2420 case Token::BIT_AND:
2421 __ And(v0, left, Operand(right));
2422 break;
2423 case Token::BIT_XOR:
2424 __ Xor(v0, left, Operand(right));
2425 break;
2426 default:
2427 UNREACHABLE();
2428 }
2429
2430 __ bind(&done);
2431 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002432}
2433
2434
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002435void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
2436 Token::Value op,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002437 OverwriteMode mode) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002438 __ mov(a0, result_register());
2439 __ pop(a1);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002440 BinaryOpICStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002441 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002442 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002443 patch_site.EmitPatchInfo();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002444 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002445}
2446
2447
ulan@chromium.org812308e2012-02-29 15:58:45 +00002448void FullCodeGenerator::EmitAssignment(Expression* expr) {
machenbach@chromium.orgda0c8282014-04-03 07:05:51 +00002449 ASSERT(expr->IsValidReferenceExpression());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002450
2451 // Left-hand side can only be a property, a global or a (parameter or local)
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002452 // slot.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002453 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2454 LhsKind assign_type = VARIABLE;
2455 Property* prop = expr->AsProperty();
2456 if (prop != NULL) {
2457 assign_type = (prop->key()->IsPropertyName())
2458 ? NAMED_PROPERTY
2459 : KEYED_PROPERTY;
2460 }
2461
2462 switch (assign_type) {
2463 case VARIABLE: {
2464 Variable* var = expr->AsVariableProxy()->var();
2465 EffectContext context(this);
2466 EmitVariableAssignment(var, Token::ASSIGN);
2467 break;
2468 }
2469 case NAMED_PROPERTY: {
2470 __ push(result_register()); // Preserve value.
2471 VisitForAccumulatorValue(prop->obj());
2472 __ mov(a1, result_register());
2473 __ pop(a0); // Restore value.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002474 __ li(a2, Operand(prop->key()->AsLiteral()->value()));
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002475 CallStoreIC();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002476 break;
2477 }
2478 case KEYED_PROPERTY: {
2479 __ push(result_register()); // Preserve value.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002480 VisitForStackValue(prop->obj());
2481 VisitForAccumulatorValue(prop->key());
2482 __ mov(a1, result_register());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002483 __ Pop(a0, a2); // a0 = restored value.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002484 Handle<Code> ic = strict_mode() == SLOPPY
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002485 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2486 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002487 CallIC(ic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002488 break;
2489 }
2490 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002491 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00002492}
2493
2494
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002495void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2496 Variable* var, MemOperand location) {
2497 __ sw(result_register(), location);
2498 if (var->IsContextSlot()) {
2499 // RecordWrite may destroy all its register arguments.
2500 __ Move(a3, result_register());
2501 int offset = Context::SlotOffset(var->index());
2502 __ RecordWriteContextSlot(
2503 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs);
2504 }
2505}
2506
2507
2508void FullCodeGenerator::EmitCallStoreContextSlot(
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002509 Handle<String> name, StrictMode strict_mode) {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002510 __ li(a1, Operand(name));
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002511 __ li(a0, Operand(Smi::FromInt(strict_mode)));
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002512 __ Push(v0, cp, a1, a0); // Value, context, name, strict mode.
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002513 __ CallRuntime(Runtime::kHiddenStoreContextSlot, 4);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002514}
2515
2516
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002517void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002518 if (var->IsUnallocated()) {
2519 // Global var, const, or let.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002520 __ mov(a0, result_register());
2521 __ li(a2, Operand(var->name()));
2522 __ lw(a1, GlobalObjectOperand());
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002523 CallStoreIC();
2524
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002525 } else if (op == Token::INIT_CONST_LEGACY) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002526 // Const initializers need a write barrier.
2527 ASSERT(!var->IsParameter()); // No const parameters.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002528 if (var->IsLookupSlot()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002529 __ li(a0, Operand(var->name()));
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +00002530 __ Push(v0, cp, a0); // Context and name.
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002531 __ CallRuntime(Runtime::kHiddenInitializeConstContextSlot, 3);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002532 } else {
2533 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
2534 Label skip;
2535 MemOperand location = VarOperand(var, a1);
2536 __ lw(a2, location);
2537 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2538 __ Branch(&skip, ne, a2, Operand(at));
2539 EmitStoreToStackLocalOrContextSlot(var, location);
2540 __ bind(&skip);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002541 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002542
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002543 } else if (var->mode() == LET && op != Token::INIT_LET) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002544 // Non-initializing assignment to let variable needs a write barrier.
2545 if (var->IsLookupSlot()) {
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002546 EmitCallStoreContextSlot(var->name(), strict_mode());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002547 } else {
2548 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
2549 Label assign;
2550 MemOperand location = VarOperand(var, a1);
2551 __ lw(a3, location);
2552 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
2553 __ Branch(&assign, ne, a3, Operand(t0));
2554 __ li(a3, Operand(var->name()));
2555 __ push(a3);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002556 __ CallRuntime(Runtime::kHiddenThrowReferenceError, 1);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002557 // Perform the assignment.
2558 __ bind(&assign);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002559 EmitStoreToStackLocalOrContextSlot(var, location);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002560 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002561
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002562 } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002563 // Assignment to var or initializing assignment to let/const
2564 // in harmony mode.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002565 if (var->IsLookupSlot()) {
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002566 EmitCallStoreContextSlot(var->name(), strict_mode());
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002567 } else {
2568 ASSERT((var->IsStackAllocated() || var->IsContextSlot()));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002569 MemOperand location = VarOperand(var, a1);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002570 if (generate_debug_code_ && op == Token::INIT_LET) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002571 // Check for an uninitialized let binding.
2572 __ lw(a2, location);
2573 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
danno@chromium.org59400602013-08-13 17:09:37 +00002574 __ Check(eq, kLetBindingReInitialization, a2, Operand(t0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002575 }
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002576 EmitStoreToStackLocalOrContextSlot(var, location);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002577 }
2578 }
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002579 // Non-initializing assignments to consts are ignored.
ager@chromium.org5c838252010-02-19 08:53:10 +00002580}
2581
2582
2583void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002584 // Assignment to a property, using a named store IC.
2585 Property* prop = expr->target()->AsProperty();
2586 ASSERT(prop != NULL);
2587 ASSERT(prop->key()->AsLiteral() != NULL);
2588
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002589 // Record source code position before IC call.
2590 SetSourcePosition(expr->position());
2591 __ mov(a0, result_register()); // Load the value.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002592 __ li(a2, Operand(prop->key()->AsLiteral()->value()));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002593 __ pop(a1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002594
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002595 CallStoreIC(expr->AssignmentFeedbackId());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002596
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002597 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2598 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00002599}
2600
2601
2602void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002603 // Assignment to a property, using a keyed store IC.
2604
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002605 // Record source code position before IC call.
2606 SetSourcePosition(expr->position());
2607 // Call keyed store IC.
2608 // The arguments are:
2609 // - a0 is the value,
2610 // - a1 is the key,
2611 // - a2 is the receiver.
2612 __ mov(a0, result_register());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002613 __ Pop(a2, a1); // a1 = key.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002614
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002615 Handle<Code> ic = strict_mode() == SLOPPY
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002616 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2617 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002618 CallIC(ic, expr->AssignmentFeedbackId());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002619
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002620 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2621 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00002622}
2623
2624
2625void FullCodeGenerator::VisitProperty(Property* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002626 Comment cmnt(masm_, "[ Property");
2627 Expression* key = expr->key();
2628
2629 if (key->IsPropertyName()) {
2630 VisitForAccumulatorValue(expr->obj());
2631 EmitNamedPropertyLoad(expr);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002632 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002633 context()->Plug(v0);
2634 } else {
2635 VisitForStackValue(expr->obj());
2636 VisitForAccumulatorValue(expr->key());
2637 __ pop(a1);
2638 EmitKeyedPropertyLoad(expr);
2639 context()->Plug(v0);
2640 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002641}
2642
lrn@chromium.org7516f052011-03-30 08:52:27 +00002643
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002644void FullCodeGenerator::CallIC(Handle<Code> code,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002645 TypeFeedbackId id) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002646 ic_total_count_++;
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002647 __ Call(code, RelocInfo::CODE_TARGET, id);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002648}
2649
2650
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002651// Code common for calls using the IC.
2652void FullCodeGenerator::EmitCallWithIC(Call* expr) {
2653 Expression* callee = expr->expression();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002654 ZoneList<Expression*>* args = expr->arguments();
2655 int arg_count = args->length();
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002656
2657 CallFunctionFlags flags;
2658 // Get the target function.
2659 if (callee->IsVariableProxy()) {
2660 { StackValueContext context(this);
2661 EmitVariableLoad(callee->AsVariableProxy());
2662 PrepareForBailout(callee, NO_REGISTERS);
2663 }
2664 // Push undefined as receiver. This is patched in the method prologue if it
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002665 // is a sloppy mode method.
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002666 __ Push(isolate()->factory()->undefined_value());
2667 flags = NO_CALL_FUNCTION_FLAGS;
2668 } else {
2669 // Load the function from the receiver.
2670 ASSERT(callee->IsProperty());
2671 __ lw(v0, MemOperand(sp, 0));
2672 EmitNamedPropertyLoad(callee->AsProperty());
2673 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2674 // Push the target function under the receiver.
2675 __ lw(at, MemOperand(sp, 0));
2676 __ push(at);
2677 __ sw(v0, MemOperand(sp, kPointerSize));
2678 flags = CALL_AS_METHOD;
2679 }
2680
2681 // Load the arguments.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002682 { PreservePositionScope scope(masm()->positions_recorder());
2683 for (int i = 0; i < arg_count; i++) {
2684 VisitForStackValue(args->at(i));
2685 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002686 }
2687 // Record source position for debugger.
2688 SetSourcePosition(expr->position());
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002689 CallFunctionStub stub(arg_count, flags);
2690 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2691 __ CallStub(&stub);
2692
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002693 RecordJSReturnSite(expr);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002694
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002695 // Restore context register.
2696 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002697
2698 context()->DropAndPlug(1, v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00002699}
2700
2701
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002702// Code common for calls using the IC.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002703void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002704 Expression* key) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002705 // Load the key.
2706 VisitForAccumulatorValue(key);
2707
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002708 Expression* callee = expr->expression();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002709 ZoneList<Expression*>* args = expr->arguments();
2710 int arg_count = args->length();
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002711
2712 // Load the function from the receiver.
2713 ASSERT(callee->IsProperty());
2714 __ lw(a1, MemOperand(sp, 0));
2715 EmitKeyedPropertyLoad(callee->AsProperty());
2716 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2717
2718 // Push the target function under the receiver.
2719 __ lw(at, MemOperand(sp, 0));
2720 __ push(at);
2721 __ sw(v0, MemOperand(sp, kPointerSize));
2722
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002723 { PreservePositionScope scope(masm()->positions_recorder());
2724 for (int i = 0; i < arg_count; i++) {
2725 VisitForStackValue(args->at(i));
2726 }
2727 }
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002728
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002729 // Record source position for debugger.
2730 SetSourcePosition(expr->position());
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002731 CallFunctionStub stub(arg_count, CALL_AS_METHOD);
2732 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2733 __ CallStub(&stub);
2734
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002735 RecordJSReturnSite(expr);
2736 // Restore context register.
2737 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002738
2739 context()->DropAndPlug(1, v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002740}
2741
2742
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002743void FullCodeGenerator::EmitCallWithStub(Call* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002744 // Code common for calls using the call stub.
2745 ZoneList<Expression*>* args = expr->arguments();
2746 int arg_count = args->length();
2747 { PreservePositionScope scope(masm()->positions_recorder());
2748 for (int i = 0; i < arg_count; i++) {
2749 VisitForStackValue(args->at(i));
2750 }
2751 }
2752 // Record source position for debugger.
2753 SetSourcePosition(expr->position());
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002754
machenbach@chromium.org8545d492014-03-17 09:28:03 +00002755 Handle<Object> uninitialized =
2756 TypeFeedbackInfo::UninitializedSentinel(isolate());
2757 StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002758 __ li(a2, FeedbackVector());
2759 __ li(a3, Operand(Smi::FromInt(expr->CallFeedbackSlot())));
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002760
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002761 // Record call targets in unoptimized code.
2762 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002763 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002764 __ CallStub(&stub);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002765 RecordJSReturnSite(expr);
2766 // Restore context register.
2767 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2768 context()->DropAndPlug(1, v0);
2769}
2770
2771
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002772void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002773 // t2: copy of the first argument or undefined if it doesn't exist.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002774 if (arg_count > 0) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002775 __ lw(t2, MemOperand(sp, arg_count * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002776 } else {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002777 __ LoadRoot(t2, Heap::kUndefinedValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002778 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002779
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002780 // t1: the receiver of the enclosing function.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002781 int receiver_offset = 2 + info_->scope()->num_parameters();
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002782 __ lw(t1, MemOperand(fp, receiver_offset * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002783
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002784 // t0: the strict mode.
2785 __ li(t0, Operand(Smi::FromInt(strict_mode())));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002786
2787 // a1: the start position of the scope the calls resides in.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002788 __ li(a1, Operand(Smi::FromInt(scope()->start_position())));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002789
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002790 // Do the runtime call.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002791 __ Push(t2, t1, t0, a1);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002792 __ CallRuntime(Runtime::kHiddenResolvePossiblyDirectEval, 5);
ager@chromium.org5c838252010-02-19 08:53:10 +00002793}
2794
2795
2796void FullCodeGenerator::VisitCall(Call* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002797#ifdef DEBUG
2798 // We want to verify that RecordJSReturnSite gets called on all paths
2799 // through this function. Avoid early returns.
2800 expr->return_is_recorded_ = false;
2801#endif
2802
2803 Comment cmnt(masm_, "[ Call");
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002804 Expression* callee = expr->expression();
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002805 Call::CallType call_type = expr->GetCallType(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002806
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002807 if (call_type == Call::POSSIBLY_EVAL_CALL) {
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002808 // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
2809 // to resolve the function we need to call and the receiver of the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002810 // call. Then we call the resolved function using the given
2811 // arguments.
2812 ZoneList<Expression*>* args = expr->arguments();
2813 int arg_count = args->length();
2814
2815 { PreservePositionScope pos_scope(masm()->positions_recorder());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002816 VisitForStackValue(callee);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002817 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
2818 __ push(a2); // Reserved receiver slot.
2819
2820 // Push the arguments.
2821 for (int i = 0; i < arg_count; i++) {
2822 VisitForStackValue(args->at(i));
2823 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002824
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002825 // Push a copy of the function (found below the arguments) and
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002826 // resolve eval.
2827 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2828 __ push(a1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002829 EmitResolvePossiblyDirectEval(arg_count);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002830
2831 // The runtime call returns a pair of values in v0 (function) and
2832 // v1 (receiver). Touch up the stack with the right values.
2833 __ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
2834 __ sw(v1, MemOperand(sp, arg_count * kPointerSize));
2835 }
2836 // Record source position for debugger.
2837 SetSourcePosition(expr->position());
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002838 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002839 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002840 __ CallStub(&stub);
2841 RecordJSReturnSite(expr);
2842 // Restore context register.
2843 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2844 context()->DropAndPlug(1, v0);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002845 } else if (call_type == Call::GLOBAL_CALL) {
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002846 EmitCallWithIC(expr);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002847 } else if (call_type == Call::LOOKUP_SLOT_CALL) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002848 // Call to a lookup slot (dynamically introduced variable).
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002849 VariableProxy* proxy = callee->AsVariableProxy();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002850 Label slow, done;
2851
2852 { PreservePositionScope scope(masm()->positions_recorder());
2853 // Generate code for loading from variables potentially shadowed
2854 // by eval-introduced variables.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002855 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002856 }
2857
2858 __ bind(&slow);
2859 // Call the runtime to find the function to call (returned in v0)
2860 // and the object holding it (returned in v1).
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002861 ASSERT(!context_register().is(a2));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002862 __ li(a2, Operand(proxy->name()));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002863 __ Push(context_register(), a2);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002864 __ CallRuntime(Runtime::kHiddenLoadContextSlot, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002865 __ Push(v0, v1); // Function, receiver.
2866
2867 // If fast case code has been generated, emit code to push the
2868 // function and receiver and have the slow path jump around this
2869 // code.
2870 if (done.is_linked()) {
2871 Label call;
2872 __ Branch(&call);
2873 __ bind(&done);
2874 // Push function.
2875 __ push(v0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002876 // The receiver is implicitly the global receiver. Indicate this
2877 // by passing the hole to the call function stub.
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002878 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002879 __ push(a1);
2880 __ bind(&call);
2881 }
2882
danno@chromium.org40cb8782011-05-25 07:58:50 +00002883 // The receiver is either the global receiver or an object found
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002884 // by LoadContextSlot.
2885 EmitCallWithStub(expr);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002886 } else if (call_type == Call::PROPERTY_CALL) {
2887 Property* property = callee->AsProperty();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002888 { PreservePositionScope scope(masm()->positions_recorder());
2889 VisitForStackValue(property->obj());
2890 }
2891 if (property->key()->IsPropertyName()) {
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00002892 EmitCallWithIC(expr);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002893 } else {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002894 EmitKeyedCallWithIC(expr, property->key());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002895 }
2896 } else {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002897 ASSERT(call_type == Call::OTHER_CALL);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002898 // Call to an arbitrary expression not handled specially above.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002899 { PreservePositionScope scope(masm()->positions_recorder());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002900 VisitForStackValue(callee);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002901 }
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002902 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002903 __ push(a1);
2904 // Emit function call.
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002905 EmitCallWithStub(expr);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002906 }
2907
2908#ifdef DEBUG
2909 // RecordJSReturnSite should have been called.
2910 ASSERT(expr->return_is_recorded_);
2911#endif
ager@chromium.org5c838252010-02-19 08:53:10 +00002912}
2913
2914
2915void FullCodeGenerator::VisitCallNew(CallNew* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002916 Comment cmnt(masm_, "[ CallNew");
2917 // According to ECMA-262, section 11.2.2, page 44, the function
2918 // expression in new calls must be evaluated before the
2919 // arguments.
2920
2921 // Push constructor on the stack. If it's not a function it's used as
2922 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2923 // ignored.
2924 VisitForStackValue(expr->expression());
2925
2926 // Push the arguments ("left-to-right") on the stack.
2927 ZoneList<Expression*>* args = expr->arguments();
2928 int arg_count = args->length();
2929 for (int i = 0; i < arg_count; i++) {
2930 VisitForStackValue(args->at(i));
2931 }
2932
2933 // Call the construct call builtin that handles allocation and
2934 // constructor invocation.
2935 SetSourcePosition(expr->position());
2936
2937 // Load function and argument count into a1 and a0.
2938 __ li(a0, Operand(arg_count));
2939 __ lw(a1, MemOperand(sp, arg_count * kPointerSize));
2940
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002941 // Record call targets in unoptimized code.
machenbach@chromium.org8545d492014-03-17 09:28:03 +00002942 Handle<Object> uninitialized =
2943 TypeFeedbackInfo::UninitializedSentinel(isolate());
2944 StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized);
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00002945 if (FLAG_pretenuring_call_new) {
2946 StoreFeedbackVectorSlot(expr->AllocationSiteFeedbackSlot(),
2947 isolate()->factory()->NewAllocationSite());
2948 ASSERT(expr->AllocationSiteFeedbackSlot() ==
2949 expr->CallNewFeedbackSlot() + 1);
2950 }
2951
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002952 __ li(a2, FeedbackVector());
2953 __ li(a3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot())));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002954
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002955 CallConstructStub stub(RECORD_CALL_TARGET);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002956 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL);
ulan@chromium.org967e2702012-02-28 09:49:15 +00002957 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002958 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00002959}
2960
2961
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002962void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2963 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002964 ASSERT(args->length() == 1);
2965
2966 VisitForAccumulatorValue(args->at(0));
2967
2968 Label materialize_true, materialize_false;
2969 Label* if_true = NULL;
2970 Label* if_false = NULL;
2971 Label* fall_through = NULL;
2972 context()->PrepareTest(&materialize_true, &materialize_false,
2973 &if_true, &if_false, &fall_through);
2974
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002975 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00002976 __ SmiTst(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002977 Split(eq, t0, Operand(zero_reg), if_true, if_false, fall_through);
2978
2979 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002980}
2981
2982
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002983void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2984 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002985 ASSERT(args->length() == 1);
2986
2987 VisitForAccumulatorValue(args->at(0));
2988
2989 Label materialize_true, materialize_false;
2990 Label* if_true = NULL;
2991 Label* if_false = NULL;
2992 Label* fall_through = NULL;
2993 context()->PrepareTest(&materialize_true, &materialize_false,
2994 &if_true, &if_false, &fall_through);
2995
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002996 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00002997 __ NonNegativeSmiTst(v0, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002998 Split(eq, at, Operand(zero_reg), if_true, if_false, fall_through);
2999
3000 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003001}
3002
3003
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003004void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
3005 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003006 ASSERT(args->length() == 1);
3007
3008 VisitForAccumulatorValue(args->at(0));
3009
3010 Label materialize_true, materialize_false;
3011 Label* if_true = NULL;
3012 Label* if_false = NULL;
3013 Label* fall_through = NULL;
3014 context()->PrepareTest(&materialize_true, &materialize_false,
3015 &if_true, &if_false, &fall_through);
3016
3017 __ JumpIfSmi(v0, if_false);
3018 __ LoadRoot(at, Heap::kNullValueRootIndex);
3019 __ Branch(if_true, eq, v0, Operand(at));
3020 __ lw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
3021 // Undetectable objects behave like undefined when tested with typeof.
3022 __ lbu(a1, FieldMemOperand(a2, Map::kBitFieldOffset));
3023 __ And(at, a1, Operand(1 << Map::kIsUndetectable));
3024 __ Branch(if_false, ne, at, Operand(zero_reg));
3025 __ lbu(a1, FieldMemOperand(a2, Map::kInstanceTypeOffset));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003026 __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003027 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003028 Split(le, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE),
3029 if_true, if_false, fall_through);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003030
3031 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003032}
3033
3034
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003035void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
3036 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003037 ASSERT(args->length() == 1);
3038
3039 VisitForAccumulatorValue(args->at(0));
3040
3041 Label materialize_true, materialize_false;
3042 Label* if_true = NULL;
3043 Label* if_false = NULL;
3044 Label* fall_through = NULL;
3045 context()->PrepareTest(&materialize_true, &materialize_false,
3046 &if_true, &if_false, &fall_through);
3047
3048 __ JumpIfSmi(v0, if_false);
3049 __ GetObjectType(v0, a1, a1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003050 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003051 Split(ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003052 if_true, if_false, fall_through);
3053
3054 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003055}
3056
3057
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003058void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
3059 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003060 ASSERT(args->length() == 1);
3061
3062 VisitForAccumulatorValue(args->at(0));
3063
3064 Label materialize_true, materialize_false;
3065 Label* if_true = NULL;
3066 Label* if_false = NULL;
3067 Label* fall_through = NULL;
3068 context()->PrepareTest(&materialize_true, &materialize_false,
3069 &if_true, &if_false, &fall_through);
3070
3071 __ JumpIfSmi(v0, if_false);
3072 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
3073 __ lbu(a1, FieldMemOperand(a1, Map::kBitFieldOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003074 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
bmeurer@chromium.org25530ce2014-02-07 09:11:16 +00003075 __ And(at, a1, Operand(1 << Map::kIsUndetectable));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003076 Split(ne, at, Operand(zero_reg), if_true, if_false, fall_through);
3077
3078 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003079}
3080
3081
3082void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003083 CallRuntime* expr) {
3084 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003085 ASSERT(args->length() == 1);
3086
3087 VisitForAccumulatorValue(args->at(0));
3088
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003089 Label materialize_true, materialize_false, skip_lookup;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003090 Label* if_true = NULL;
3091 Label* if_false = NULL;
3092 Label* fall_through = NULL;
3093 context()->PrepareTest(&materialize_true, &materialize_false,
3094 &if_true, &if_false, &fall_through);
3095
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003096 __ AssertNotSmi(v0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003097
3098 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
3099 __ lbu(t0, FieldMemOperand(a1, Map::kBitField2Offset));
3100 __ And(t0, t0, 1 << Map::kStringWrapperSafeForDefaultValueOf);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003101 __ Branch(&skip_lookup, ne, t0, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003102
3103 // Check for fast case object. Generate false result for slow case object.
3104 __ lw(a2, FieldMemOperand(v0, JSObject::kPropertiesOffset));
3105 __ lw(a2, FieldMemOperand(a2, HeapObject::kMapOffset));
3106 __ LoadRoot(t0, Heap::kHashTableMapRootIndex);
3107 __ Branch(if_false, eq, a2, Operand(t0));
3108
ulan@chromium.org750145a2013-03-07 15:14:13 +00003109 // Look for valueOf name in the descriptor array, and indicate false if
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003110 // found. Since we omit an enumeration index check, if it is added via a
3111 // transition that shares its descriptor array, this is a false positive.
3112 Label entry, loop, done;
3113
3114 // Skip loop if no descriptors are valid.
3115 __ NumberOfOwnDescriptors(a3, a1);
3116 __ Branch(&done, eq, a3, Operand(zero_reg));
3117
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003118 __ LoadInstanceDescriptors(a1, t0);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003119 // t0: descriptor array.
3120 // a3: valid entries in the descriptor array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003121 STATIC_ASSERT(kSmiTag == 0);
3122 STATIC_ASSERT(kSmiTagSize == 1);
3123 STATIC_ASSERT(kPointerSize == 4);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003124 __ li(at, Operand(DescriptorArray::kDescriptorSize));
3125 __ Mul(a3, a3, at);
3126 // Calculate location of the first key name.
3127 __ Addu(t0, t0, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag));
3128 // Calculate the end of the descriptor array.
3129 __ mov(a2, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003130 __ sll(t1, a3, kPointerSizeLog2 - kSmiTagSize);
3131 __ Addu(a2, a2, t1);
3132
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003133 // Loop through all the keys in the descriptor array. If one of these is the
ulan@chromium.org750145a2013-03-07 15:14:13 +00003134 // string "valueOf" the result is false.
3135 // The use of t2 to store the valueOf string assumes that it is not otherwise
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003136 // used in the loop below.
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003137 __ li(t2, Operand(isolate()->factory()->value_of_string()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003138 __ jmp(&entry);
3139 __ bind(&loop);
3140 __ lw(a3, MemOperand(t0, 0));
3141 __ Branch(if_false, eq, a3, Operand(t2));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003142 __ Addu(t0, t0, Operand(DescriptorArray::kDescriptorSize * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003143 __ bind(&entry);
3144 __ Branch(&loop, ne, t0, Operand(a2));
3145
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003146 __ bind(&done);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003147
3148 // Set the bit in the map to indicate that there is no local valueOf field.
3149 __ lbu(a2, FieldMemOperand(a1, Map::kBitField2Offset));
3150 __ Or(a2, a2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
3151 __ sb(a2, FieldMemOperand(a1, Map::kBitField2Offset));
3152
3153 __ bind(&skip_lookup);
3154
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003155 // If a valueOf property is not found on the object check that its
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003156 // prototype is the un-modified String prototype. If not result is false.
3157 __ lw(a2, FieldMemOperand(a1, Map::kPrototypeOffset));
3158 __ JumpIfSmi(a2, if_false);
3159 __ lw(a2, FieldMemOperand(a2, HeapObject::kMapOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003160 __ lw(a3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
3161 __ lw(a3, FieldMemOperand(a3, GlobalObject::kNativeContextOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003162 __ lw(a3, ContextOperand(a3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003163 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003164 Split(eq, a2, Operand(a3), if_true, if_false, fall_through);
3165
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003166 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003167}
3168
3169
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003170void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
3171 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003172 ASSERT(args->length() == 1);
3173
3174 VisitForAccumulatorValue(args->at(0));
3175
3176 Label materialize_true, materialize_false;
3177 Label* if_true = NULL;
3178 Label* if_false = NULL;
3179 Label* fall_through = NULL;
3180 context()->PrepareTest(&materialize_true, &materialize_false,
3181 &if_true, &if_false, &fall_through);
3182
3183 __ JumpIfSmi(v0, if_false);
3184 __ GetObjectType(v0, a1, a2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003185 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003186 __ Branch(if_true, eq, a2, Operand(JS_FUNCTION_TYPE));
3187 __ Branch(if_false);
3188
3189 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003190}
3191
3192
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00003193void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
3194 ZoneList<Expression*>* args = expr->arguments();
3195 ASSERT(args->length() == 1);
3196
3197 VisitForAccumulatorValue(args->at(0));
3198
3199 Label materialize_true, materialize_false;
3200 Label* if_true = NULL;
3201 Label* if_false = NULL;
3202 Label* fall_through = NULL;
3203 context()->PrepareTest(&materialize_true, &materialize_false,
3204 &if_true, &if_false, &fall_through);
3205
3206 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, if_false, DO_SMI_CHECK);
3207 __ lw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3208 __ lw(a1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3209 __ li(t0, 0x80000000);
3210 Label not_nan;
3211 __ Branch(&not_nan, ne, a2, Operand(t0));
3212 __ mov(t0, zero_reg);
3213 __ mov(a2, a1);
3214 __ bind(&not_nan);
3215
3216 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3217 Split(eq, a2, Operand(t0), if_true, if_false, fall_through);
3218
3219 context()->Plug(if_true, if_false);
3220}
3221
3222
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003223void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
3224 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003225 ASSERT(args->length() == 1);
3226
3227 VisitForAccumulatorValue(args->at(0));
3228
3229 Label materialize_true, materialize_false;
3230 Label* if_true = NULL;
3231 Label* if_false = NULL;
3232 Label* fall_through = NULL;
3233 context()->PrepareTest(&materialize_true, &materialize_false,
3234 &if_true, &if_false, &fall_through);
3235
3236 __ JumpIfSmi(v0, if_false);
3237 __ GetObjectType(v0, a1, a1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003238 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003239 Split(eq, a1, Operand(JS_ARRAY_TYPE),
3240 if_true, if_false, fall_through);
3241
3242 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003243}
3244
3245
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003246void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
3247 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003248 ASSERT(args->length() == 1);
3249
3250 VisitForAccumulatorValue(args->at(0));
3251
3252 Label materialize_true, materialize_false;
3253 Label* if_true = NULL;
3254 Label* if_false = NULL;
3255 Label* fall_through = NULL;
3256 context()->PrepareTest(&materialize_true, &materialize_false,
3257 &if_true, &if_false, &fall_through);
3258
3259 __ JumpIfSmi(v0, if_false);
3260 __ GetObjectType(v0, a1, a1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003261 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003262 Split(eq, a1, Operand(JS_REGEXP_TYPE), if_true, if_false, fall_through);
3263
3264 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003265}
3266
3267
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003268void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
3269 ASSERT(expr->arguments()->length() == 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003270
3271 Label materialize_true, materialize_false;
3272 Label* if_true = NULL;
3273 Label* if_false = NULL;
3274 Label* fall_through = NULL;
3275 context()->PrepareTest(&materialize_true, &materialize_false,
3276 &if_true, &if_false, &fall_through);
3277
3278 // Get the frame pointer for the calling frame.
3279 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3280
3281 // Skip the arguments adaptor frame if it exists.
3282 Label check_frame_marker;
3283 __ lw(a1, MemOperand(a2, StandardFrameConstants::kContextOffset));
3284 __ Branch(&check_frame_marker, ne,
3285 a1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3286 __ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
3287
3288 // Check the marker in the calling frame.
3289 __ bind(&check_frame_marker);
3290 __ lw(a1, MemOperand(a2, StandardFrameConstants::kMarkerOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003291 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003292 Split(eq, a1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)),
3293 if_true, if_false, fall_through);
3294
3295 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003296}
3297
3298
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003299void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
3300 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003301 ASSERT(args->length() == 2);
3302
3303 // Load the two objects into registers and perform the comparison.
3304 VisitForStackValue(args->at(0));
3305 VisitForAccumulatorValue(args->at(1));
3306
3307 Label materialize_true, materialize_false;
3308 Label* if_true = NULL;
3309 Label* if_false = NULL;
3310 Label* fall_through = NULL;
3311 context()->PrepareTest(&materialize_true, &materialize_false,
3312 &if_true, &if_false, &fall_through);
3313
3314 __ pop(a1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003315 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003316 Split(eq, v0, Operand(a1), if_true, if_false, fall_through);
3317
3318 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003319}
3320
3321
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003322void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3323 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003324 ASSERT(args->length() == 1);
3325
3326 // ArgumentsAccessStub expects the key in a1 and the formal
3327 // parameter count in a0.
3328 VisitForAccumulatorValue(args->at(0));
3329 __ mov(a1, v0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003330 __ li(a0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003331 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
3332 __ CallStub(&stub);
3333 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003334}
3335
3336
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003337void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
3338 ASSERT(expr->arguments()->length() == 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003339 Label exit;
3340 // Get the number of formal parameters.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003341 __ li(v0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003342
3343 // Check if the calling frame is an arguments adaptor frame.
3344 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3345 __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
3346 __ Branch(&exit, ne, a3,
3347 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3348
3349 // Arguments adaptor case: Read the arguments length from the
3350 // adaptor frame.
3351 __ lw(v0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
3352
3353 __ bind(&exit);
3354 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003355}
3356
3357
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003358void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3359 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003360 ASSERT(args->length() == 1);
3361 Label done, null, function, non_function_constructor;
3362
3363 VisitForAccumulatorValue(args->at(0));
3364
3365 // If the object is a smi, we return null.
3366 __ JumpIfSmi(v0, &null);
3367
3368 // Check that the object is a JS object but take special care of JS
3369 // functions to make sure they have 'Function' as their class.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003370 // Assume that there are only two callable types, and one of them is at
3371 // either end of the type range for JS object types. Saves extra comparisons.
3372 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003373 __ GetObjectType(v0, v0, a1); // Map is now in v0.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003374 __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003375
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003376 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3377 FIRST_SPEC_OBJECT_TYPE + 1);
3378 __ Branch(&function, eq, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003379
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003380 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3381 LAST_SPEC_OBJECT_TYPE - 1);
3382 __ Branch(&function, eq, a1, Operand(LAST_SPEC_OBJECT_TYPE));
3383 // Assume that there is no larger type.
3384 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
3385
3386 // Check if the constructor in the map is a JS function.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003387 __ lw(v0, FieldMemOperand(v0, Map::kConstructorOffset));
3388 __ GetObjectType(v0, a1, a1);
3389 __ Branch(&non_function_constructor, ne, a1, Operand(JS_FUNCTION_TYPE));
3390
3391 // v0 now contains the constructor function. Grab the
3392 // instance class name from there.
3393 __ lw(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset));
3394 __ lw(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset));
3395 __ Branch(&done);
3396
3397 // Functions have class 'Function'.
3398 __ bind(&function);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003399 __ LoadRoot(v0, Heap::kfunction_class_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003400 __ jmp(&done);
3401
3402 // Objects with a non-function constructor have class 'Object'.
3403 __ bind(&non_function_constructor);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003404 __ LoadRoot(v0, Heap::kObject_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003405 __ jmp(&done);
3406
3407 // Non-JS objects have class null.
3408 __ bind(&null);
3409 __ LoadRoot(v0, Heap::kNullValueRootIndex);
3410
3411 // All done.
3412 __ bind(&done);
3413
3414 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003415}
3416
3417
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003418void FullCodeGenerator::EmitLog(CallRuntime* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003419 // Conditionally generate a log call.
3420 // Args:
3421 // 0 (literal string): The type of logging (corresponds to the flags).
3422 // This is used to determine whether or not to generate the log call.
3423 // 1 (string): Format string. Access the string at argument index 2
3424 // with '%2s' (see Logger::LogRuntime for all the formats).
3425 // 2 (array): Arguments to the format string.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003426 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003427 ASSERT_EQ(args->length(), 3);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003428 if (CodeGenerator::ShouldGenerateLog(isolate(), args->at(0))) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003429 VisitForStackValue(args->at(1));
3430 VisitForStackValue(args->at(2));
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +00003431 __ CallRuntime(Runtime::kHiddenLog, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003432 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003433
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003434 // Finally, we're expected to leave a value on the top of the stack.
3435 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
3436 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003437}
3438
3439
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003440void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003441 // Load the arguments on the stack and call the stub.
3442 SubStringStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003443 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003444 ASSERT(args->length() == 3);
3445 VisitForStackValue(args->at(0));
3446 VisitForStackValue(args->at(1));
3447 VisitForStackValue(args->at(2));
3448 __ CallStub(&stub);
3449 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003450}
3451
3452
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003453void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003454 // Load the arguments on the stack and call the stub.
3455 RegExpExecStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003456 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003457 ASSERT(args->length() == 4);
3458 VisitForStackValue(args->at(0));
3459 VisitForStackValue(args->at(1));
3460 VisitForStackValue(args->at(2));
3461 VisitForStackValue(args->at(3));
3462 __ CallStub(&stub);
3463 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003464}
3465
3466
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003467void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3468 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003469 ASSERT(args->length() == 1);
3470
3471 VisitForAccumulatorValue(args->at(0)); // Load the object.
3472
3473 Label done;
3474 // If the object is a smi return the object.
3475 __ JumpIfSmi(v0, &done);
3476 // If the object is not a value type, return the object.
3477 __ GetObjectType(v0, a1, a1);
3478 __ Branch(&done, ne, a1, Operand(JS_VALUE_TYPE));
3479
3480 __ lw(v0, FieldMemOperand(v0, JSValue::kValueOffset));
3481
3482 __ bind(&done);
3483 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003484}
3485
3486
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003487void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3488 ZoneList<Expression*>* args = expr->arguments();
3489 ASSERT(args->length() == 2);
3490 ASSERT_NE(NULL, args->at(1)->AsLiteral());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003491 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003492
3493 VisitForAccumulatorValue(args->at(0)); // Load the object.
3494
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003495 Label runtime, done, not_date_object;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003496 Register object = v0;
3497 Register result = v0;
3498 Register scratch0 = t5;
3499 Register scratch1 = a1;
3500
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003501 __ JumpIfSmi(object, &not_date_object);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003502 __ GetObjectType(object, scratch1, scratch1);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003503 __ Branch(&not_date_object, ne, scratch1, Operand(JS_DATE_TYPE));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003504
3505 if (index->value() == 0) {
3506 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset));
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003507 __ jmp(&done);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003508 } else {
3509 if (index->value() < JSDate::kFirstUncachedField) {
3510 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3511 __ li(scratch1, Operand(stamp));
3512 __ lw(scratch1, MemOperand(scratch1));
3513 __ lw(scratch0, FieldMemOperand(object, JSDate::kCacheStampOffset));
3514 __ Branch(&runtime, ne, scratch1, Operand(scratch0));
3515 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset +
3516 kPointerSize * index->value()));
3517 __ jmp(&done);
3518 }
3519 __ bind(&runtime);
3520 __ PrepareCallCFunction(2, scratch1);
3521 __ li(a1, Operand(index));
3522 __ Move(a0, object);
3523 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003524 __ jmp(&done);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003525 }
3526
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003527 __ bind(&not_date_object);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00003528 __ CallRuntime(Runtime::kHiddenThrowNotDateError, 0);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003529 __ bind(&done);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003530 context()->Plug(v0);
3531}
3532
3533
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003534void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3535 ZoneList<Expression*>* args = expr->arguments();
3536 ASSERT_EQ(3, args->length());
3537
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003538 Register string = v0;
3539 Register index = a1;
3540 Register value = a2;
3541
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003542 VisitForStackValue(args->at(1)); // index
3543 VisitForStackValue(args->at(2)); // value
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003544 VisitForAccumulatorValue(args->at(0)); // string
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003545 __ Pop(index, value);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003546
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003547 if (FLAG_debug_code) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00003548 __ SmiTst(value, at);
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00003549 __ Check(eq, kNonSmiValue, at, Operand(zero_reg));
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00003550 __ SmiTst(index, at);
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00003551 __ Check(eq, kNonSmiIndex, at, Operand(zero_reg));
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003552 __ SmiUntag(index, index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003553 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003554 Register scratch = t5;
3555 __ EmitSeqStringSetCharCheck(
3556 string, index, value, scratch, one_byte_seq_type);
3557 __ SmiTag(index, index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003558 }
3559
3560 __ SmiUntag(value, value);
3561 __ Addu(at,
3562 string,
3563 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
3564 __ SmiUntag(index);
3565 __ Addu(at, at, index);
3566 __ sb(value, MemOperand(at));
3567 context()->Plug(string);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003568}
3569
3570
3571void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3572 ZoneList<Expression*>* args = expr->arguments();
3573 ASSERT_EQ(3, args->length());
3574
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003575 Register string = v0;
3576 Register index = a1;
3577 Register value = a2;
3578
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003579 VisitForStackValue(args->at(1)); // index
3580 VisitForStackValue(args->at(2)); // value
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003581 VisitForAccumulatorValue(args->at(0)); // string
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003582 __ Pop(index, value);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003583
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003584 if (FLAG_debug_code) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00003585 __ SmiTst(value, at);
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00003586 __ Check(eq, kNonSmiValue, at, Operand(zero_reg));
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00003587 __ SmiTst(index, at);
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00003588 __ Check(eq, kNonSmiIndex, at, Operand(zero_reg));
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003589 __ SmiUntag(index, index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003590 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003591 Register scratch = t5;
3592 __ EmitSeqStringSetCharCheck(
3593 string, index, value, scratch, two_byte_seq_type);
3594 __ SmiTag(index, index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003595 }
3596
3597 __ SmiUntag(value, value);
3598 __ Addu(at,
3599 string,
3600 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
3601 __ Addu(at, at, index);
3602 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
3603 __ sh(value, MemOperand(at));
3604 context()->Plug(string);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003605}
3606
3607
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003608void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003609 // Load the arguments on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003610 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003611 ASSERT(args->length() == 2);
3612 VisitForStackValue(args->at(0));
3613 VisitForStackValue(args->at(1));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003614 MathPowStub stub(MathPowStub::ON_STACK);
3615 __ CallStub(&stub);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003616 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003617}
3618
3619
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003620void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3621 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003622 ASSERT(args->length() == 2);
3623
3624 VisitForStackValue(args->at(0)); // Load the object.
3625 VisitForAccumulatorValue(args->at(1)); // Load the value.
3626 __ pop(a1); // v0 = value. a1 = object.
3627
3628 Label done;
3629 // If the object is a smi, return the value.
3630 __ JumpIfSmi(a1, &done);
3631
3632 // If the object is not a value type, return the value.
3633 __ GetObjectType(a1, a2, a2);
3634 __ Branch(&done, ne, a2, Operand(JS_VALUE_TYPE));
3635
3636 // Store the value.
3637 __ sw(v0, FieldMemOperand(a1, JSValue::kValueOffset));
3638 // Update the write barrier. Save the value as it will be
3639 // overwritten by the write barrier code and is needed afterward.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003640 __ mov(a2, v0);
3641 __ RecordWriteField(
3642 a1, JSValue::kValueOffset, a2, a3, kRAHasBeenSaved, kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003643
3644 __ bind(&done);
3645 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003646}
3647
3648
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003649void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3650 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003651 ASSERT_EQ(args->length(), 1);
3652
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003653 // Load the argument into a0 and call the stub.
3654 VisitForAccumulatorValue(args->at(0));
3655 __ mov(a0, result_register());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003656
3657 NumberToStringStub stub;
3658 __ CallStub(&stub);
3659 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003660}
3661
3662
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003663void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3664 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003665 ASSERT(args->length() == 1);
3666
3667 VisitForAccumulatorValue(args->at(0));
3668
3669 Label done;
3670 StringCharFromCodeGenerator generator(v0, a1);
3671 generator.GenerateFast(masm_);
3672 __ jmp(&done);
3673
3674 NopRuntimeCallHelper call_helper;
3675 generator.GenerateSlow(masm_, call_helper);
3676
3677 __ bind(&done);
3678 context()->Plug(a1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003679}
3680
3681
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003682void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3683 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003684 ASSERT(args->length() == 2);
3685
3686 VisitForStackValue(args->at(0));
3687 VisitForAccumulatorValue(args->at(1));
3688 __ mov(a0, result_register());
3689
3690 Register object = a1;
3691 Register index = a0;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003692 Register result = v0;
3693
3694 __ pop(object);
3695
3696 Label need_conversion;
3697 Label index_out_of_range;
3698 Label done;
3699 StringCharCodeAtGenerator generator(object,
3700 index,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003701 result,
3702 &need_conversion,
3703 &need_conversion,
3704 &index_out_of_range,
3705 STRING_INDEX_IS_NUMBER);
3706 generator.GenerateFast(masm_);
3707 __ jmp(&done);
3708
3709 __ bind(&index_out_of_range);
3710 // When the index is out of range, the spec requires us to return
3711 // NaN.
3712 __ LoadRoot(result, Heap::kNanValueRootIndex);
3713 __ jmp(&done);
3714
3715 __ bind(&need_conversion);
3716 // Load the undefined value into the result register, which will
3717 // trigger conversion.
3718 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
3719 __ jmp(&done);
3720
3721 NopRuntimeCallHelper call_helper;
3722 generator.GenerateSlow(masm_, call_helper);
3723
3724 __ bind(&done);
3725 context()->Plug(result);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003726}
3727
3728
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003729void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3730 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003731 ASSERT(args->length() == 2);
3732
3733 VisitForStackValue(args->at(0));
3734 VisitForAccumulatorValue(args->at(1));
3735 __ mov(a0, result_register());
3736
3737 Register object = a1;
3738 Register index = a0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003739 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003740 Register result = v0;
3741
3742 __ pop(object);
3743
3744 Label need_conversion;
3745 Label index_out_of_range;
3746 Label done;
3747 StringCharAtGenerator generator(object,
3748 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00003749 scratch,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003750 result,
3751 &need_conversion,
3752 &need_conversion,
3753 &index_out_of_range,
3754 STRING_INDEX_IS_NUMBER);
3755 generator.GenerateFast(masm_);
3756 __ jmp(&done);
3757
3758 __ bind(&index_out_of_range);
3759 // When the index is out of range, the spec requires us to return
3760 // the empty string.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003761 __ LoadRoot(result, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003762 __ jmp(&done);
3763
3764 __ bind(&need_conversion);
3765 // Move smi zero into the result register, which will trigger
3766 // conversion.
3767 __ li(result, Operand(Smi::FromInt(0)));
3768 __ jmp(&done);
3769
3770 NopRuntimeCallHelper call_helper;
3771 generator.GenerateSlow(masm_, call_helper);
3772
3773 __ bind(&done);
3774 context()->Plug(result);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003775}
3776
3777
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003778void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3779 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003780 ASSERT_EQ(2, args->length());
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +00003781 VisitForStackValue(args->at(0));
3782 VisitForAccumulatorValue(args->at(1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003783
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +00003784 __ pop(a1);
3785 __ mov(a0, result_register()); // StringAddStub requires args in a0, a1.
3786 StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
3787 __ CallStub(&stub);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003788 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003789}
3790
3791
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003792void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3793 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003794 ASSERT_EQ(2, args->length());
3795
3796 VisitForStackValue(args->at(0));
3797 VisitForStackValue(args->at(1));
3798
3799 StringCompareStub stub;
3800 __ CallStub(&stub);
3801 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003802}
3803
3804
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003805void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3806 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003807 ASSERT(args->length() >= 2);
3808
3809 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3810 for (int i = 0; i < arg_count + 1; i++) {
3811 VisitForStackValue(args->at(i));
3812 }
3813 VisitForAccumulatorValue(args->last()); // Function.
3814
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003815 Label runtime, done;
3816 // Check for non-function argument (including proxy).
3817 __ JumpIfSmi(v0, &runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003818 __ GetObjectType(v0, a1, a1);
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003819 __ Branch(&runtime, ne, a1, Operand(JS_FUNCTION_TYPE));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003820
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003821 // InvokeFunction requires the function in a1. Move it in there.
3822 __ mov(a1, result_register());
3823 ParameterCount count(arg_count);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003824 __ InvokeFunction(a1, count, CALL_FUNCTION, NullCallWrapper());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003825 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003826 __ jmp(&done);
3827
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003828 __ bind(&runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003829 __ push(v0);
3830 __ CallRuntime(Runtime::kCall, args->length());
3831 __ bind(&done);
3832
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003833 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003834}
3835
3836
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003837void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003838 RegExpConstructResultStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003839 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003840 ASSERT(args->length() == 3);
3841 VisitForStackValue(args->at(0));
3842 VisitForStackValue(args->at(1));
machenbach@chromium.org09cae8d2014-01-30 01:05:27 +00003843 VisitForAccumulatorValue(args->at(2));
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00003844 __ mov(a0, result_register());
machenbach@chromium.org09cae8d2014-01-30 01:05:27 +00003845 __ pop(a1);
3846 __ pop(a2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003847 __ CallStub(&stub);
3848 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003849}
3850
3851
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003852void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3853 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003854 ASSERT_EQ(2, args->length());
3855
3856 ASSERT_NE(NULL, args->at(0)->AsLiteral());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003857 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003858
3859 Handle<FixedArray> jsfunction_result_caches(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003860 isolate()->native_context()->jsfunction_result_caches());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003861 if (jsfunction_result_caches->length() <= cache_id) {
danno@chromium.org59400602013-08-13 17:09:37 +00003862 __ Abort(kAttemptToUseUndefinedCache);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003863 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
3864 context()->Plug(v0);
3865 return;
3866 }
3867
3868 VisitForAccumulatorValue(args->at(1));
3869
3870 Register key = v0;
3871 Register cache = a1;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003872 __ lw(cache, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
3873 __ lw(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003874 __ lw(cache,
3875 ContextOperand(
3876 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
3877 __ lw(cache,
3878 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3879
3880
3881 Label done, not_found;
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003882 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003883 __ lw(a2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
3884 // a2 now holds finger offset as a smi.
3885 __ Addu(a3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3886 // a3 now points to the start of fixed array elements.
3887 __ sll(at, a2, kPointerSizeLog2 - kSmiTagSize);
3888 __ addu(a3, a3, at);
3889 // a3 now points to key of indexed element of cache.
3890 __ lw(a2, MemOperand(a3));
3891 __ Branch(&not_found, ne, key, Operand(a2));
3892
3893 __ lw(v0, MemOperand(a3, kPointerSize));
3894 __ Branch(&done);
3895
3896 __ bind(&not_found);
3897 // Call runtime to perform the lookup.
3898 __ Push(cache, key);
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +00003899 __ CallRuntime(Runtime::kHiddenGetFromCache, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003900
3901 __ bind(&done);
3902 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003903}
3904
3905
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003906void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3907 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003908 VisitForAccumulatorValue(args->at(0));
3909
3910 Label materialize_true, materialize_false;
3911 Label* if_true = NULL;
3912 Label* if_false = NULL;
3913 Label* fall_through = NULL;
3914 context()->PrepareTest(&materialize_true, &materialize_false,
3915 &if_true, &if_false, &fall_through);
3916
3917 __ lw(a0, FieldMemOperand(v0, String::kHashFieldOffset));
3918 __ And(a0, a0, Operand(String::kContainsCachedArrayIndexMask));
3919
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003920 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003921 Split(eq, a0, Operand(zero_reg), if_true, if_false, fall_through);
3922
3923 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003924}
3925
3926
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003927void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3928 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003929 ASSERT(args->length() == 1);
3930 VisitForAccumulatorValue(args->at(0));
3931
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003932 __ AssertString(v0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003933
3934 __ lw(v0, FieldMemOperand(v0, String::kHashFieldOffset));
3935 __ IndexFromHash(v0, v0);
3936
3937 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003938}
3939
3940
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003941void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003942 Label bailout, done, one_char_separator, long_separator,
3943 non_trivial_array, not_size_one_array, loop,
3944 empty_separator_loop, one_char_separator_loop,
3945 one_char_separator_loop_entry, long_separator_loop;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003946 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003947 ASSERT(args->length() == 2);
3948 VisitForStackValue(args->at(1));
3949 VisitForAccumulatorValue(args->at(0));
3950
3951 // All aliases of the same register have disjoint lifetimes.
3952 Register array = v0;
3953 Register elements = no_reg; // Will be v0.
3954 Register result = no_reg; // Will be v0.
3955 Register separator = a1;
3956 Register array_length = a2;
3957 Register result_pos = no_reg; // Will be a2.
3958 Register string_length = a3;
3959 Register string = t0;
3960 Register element = t1;
3961 Register elements_end = t2;
3962 Register scratch1 = t3;
3963 Register scratch2 = t5;
3964 Register scratch3 = t4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003965
3966 // Separator operand is on the stack.
3967 __ pop(separator);
3968
3969 // Check that the array is a JSArray.
3970 __ JumpIfSmi(array, &bailout);
3971 __ GetObjectType(array, scratch1, scratch2);
3972 __ Branch(&bailout, ne, scratch2, Operand(JS_ARRAY_TYPE));
3973
3974 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003975 __ CheckFastElements(scratch1, scratch2, &bailout);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003976
3977 // If the array has length zero, return the empty string.
3978 __ lw(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
3979 __ SmiUntag(array_length);
3980 __ Branch(&non_trivial_array, ne, array_length, Operand(zero_reg));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003981 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003982 __ Branch(&done);
3983
3984 __ bind(&non_trivial_array);
3985
3986 // Get the FixedArray containing array's elements.
3987 elements = array;
3988 __ lw(elements, FieldMemOperand(array, JSArray::kElementsOffset));
3989 array = no_reg; // End of array's live range.
3990
3991 // Check that all array elements are sequential ASCII strings, and
3992 // accumulate the sum of their lengths, as a smi-encoded value.
3993 __ mov(string_length, zero_reg);
3994 __ Addu(element,
3995 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3996 __ sll(elements_end, array_length, kPointerSizeLog2);
3997 __ Addu(elements_end, element, elements_end);
3998 // Loop condition: while (element < elements_end).
3999 // Live values in registers:
4000 // elements: Fixed array of strings.
4001 // array_length: Length of the fixed array of strings (not smi)
4002 // separator: Separator string
4003 // string_length: Accumulated sum of string lengths (smi).
4004 // element: Current array element.
4005 // elements_end: Array end.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004006 if (generate_debug_code_) {
danno@chromium.org59400602013-08-13 17:09:37 +00004007 __ Assert(gt, kNoEmptyArraysHereInEmitFastAsciiArrayJoin,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004008 array_length, Operand(zero_reg));
4009 }
4010 __ bind(&loop);
4011 __ lw(string, MemOperand(element));
4012 __ Addu(element, element, kPointerSize);
4013 __ JumpIfSmi(string, &bailout);
4014 __ lw(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
4015 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
4016 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004017 __ lw(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004018 __ AdduAndCheckForOverflow(string_length, string_length, scratch1, scratch3);
4019 __ BranchOnOverflow(&bailout, scratch3);
4020 __ Branch(&loop, lt, element, Operand(elements_end));
4021
4022 // If array_length is 1, return elements[0], a string.
4023 __ Branch(&not_size_one_array, ne, array_length, Operand(1));
4024 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
4025 __ Branch(&done);
4026
4027 __ bind(&not_size_one_array);
4028
4029 // Live values in registers:
4030 // separator: Separator string
4031 // array_length: Length of the array.
4032 // string_length: Sum of string lengths (smi).
4033 // elements: FixedArray of strings.
4034
4035 // Check that the separator is a flat ASCII string.
4036 __ JumpIfSmi(separator, &bailout);
4037 __ lw(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
4038 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
4039 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
4040
4041 // Add (separator length times array_length) - separator length to the
4042 // string_length to get the length of the result string. array_length is not
4043 // smi but the other values are, so the result is a smi.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004044 __ lw(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004045 __ Subu(string_length, string_length, Operand(scratch1));
4046 __ Mult(array_length, scratch1);
4047 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
4048 // zero.
4049 __ mfhi(scratch2);
4050 __ Branch(&bailout, ne, scratch2, Operand(zero_reg));
4051 __ mflo(scratch2);
4052 __ And(scratch3, scratch2, Operand(0x80000000));
4053 __ Branch(&bailout, ne, scratch3, Operand(zero_reg));
4054 __ AdduAndCheckForOverflow(string_length, string_length, scratch2, scratch3);
4055 __ BranchOnOverflow(&bailout, scratch3);
4056 __ SmiUntag(string_length);
4057
4058 // Get first element in the array to free up the elements register to be used
4059 // for the result.
4060 __ Addu(element,
4061 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4062 result = elements; // End of live range for elements.
4063 elements = no_reg;
4064 // Live values in registers:
4065 // element: First array element
4066 // separator: Separator string
4067 // string_length: Length of result string (not smi)
4068 // array_length: Length of the array.
4069 __ AllocateAsciiString(result,
4070 string_length,
4071 scratch1,
4072 scratch2,
4073 elements_end,
4074 &bailout);
4075 // Prepare for looping. Set up elements_end to end of the array. Set
4076 // result_pos to the position of the result where to write the first
4077 // character.
4078 __ sll(elements_end, array_length, kPointerSizeLog2);
4079 __ Addu(elements_end, element, elements_end);
4080 result_pos = array_length; // End of live range for array_length.
4081 array_length = no_reg;
4082 __ Addu(result_pos,
4083 result,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004084 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004085
4086 // Check the length of the separator.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004087 __ lw(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004088 __ li(at, Operand(Smi::FromInt(1)));
4089 __ Branch(&one_char_separator, eq, scratch1, Operand(at));
4090 __ Branch(&long_separator, gt, scratch1, Operand(at));
4091
4092 // Empty separator case.
4093 __ bind(&empty_separator_loop);
4094 // Live values in registers:
4095 // result_pos: the position to which we are currently copying characters.
4096 // element: Current array element.
4097 // elements_end: Array end.
4098
4099 // Copy next array element to the result.
4100 __ lw(string, MemOperand(element));
4101 __ Addu(element, element, kPointerSize);
4102 __ lw(string_length, FieldMemOperand(string, String::kLengthOffset));
4103 __ SmiUntag(string_length);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004104 __ Addu(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004105 __ CopyBytes(string, result_pos, string_length, scratch1);
4106 // End while (element < elements_end).
4107 __ Branch(&empty_separator_loop, lt, element, Operand(elements_end));
4108 ASSERT(result.is(v0));
4109 __ Branch(&done);
4110
4111 // One-character separator case.
4112 __ bind(&one_char_separator);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004113 // Replace separator with its ASCII character value.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004114 __ lbu(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004115 // Jump into the loop after the code that copies the separator, so the first
4116 // element is not preceded by a separator.
4117 __ jmp(&one_char_separator_loop_entry);
4118
4119 __ bind(&one_char_separator_loop);
4120 // Live values in registers:
4121 // result_pos: the position to which we are currently copying characters.
4122 // element: Current array element.
4123 // elements_end: Array end.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004124 // separator: Single separator ASCII char (in lower byte).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004125
4126 // Copy the separator character to the result.
4127 __ sb(separator, MemOperand(result_pos));
4128 __ Addu(result_pos, result_pos, 1);
4129
4130 // Copy next array element to the result.
4131 __ bind(&one_char_separator_loop_entry);
4132 __ lw(string, MemOperand(element));
4133 __ Addu(element, element, kPointerSize);
4134 __ lw(string_length, FieldMemOperand(string, String::kLengthOffset));
4135 __ SmiUntag(string_length);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004136 __ Addu(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004137 __ CopyBytes(string, result_pos, string_length, scratch1);
4138 // End while (element < elements_end).
4139 __ Branch(&one_char_separator_loop, lt, element, Operand(elements_end));
4140 ASSERT(result.is(v0));
4141 __ Branch(&done);
4142
4143 // Long separator case (separator is more than one character). Entry is at the
4144 // label long_separator below.
4145 __ bind(&long_separator_loop);
4146 // Live values in registers:
4147 // result_pos: the position to which we are currently copying characters.
4148 // element: Current array element.
4149 // elements_end: Array end.
4150 // separator: Separator string.
4151
4152 // Copy the separator to the result.
4153 __ lw(string_length, FieldMemOperand(separator, String::kLengthOffset));
4154 __ SmiUntag(string_length);
4155 __ Addu(string,
4156 separator,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004157 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004158 __ CopyBytes(string, result_pos, string_length, scratch1);
4159
4160 __ bind(&long_separator);
4161 __ lw(string, MemOperand(element));
4162 __ Addu(element, element, kPointerSize);
4163 __ lw(string_length, FieldMemOperand(string, String::kLengthOffset));
4164 __ SmiUntag(string_length);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004165 __ Addu(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004166 __ CopyBytes(string, result_pos, string_length, scratch1);
4167 // End while (element < elements_end).
4168 __ Branch(&long_separator_loop, lt, element, Operand(elements_end));
4169 ASSERT(result.is(v0));
4170 __ Branch(&done);
4171
4172 __ bind(&bailout);
4173 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
4174 __ bind(&done);
4175 context()->Plug(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004176}
4177
4178
ager@chromium.org5c838252010-02-19 08:53:10 +00004179void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +00004180 if (expr->function() != NULL &&
4181 expr->function()->intrinsic_type == Runtime::INLINE) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004182 Comment cmnt(masm_, "[ InlineRuntimeCall");
4183 EmitInlineRuntimeCall(expr);
4184 return;
4185 }
4186
4187 Comment cmnt(masm_, "[ CallRuntime");
4188 ZoneList<Expression*>* args = expr->arguments();
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004189 int arg_count = args->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004190
4191 if (expr->is_jsruntime()) {
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004192 // Push the builtins object as the receiver.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004193 __ lw(a0, GlobalObjectOperand());
4194 __ lw(a0, FieldMemOperand(a0, GlobalObject::kBuiltinsOffset));
4195 __ push(a0);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004196 // Load the function from the receiver.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004197 __ li(a2, Operand(expr->name()));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004198 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
4199
4200 // Push the target function under the receiver.
4201 __ lw(at, MemOperand(sp, 0));
4202 __ push(at);
4203 __ sw(v0, MemOperand(sp, kPointerSize));
4204
4205 // Push the arguments ("left-to-right").
4206 int arg_count = args->length();
4207 for (int i = 0; i < arg_count; i++) {
4208 VisitForStackValue(args->at(i));
4209 }
4210
4211 // Record source position of the IC call.
4212 SetSourcePosition(expr->position());
4213 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS);
4214 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
4215 __ CallStub(&stub);
4216
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004217 // Restore context register.
4218 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004219
4220 context()->DropAndPlug(1, v0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004221 } else {
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004222 // Push the arguments ("left-to-right").
4223 for (int i = 0; i < arg_count; i++) {
4224 VisitForStackValue(args->at(i));
4225 }
4226
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004227 // Call the C runtime function.
4228 __ CallRuntime(expr->function(), arg_count);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004229 context()->Plug(v0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004230 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004231}
4232
4233
4234void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004235 switch (expr->op()) {
4236 case Token::DELETE: {
4237 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004238 Property* property = expr->expression()->AsProperty();
4239 VariableProxy* proxy = expr->expression()->AsVariableProxy();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004240
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004241 if (property != NULL) {
4242 VisitForStackValue(property->obj());
4243 VisitForStackValue(property->key());
dslomov@chromium.org486536d2014-03-12 13:09:18 +00004244 __ li(a1, Operand(Smi::FromInt(strict_mode())));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004245 __ push(a1);
4246 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4247 context()->Plug(v0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004248 } else if (proxy != NULL) {
4249 Variable* var = proxy->var();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004250 // Delete of an unqualified identifier is disallowed in strict mode
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004251 // but "delete this" is allowed.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00004252 ASSERT(strict_mode() == SLOPPY || var->is_this());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004253 if (var->IsUnallocated()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004254 __ lw(a2, GlobalObjectOperand());
4255 __ li(a1, Operand(var->name()));
dslomov@chromium.org486536d2014-03-12 13:09:18 +00004256 __ li(a0, Operand(Smi::FromInt(SLOPPY)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004257 __ Push(a2, a1, a0);
4258 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4259 context()->Plug(v0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004260 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004261 // Result of deleting non-global, non-dynamic variables is false.
4262 // The subexpression does not have side effects.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004263 context()->Plug(var->is_this());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004264 } else {
4265 // Non-global variable. Call the runtime to try to delete from the
4266 // context where the variable was introduced.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004267 ASSERT(!context_register().is(a2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004268 __ li(a2, Operand(var->name()));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004269 __ Push(context_register(), a2);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00004270 __ CallRuntime(Runtime::kHiddenDeleteContextSlot, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004271 context()->Plug(v0);
4272 }
4273 } else {
4274 // Result of deleting non-property, non-variable reference is true.
4275 // The subexpression may have side effects.
4276 VisitForEffect(expr->expression());
4277 context()->Plug(true);
4278 }
4279 break;
4280 }
4281
4282 case Token::VOID: {
4283 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
4284 VisitForEffect(expr->expression());
4285 context()->Plug(Heap::kUndefinedValueRootIndex);
4286 break;
4287 }
4288
4289 case Token::NOT: {
4290 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
4291 if (context()->IsEffect()) {
4292 // Unary NOT has no side effects so it's only necessary to visit the
4293 // subexpression. Match the optimizing compiler by not branching.
4294 VisitForEffect(expr->expression());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004295 } else if (context()->IsTest()) {
4296 const TestContext* test = TestContext::cast(context());
4297 // The labels are swapped for the recursive call.
4298 VisitForControl(expr->expression(),
4299 test->false_label(),
4300 test->true_label(),
4301 test->fall_through());
4302 context()->Plug(test->true_label(), test->false_label());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004303 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004304 // We handle value contexts explicitly rather than simply visiting
4305 // for control and plugging the control flow into the context,
4306 // because we need to prepare a pair of extra administrative AST ids
4307 // for the optimizing compiler.
4308 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
4309 Label materialize_true, materialize_false, done;
4310 VisitForControl(expr->expression(),
4311 &materialize_false,
4312 &materialize_true,
4313 &materialize_true);
4314 __ bind(&materialize_true);
4315 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4316 __ LoadRoot(v0, Heap::kTrueValueRootIndex);
4317 if (context()->IsStackValue()) __ push(v0);
4318 __ jmp(&done);
4319 __ bind(&materialize_false);
4320 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4321 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
4322 if (context()->IsStackValue()) __ push(v0);
4323 __ bind(&done);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004324 }
4325 break;
4326 }
4327
4328 case Token::TYPEOF: {
4329 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
4330 { StackValueContext context(this);
4331 VisitForTypeofValue(expr->expression());
4332 }
4333 __ CallRuntime(Runtime::kTypeof, 1);
4334 context()->Plug(v0);
4335 break;
4336 }
4337
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004338 default:
4339 UNREACHABLE();
4340 }
4341}
4342
4343
ager@chromium.org5c838252010-02-19 08:53:10 +00004344void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
machenbach@chromium.orgda0c8282014-04-03 07:05:51 +00004345 ASSERT(expr->expression()->IsValidReferenceExpression());
machenbach@chromium.org2904d1a2014-03-18 01:05:18 +00004346
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004347 Comment cmnt(masm_, "[ CountOperation");
4348 SetSourcePosition(expr->position());
4349
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004350 // Expression can only be a property, a global or a (parameter or local)
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00004351 // slot.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004352 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
4353 LhsKind assign_type = VARIABLE;
4354 Property* prop = expr->expression()->AsProperty();
4355 // In case of a property we use the uninitialized expression context
4356 // of the key to detect a named property.
4357 if (prop != NULL) {
4358 assign_type =
4359 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
4360 }
4361
4362 // Evaluate expression and get value.
4363 if (assign_type == VARIABLE) {
4364 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
4365 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00004366 EmitVariableLoad(expr->expression()->AsVariableProxy());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004367 } else {
4368 // Reserve space for result of postfix operation.
4369 if (expr->is_postfix() && !context()->IsEffect()) {
4370 __ li(at, Operand(Smi::FromInt(0)));
4371 __ push(at);
4372 }
4373 if (assign_type == NAMED_PROPERTY) {
4374 // Put the object both on the stack and in the accumulator.
4375 VisitForAccumulatorValue(prop->obj());
4376 __ push(v0);
4377 EmitNamedPropertyLoad(prop);
4378 } else {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00004379 VisitForStackValue(prop->obj());
4380 VisitForAccumulatorValue(prop->key());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004381 __ lw(a1, MemOperand(sp, 0));
4382 __ push(v0);
4383 EmitKeyedPropertyLoad(prop);
4384 }
4385 }
4386
4387 // We need a second deoptimization point after loading the value
4388 // in case evaluating the property load my have a side effect.
4389 if (assign_type == VARIABLE) {
4390 PrepareForBailout(expr->expression(), TOS_REG);
4391 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004392 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004393 }
4394
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004395 // Inline smi case if we are in a loop.
4396 Label stub_call, done;
4397 JumpPatchSite patch_site(masm_);
4398
4399 int count_value = expr->op() == Token::INC ? 1 : -1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004400 __ mov(a0, v0);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004401 if (ShouldInlineSmiCase(expr->op())) {
4402 Label slow;
4403 patch_site.EmitJumpIfNotSmi(v0, &slow);
4404
4405 // Save result for postfix expressions.
4406 if (expr->is_postfix()) {
4407 if (!context()->IsEffect()) {
4408 // Save the result on the stack. If we have a named or keyed property
4409 // we store the result under the receiver that is currently on top
4410 // of the stack.
4411 switch (assign_type) {
4412 case VARIABLE:
4413 __ push(v0);
4414 break;
4415 case NAMED_PROPERTY:
4416 __ sw(v0, MemOperand(sp, kPointerSize));
4417 break;
4418 case KEYED_PROPERTY:
4419 __ sw(v0, MemOperand(sp, 2 * kPointerSize));
4420 break;
4421 }
4422 }
4423 }
4424
4425 Register scratch1 = a1;
4426 Register scratch2 = t0;
4427 __ li(scratch1, Operand(Smi::FromInt(count_value)));
4428 __ AdduAndCheckForOverflow(v0, v0, scratch1, scratch2);
4429 __ BranchOnNoOverflow(&done, scratch2);
4430 // Call stub. Undo operation first.
4431 __ Move(v0, a0);
4432 __ jmp(&stub_call);
4433 __ bind(&slow);
4434 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004435 ToNumberStub convert_stub;
4436 __ CallStub(&convert_stub);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004437
4438 // Save result for postfix expressions.
4439 if (expr->is_postfix()) {
4440 if (!context()->IsEffect()) {
4441 // Save the result on the stack. If we have a named or keyed property
4442 // we store the result under the receiver that is currently on top
4443 // of the stack.
4444 switch (assign_type) {
4445 case VARIABLE:
4446 __ push(v0);
4447 break;
4448 case NAMED_PROPERTY:
4449 __ sw(v0, MemOperand(sp, kPointerSize));
4450 break;
4451 case KEYED_PROPERTY:
4452 __ sw(v0, MemOperand(sp, 2 * kPointerSize));
4453 break;
4454 }
4455 }
4456 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004457
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004458 __ bind(&stub_call);
4459 __ mov(a1, v0);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004460 __ li(a0, Operand(Smi::FromInt(count_value)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004461
4462 // Record position before stub call.
4463 SetSourcePosition(expr->position());
4464
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00004465 BinaryOpICStub stub(Token::ADD, NO_OVERWRITE);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004466 CallIC(stub.GetCode(isolate()), expr->CountBinOpFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004467 patch_site.EmitPatchInfo();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004468 __ bind(&done);
4469
4470 // Store the value returned in v0.
4471 switch (assign_type) {
4472 case VARIABLE:
4473 if (expr->is_postfix()) {
4474 { EffectContext context(this);
4475 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4476 Token::ASSIGN);
4477 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4478 context.Plug(v0);
4479 }
4480 // For all contexts except EffectConstant we have the result on
4481 // top of the stack.
4482 if (!context()->IsEffect()) {
4483 context()->PlugTOS();
4484 }
4485 } else {
4486 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4487 Token::ASSIGN);
4488 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4489 context()->Plug(v0);
4490 }
4491 break;
4492 case NAMED_PROPERTY: {
4493 __ mov(a0, result_register()); // Value.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004494 __ li(a2, Operand(prop->key()->AsLiteral()->value())); // Name.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004495 __ pop(a1); // Receiver.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004496 CallStoreIC(expr->CountStoreFeedbackId());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004497 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4498 if (expr->is_postfix()) {
4499 if (!context()->IsEffect()) {
4500 context()->PlugTOS();
4501 }
4502 } else {
4503 context()->Plug(v0);
4504 }
4505 break;
4506 }
4507 case KEYED_PROPERTY: {
4508 __ mov(a0, result_register()); // Value.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004509 __ Pop(a2, a1); // a1 = key, a2 = receiver.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00004510 Handle<Code> ic = strict_mode() == SLOPPY
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004511 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4512 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004513 CallIC(ic, expr->CountStoreFeedbackId());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004514 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4515 if (expr->is_postfix()) {
4516 if (!context()->IsEffect()) {
4517 context()->PlugTOS();
4518 }
4519 } else {
4520 context()->Plug(v0);
4521 }
4522 break;
4523 }
4524 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004525}
4526
4527
lrn@chromium.org7516f052011-03-30 08:52:27 +00004528void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004529 ASSERT(!context()->IsEffect());
4530 ASSERT(!context()->IsTest());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004531 VariableProxy* proxy = expr->AsVariableProxy();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004532 if (proxy != NULL && proxy->var()->IsUnallocated()) {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004533 Comment cmnt(masm_, "[ Global variable");
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004534 __ lw(a0, GlobalObjectOperand());
4535 __ li(a2, Operand(proxy->name()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004536 // Use a regular load, not a contextual load, to avoid a reference
4537 // error.
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00004538 CallLoadIC(NOT_CONTEXTUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004539 PrepareForBailout(expr, TOS_REG);
4540 context()->Plug(v0);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004541 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004542 Comment cmnt(masm_, "[ Lookup slot");
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004543 Label done, slow;
4544
4545 // Generate code for loading from variables potentially shadowed
4546 // by eval-introduced variables.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004547 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004548
4549 __ bind(&slow);
4550 __ li(a0, Operand(proxy->name()));
4551 __ Push(cp, a0);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00004552 __ CallRuntime(Runtime::kHiddenLoadContextSlotNoReferenceError, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004553 PrepareForBailout(expr, TOS_REG);
4554 __ bind(&done);
4555
4556 context()->Plug(v0);
4557 } else {
4558 // This expression cannot throw a reference error at the top level.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004559 VisitInDuplicateContext(expr);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004560 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004561}
4562
ager@chromium.org04921a82011-06-27 13:21:41 +00004563void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004564 Expression* sub_expr,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004565 Handle<String> check) {
4566 Label materialize_true, materialize_false;
4567 Label* if_true = NULL;
4568 Label* if_false = NULL;
4569 Label* fall_through = NULL;
4570 context()->PrepareTest(&materialize_true, &materialize_false,
4571 &if_true, &if_false, &fall_through);
4572
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004573 { AccumulatorValueContext context(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004574 VisitForTypeofValue(sub_expr);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004575 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004576 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004577
ulan@chromium.org750145a2013-03-07 15:14:13 +00004578 if (check->Equals(isolate()->heap()->number_string())) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004579 __ JumpIfSmi(v0, if_true);
4580 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
4581 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4582 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004583 } else if (check->Equals(isolate()->heap()->string_string())) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004584 __ JumpIfSmi(v0, if_false);
4585 // Check for undetectable objects => false.
4586 __ GetObjectType(v0, v0, a1);
4587 __ Branch(if_false, ge, a1, Operand(FIRST_NONSTRING_TYPE));
4588 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
4589 __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
4590 Split(eq, a1, Operand(zero_reg),
4591 if_true, if_false, fall_through);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004592 } else if (check->Equals(isolate()->heap()->symbol_string())) {
4593 __ JumpIfSmi(v0, if_false);
4594 __ GetObjectType(v0, v0, a1);
4595 Split(eq, a1, Operand(SYMBOL_TYPE), if_true, if_false, fall_through);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004596 } else if (check->Equals(isolate()->heap()->boolean_string())) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004597 __ LoadRoot(at, Heap::kTrueValueRootIndex);
4598 __ Branch(if_true, eq, v0, Operand(at));
4599 __ LoadRoot(at, Heap::kFalseValueRootIndex);
4600 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
danno@chromium.orgb6451162011-08-17 14:33:23 +00004601 } else if (FLAG_harmony_typeof &&
ulan@chromium.org750145a2013-03-07 15:14:13 +00004602 check->Equals(isolate()->heap()->null_string())) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00004603 __ LoadRoot(at, Heap::kNullValueRootIndex);
4604 Split(eq, v0, Operand(at), if_true, if_false, fall_through);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004605 } else if (check->Equals(isolate()->heap()->undefined_string())) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004606 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4607 __ Branch(if_true, eq, v0, Operand(at));
4608 __ JumpIfSmi(v0, if_false);
4609 // Check for undetectable objects => true.
4610 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
4611 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
4612 __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
4613 Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004614 } else if (check->Equals(isolate()->heap()->function_string())) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004615 __ JumpIfSmi(v0, if_false);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004616 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4617 __ GetObjectType(v0, v0, a1);
4618 __ Branch(if_true, eq, a1, Operand(JS_FUNCTION_TYPE));
4619 Split(eq, a1, Operand(JS_FUNCTION_PROXY_TYPE),
4620 if_true, if_false, fall_through);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004621 } else if (check->Equals(isolate()->heap()->object_string())) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004622 __ JumpIfSmi(v0, if_false);
danno@chromium.orgb6451162011-08-17 14:33:23 +00004623 if (!FLAG_harmony_typeof) {
4624 __ LoadRoot(at, Heap::kNullValueRootIndex);
4625 __ Branch(if_true, eq, v0, Operand(at));
4626 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004627 // Check for JS objects => true.
4628 __ GetObjectType(v0, v0, a1);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004629 __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004630 __ lbu(a1, FieldMemOperand(v0, Map::kInstanceTypeOffset));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004631 __ Branch(if_false, gt, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004632 // Check for undetectable objects => false.
4633 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
4634 __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
4635 Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through);
4636 } else {
4637 if (if_false != fall_through) __ jmp(if_false);
4638 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004639 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004640}
4641
4642
ager@chromium.org5c838252010-02-19 08:53:10 +00004643void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004644 Comment cmnt(masm_, "[ CompareOperation");
4645 SetSourcePosition(expr->position());
4646
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004647 // First we try a fast inlined version of the compare when one of
4648 // the operands is a literal.
4649 if (TryLiteralCompare(expr)) return;
4650
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004651 // Always perform the comparison for its control flow. Pack the result
4652 // into the expression's context after the comparison is performed.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004653 Label materialize_true, materialize_false;
4654 Label* if_true = NULL;
4655 Label* if_false = NULL;
4656 Label* fall_through = NULL;
4657 context()->PrepareTest(&materialize_true, &materialize_false,
4658 &if_true, &if_false, &fall_through);
4659
ager@chromium.org04921a82011-06-27 13:21:41 +00004660 Token::Value op = expr->op();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004661 VisitForStackValue(expr->left());
4662 switch (op) {
4663 case Token::IN:
4664 VisitForStackValue(expr->right());
4665 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004666 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004667 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
4668 Split(eq, v0, Operand(t0), if_true, if_false, fall_through);
4669 break;
4670
4671 case Token::INSTANCEOF: {
4672 VisitForStackValue(expr->right());
4673 InstanceofStub stub(InstanceofStub::kNoFlags);
4674 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004675 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004676 // The stub returns 0 for true.
4677 Split(eq, v0, Operand(zero_reg), if_true, if_false, fall_through);
4678 break;
4679 }
4680
4681 default: {
4682 VisitForAccumulatorValue(expr->right());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004683 Condition cc = CompareIC::ComputeCondition(op);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004684 __ mov(a0, result_register());
4685 __ pop(a1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004686
4687 bool inline_smi_code = ShouldInlineSmiCase(op);
4688 JumpPatchSite patch_site(masm_);
4689 if (inline_smi_code) {
4690 Label slow_case;
4691 __ Or(a2, a0, Operand(a1));
4692 patch_site.EmitJumpIfNotSmi(a2, &slow_case);
4693 Split(cc, a1, Operand(a0), if_true, if_false, NULL);
4694 __ bind(&slow_case);
4695 }
4696 // Record position and call the compare IC.
4697 SetSourcePosition(expr->position());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004698 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004699 CallIC(ic, expr->CompareOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004700 patch_site.EmitPatchInfo();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004701 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004702 Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through);
4703 }
4704 }
4705
4706 // Convert the result of the comparison into one expected for this
4707 // expression's context.
4708 context()->Plug(if_true, if_false);
ager@chromium.org5c838252010-02-19 08:53:10 +00004709}
4710
4711
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004712void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4713 Expression* sub_expr,
4714 NilValue nil) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004715 Label materialize_true, materialize_false;
4716 Label* if_true = NULL;
4717 Label* if_false = NULL;
4718 Label* fall_through = NULL;
4719 context()->PrepareTest(&materialize_true, &materialize_false,
4720 &if_true, &if_false, &fall_through);
4721
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004722 VisitForAccumulatorValue(sub_expr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004723 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004724 __ mov(a0, result_register());
ulan@chromium.org837a67e2013-06-11 15:39:48 +00004725 if (expr->op() == Token::EQ_STRICT) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004726 Heap::RootListIndex nil_value = nil == kNullValue ?
4727 Heap::kNullValueRootIndex :
4728 Heap::kUndefinedValueRootIndex;
4729 __ LoadRoot(a1, nil_value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004730 Split(eq, a0, Operand(a1), if_true, if_false, fall_through);
4731 } else {
ulan@chromium.org837a67e2013-06-11 15:39:48 +00004732 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004733 CallIC(ic, expr->CompareOperationFeedbackId());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004734 Split(ne, v0, Operand(zero_reg), if_true, if_false, fall_through);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004735 }
4736 context()->Plug(if_true, if_false);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004737}
4738
4739
ager@chromium.org5c838252010-02-19 08:53:10 +00004740void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004741 __ lw(v0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4742 context()->Plug(v0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004743}
4744
4745
lrn@chromium.org7516f052011-03-30 08:52:27 +00004746Register FullCodeGenerator::result_register() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00004747 return v0;
4748}
ager@chromium.org5c838252010-02-19 08:53:10 +00004749
4750
lrn@chromium.org7516f052011-03-30 08:52:27 +00004751Register FullCodeGenerator::context_register() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00004752 return cp;
4753}
4754
4755
ager@chromium.org5c838252010-02-19 08:53:10 +00004756void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004757 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4758 __ sw(value, MemOperand(fp, frame_offset));
ager@chromium.org5c838252010-02-19 08:53:10 +00004759}
4760
4761
4762void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004763 __ lw(dst, ContextOperand(cp, context_index));
ager@chromium.org5c838252010-02-19 08:53:10 +00004764}
4765
4766
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004767void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
4768 Scope* declaration_scope = scope()->DeclarationScope();
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004769 if (declaration_scope->is_global_scope() ||
4770 declaration_scope->is_module_scope()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004771 // Contexts nested in the native context have a canonical empty function
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004772 // as their closure, not the anonymous closure containing the global
4773 // code. Pass a smi sentinel and let the runtime look up the empty
4774 // function.
4775 __ li(at, Operand(Smi::FromInt(0)));
4776 } else if (declaration_scope->is_eval_scope()) {
4777 // Contexts created by a call to eval have the same closure as the
4778 // context calling eval, not the anonymous closure containing the eval
4779 // code. Fetch it from the context.
4780 __ lw(at, ContextOperand(cp, Context::CLOSURE_INDEX));
4781 } else {
4782 ASSERT(declaration_scope->is_function_scope());
4783 __ lw(at, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4784 }
4785 __ push(at);
4786}
4787
4788
ager@chromium.org5c838252010-02-19 08:53:10 +00004789// ----------------------------------------------------------------------------
4790// Non-local control flow support.
4791
4792void FullCodeGenerator::EnterFinallyBlock() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004793 ASSERT(!result_register().is(a1));
4794 // Store result register while executing finally block.
4795 __ push(result_register());
4796 // Cook return address in link register to stack (smi encoded Code* delta).
4797 __ Subu(a1, ra, Operand(masm_->CodeObject()));
4798 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004799 STATIC_ASSERT(0 == kSmiTag);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004800 __ Addu(a1, a1, Operand(a1)); // Convert to smi.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004801
4802 // Store result register while executing finally block.
4803 __ push(a1);
4804
4805 // Store pending message while executing finally block.
4806 ExternalReference pending_message_obj =
4807 ExternalReference::address_of_pending_message_obj(isolate());
4808 __ li(at, Operand(pending_message_obj));
4809 __ lw(a1, MemOperand(at));
4810 __ push(a1);
4811
4812 ExternalReference has_pending_message =
4813 ExternalReference::address_of_has_pending_message(isolate());
4814 __ li(at, Operand(has_pending_message));
4815 __ lw(a1, MemOperand(at));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004816 __ SmiTag(a1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004817 __ push(a1);
4818
4819 ExternalReference pending_message_script =
4820 ExternalReference::address_of_pending_message_script(isolate());
4821 __ li(at, Operand(pending_message_script));
4822 __ lw(a1, MemOperand(at));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004823 __ push(a1);
ager@chromium.org5c838252010-02-19 08:53:10 +00004824}
4825
4826
4827void FullCodeGenerator::ExitFinallyBlock() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004828 ASSERT(!result_register().is(a1));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004829 // Restore pending message from stack.
4830 __ pop(a1);
4831 ExternalReference pending_message_script =
4832 ExternalReference::address_of_pending_message_script(isolate());
4833 __ li(at, Operand(pending_message_script));
4834 __ sw(a1, MemOperand(at));
4835
4836 __ pop(a1);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004837 __ SmiUntag(a1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004838 ExternalReference has_pending_message =
4839 ExternalReference::address_of_has_pending_message(isolate());
4840 __ li(at, Operand(has_pending_message));
4841 __ sw(a1, MemOperand(at));
4842
4843 __ pop(a1);
4844 ExternalReference pending_message_obj =
4845 ExternalReference::address_of_pending_message_obj(isolate());
4846 __ li(at, Operand(pending_message_obj));
4847 __ sw(a1, MemOperand(at));
4848
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004849 // Restore result register from stack.
4850 __ pop(a1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004851
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004852 // Uncook return address and return.
4853 __ pop(result_register());
4854 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4855 __ sra(a1, a1, 1); // Un-smi-tag value.
4856 __ Addu(at, a1, Operand(masm_->CodeObject()));
4857 __ Jump(at);
ager@chromium.org5c838252010-02-19 08:53:10 +00004858}
4859
4860
4861#undef __
4862
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004863#define __ ACCESS_MASM(masm())
4864
4865FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4866 int* stack_depth,
4867 int* context_length) {
4868 // The macros used here must preserve the result register.
4869
4870 // Because the handler block contains the context of the finally
4871 // code, we can restore it directly from there for the finally code
4872 // rather than iteratively unwinding contexts via their previous
4873 // links.
4874 __ Drop(*stack_depth); // Down to the handler block.
4875 if (*context_length > 0) {
4876 // Restore the context to its dedicated register and the stack.
4877 __ lw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
4878 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
4879 }
4880 __ PopTryHandler();
4881 __ Call(finally_entry_);
4882
4883 *stack_depth = 0;
4884 *context_length = 0;
4885 return previous_;
4886}
4887
4888
4889#undef __
4890
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004891
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004892void BackEdgeTable::PatchAt(Code* unoptimized_code,
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004893 Address pc,
4894 BackEdgeState target_state,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004895 Code* replacement_code) {
4896 static const int kInstrSize = Assembler::kInstrSize;
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004897 Address branch_address = pc - 6 * kInstrSize;
4898 CodePatcher patcher(branch_address, 1);
4899
4900 switch (target_state) {
4901 case INTERRUPT:
4902 // slt at, a3, zero_reg (in case of count based interrupts)
4903 // beq at, zero_reg, ok
4904 // lui t9, <interrupt stub address> upper
4905 // ori t9, <interrupt stub address> lower
4906 // jalr t9
4907 // nop
4908 // ok-label ----- pc_after points here
4909 patcher.masm()->slt(at, a3, zero_reg);
4910 break;
4911 case ON_STACK_REPLACEMENT:
4912 case OSR_AFTER_STACK_CHECK:
4913 // addiu at, zero_reg, 1
4914 // beq at, zero_reg, ok ;; Not changed
4915 // lui t9, <on-stack replacement address> upper
4916 // ori t9, <on-stack replacement address> lower
4917 // jalr t9 ;; Not changed
4918 // nop ;; Not changed
4919 // ok-label ----- pc_after points here
4920 patcher.masm()->addiu(at, zero_reg, 1);
4921 break;
4922 }
4923 Address pc_immediate_load_address = pc - 4 * kInstrSize;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004924 // Replace the stack check address in the load-immediate (lui/ori pair)
4925 // with the entry address of the replacement code.
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004926 Assembler::set_target_address_at(pc_immediate_load_address,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004927 replacement_code->entry());
4928
4929 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004930 unoptimized_code, pc_immediate_load_address, replacement_code);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004931}
4932
4933
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004934BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
4935 Isolate* isolate,
4936 Code* unoptimized_code,
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004937 Address pc) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004938 static const int kInstrSize = Assembler::kInstrSize;
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004939 Address branch_address = pc - 6 * kInstrSize;
4940 Address pc_immediate_load_address = pc - 4 * kInstrSize;
4941
4942 ASSERT(Assembler::IsBeq(Assembler::instr_at(pc - 5 * kInstrSize)));
4943 if (!Assembler::IsAddImmediate(Assembler::instr_at(branch_address))) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004944 ASSERT(reinterpret_cast<uint32_t>(
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004945 Assembler::target_address_at(pc_immediate_load_address)) ==
4946 reinterpret_cast<uint32_t>(
4947 isolate->builtins()->InterruptCheck()->entry()));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004948 return INTERRUPT;
4949 }
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004950
4951 ASSERT(Assembler::IsAddImmediate(Assembler::instr_at(branch_address)));
4952
4953 if (reinterpret_cast<uint32_t>(
4954 Assembler::target_address_at(pc_immediate_load_address)) ==
4955 reinterpret_cast<uint32_t>(
4956 isolate->builtins()->OnStackReplacement()->entry())) {
4957 return ON_STACK_REPLACEMENT;
4958 }
4959
4960 ASSERT(reinterpret_cast<uint32_t>(
4961 Assembler::target_address_at(pc_immediate_load_address)) ==
4962 reinterpret_cast<uint32_t>(
4963 isolate->builtins()->OsrAfterStackCheck()->entry()));
4964 return OSR_AFTER_STACK_CHECK;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004965}
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004966
4967
ager@chromium.org5c838252010-02-19 08:53:10 +00004968} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004969
4970#endif // V8_TARGET_ARCH_MIPS