blob: ede810c7b7b3ad6c01a0bad86cad5201db3358b5 [file] [log] [blame]
Ben Murdoch086aeea2011-05-13 15:57:08 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Block3ce2e202009-11-05 08:53:23 +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
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_IA32)
31
Kristian Monsen80d68ea2010-09-08 11:05:35 +010032#include "code-stubs.h"
Ben Murdoch8b112d22011-06-08 16:22:53 +010033#include "codegen.h"
Steve Blockd0582a62009-12-15 09:54:21 +000034#include "compiler.h"
Leon Clarkee46be812010-01-19 14:06:41 +000035#include "debug.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000036#include "full-codegen.h"
Steve Block3ce2e202009-11-05 08:53:23 +000037#include "parser.h"
Steve Block6ded16b2010-05-10 14:33:55 +010038#include "scopes.h"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080039#include "stub-cache.h"
Steve Block3ce2e202009-11-05 08:53:23 +000040
41namespace v8 {
42namespace internal {
43
44#define __ ACCESS_MASM(masm_)
45
Ben Murdochb0fe1622011-05-05 13:52:32 +010046
47class JumpPatchSite BASE_EMBEDDED {
48 public:
Steve Block1e0659c2011-05-24 12:43:12 +010049 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010050#ifdef DEBUG
51 info_emitted_ = false;
52#endif
53 }
54
55 ~JumpPatchSite() {
56 ASSERT(patch_site_.is_bound() == info_emitted_);
57 }
58
Ben Murdoch257744e2011-11-30 15:57:28 +000059 void EmitJumpIfNotSmi(Register reg,
60 Label* target,
61 Label::Distance distance = Label::kFar) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010062 __ test(reg, Immediate(kSmiTagMask));
Ben Murdoch257744e2011-11-30 15:57:28 +000063 EmitJump(not_carry, target, distance); // Always taken before patched.
Ben Murdochb0fe1622011-05-05 13:52:32 +010064 }
65
Ben Murdoch257744e2011-11-30 15:57:28 +000066 void EmitJumpIfSmi(Register reg,
67 Label* target,
68 Label::Distance distance = Label::kFar) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010069 __ test(reg, Immediate(kSmiTagMask));
Ben Murdoch257744e2011-11-30 15:57:28 +000070 EmitJump(carry, target, distance); // Never taken before patched.
Ben Murdochb0fe1622011-05-05 13:52:32 +010071 }
72
73 void EmitPatchInfo() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000074 if (patch_site_.is_bound()) {
75 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
76 ASSERT(is_int8(delta_to_patch_site));
77 __ test(eax, Immediate(delta_to_patch_site));
Ben Murdochb0fe1622011-05-05 13:52:32 +010078#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000079 info_emitted_ = true;
Ben Murdochb0fe1622011-05-05 13:52:32 +010080#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000081 } else {
82 __ nop(); // Signals no inlined code.
83 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010084 }
85
Ben Murdochb0fe1622011-05-05 13:52:32 +010086 private:
87 // jc will be patched with jz, jnc will become jnz.
Ben Murdoch257744e2011-11-30 15:57:28 +000088 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010089 ASSERT(!patch_site_.is_bound() && !info_emitted_);
90 ASSERT(cc == carry || cc == not_carry);
91 __ bind(&patch_site_);
Ben Murdoch257744e2011-11-30 15:57:28 +000092 __ j(cc, target, distance);
Ben Murdochb0fe1622011-05-05 13:52:32 +010093 }
94
95 MacroAssembler* masm_;
96 Label patch_site_;
97#ifdef DEBUG
98 bool info_emitted_;
99#endif
100};
101
102
Steve Block3ce2e202009-11-05 08:53:23 +0000103// Generate code for a JS function. On entry to the function the receiver
104// and arguments have been pushed on the stack left to right, with the
105// return address on top of them. The actual argument count matches the
106// formal parameter count expected by the function.
107//
108// The live registers are:
Ben Murdochc7cc0282012-03-05 14:35:55 +0000109// o edi: the JS function object being called (i.e. ourselves)
Steve Block3ce2e202009-11-05 08:53:23 +0000110// o esi: our context
111// o ebp: our caller's frame pointer
112// o esp: stack pointer (pointing to return address)
113//
114// The function builds a JS frame. Please see JavaScriptFrameConstants in
115// frames-ia32.h for its layout.
Iain Merrick75681382010-08-19 15:07:18 +0100116void FullCodeGenerator::Generate(CompilationInfo* info) {
Andrei Popescu31002712010-02-23 13:46:05 +0000117 ASSERT(info_ == NULL);
118 info_ = info;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000119 scope_ = info->scope();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000120 handler_table_ =
121 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
Andrei Popescu31002712010-02-23 13:46:05 +0000122 SetFunctionPosition(function());
Steve Block6ded16b2010-05-10 14:33:55 +0100123 Comment cmnt(masm_, "[ function compiled by full code generator");
Steve Block3ce2e202009-11-05 08:53:23 +0000124
Ben Murdochf87a2032010-10-22 12:50:53 +0100125#ifdef DEBUG
126 if (strlen(FLAG_stop_at) > 0 &&
127 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
128 __ int3();
129 }
130#endif
131
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000132 // Strict mode functions and builtins need to replace the receiver
133 // with undefined when called as functions (without an explicit
134 // receiver object). ecx is zero for method calls and non-zero for
135 // function calls.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000136 if (!info->is_classic_mode() || info->is_native()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000137 Label ok;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000138 __ test(ecx, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +0000139 __ j(zero, &ok, Label::kNear);
140 // +1 for return address.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000141 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000142 __ mov(ecx, Operand(esp, receiver_offset));
143 __ JumpIfSmi(ecx, &ok);
144 __ CmpObjectType(ecx, JS_GLOBAL_PROXY_TYPE, ecx);
145 __ j(not_equal, &ok, Label::kNear);
Ben Murdoch257744e2011-11-30 15:57:28 +0000146 __ mov(Operand(esp, receiver_offset),
147 Immediate(isolate()->factory()->undefined_value()));
148 __ bind(&ok);
149 }
150
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000151 // Open a frame scope to indicate that there is a frame on the stack. The
152 // MANUAL indicates that the scope shouldn't actually generate code to set up
153 // the frame (that is done below).
154 FrameScope frame_scope(masm_, StackFrame::MANUAL);
155
Iain Merrick75681382010-08-19 15:07:18 +0100156 __ push(ebp); // Caller's frame pointer.
157 __ mov(ebp, esp);
158 __ push(esi); // Callee's context.
159 __ push(edi); // Callee's JS Function.
Steve Block3ce2e202009-11-05 08:53:23 +0000160
Iain Merrick75681382010-08-19 15:07:18 +0100161 { Comment cmnt(masm_, "[ Allocate locals");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000162 int locals_count = info->scope()->num_stack_slots();
Iain Merrick75681382010-08-19 15:07:18 +0100163 if (locals_count == 1) {
Steve Block44f0eee2011-05-26 01:26:41 +0100164 __ push(Immediate(isolate()->factory()->undefined_value()));
Iain Merrick75681382010-08-19 15:07:18 +0100165 } else if (locals_count > 1) {
Steve Block44f0eee2011-05-26 01:26:41 +0100166 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
Iain Merrick75681382010-08-19 15:07:18 +0100167 for (int i = 0; i < locals_count; i++) {
168 __ push(eax);
Steve Blockd0582a62009-12-15 09:54:21 +0000169 }
Steve Block3ce2e202009-11-05 08:53:23 +0000170 }
Iain Merrick75681382010-08-19 15:07:18 +0100171 }
Steve Block3ce2e202009-11-05 08:53:23 +0000172
Iain Merrick75681382010-08-19 15:07:18 +0100173 bool function_in_register = true;
Steve Blockd0582a62009-12-15 09:54:21 +0000174
Iain Merrick75681382010-08-19 15:07:18 +0100175 // Possibly allocate a local context.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000176 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
Iain Merrick75681382010-08-19 15:07:18 +0100177 if (heap_slots > 0) {
178 Comment cmnt(masm_, "[ Allocate local context");
179 // Argument to NewContext is the function, which is still in edi.
180 __ push(edi);
181 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
182 FastNewContextStub stub(heap_slots);
Leon Clarke4515c472010-02-03 11:58:03 +0000183 __ CallStub(&stub);
Iain Merrick75681382010-08-19 15:07:18 +0100184 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000185 __ CallRuntime(Runtime::kNewFunctionContext, 1);
Leon Clarke4515c472010-02-03 11:58:03 +0000186 }
Iain Merrick75681382010-08-19 15:07:18 +0100187 function_in_register = false;
188 // Context is returned in both eax and esi. It replaces the context
189 // passed to us. It's saved in the stack and kept live in esi.
190 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
191
192 // Copy parameters into context if necessary.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000193 int num_parameters = info->scope()->num_parameters();
Iain Merrick75681382010-08-19 15:07:18 +0100194 for (int i = 0; i < num_parameters; i++) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000195 Variable* var = scope()->parameter(i);
196 if (var->IsContextSlot()) {
Iain Merrick75681382010-08-19 15:07:18 +0100197 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
198 (num_parameters - 1 - i) * kPointerSize;
199 // Load parameter from stack.
200 __ mov(eax, Operand(ebp, parameter_offset));
201 // Store it in the context.
Ben Murdoch589d6972011-11-30 16:04:58 +0000202 int context_offset = Context::SlotOffset(var->index());
Iain Merrick75681382010-08-19 15:07:18 +0100203 __ mov(Operand(esi, context_offset), eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000204 // Update the write barrier. This clobbers eax and ebx.
205 __ RecordWriteContextSlot(esi,
206 context_offset,
207 eax,
208 ebx,
209 kDontSaveFPRegs);
Iain Merrick75681382010-08-19 15:07:18 +0100210 }
211 }
212 }
213
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100214 Variable* arguments = scope()->arguments();
Iain Merrick75681382010-08-19 15:07:18 +0100215 if (arguments != NULL) {
216 // Function uses arguments object.
217 Comment cmnt(masm_, "[ Allocate arguments object");
218 if (function_in_register) {
219 __ push(edi);
220 } else {
221 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
222 }
223 // Receiver is just before the parameters on the caller's stack.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000224 int num_parameters = info->scope()->num_parameters();
225 int offset = num_parameters * kPointerSize;
Iain Merrick75681382010-08-19 15:07:18 +0100226 __ lea(edx,
227 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
228 __ push(edx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000229 __ SafePush(Immediate(Smi::FromInt(num_parameters)));
Ben Murdochc7cc0282012-03-05 14:35:55 +0000230 // Arguments to ArgumentsAccessStub:
Iain Merrick75681382010-08-19 15:07:18 +0100231 // function, receiver address, parameter count.
232 // The stub will rewrite receiver and parameter count if the previous
233 // stack frame was an arguments adapter frame.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000234 ArgumentsAccessStub::Type type;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000235 if (!is_classic_mode()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000236 type = ArgumentsAccessStub::NEW_STRICT;
237 } else if (function()->has_duplicate_parameters()) {
238 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
239 } else {
240 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
241 }
242 ArgumentsAccessStub stub(type);
Iain Merrick75681382010-08-19 15:07:18 +0100243 __ CallStub(&stub);
Steve Block44f0eee2011-05-26 01:26:41 +0100244
Ben Murdoch589d6972011-11-30 16:04:58 +0000245 SetVar(arguments, eax, ebx, edx);
Steve Blockd0582a62009-12-15 09:54:21 +0000246 }
247
Ben Murdochb0fe1622011-05-05 13:52:32 +0100248 if (FLAG_trace) {
249 __ CallRuntime(Runtime::kTraceEnter, 0);
250 }
251
Steve Block1e0659c2011-05-24 12:43:12 +0100252 // Visit the declarations and body unless there is an illegal
253 // redeclaration.
254 if (scope()->HasIllegalRedeclaration()) {
255 Comment cmnt(masm_, "[ Declarations");
256 scope()->VisitIllegalRedeclaration(this);
257
258 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000259 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
Steve Block1e0659c2011-05-24 12:43:12 +0100260 { Comment cmnt(masm_, "[ Declarations");
261 // For named function expressions, declare the function name as a
262 // constant.
263 if (scope()->is_function_scope() && scope()->function() != NULL) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000264 int ignored = 0;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000265 VariableProxy* proxy = scope()->function();
266 ASSERT(proxy->var()->mode() == CONST ||
267 proxy->var()->mode() == CONST_HARMONY);
268 EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored);
Steve Block1e0659c2011-05-24 12:43:12 +0100269 }
270 VisitDeclarations(scope()->declarations());
271 }
272
273 { Comment cmnt(masm_, "[ Stack check");
Ben Murdoch589d6972011-11-30 16:04:58 +0000274 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Ben Murdoch257744e2011-11-30 15:57:28 +0000275 Label ok;
Steve Block1e0659c2011-05-24 12:43:12 +0100276 ExternalReference stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +0100277 ExternalReference::address_of_stack_limit(isolate());
Steve Block1e0659c2011-05-24 12:43:12 +0100278 __ cmp(esp, Operand::StaticVariable(stack_limit));
Ben Murdoch257744e2011-11-30 15:57:28 +0000279 __ j(above_equal, &ok, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +0100280 StackCheckStub stub;
281 __ CallStub(&stub);
282 __ bind(&ok);
283 }
284
285 { Comment cmnt(masm_, "[ Body");
286 ASSERT(loop_depth() == 0);
287 VisitStatements(function()->body());
288 ASSERT(loop_depth() == 0);
289 }
Steve Block3ce2e202009-11-05 08:53:23 +0000290 }
291
Steve Block1e0659c2011-05-24 12:43:12 +0100292 // Always emit a 'return undefined' in case control fell off the end of
293 // the body.
Steve Block3ce2e202009-11-05 08:53:23 +0000294 { Comment cmnt(masm_, "[ return <undefined>;");
Steve Block44f0eee2011-05-26 01:26:41 +0100295 __ mov(eax, isolate()->factory()->undefined_value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100296 EmitReturnSequence();
Steve Blockd0582a62009-12-15 09:54:21 +0000297 }
298}
Steve Block3ce2e202009-11-05 08:53:23 +0000299
Steve Blockd0582a62009-12-15 09:54:21 +0000300
Ben Murdochdb5a90a2011-01-06 18:27:03 +0000301void FullCodeGenerator::ClearAccumulator() {
302 __ Set(eax, Immediate(Smi::FromInt(0)));
303}
304
305
Ben Murdochb0fe1622011-05-05 13:52:32 +0100306void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
307 Comment cmnt(masm_, "[ Stack check");
Ben Murdoch257744e2011-11-30 15:57:28 +0000308 Label ok;
Steve Block44f0eee2011-05-26 01:26:41 +0100309 ExternalReference stack_limit =
310 ExternalReference::address_of_stack_limit(isolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100311 __ cmp(esp, Operand::StaticVariable(stack_limit));
Ben Murdoch257744e2011-11-30 15:57:28 +0000312 __ j(above_equal, &ok, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100313 StackCheckStub stub;
314 __ CallStub(&stub);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100315 // Record a mapping of this PC offset to the OSR id. This is used to find
316 // the AST id from the unoptimized code in order to use it as a key into
317 // the deoptimization input data found in the optimized code.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100318 RecordStackCheck(stmt->OsrEntryId());
Ben Murdoch086aeea2011-05-13 15:57:08 +0100319
320 // Loop stack checks can be patched to perform on-stack replacement. In
321 // order to decide whether or not to perform OSR we embed the loop depth
322 // in a test instruction after the call so we can extract it from the OSR
323 // builtin.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100324 ASSERT(loop_depth() > 0);
325 __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
Ben Murdoch086aeea2011-05-13 15:57:08 +0100326
327 __ bind(&ok);
328 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
329 // Record a mapping of the OSR id to this PC. This is used if the OSR
330 // entry becomes the target of a bailout. We don't expect it to be, but
331 // we want it to work if it is.
332 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100333}
334
335
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100336void FullCodeGenerator::EmitReturnSequence() {
Steve Blockd0582a62009-12-15 09:54:21 +0000337 Comment cmnt(masm_, "[ Return sequence");
338 if (return_label_.is_bound()) {
339 __ jmp(&return_label_);
340 } else {
341 // Common return label
342 __ bind(&return_label_);
Steve Block3ce2e202009-11-05 08:53:23 +0000343 if (FLAG_trace) {
344 __ push(eax);
345 __ CallRuntime(Runtime::kTraceExit, 1);
346 }
Steve Blockd0582a62009-12-15 09:54:21 +0000347#ifdef DEBUG
348 // Add a label for checking the size of the code used for returning.
349 Label check_exit_codesize;
350 masm_->bind(&check_exit_codesize);
351#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100352 SetSourcePosition(function()->end_position() - 1);
Steve Block3ce2e202009-11-05 08:53:23 +0000353 __ RecordJSReturn();
354 // Do not use the leave instruction here because it is too short to
355 // patch with the code required by the debugger.
356 __ mov(esp, ebp);
357 __ pop(ebp);
Steve Block1e0659c2011-05-24 12:43:12 +0100358
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000359 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
Steve Block1e0659c2011-05-24 12:43:12 +0100360 __ Ret(arguments_bytes, ecx);
Steve Blockd0582a62009-12-15 09:54:21 +0000361#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block1e0659c2011-05-24 12:43:12 +0100362 // Check that the size of the code used for returning is large enough
363 // for the debugger's requirements.
364 ASSERT(Assembler::kJSReturnSequenceLength <=
365 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
Steve Blockd0582a62009-12-15 09:54:21 +0000366#endif
367 }
368}
369
370
Ben Murdoch589d6972011-11-30 16:04:58 +0000371void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
372 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
Steve Blockd0582a62009-12-15 09:54:21 +0000373}
374
375
Ben Murdoch589d6972011-11-30 16:04:58 +0000376void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
377 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
378 codegen()->GetVar(result_register(), var);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100379}
380
381
Ben Murdoch589d6972011-11-30 16:04:58 +0000382void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
383 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
384 MemOperand operand = codegen()->VarOperand(var, result_register());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100385 // Memory operands can be pushed directly.
Ben Murdoch589d6972011-11-30 16:04:58 +0000386 __ push(operand);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100387}
388
389
Ben Murdoch589d6972011-11-30 16:04:58 +0000390void FullCodeGenerator::TestContext::Plug(Variable* var) const {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100391 // For simplicity we always test the accumulator register.
Ben Murdoch589d6972011-11-30 16:04:58 +0000392 codegen()->GetVar(result_register(), var);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000393 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000394 codegen()->DoTest(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100395}
396
397
398void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
399 UNREACHABLE(); // Not used on IA32.
400}
401
402
403void FullCodeGenerator::AccumulatorValueContext::Plug(
404 Heap::RootListIndex index) const {
405 UNREACHABLE(); // Not used on IA32.
406}
407
408
409void FullCodeGenerator::StackValueContext::Plug(
410 Heap::RootListIndex index) const {
411 UNREACHABLE(); // Not used on IA32.
412}
413
414
415void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
416 UNREACHABLE(); // Not used on IA32.
417}
418
419
420void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
421}
422
423
424void FullCodeGenerator::AccumulatorValueContext::Plug(
425 Handle<Object> lit) const {
Steve Block053d10c2011-06-13 19:13:29 +0100426 if (lit->IsSmi()) {
427 __ SafeSet(result_register(), Immediate(lit));
428 } else {
429 __ Set(result_register(), Immediate(lit));
430 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100431}
432
433
434void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
Steve Block053d10c2011-06-13 19:13:29 +0100435 if (lit->IsSmi()) {
436 __ SafePush(Immediate(lit));
437 } else {
438 __ push(Immediate(lit));
439 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100440}
441
442
443void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000444 codegen()->PrepareForBailoutBeforeSplit(condition(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100445 true,
446 true_label_,
447 false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100448 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
449 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100450 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100451 } else if (lit->IsTrue() || lit->IsJSObject()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100452 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100453 } else if (lit->IsString()) {
454 if (String::cast(*lit)->length() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100455 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100456 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100457 if (true_label_ != fall_through_) __ jmp(true_label_);
Steve Blockd0582a62009-12-15 09:54:21 +0000458 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100459 } else if (lit->IsSmi()) {
460 if (Smi::cast(*lit)->value() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100461 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100462 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100463 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100464 }
465 } else {
466 // For simplicity we always test the accumulator register.
467 __ mov(result_register(), lit);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000468 codegen()->DoTest(this);
Steve Blockd0582a62009-12-15 09:54:21 +0000469 }
470}
471
472
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100473void FullCodeGenerator::EffectContext::DropAndPlug(int count,
474 Register reg) const {
Leon Clarkee46be812010-01-19 14:06:41 +0000475 ASSERT(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100476 __ Drop(count);
Leon Clarkef7060e22010-06-03 12:02:55 +0100477}
478
479
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100480void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
481 int count,
482 Register reg) const {
483 ASSERT(count > 0);
484 __ Drop(count);
485 __ Move(result_register(), reg);
Leon Clarkee46be812010-01-19 14:06:41 +0000486}
487
488
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100489void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
490 Register reg) const {
491 ASSERT(count > 0);
492 if (count > 1) __ Drop(count - 1);
493 __ mov(Operand(esp, 0), reg);
494}
495
496
497void FullCodeGenerator::TestContext::DropAndPlug(int count,
498 Register reg) const {
499 ASSERT(count > 0);
500 // For simplicity we always test the accumulator register.
501 __ Drop(count);
502 __ Move(result_register(), reg);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000503 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000504 codegen()->DoTest(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100505}
506
507
508void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
509 Label* materialize_false) const {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100510 ASSERT(materialize_true == materialize_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100511 __ bind(materialize_true);
512}
513
514
515void FullCodeGenerator::AccumulatorValueContext::Plug(
516 Label* materialize_true,
517 Label* materialize_false) const {
Ben Murdoch257744e2011-11-30 15:57:28 +0000518 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100519 __ bind(materialize_true);
Steve Block44f0eee2011-05-26 01:26:41 +0100520 __ mov(result_register(), isolate()->factory()->true_value());
Ben Murdoch257744e2011-11-30 15:57:28 +0000521 __ jmp(&done, Label::kNear);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100522 __ bind(materialize_false);
Steve Block44f0eee2011-05-26 01:26:41 +0100523 __ mov(result_register(), isolate()->factory()->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100524 __ bind(&done);
525}
526
527
528void FullCodeGenerator::StackValueContext::Plug(
529 Label* materialize_true,
530 Label* materialize_false) const {
Ben Murdoch257744e2011-11-30 15:57:28 +0000531 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100532 __ bind(materialize_true);
Steve Block44f0eee2011-05-26 01:26:41 +0100533 __ push(Immediate(isolate()->factory()->true_value()));
Ben Murdoch257744e2011-11-30 15:57:28 +0000534 __ jmp(&done, Label::kNear);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100535 __ bind(materialize_false);
Steve Block44f0eee2011-05-26 01:26:41 +0100536 __ push(Immediate(isolate()->factory()->false_value()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100537 __ bind(&done);
538}
539
540
541void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
542 Label* materialize_false) const {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100543 ASSERT(materialize_true == true_label_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100544 ASSERT(materialize_false == false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100545}
546
547
548void FullCodeGenerator::EffectContext::Plug(bool flag) const {
549}
550
551
552void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100553 Handle<Object> value = flag
554 ? isolate()->factory()->true_value()
555 : isolate()->factory()->false_value();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100556 __ mov(result_register(), value);
557}
558
559
560void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100561 Handle<Object> value = flag
562 ? isolate()->factory()->true_value()
563 : isolate()->factory()->false_value();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100564 __ push(Immediate(value));
565}
566
567
568void FullCodeGenerator::TestContext::Plug(bool flag) const {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000569 codegen()->PrepareForBailoutBeforeSplit(condition(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100570 true,
571 true_label_,
572 false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100573 if (flag) {
574 if (true_label_ != fall_through_) __ jmp(true_label_);
575 } else {
576 if (false_label_ != fall_through_) __ jmp(false_label_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100577 }
578}
579
580
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000581void FullCodeGenerator::DoTest(Expression* condition,
582 Label* if_true,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100583 Label* if_false,
584 Label* fall_through) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000585 ToBooleanStub stub(result_register());
Leon Clarkee46be812010-01-19 14:06:41 +0000586 __ push(result_register());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000587 __ CallStub(&stub, condition->test_id());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000588 __ test(result_register(), result_register());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100589 // The stub returns nonzero for true.
590 Split(not_zero, if_true, if_false, fall_through);
591}
Leon Clarkee46be812010-01-19 14:06:41 +0000592
Leon Clarkee46be812010-01-19 14:06:41 +0000593
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100594void FullCodeGenerator::Split(Condition cc,
595 Label* if_true,
596 Label* if_false,
597 Label* fall_through) {
598 if (if_false == fall_through) {
599 __ j(cc, if_true);
600 } else if (if_true == fall_through) {
601 __ j(NegateCondition(cc), if_false);
602 } else {
603 __ j(cc, if_true);
604 __ jmp(if_false);
Leon Clarkee46be812010-01-19 14:06:41 +0000605 }
606}
607
608
Ben Murdoch589d6972011-11-30 16:04:58 +0000609MemOperand FullCodeGenerator::StackOperand(Variable* var) {
610 ASSERT(var->IsStackAllocated());
611 // Offset is negative because higher indexes are at lower addresses.
612 int offset = -var->index() * kPointerSize;
613 // Adjust by a (parameter or local) base offset.
614 if (var->IsParameter()) {
615 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
616 } else {
617 offset += JavaScriptFrameConstants::kLocal0Offset;
Leon Clarkee46be812010-01-19 14:06:41 +0000618 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000619 return Operand(ebp, offset);
Leon Clarkee46be812010-01-19 14:06:41 +0000620}
621
622
Ben Murdoch589d6972011-11-30 16:04:58 +0000623MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
624 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
625 if (var->IsContextSlot()) {
626 int context_chain_length = scope()->ContextChainLength(var->scope());
627 __ LoadContext(scratch, context_chain_length);
628 return ContextOperand(scratch, var->index());
629 } else {
630 return StackOperand(var);
631 }
Leon Clarkee46be812010-01-19 14:06:41 +0000632}
633
634
Ben Murdoch589d6972011-11-30 16:04:58 +0000635void FullCodeGenerator::GetVar(Register dest, Variable* var) {
636 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
637 MemOperand location = VarOperand(var, dest);
638 __ mov(dest, location);
639}
640
641
642void FullCodeGenerator::SetVar(Variable* var,
643 Register src,
644 Register scratch0,
645 Register scratch1) {
646 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
647 ASSERT(!scratch0.is(src));
648 ASSERT(!scratch0.is(scratch1));
649 ASSERT(!scratch1.is(src));
650 MemOperand location = VarOperand(var, scratch0);
Leon Clarkee46be812010-01-19 14:06:41 +0000651 __ mov(location, src);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000652
Leon Clarkee46be812010-01-19 14:06:41 +0000653 // Emit the write barrier code if the location is in the heap.
Ben Murdoch589d6972011-11-30 16:04:58 +0000654 if (var->IsContextSlot()) {
655 int offset = Context::SlotOffset(var->index());
656 ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000657 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
Steve Blockd0582a62009-12-15 09:54:21 +0000658 }
659}
660
661
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000662void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100663 bool should_normalize,
664 Label* if_true,
665 Label* if_false) {
666 // Only prepare for bailouts before splits if we're in a test
667 // context. Otherwise, we let the Visit function deal with the
668 // preparation to avoid preparing with the same AST id twice.
669 if (!context()->IsTest() || !info_->IsOptimizable()) return;
670
Ben Murdoch257744e2011-11-30 15:57:28 +0000671 Label skip;
672 if (should_normalize) __ jmp(&skip, Label::kNear);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000673 PrepareForBailout(expr, TOS_REG);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100674 if (should_normalize) {
Steve Block44f0eee2011-05-26 01:26:41 +0100675 __ cmp(eax, isolate()->factory()->true_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100676 Split(equal, if_true, if_false, NULL);
677 __ bind(&skip);
678 }
679}
680
681
Ben Murdoch589d6972011-11-30 16:04:58 +0000682void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000683 VariableMode mode,
Ben Murdoch589d6972011-11-30 16:04:58 +0000684 FunctionLiteral* function,
685 int* global_count) {
686 // If it was not possible to allocate the variable at compile time, we
687 // need to "declare" it at runtime to make sure it actually exists in the
688 // local context.
689 Variable* variable = proxy->var();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000690 bool binding_needs_init = (function == NULL) &&
691 (mode == CONST || mode == CONST_HARMONY || mode == LET);
Ben Murdoch589d6972011-11-30 16:04:58 +0000692 switch (variable->location()) {
693 case Variable::UNALLOCATED:
694 ++(*global_count);
695 break;
696
697 case Variable::PARAMETER:
698 case Variable::LOCAL:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000699 if (function != NULL) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000700 Comment cmnt(masm_, "[ Declaration");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000701 VisitForAccumulatorValue(function);
Ben Murdoch589d6972011-11-30 16:04:58 +0000702 __ mov(StackOperand(variable), result_register());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000703 } else if (binding_needs_init) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000704 Comment cmnt(masm_, "[ Declaration");
705 __ mov(StackOperand(variable),
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000706 Immediate(isolate()->factory()->the_hole_value()));
Steve Blockd0582a62009-12-15 09:54:21 +0000707 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000708 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000709
Ben Murdoch589d6972011-11-30 16:04:58 +0000710 case Variable::CONTEXT:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000711 // The variable in the decl always resides in the current function
712 // context.
713 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
714 if (FLAG_debug_code) {
715 // Check that we're not inside a with or catch context.
716 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
717 __ cmp(ebx, isolate()->factory()->with_context_map());
718 __ Check(not_equal, "Declaration in with context.");
719 __ cmp(ebx, isolate()->factory()->catch_context_map());
720 __ Check(not_equal, "Declaration in catch context.");
Steve Blockd0582a62009-12-15 09:54:21 +0000721 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000722 if (function != NULL) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000723 Comment cmnt(masm_, "[ Declaration");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000724 VisitForAccumulatorValue(function);
Ben Murdoch589d6972011-11-30 16:04:58 +0000725 __ mov(ContextOperand(esi, variable->index()), result_register());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000726 // We know that we have written a function, which is not a smi.
727 __ RecordWriteContextSlot(esi,
728 Context::SlotOffset(variable->index()),
729 result_register(),
730 ecx,
731 kDontSaveFPRegs,
732 EMIT_REMEMBERED_SET,
733 OMIT_SMI_CHECK);
Ben Murdoch589d6972011-11-30 16:04:58 +0000734 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000735 } else if (binding_needs_init) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000736 Comment cmnt(masm_, "[ Declaration");
737 __ mov(ContextOperand(esi, variable->index()),
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000738 Immediate(isolate()->factory()->the_hole_value()));
739 // No write barrier since the hole value is in old space.
Ben Murdoch589d6972011-11-30 16:04:58 +0000740 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000741 }
742 break;
Steve Block1e0659c2011-05-24 12:43:12 +0100743
Ben Murdoch589d6972011-11-30 16:04:58 +0000744 case Variable::LOOKUP: {
745 Comment cmnt(masm_, "[ Declaration");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000746 __ push(esi);
747 __ push(Immediate(variable->name()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000748 // Declaration nodes are always introduced in one of four modes.
749 ASSERT(mode == VAR ||
750 mode == CONST ||
751 mode == CONST_HARMONY ||
752 mode == LET);
753 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY)
754 ? READ_ONLY : NONE;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000755 __ push(Immediate(Smi::FromInt(attr)));
756 // Push initial value, if any.
757 // Note: For variables we must not push an initial value (such as
758 // 'undefined') because we may have a (legal) redeclaration and we
759 // must not destroy the current value.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000760 if (function != NULL) {
761 VisitForStackValue(function);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000762 } else if (binding_needs_init) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000763 __ push(Immediate(isolate()->factory()->the_hole_value()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000764 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000765 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000766 }
767 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000768 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000769 }
Steve Block3ce2e202009-11-05 08:53:23 +0000770 }
771}
772
773
Ben Murdoch589d6972011-11-30 16:04:58 +0000774void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
Leon Clarkef7060e22010-06-03 12:02:55 +0100775
776
Leon Clarked91b9f72010-01-27 17:25:45 +0000777void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
Steve Block3ce2e202009-11-05 08:53:23 +0000778 // Call the runtime to declare the globals.
779 __ push(esi); // The context is the first argument.
780 __ push(Immediate(pairs));
Ben Murdoch589d6972011-11-30 16:04:58 +0000781 __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags())));
782 __ CallRuntime(Runtime::kDeclareGlobals, 3);
Steve Block3ce2e202009-11-05 08:53:23 +0000783 // Return value is ignored.
784}
785
786
Leon Clarkef7060e22010-06-03 12:02:55 +0100787void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
788 Comment cmnt(masm_, "[ SwitchStatement");
789 Breakable nested_statement(this, stmt);
790 SetStatementPosition(stmt);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100791
Leon Clarkef7060e22010-06-03 12:02:55 +0100792 // Keep the switch value on the stack until a case matches.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100793 VisitForStackValue(stmt->tag());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100794 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +0000795
Leon Clarkef7060e22010-06-03 12:02:55 +0100796 ZoneList<CaseClause*>* clauses = stmt->cases();
797 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
Steve Block3ce2e202009-11-05 08:53:23 +0000798
Leon Clarkef7060e22010-06-03 12:02:55 +0100799 Label next_test; // Recycled for each test.
800 // Compile all the tests with branches to their bodies.
801 for (int i = 0; i < clauses->length(); i++) {
802 CaseClause* clause = clauses->at(i);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100803 clause->body_target()->Unuse();
Steve Block1e0659c2011-05-24 12:43:12 +0100804
Leon Clarkef7060e22010-06-03 12:02:55 +0100805 // The default is not a test, but remember it as final fall through.
806 if (clause->is_default()) {
807 default_clause = clause;
808 continue;
809 }
810
811 Comment cmnt(masm_, "[ Case comparison");
812 __ bind(&next_test);
813 next_test.Unuse();
814
815 // Compile the label expression.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100816 VisitForAccumulatorValue(clause->label());
Leon Clarkef7060e22010-06-03 12:02:55 +0100817
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100818 // Perform the comparison as if via '==='.
Leon Clarkef7060e22010-06-03 12:02:55 +0100819 __ mov(edx, Operand(esp, 0)); // Switch value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100820 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100821 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100822 if (inline_smi_code) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000823 Label slow_case;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100824 __ mov(ecx, edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000825 __ or_(ecx, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +0000826 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100827
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000828 __ cmp(edx, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100829 __ j(not_equal, &next_test);
830 __ Drop(1); // Switch value is no longer needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100831 __ jmp(clause->body_target());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100832 __ bind(&slow_case);
833 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100834
Ben Murdochb0fe1622011-05-05 13:52:32 +0100835 // Record position before stub call for type feedback.
836 SetSourcePosition(clause->position());
837 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000838 __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
839 patch_site.EmitPatchInfo();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000840 __ test(eax, eax);
Leon Clarkef7060e22010-06-03 12:02:55 +0100841 __ j(not_equal, &next_test);
842 __ Drop(1); // Switch value is no longer needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100843 __ jmp(clause->body_target());
Leon Clarkef7060e22010-06-03 12:02:55 +0100844 }
845
846 // Discard the test value and jump to the default if present, otherwise to
847 // the end of the statement.
848 __ bind(&next_test);
849 __ Drop(1); // Switch value is no longer needed.
850 if (default_clause == NULL) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000851 __ jmp(nested_statement.break_label());
Leon Clarkef7060e22010-06-03 12:02:55 +0100852 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100853 __ jmp(default_clause->body_target());
Leon Clarkef7060e22010-06-03 12:02:55 +0100854 }
855
856 // Compile all the case bodies.
857 for (int i = 0; i < clauses->length(); i++) {
858 Comment cmnt(masm_, "[ Case body");
859 CaseClause* clause = clauses->at(i);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100860 __ bind(clause->body_target());
Steve Block44f0eee2011-05-26 01:26:41 +0100861 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +0100862 VisitStatements(clause->statements());
863 }
864
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000865 __ bind(nested_statement.break_label());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100866 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +0100867}
868
869
870void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
871 Comment cmnt(masm_, "[ ForInStatement");
872 SetStatementPosition(stmt);
873
874 Label loop, exit;
875 ForIn loop_statement(this, stmt);
876 increment_loop_depth();
877
878 // Get the object to enumerate over. Both SpiderMonkey and JSC
879 // ignore null and undefined in contrast to the specification; see
880 // ECMA-262 section 12.6.4.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100881 VisitForAccumulatorValue(stmt->enumerable());
Steve Block44f0eee2011-05-26 01:26:41 +0100882 __ cmp(eax, isolate()->factory()->undefined_value());
Leon Clarkef7060e22010-06-03 12:02:55 +0100883 __ j(equal, &exit);
Steve Block44f0eee2011-05-26 01:26:41 +0100884 __ cmp(eax, isolate()->factory()->null_value());
Leon Clarkef7060e22010-06-03 12:02:55 +0100885 __ j(equal, &exit);
886
887 // Convert the object to a JS object.
Ben Murdoch257744e2011-11-30 15:57:28 +0000888 Label convert, done_convert;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000889 __ JumpIfSmi(eax, &convert, Label::kNear);
890 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +0000891 __ j(above_equal, &done_convert, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +0100892 __ bind(&convert);
893 __ push(eax);
894 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
895 __ bind(&done_convert);
896 __ push(eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000897
898 // Check for proxies.
899 Label call_runtime;
900 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
901 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
902 __ j(below_equal, &call_runtime);
Leon Clarkef7060e22010-06-03 12:02:55 +0100903
Steve Block59151502010-09-22 15:07:15 +0100904 // Check cache validity in generated code. This is a fast case for
905 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
906 // guarantee cache validity, call the runtime system to check cache
907 // validity or get the property names in a fixed array.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000908 Label next;
Steve Block59151502010-09-22 15:07:15 +0100909 __ mov(ecx, eax);
910 __ bind(&next);
911
912 // Check that there are no elements. Register ecx contains the
913 // current JS object we've reached through the prototype chain.
914 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset),
Steve Block44f0eee2011-05-26 01:26:41 +0100915 isolate()->factory()->empty_fixed_array());
Steve Block59151502010-09-22 15:07:15 +0100916 __ j(not_equal, &call_runtime);
917
918 // Check that instance descriptors are not empty so that we can
919 // check for an enum cache. Leave the map in ebx for the subsequent
920 // prototype load.
921 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +0000922 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset));
923 __ JumpIfSmi(edx, &call_runtime);
Steve Block59151502010-09-22 15:07:15 +0100924
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100925 // Check that there is an enum cache in the non-empty instance
Steve Block59151502010-09-22 15:07:15 +0100926 // descriptors (edx). This is the case if the next enumeration
927 // index field does not contain a smi.
928 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000929 __ JumpIfSmi(edx, &call_runtime);
Steve Block59151502010-09-22 15:07:15 +0100930
931 // For all objects but the receiver, check that the cache is empty.
Ben Murdoch257744e2011-11-30 15:57:28 +0000932 Label check_prototype;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000933 __ cmp(ecx, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +0000934 __ j(equal, &check_prototype, Label::kNear);
Steve Block59151502010-09-22 15:07:15 +0100935 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
Steve Block44f0eee2011-05-26 01:26:41 +0100936 __ cmp(edx, isolate()->factory()->empty_fixed_array());
Steve Block59151502010-09-22 15:07:15 +0100937 __ j(not_equal, &call_runtime);
938
939 // Load the prototype from the map and loop if non-null.
940 __ bind(&check_prototype);
941 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
Steve Block44f0eee2011-05-26 01:26:41 +0100942 __ cmp(ecx, isolate()->factory()->null_value());
Steve Block59151502010-09-22 15:07:15 +0100943 __ j(not_equal, &next);
944
945 // The enum cache is valid. Load the map of the object being
946 // iterated over and use the cache for the iteration.
Ben Murdoch257744e2011-11-30 15:57:28 +0000947 Label use_cache;
Steve Block59151502010-09-22 15:07:15 +0100948 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +0000949 __ jmp(&use_cache, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +0100950
951 // Get the set of properties to enumerate.
Steve Block59151502010-09-22 15:07:15 +0100952 __ bind(&call_runtime);
Leon Clarkef7060e22010-06-03 12:02:55 +0100953 __ push(eax); // Duplicate the enumerable object on the stack.
954 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
955
956 // If we got a map from the runtime call, we can do a fast
957 // modification check. Otherwise, we got a fixed array, and we have
958 // to do a slow check.
Ben Murdoch257744e2011-11-30 15:57:28 +0000959 Label fixed_array;
Steve Block44f0eee2011-05-26 01:26:41 +0100960 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
961 isolate()->factory()->meta_map());
Ben Murdoch257744e2011-11-30 15:57:28 +0000962 __ j(not_equal, &fixed_array, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +0100963
964 // We got a map in register eax. Get the enumeration cache from it.
Steve Block59151502010-09-22 15:07:15 +0100965 __ bind(&use_cache);
Ben Murdoch257744e2011-11-30 15:57:28 +0000966 __ LoadInstanceDescriptors(eax, ecx);
Leon Clarkef7060e22010-06-03 12:02:55 +0100967 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
968 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
969
Ben Murdochc7cc0282012-03-05 14:35:55 +0000970 // Set up the four remaining stack slots.
Leon Clarkef7060e22010-06-03 12:02:55 +0100971 __ push(eax); // Map.
972 __ push(edx); // Enumeration cache.
973 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +0100974 __ push(eax); // Enumeration cache length (as smi).
975 __ push(Immediate(Smi::FromInt(0))); // Initial index.
976 __ jmp(&loop);
977
978 // We got a fixed array in register eax. Iterate through that.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000979 Label non_proxy;
Leon Clarkef7060e22010-06-03 12:02:55 +0100980 __ bind(&fixed_array);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000981 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
982 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object
983 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
984 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx);
985 __ j(above, &non_proxy);
986 __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
987 __ bind(&non_proxy);
988 __ push(ebx); // Smi
989 __ push(eax); // Array
Leon Clarkef7060e22010-06-03 12:02:55 +0100990 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +0100991 __ push(eax); // Fixed array length (as smi).
992 __ push(Immediate(Smi::FromInt(0))); // Initial index.
993
994 // Generate code for doing the condition check.
995 __ bind(&loop);
996 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
997 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000998 __ j(above_equal, loop_statement.break_label());
Leon Clarkef7060e22010-06-03 12:02:55 +0100999
1000 // Get the current entry of the array into register ebx.
1001 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1002 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1003
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001004 // Get the expected map from the stack or a smi in the
Leon Clarkef7060e22010-06-03 12:02:55 +01001005 // permanent slow case into register edx.
1006 __ mov(edx, Operand(esp, 3 * kPointerSize));
1007
1008 // Check if the expected map still matches that of the enumerable.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001009 // If not, we may have to filter the key.
Ben Murdoch257744e2011-11-30 15:57:28 +00001010 Label update_each;
Leon Clarkef7060e22010-06-03 12:02:55 +01001011 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1012 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001013 __ j(equal, &update_each, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01001014
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001015 // For proxies, no filtering is done.
1016 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1017 ASSERT(Smi::FromInt(0) == 0);
1018 __ test(edx, edx);
1019 __ j(zero, &update_each);
1020
Leon Clarkef7060e22010-06-03 12:02:55 +01001021 // Convert the entry to a string or null if it isn't a property
1022 // anymore. If the property has been removed while iterating, we
1023 // just skip it.
1024 __ push(ecx); // Enumerable.
1025 __ push(ebx); // Current entry.
1026 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001027 __ test(eax, eax);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001028 __ j(equal, loop_statement.continue_label());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001029 __ mov(ebx, eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001030
1031 // Update the 'each' property or variable from the possibly filtered
1032 // entry in register ebx.
1033 __ bind(&update_each);
1034 __ mov(result_register(), ebx);
1035 // Perform the assignment as if via '='.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001036 { EffectContext context(this);
1037 EmitAssignment(stmt->each(), stmt->AssignmentId());
1038 }
Leon Clarkef7060e22010-06-03 12:02:55 +01001039
1040 // Generate code for the body of the loop.
Leon Clarkef7060e22010-06-03 12:02:55 +01001041 Visit(stmt->body());
1042
Leon Clarkef7060e22010-06-03 12:02:55 +01001043 // Generate code for going to the next element by incrementing the
1044 // index (smi) stored on top of the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001045 __ bind(loop_statement.continue_label());
Leon Clarkef7060e22010-06-03 12:02:55 +01001046 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
Leon Clarkef7060e22010-06-03 12:02:55 +01001047
Ben Murdochb0fe1622011-05-05 13:52:32 +01001048 EmitStackCheck(stmt);
1049 __ jmp(&loop);
Leon Clarkef7060e22010-06-03 12:02:55 +01001050
1051 // Remove the pointers stored on the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001052 __ bind(loop_statement.break_label());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001053 __ add(esp, Immediate(5 * kPointerSize));
Leon Clarkef7060e22010-06-03 12:02:55 +01001054
1055 // Exit and decrement the loop depth.
1056 __ bind(&exit);
1057 decrement_loop_depth();
1058}
1059
1060
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001061void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1062 bool pretenure) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001063 // Use the fast case closure allocation code that allocates in new
Ben Murdochb0fe1622011-05-05 13:52:32 +01001064 // space for nested functions that don't need literals cloning. If
1065 // we're running with the --always-opt or the --prepare-always-opt
1066 // flag, we need to use the runtime function so that the new function
1067 // we are creating here gets a chance to have its code optimized and
1068 // doesn't just get a copy of the existing unoptimized code.
1069 if (!FLAG_always_opt &&
1070 !FLAG_prepare_always_opt &&
Steve Block44f0eee2011-05-26 01:26:41 +01001071 !pretenure &&
Ben Murdochb0fe1622011-05-05 13:52:32 +01001072 scope()->is_function_scope() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001073 info->num_literals() == 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001074 FastNewClosureStub stub(info->language_mode());
Leon Clarkef7060e22010-06-03 12:02:55 +01001075 __ push(Immediate(info));
1076 __ CallStub(&stub);
1077 } else {
1078 __ push(esi);
1079 __ push(Immediate(info));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001080 __ push(Immediate(pretenure
Steve Block44f0eee2011-05-26 01:26:41 +01001081 ? isolate()->factory()->true_value()
1082 : isolate()->factory()->false_value()));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001083 __ CallRuntime(Runtime::kNewClosure, 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01001084 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001085 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001086}
1087
1088
Leon Clarked91b9f72010-01-27 17:25:45 +00001089void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001090 Comment cmnt(masm_, "[ VariableProxy");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001091 EmitVariableLoad(expr);
Leon Clarkee46be812010-01-19 14:06:41 +00001092}
1093
1094
Ben Murdoch589d6972011-11-30 16:04:58 +00001095void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1096 TypeofState typeof_state,
1097 Label* slow) {
Steve Block59151502010-09-22 15:07:15 +01001098 Register context = esi;
1099 Register temp = edx;
1100
1101 Scope* s = scope();
1102 while (s != NULL) {
1103 if (s->num_heap_slots() > 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001104 if (s->calls_non_strict_eval()) {
Steve Block59151502010-09-22 15:07:15 +01001105 // Check that extension is NULL.
1106 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1107 Immediate(0));
1108 __ j(not_equal, slow);
1109 }
1110 // Load next context in chain.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001111 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001112 // Walk the rest of the chain without clobbering esi.
1113 context = temp;
1114 }
1115 // If no outer scope calls eval, we do not need to check more
1116 // context extensions. If we have reached an eval scope, we check
1117 // all extensions from this point.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001118 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break;
Steve Block59151502010-09-22 15:07:15 +01001119 s = s->outer_scope();
1120 }
1121
1122 if (s != NULL && s->is_eval_scope()) {
1123 // Loop up the context chain. There is no frame effect so it is
1124 // safe to use raw labels here.
Ben Murdoch257744e2011-11-30 15:57:28 +00001125 Label next, fast;
Steve Block59151502010-09-22 15:07:15 +01001126 if (!context.is(temp)) {
1127 __ mov(temp, context);
1128 }
1129 __ bind(&next);
1130 // Terminate at global context.
1131 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +01001132 Immediate(isolate()->factory()->global_context_map()));
Ben Murdoch257744e2011-11-30 15:57:28 +00001133 __ j(equal, &fast, Label::kNear);
Steve Block59151502010-09-22 15:07:15 +01001134 // Check that extension is NULL.
1135 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1136 __ j(not_equal, slow);
1137 // Load next context in chain.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001138 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001139 __ jmp(&next);
1140 __ bind(&fast);
1141 }
1142
1143 // All extension objects were empty and it is safe to use a global
1144 // load IC call.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001145 __ mov(eax, GlobalObjectOperand());
Ben Murdoch589d6972011-11-30 16:04:58 +00001146 __ mov(ecx, var->name());
Steve Block44f0eee2011-05-26 01:26:41 +01001147 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
Steve Block59151502010-09-22 15:07:15 +01001148 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1149 ? RelocInfo::CODE_TARGET
1150 : RelocInfo::CODE_TARGET_CONTEXT;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001151 __ call(ic, mode);
Steve Block59151502010-09-22 15:07:15 +01001152}
1153
1154
Ben Murdoch589d6972011-11-30 16:04:58 +00001155MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1156 Label* slow) {
1157 ASSERT(var->IsContextSlot());
Steve Block59151502010-09-22 15:07:15 +01001158 Register context = esi;
1159 Register temp = ebx;
1160
Ben Murdoch589d6972011-11-30 16:04:58 +00001161 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
Steve Block59151502010-09-22 15:07:15 +01001162 if (s->num_heap_slots() > 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001163 if (s->calls_non_strict_eval()) {
Steve Block59151502010-09-22 15:07:15 +01001164 // Check that extension is NULL.
1165 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1166 Immediate(0));
1167 __ j(not_equal, slow);
1168 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001169 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001170 // Walk the rest of the chain without clobbering esi.
1171 context = temp;
1172 }
1173 }
1174 // Check that last extension is NULL.
1175 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1176 __ j(not_equal, slow);
Steve Block1e0659c2011-05-24 12:43:12 +01001177
1178 // This function is used only for loads, not stores, so it's safe to
1179 // return an esi-based operand (the write barrier cannot be allowed to
1180 // destroy the esi register).
Ben Murdoch589d6972011-11-30 16:04:58 +00001181 return ContextOperand(context, var->index());
Steve Block59151502010-09-22 15:07:15 +01001182}
1183
1184
Ben Murdoch589d6972011-11-30 16:04:58 +00001185void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1186 TypeofState typeof_state,
1187 Label* slow,
1188 Label* done) {
Steve Block59151502010-09-22 15:07:15 +01001189 // Generate fast-case code for variables that might be shadowed by
1190 // eval-introduced variables. Eval is used a lot without
1191 // introducing variables. In those cases, we do not want to
1192 // perform a runtime call for all variables in the scope
1193 // containing the eval.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001194 if (var->mode() == DYNAMIC_GLOBAL) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001195 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
Steve Block59151502010-09-22 15:07:15 +01001196 __ jmp(done);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001197 } else if (var->mode() == DYNAMIC_LOCAL) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001198 Variable* local = var->local_if_not_shadowed();
1199 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001200 if (local->mode() == CONST ||
1201 local->mode() == CONST_HARMONY ||
1202 local->mode() == LET) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001203 __ cmp(eax, isolate()->factory()->the_hole_value());
1204 __ j(not_equal, done);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001205 if (local->mode() == CONST) {
1206 __ mov(eax, isolate()->factory()->undefined_value());
1207 } else { // LET || CONST_HARMONY
1208 __ push(Immediate(var->name()));
1209 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1210 }
Steve Block59151502010-09-22 15:07:15 +01001211 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001212 __ jmp(done);
Steve Block59151502010-09-22 15:07:15 +01001213 }
1214}
1215
1216
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001217void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1218 // Record position before possible IC call.
1219 SetSourcePosition(proxy->position());
1220 Variable* var = proxy->var();
Leon Clarked91b9f72010-01-27 17:25:45 +00001221
Ben Murdoch589d6972011-11-30 16:04:58 +00001222 // Three cases: global variables, lookup variables, and all other types of
1223 // variables.
1224 switch (var->location()) {
1225 case Variable::UNALLOCATED: {
1226 Comment cmnt(masm_, "Global variable");
1227 // Use inline caching. Variable name is passed in ecx and the global
1228 // object in eax.
1229 __ mov(eax, GlobalObjectOperand());
1230 __ mov(ecx, var->name());
1231 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
1232 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001233 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00001234 break;
1235 }
1236
1237 case Variable::PARAMETER:
1238 case Variable::LOCAL:
1239 case Variable::CONTEXT: {
1240 Comment cmnt(masm_, var->IsContextSlot()
1241 ? "Context variable"
1242 : "Stack variable");
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001243 if (var->binding_needs_init()) {
1244 // var->scope() may be NULL when the proxy is located in eval code and
1245 // refers to a potential outside binding. Currently those bindings are
1246 // always looked up dynamically, i.e. in that case
1247 // var->location() == LOOKUP.
1248 // always holds.
1249 ASSERT(var->scope() != NULL);
1250
1251 // Check if the binding really needs an initialization check. The check
1252 // can be skipped in the following situation: we have a LET or CONST
1253 // binding in harmony mode, both the Variable and the VariableProxy have
1254 // the same declaration scope (i.e. they are both in global code, in the
1255 // same function or in the same eval code) and the VariableProxy is in
1256 // the source physically located after the initializer of the variable.
1257 //
1258 // We cannot skip any initialization checks for CONST in non-harmony
1259 // mode because const variables may be declared but never initialized:
1260 // if (false) { const x; }; var y = x;
1261 //
1262 // The condition on the declaration scopes is a conservative check for
1263 // nested functions that access a binding and are called before the
1264 // binding is initialized:
1265 // function() { f(); let x = 1; function f() { x = 2; } }
1266 //
1267 bool skip_init_check;
1268 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1269 skip_init_check = false;
1270 } else {
1271 // Check that we always have valid source position.
1272 ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1273 ASSERT(proxy->position() != RelocInfo::kNoPosition);
1274 skip_init_check = var->mode() != CONST &&
1275 var->initializer_position() < proxy->position();
Ben Murdoch589d6972011-11-30 16:04:58 +00001276 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001277
1278 if (!skip_init_check) {
1279 // Let and const need a read barrier.
1280 Label done;
1281 GetVar(eax, var);
1282 __ cmp(eax, isolate()->factory()->the_hole_value());
1283 __ j(not_equal, &done, Label::kNear);
1284 if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1285 // Throw a reference error when using an uninitialized let/const
1286 // binding in harmony mode.
1287 __ push(Immediate(var->name()));
1288 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1289 } else {
1290 // Uninitalized const bindings outside of harmony mode are unholed.
1291 ASSERT(var->mode() == CONST);
1292 __ mov(eax, isolate()->factory()->undefined_value());
1293 }
1294 __ bind(&done);
1295 context()->Plug(eax);
1296 break;
1297 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001298 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001299 context()->Plug(var);
Ben Murdoch589d6972011-11-30 16:04:58 +00001300 break;
1301 }
1302
1303 case Variable::LOOKUP: {
1304 Label done, slow;
1305 // Generate code for loading from variables potentially shadowed
1306 // by eval-introduced variables.
1307 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1308 __ bind(&slow);
1309 Comment cmnt(masm_, "Lookup variable");
1310 __ push(esi); // Context.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001311 __ push(Immediate(var->name()));
Ben Murdoch589d6972011-11-30 16:04:58 +00001312 __ CallRuntime(Runtime::kLoadContextSlot, 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001313 __ bind(&done);
1314 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00001315 break;
Leon Clarkef7060e22010-06-03 12:02:55 +01001316 }
Steve Block3ce2e202009-11-05 08:53:23 +00001317 }
1318}
1319
1320
Leon Clarked91b9f72010-01-27 17:25:45 +00001321void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001322 Comment cmnt(masm_, "[ RegExpLiteral");
Ben Murdoch257744e2011-11-30 15:57:28 +00001323 Label materialized;
Steve Block3ce2e202009-11-05 08:53:23 +00001324 // Registers will be used as follows:
1325 // edi = JS function.
Ben Murdochbb769b22010-08-11 14:56:33 +01001326 // ecx = literals array.
1327 // ebx = regexp literal.
1328 // eax = regexp literal clone.
Steve Block3ce2e202009-11-05 08:53:23 +00001329 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdochbb769b22010-08-11 14:56:33 +01001330 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001331 int literal_offset =
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001332 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
Ben Murdochbb769b22010-08-11 14:56:33 +01001333 __ mov(ebx, FieldOperand(ecx, literal_offset));
Steve Block44f0eee2011-05-26 01:26:41 +01001334 __ cmp(ebx, isolate()->factory()->undefined_value());
Ben Murdoch257744e2011-11-30 15:57:28 +00001335 __ j(not_equal, &materialized, Label::kNear);
Ben Murdochbb769b22010-08-11 14:56:33 +01001336
Steve Block3ce2e202009-11-05 08:53:23 +00001337 // Create regexp literal using runtime function
1338 // Result will be in eax.
Ben Murdochbb769b22010-08-11 14:56:33 +01001339 __ push(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001340 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1341 __ push(Immediate(expr->pattern()));
1342 __ push(Immediate(expr->flags()));
1343 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
Ben Murdochbb769b22010-08-11 14:56:33 +01001344 __ mov(ebx, eax);
1345
1346 __ bind(&materialized);
1347 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1348 Label allocated, runtime_allocate;
1349 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1350 __ jmp(&allocated);
1351
1352 __ bind(&runtime_allocate);
1353 __ push(ebx);
1354 __ push(Immediate(Smi::FromInt(size)));
1355 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1356 __ pop(ebx);
1357
1358 __ bind(&allocated);
1359 // Copy the content into the newly allocated memory.
1360 // (Unroll copy loop once for better throughput).
1361 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1362 __ mov(edx, FieldOperand(ebx, i));
1363 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1364 __ mov(FieldOperand(eax, i), edx);
1365 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1366 }
1367 if ((size % (2 * kPointerSize)) != 0) {
1368 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1369 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1370 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001371 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00001372}
1373
1374
Leon Clarked91b9f72010-01-27 17:25:45 +00001375void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001376 Comment cmnt(masm_, "[ ObjectLiteral");
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001377 Handle<FixedArray> constant_properties = expr->constant_properties();
Steve Blockd0582a62009-12-15 09:54:21 +00001378 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00001379 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
Steve Blockd0582a62009-12-15 09:54:21 +00001380 __ push(Immediate(Smi::FromInt(expr->literal_index())));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001381 __ push(Immediate(constant_properties));
Steve Block44f0eee2011-05-26 01:26:41 +01001382 int flags = expr->fast_elements()
1383 ? ObjectLiteral::kFastElements
1384 : ObjectLiteral::kNoFlags;
1385 flags |= expr->has_function()
1386 ? ObjectLiteral::kHasFunction
1387 : ObjectLiteral::kNoFlags;
1388 __ push(Immediate(Smi::FromInt(flags)));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001389 int properties_count = constant_properties->length() / 2;
Leon Clarkee46be812010-01-19 14:06:41 +00001390 if (expr->depth() > 1) {
Steve Block6ded16b2010-05-10 14:33:55 +01001391 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001392 } else if (flags != ObjectLiteral::kFastElements ||
1393 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
Steve Block6ded16b2010-05-10 14:33:55 +01001394 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001395 } else {
1396 FastCloneShallowObjectStub stub(properties_count);
1397 __ CallStub(&stub);
Steve Blockd0582a62009-12-15 09:54:21 +00001398 }
1399
Leon Clarkee46be812010-01-19 14:06:41 +00001400 // If result_saved is true the result is on top of the stack. If
1401 // result_saved is false the result is in eax.
Steve Blockd0582a62009-12-15 09:54:21 +00001402 bool result_saved = false;
1403
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001404 // Mark all computed expressions that are bound to a key that
1405 // is shadowed by a later occurrence of the same key. For the
1406 // marked expressions, no store code is emitted.
1407 expr->CalculateEmitStore();
1408
Steve Blockd0582a62009-12-15 09:54:21 +00001409 for (int i = 0; i < expr->properties()->length(); i++) {
1410 ObjectLiteral::Property* property = expr->properties()->at(i);
1411 if (property->IsCompileTimeValue()) continue;
1412
1413 Literal* key = property->key();
1414 Expression* value = property->value();
1415 if (!result_saved) {
1416 __ push(eax); // Save result on the stack
1417 result_saved = true;
1418 }
1419 switch (property->kind()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001420 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
Steve Blockd0582a62009-12-15 09:54:21 +00001421 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
Leon Clarkee46be812010-01-19 14:06:41 +00001422 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001423 case ObjectLiteral::Property::COMPUTED:
1424 if (key->handle()->IsSymbol()) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001425 if (property->emit_store()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001426 VisitForAccumulatorValue(value);
1427 __ mov(ecx, Immediate(key->handle()));
1428 __ mov(edx, Operand(esp, 0));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001429 Handle<Code> ic = is_classic_mode()
1430 ? isolate()->builtins()->StoreIC_Initialize()
1431 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001432 __ call(ic, RelocInfo::CODE_TARGET, key->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001433 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1434 } else {
1435 VisitForEffect(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001436 }
Steve Blockd0582a62009-12-15 09:54:21 +00001437 break;
1438 }
Leon Clarkee46be812010-01-19 14:06:41 +00001439 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001440 case ObjectLiteral::Property::PROTOTYPE:
Leon Clarkee46be812010-01-19 14:06:41 +00001441 __ push(Operand(esp, 0)); // Duplicate receiver.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001442 VisitForStackValue(key);
1443 VisitForStackValue(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001444 if (property->emit_store()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001445 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1446 __ CallRuntime(Runtime::kSetProperty, 4);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001447 } else {
1448 __ Drop(3);
1449 }
Steve Blockd0582a62009-12-15 09:54:21 +00001450 break;
Leon Clarkee46be812010-01-19 14:06:41 +00001451 case ObjectLiteral::Property::SETTER:
Steve Blockd0582a62009-12-15 09:54:21 +00001452 case ObjectLiteral::Property::GETTER:
Leon Clarkee46be812010-01-19 14:06:41 +00001453 __ push(Operand(esp, 0)); // Duplicate receiver.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001454 VisitForStackValue(key);
Steve Blockd0582a62009-12-15 09:54:21 +00001455 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
1456 Smi::FromInt(1) :
1457 Smi::FromInt(0)));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001458 VisitForStackValue(value);
Steve Blockd0582a62009-12-15 09:54:21 +00001459 __ CallRuntime(Runtime::kDefineAccessor, 4);
Steve Blockd0582a62009-12-15 09:54:21 +00001460 break;
1461 default: UNREACHABLE();
1462 }
1463 }
Leon Clarkee46be812010-01-19 14:06:41 +00001464
Steve Block44f0eee2011-05-26 01:26:41 +01001465 if (expr->has_function()) {
1466 ASSERT(result_saved);
1467 __ push(Operand(esp, 0));
1468 __ CallRuntime(Runtime::kToFastProperties, 1);
1469 }
1470
Leon Clarkee46be812010-01-19 14:06:41 +00001471 if (result_saved) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001472 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001473 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001474 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001475 }
1476}
1477
1478
Leon Clarked91b9f72010-01-27 17:25:45 +00001479void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001480 Comment cmnt(masm_, "[ ArrayLiteral");
Leon Clarkef7060e22010-06-03 12:02:55 +01001481
1482 ZoneList<Expression*>* subexprs = expr->values();
1483 int length = subexprs->length();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001484 Handle<FixedArray> constant_elements = expr->constant_elements();
1485 ASSERT_EQ(2, constant_elements->length());
1486 ElementsKind constant_elements_kind =
1487 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
1488 bool has_constant_fast_elements = constant_elements_kind == FAST_ELEMENTS;
1489 Handle<FixedArrayBase> constant_elements_values(
1490 FixedArrayBase::cast(constant_elements->get(1)));
Leon Clarkef7060e22010-06-03 12:02:55 +01001491
Steve Block3ce2e202009-11-05 08:53:23 +00001492 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00001493 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001494 __ push(Immediate(Smi::FromInt(expr->literal_index())));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001495 __ push(Immediate(constant_elements));
1496 Heap* heap = isolate()->heap();
1497 if (has_constant_fast_elements &&
1498 constant_elements_values->map() == heap->fixed_cow_array_map()) {
1499 // If the elements are already FAST_ELEMENTS, the boilerplate cannot
1500 // change, so it's possible to specialize the stub in advance.
Steve Block44f0eee2011-05-26 01:26:41 +01001501 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001502 FastCloneShallowArrayStub stub(
1503 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
1504 length);
1505 __ CallStub(&stub);
Iain Merrick75681382010-08-19 15:07:18 +01001506 } else if (expr->depth() > 1) {
Leon Clarkee46be812010-01-19 14:06:41 +00001507 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
Iain Merrick75681382010-08-19 15:07:18 +01001508 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
Leon Clarkee46be812010-01-19 14:06:41 +00001509 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01001510 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001511 ASSERT(constant_elements_kind == FAST_ELEMENTS ||
1512 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
1513 FLAG_smi_only_arrays);
1514 // If the elements are already FAST_ELEMENTS, the boilerplate cannot
1515 // change, so it's possible to specialize the stub in advance.
1516 FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
1517 ? FastCloneShallowArrayStub::CLONE_ELEMENTS
1518 : FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
1519 FastCloneShallowArrayStub stub(mode, length);
Leon Clarkef7060e22010-06-03 12:02:55 +01001520 __ CallStub(&stub);
Steve Block3ce2e202009-11-05 08:53:23 +00001521 }
1522
1523 bool result_saved = false; // Is the result saved to the stack?
1524
1525 // Emit code to evaluate all the non-constant subexpressions and to store
1526 // them into the newly cloned array.
Leon Clarkef7060e22010-06-03 12:02:55 +01001527 for (int i = 0; i < length; i++) {
Steve Block3ce2e202009-11-05 08:53:23 +00001528 Expression* subexpr = subexprs->at(i);
1529 // If the subexpression is a literal or a simple materialized literal it
1530 // is already set in the cloned array.
1531 if (subexpr->AsLiteral() != NULL ||
1532 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1533 continue;
1534 }
1535
1536 if (!result_saved) {
1537 __ push(eax);
1538 result_saved = true;
1539 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001540 VisitForAccumulatorValue(subexpr);
Steve Block3ce2e202009-11-05 08:53:23 +00001541
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001542 if (constant_elements_kind == FAST_ELEMENTS) {
1543 // Fast-case array literal with ElementsKind of FAST_ELEMENTS, they cannot
1544 // transition and don't need to call the runtime stub.
1545 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1546 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1547 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1548 // Store the subexpression value in the array's elements.
1549 __ mov(FieldOperand(ebx, offset), result_register());
1550 // Update the write barrier for the array store.
1551 __ RecordWriteField(ebx, offset, result_register(), ecx,
1552 kDontSaveFPRegs,
1553 EMIT_REMEMBERED_SET,
1554 INLINE_SMI_CHECK);
1555 } else {
1556 // Store the subexpression value in the array's elements.
1557 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1558 __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
1559 __ mov(ecx, Immediate(Smi::FromInt(i)));
1560 __ mov(edx, Immediate(Smi::FromInt(expr->literal_index())));
1561 StoreArrayLiteralElementStub stub;
1562 __ CallStub(&stub);
1563 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001564
1565 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +00001566 }
1567
Leon Clarkee46be812010-01-19 14:06:41 +00001568 if (result_saved) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001569 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001570 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001571 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001572 }
1573}
1574
1575
Andrei Popescu402d9372010-02-26 13:31:12 +00001576void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1577 Comment cmnt(masm_, "[ Assignment");
Leon Clarkef7060e22010-06-03 12:02:55 +01001578 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1579 // on the left-hand side.
1580 if (!expr->target()->IsValidLeftHandSide()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001581 VisitForEffect(expr->target());
Leon Clarkef7060e22010-06-03 12:02:55 +01001582 return;
1583 }
1584
Andrei Popescu402d9372010-02-26 13:31:12 +00001585 // Left-hand side can only be a property, a global or a (parameter or local)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001586 // slot.
Andrei Popescu402d9372010-02-26 13:31:12 +00001587 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1588 LhsKind assign_type = VARIABLE;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001589 Property* property = expr->target()->AsProperty();
1590 if (property != NULL) {
1591 assign_type = (property->key()->IsPropertyName())
1592 ? NAMED_PROPERTY
1593 : KEYED_PROPERTY;
Andrei Popescu402d9372010-02-26 13:31:12 +00001594 }
1595
1596 // Evaluate LHS expression.
1597 switch (assign_type) {
1598 case VARIABLE:
1599 // Nothing to do here.
1600 break;
1601 case NAMED_PROPERTY:
1602 if (expr->is_compound()) {
1603 // We need the receiver both on the stack and in the accumulator.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001604 VisitForAccumulatorValue(property->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00001605 __ push(result_register());
1606 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001607 VisitForStackValue(property->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00001608 }
1609 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001610 case KEYED_PROPERTY: {
Andrei Popescu402d9372010-02-26 13:31:12 +00001611 if (expr->is_compound()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001612 VisitForStackValue(property->obj());
1613 VisitForAccumulatorValue(property->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00001614 __ mov(edx, Operand(esp, 0));
1615 __ push(eax);
1616 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001617 VisitForStackValue(property->obj());
1618 VisitForStackValue(property->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00001619 }
1620 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001621 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001622 }
1623
Ben Murdoch8b112d22011-06-08 16:22:53 +01001624 // For compound assignments we need another deoptimization point after the
1625 // variable/property load.
Andrei Popescu402d9372010-02-26 13:31:12 +00001626 if (expr->is_compound()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001627 AccumulatorValueContext result_context(this);
1628 { AccumulatorValueContext left_operand_context(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001629 switch (assign_type) {
1630 case VARIABLE:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001631 EmitVariableLoad(expr->target()->AsVariableProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001632 PrepareForBailout(expr->target(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001633 break;
1634 case NAMED_PROPERTY:
1635 EmitNamedPropertyLoad(property);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001636 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001637 break;
1638 case KEYED_PROPERTY:
1639 EmitKeyedPropertyLoad(property);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001640 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001641 break;
1642 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001643 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001644
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001645 Token::Value op = expr->binary_op();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001646 __ push(eax); // Left operand goes on the stack.
1647 VisitForAccumulatorValue(expr->value());
Andrei Popescu402d9372010-02-26 13:31:12 +00001648
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001649 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1650 ? OVERWRITE_RIGHT
1651 : NO_OVERWRITE;
1652 SetSourcePosition(expr->position() + 1);
1653 if (ShouldInlineSmiCase(op)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001654 EmitInlineSmiBinaryOp(expr->binary_operation(),
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001655 op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001656 mode,
1657 expr->target(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001658 expr->value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001659 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00001660 EmitBinaryOp(expr->binary_operation(), op, mode);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001661 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001662
1663 // Deoptimization point in case the binary operation may have side effects.
1664 PrepareForBailout(expr->binary_operation(), TOS_REG);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001665 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001666 VisitForAccumulatorValue(expr->value());
Andrei Popescu402d9372010-02-26 13:31:12 +00001667 }
1668
1669 // Record source position before possible IC call.
1670 SetSourcePosition(expr->position());
1671
1672 // Store the value.
1673 switch (assign_type) {
1674 case VARIABLE:
1675 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001676 expr->op());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001677 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1678 context()->Plug(eax);
Andrei Popescu402d9372010-02-26 13:31:12 +00001679 break;
1680 case NAMED_PROPERTY:
1681 EmitNamedPropertyAssignment(expr);
1682 break;
1683 case KEYED_PROPERTY:
1684 EmitKeyedPropertyAssignment(expr);
1685 break;
1686 }
1687}
1688
1689
Leon Clarked91b9f72010-01-27 17:25:45 +00001690void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00001691 SetSourcePosition(prop->position());
1692 Literal* key = prop->key()->AsLiteral();
Steve Block053d10c2011-06-13 19:13:29 +01001693 ASSERT(!key->handle()->IsSmi());
Leon Clarkee46be812010-01-19 14:06:41 +00001694 __ mov(ecx, Immediate(key->handle()));
Steve Block44f0eee2011-05-26 01:26:41 +01001695 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001696 __ call(ic, RelocInfo::CODE_TARGET, prop->id());
Leon Clarkee46be812010-01-19 14:06:41 +00001697}
1698
1699
Leon Clarked91b9f72010-01-27 17:25:45 +00001700void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00001701 SetSourcePosition(prop->position());
Steve Block44f0eee2011-05-26 01:26:41 +01001702 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001703 __ call(ic, RelocInfo::CODE_TARGET, prop->id());
Leon Clarkee46be812010-01-19 14:06:41 +00001704}
1705
1706
Ben Murdoch257744e2011-11-30 15:57:28 +00001707void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001708 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001709 OverwriteMode mode,
1710 Expression* left,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001711 Expression* right) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001712 // Do combined smi check of the operands. Left operand is on the
1713 // stack. Right operand is in eax.
Ben Murdoch257744e2011-11-30 15:57:28 +00001714 Label smi_case, done, stub_call;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001715 __ pop(edx);
1716 __ mov(ecx, eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001717 __ or_(eax, edx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001718 JumpPatchSite patch_site(masm_);
Ben Murdoch257744e2011-11-30 15:57:28 +00001719 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001720
1721 __ bind(&stub_call);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001722 __ mov(eax, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +00001723 BinaryOpStub stub(op, mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001724 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1725 patch_site.EmitPatchInfo();
Ben Murdoch257744e2011-11-30 15:57:28 +00001726 __ jmp(&done, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001727
Ben Murdochb0fe1622011-05-05 13:52:32 +01001728 // Smi case.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001729 __ bind(&smi_case);
1730 __ mov(eax, edx); // Copy left operand in case of a stub call.
1731
1732 switch (op) {
1733 case Token::SAR:
1734 __ SmiUntag(eax);
1735 __ SmiUntag(ecx);
1736 __ sar_cl(eax); // No checks of result necessary
1737 __ SmiTag(eax);
1738 break;
1739 case Token::SHL: {
1740 Label result_ok;
1741 __ SmiUntag(eax);
1742 __ SmiUntag(ecx);
1743 __ shl_cl(eax);
1744 // Check that the *signed* result fits in a smi.
1745 __ cmp(eax, 0xc0000000);
1746 __ j(positive, &result_ok);
1747 __ SmiTag(ecx);
1748 __ jmp(&stub_call);
1749 __ bind(&result_ok);
1750 __ SmiTag(eax);
1751 break;
1752 }
1753 case Token::SHR: {
1754 Label result_ok;
1755 __ SmiUntag(eax);
1756 __ SmiUntag(ecx);
1757 __ shr_cl(eax);
1758 __ test(eax, Immediate(0xc0000000));
1759 __ j(zero, &result_ok);
1760 __ SmiTag(ecx);
1761 __ jmp(&stub_call);
1762 __ bind(&result_ok);
1763 __ SmiTag(eax);
1764 break;
1765 }
1766 case Token::ADD:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001767 __ add(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001768 __ j(overflow, &stub_call);
1769 break;
1770 case Token::SUB:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001771 __ sub(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001772 __ j(overflow, &stub_call);
1773 break;
1774 case Token::MUL: {
1775 __ SmiUntag(eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001776 __ imul(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001777 __ j(overflow, &stub_call);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001778 __ test(eax, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00001779 __ j(not_zero, &done, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001780 __ mov(ebx, edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001781 __ or_(ebx, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001782 __ j(negative, &stub_call);
1783 break;
1784 }
1785 case Token::BIT_OR:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001786 __ or_(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001787 break;
1788 case Token::BIT_AND:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001789 __ and_(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001790 break;
1791 case Token::BIT_XOR:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001792 __ xor_(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001793 break;
1794 default:
1795 UNREACHABLE();
1796 }
1797
1798 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001799 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001800}
1801
1802
Ben Murdoch257744e2011-11-30 15:57:28 +00001803void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1804 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001805 OverwriteMode mode) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001806 __ pop(edx);
Ben Murdoch257744e2011-11-30 15:57:28 +00001807 BinaryOpStub stub(op, mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001808 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
1809 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1810 patch_site.EmitPatchInfo();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001811 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00001812}
1813
1814
Ben Murdochb0fe1622011-05-05 13:52:32 +01001815void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001816 // Invalid left-hand sides are rewritten to have a 'throw
1817 // ReferenceError' on the left-hand side.
1818 if (!expr->IsValidLeftHandSide()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001819 VisitForEffect(expr);
Leon Clarkef7060e22010-06-03 12:02:55 +01001820 return;
1821 }
1822
1823 // Left-hand side can only be a property, a global or a (parameter or local)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001824 // slot.
Leon Clarkef7060e22010-06-03 12:02:55 +01001825 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1826 LhsKind assign_type = VARIABLE;
1827 Property* prop = expr->AsProperty();
1828 if (prop != NULL) {
1829 assign_type = (prop->key()->IsPropertyName())
1830 ? NAMED_PROPERTY
1831 : KEYED_PROPERTY;
1832 }
1833
1834 switch (assign_type) {
1835 case VARIABLE: {
1836 Variable* var = expr->AsVariableProxy()->var();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001837 EffectContext context(this);
1838 EmitVariableAssignment(var, Token::ASSIGN);
Leon Clarkef7060e22010-06-03 12:02:55 +01001839 break;
1840 }
1841 case NAMED_PROPERTY: {
1842 __ push(eax); // Preserve value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001843 VisitForAccumulatorValue(prop->obj());
Leon Clarkef7060e22010-06-03 12:02:55 +01001844 __ mov(edx, eax);
1845 __ pop(eax); // Restore value.
1846 __ mov(ecx, prop->key()->AsLiteral()->handle());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001847 Handle<Code> ic = is_classic_mode()
1848 ? isolate()->builtins()->StoreIC_Initialize()
1849 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001850 __ call(ic);
Leon Clarkef7060e22010-06-03 12:02:55 +01001851 break;
1852 }
1853 case KEYED_PROPERTY: {
1854 __ push(eax); // Preserve value.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001855 VisitForStackValue(prop->obj());
1856 VisitForAccumulatorValue(prop->key());
1857 __ mov(ecx, eax);
1858 __ pop(edx);
Leon Clarkef7060e22010-06-03 12:02:55 +01001859 __ pop(eax); // Restore value.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001860 Handle<Code> ic = is_classic_mode()
1861 ? isolate()->builtins()->KeyedStoreIC_Initialize()
1862 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001863 __ call(ic);
Leon Clarkef7060e22010-06-03 12:02:55 +01001864 break;
1865 }
1866 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001867 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1868 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001869}
1870
1871
Leon Clarked91b9f72010-01-27 17:25:45 +00001872void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001873 Token::Value op) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001874 if (var->IsUnallocated()) {
1875 // Global var, const, or let.
Steve Block3ce2e202009-11-05 08:53:23 +00001876 __ mov(ecx, var->name());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001877 __ mov(edx, GlobalObjectOperand());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001878 Handle<Code> ic = is_classic_mode()
1879 ? isolate()->builtins()->StoreIC_Initialize()
1880 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001881 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
Steve Block3ce2e202009-11-05 08:53:23 +00001882
Steve Block1e0659c2011-05-24 12:43:12 +01001883 } else if (op == Token::INIT_CONST) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001884 // Const initializers need a write barrier.
1885 ASSERT(!var->IsParameter()); // No const parameters.
1886 if (var->IsStackLocal()) {
1887 Label skip;
1888 __ mov(edx, StackOperand(var));
1889 __ cmp(edx, isolate()->factory()->the_hole_value());
1890 __ j(not_equal, &skip);
1891 __ mov(StackOperand(var), eax);
1892 __ bind(&skip);
1893 } else {
1894 ASSERT(var->IsContextSlot() || var->IsLookupSlot());
1895 // Like var declarations, const declarations are hoisted to function
1896 // scope. However, unlike var initializers, const initializers are
1897 // able to drill a hole to that function context, even from inside a
1898 // 'with' context. We thus bypass the normal static scope lookup for
1899 // var->IsContextSlot().
1900 __ push(eax);
1901 __ push(esi);
1902 __ push(Immediate(var->name()));
1903 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
Steve Block1e0659c2011-05-24 12:43:12 +01001904 }
Steve Block1e0659c2011-05-24 12:43:12 +01001905
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001906 } else if (var->mode() == LET && op != Token::INIT_LET) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001907 // Non-initializing assignment to let variable needs a write barrier.
1908 if (var->IsLookupSlot()) {
1909 __ push(eax); // Value.
1910 __ push(esi); // Context.
1911 __ push(Immediate(var->name()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001912 __ push(Immediate(Smi::FromInt(language_mode())));
Ben Murdoch589d6972011-11-30 16:04:58 +00001913 __ CallRuntime(Runtime::kStoreContextSlot, 4);
1914 } else {
1915 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
1916 Label assign;
1917 MemOperand location = VarOperand(var, ecx);
1918 __ mov(edx, location);
1919 __ cmp(edx, isolate()->factory()->the_hole_value());
1920 __ j(not_equal, &assign, Label::kNear);
1921 __ push(Immediate(var->name()));
1922 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1923 __ bind(&assign);
1924 __ mov(location, eax);
1925 if (var->IsContextSlot()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001926 __ mov(edx, eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001927 int offset = Context::SlotOffset(var->index());
1928 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001929 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001930 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001931
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001932 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
1933 // Assignment to var or initializing assignment to let/const
1934 // in harmony mode.
Ben Murdoch589d6972011-11-30 16:04:58 +00001935 if (var->IsStackAllocated() || var->IsContextSlot()) {
1936 MemOperand location = VarOperand(var, ecx);
1937 if (FLAG_debug_code && op == Token::INIT_LET) {
1938 // Check for an uninitialized let binding.
1939 __ mov(edx, location);
1940 __ cmp(edx, isolate()->factory()->the_hole_value());
1941 __ Check(equal, "Let binding re-initialization.");
Steve Block3ce2e202009-11-05 08:53:23 +00001942 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001943 // Perform the assignment.
1944 __ mov(location, eax);
1945 if (var->IsContextSlot()) {
1946 __ mov(edx, eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001947 int offset = Context::SlotOffset(var->index());
1948 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
Ben Murdoch589d6972011-11-30 16:04:58 +00001949 }
1950 } else {
1951 ASSERT(var->IsLookupSlot());
1952 __ push(eax); // Value.
1953 __ push(esi); // Context.
1954 __ push(Immediate(var->name()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001955 __ push(Immediate(Smi::FromInt(language_mode())));
Ben Murdoch589d6972011-11-30 16:04:58 +00001956 __ CallRuntime(Runtime::kStoreContextSlot, 4);
Steve Block3ce2e202009-11-05 08:53:23 +00001957 }
1958 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001959 // Non-initializing assignments to consts are ignored.
Steve Block3ce2e202009-11-05 08:53:23 +00001960}
1961
1962
Leon Clarked91b9f72010-01-27 17:25:45 +00001963void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001964 // Assignment to a property, using a named store IC.
1965 Property* prop = expr->target()->AsProperty();
1966 ASSERT(prop != NULL);
1967 ASSERT(prop->key()->AsLiteral() != NULL);
Steve Block3ce2e202009-11-05 08:53:23 +00001968
Steve Blockd0582a62009-12-15 09:54:21 +00001969 // If the assignment starts a block of assignments to the same object,
1970 // change to slow case to avoid the quadratic behavior of repeatedly
1971 // adding fast properties.
1972 if (expr->starts_initialization_block()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001973 __ push(result_register());
1974 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
Steve Blockd0582a62009-12-15 09:54:21 +00001975 __ CallRuntime(Runtime::kToSlowProperties, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001976 __ pop(result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00001977 }
1978
Leon Clarkee46be812010-01-19 14:06:41 +00001979 // Record source code position before IC call.
1980 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00001981 __ mov(ecx, prop->key()->AsLiteral()->handle());
Leon Clarke4515c472010-02-03 11:58:03 +00001982 if (expr->ends_initialization_block()) {
1983 __ mov(edx, Operand(esp, 0));
1984 } else {
1985 __ pop(edx);
1986 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001987 Handle<Code> ic = is_classic_mode()
1988 ? isolate()->builtins()->StoreIC_Initialize()
1989 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001990 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
Steve Blockd0582a62009-12-15 09:54:21 +00001991
1992 // If the assignment ends an initialization block, revert to fast case.
1993 if (expr->ends_initialization_block()) {
1994 __ push(eax); // Result of assignment, saved even if not needed.
1995 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
1996 __ CallRuntime(Runtime::kToFastProperties, 1);
1997 __ pop(eax);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001998 __ Drop(1);
Steve Blockd0582a62009-12-15 09:54:21 +00001999 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002000 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2001 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002002}
2003
2004
Leon Clarked91b9f72010-01-27 17:25:45 +00002005void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002006 // Assignment to a property, using a keyed store IC.
2007
2008 // If the assignment starts a block of assignments to the same object,
2009 // change to slow case to avoid the quadratic behavior of repeatedly
2010 // adding fast properties.
2011 if (expr->starts_initialization_block()) {
Leon Clarkee46be812010-01-19 14:06:41 +00002012 __ push(result_register());
2013 // Receiver is now under the key and value.
Steve Blockd0582a62009-12-15 09:54:21 +00002014 __ push(Operand(esp, 2 * kPointerSize));
2015 __ CallRuntime(Runtime::kToSlowProperties, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00002016 __ pop(result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00002017 }
2018
Steve Block6ded16b2010-05-10 14:33:55 +01002019 __ pop(ecx);
2020 if (expr->ends_initialization_block()) {
2021 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
2022 } else {
2023 __ pop(edx);
2024 }
Leon Clarkee46be812010-01-19 14:06:41 +00002025 // Record source code position before IC call.
2026 SetSourcePosition(expr->position());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002027 Handle<Code> ic = is_classic_mode()
2028 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2029 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002030 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
Steve Blockd0582a62009-12-15 09:54:21 +00002031
2032 // If the assignment ends an initialization block, revert to fast case.
2033 if (expr->ends_initialization_block()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002034 __ pop(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00002035 __ push(eax); // Result of assignment, saved even if not needed.
Steve Block6ded16b2010-05-10 14:33:55 +01002036 __ push(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00002037 __ CallRuntime(Runtime::kToFastProperties, 1);
2038 __ pop(eax);
2039 }
2040
Ben Murdochb0fe1622011-05-05 13:52:32 +01002041 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002042 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002043}
2044
2045
Leon Clarked91b9f72010-01-27 17:25:45 +00002046void FullCodeGenerator::VisitProperty(Property* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002047 Comment cmnt(masm_, "[ Property");
2048 Expression* key = expr->key();
Steve Blockd0582a62009-12-15 09:54:21 +00002049
Leon Clarkee46be812010-01-19 14:06:41 +00002050 if (key->IsPropertyName()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002051 VisitForAccumulatorValue(expr->obj());
Leon Clarkee46be812010-01-19 14:06:41 +00002052 EmitNamedPropertyLoad(expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002053 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002054 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002055 VisitForStackValue(expr->obj());
2056 VisitForAccumulatorValue(expr->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00002057 __ pop(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00002058 EmitKeyedPropertyLoad(expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002059 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002060 }
Steve Blockd0582a62009-12-15 09:54:21 +00002061}
2062
2063
Leon Clarked91b9f72010-01-27 17:25:45 +00002064void FullCodeGenerator::EmitCallWithIC(Call* expr,
Leon Clarkee46be812010-01-19 14:06:41 +00002065 Handle<Object> name,
2066 RelocInfo::Mode mode) {
Steve Blockd0582a62009-12-15 09:54:21 +00002067 // Code common for calls using the IC.
2068 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00002069 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002070 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002071 for (int i = 0; i < arg_count; i++) {
2072 VisitForStackValue(args->at(i));
2073 }
2074 __ Set(ecx, Immediate(name));
Steve Block3ce2e202009-11-05 08:53:23 +00002075 }
Leon Clarkee46be812010-01-19 14:06:41 +00002076 // Record source position of the IC call.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002077 SetSourcePosition(expr->position());
Ben Murdoch257744e2011-11-30 15:57:28 +00002078 Handle<Code> ic =
Ben Murdoch589d6972011-11-30 16:04:58 +00002079 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002080 __ call(ic, mode, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002081 RecordJSReturnSite(expr);
Steve Block3ce2e202009-11-05 08:53:23 +00002082 // Restore context register.
2083 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002084 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002085}
2086
2087
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002088void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Ben Murdoch257744e2011-11-30 15:57:28 +00002089 Expression* key) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002090 // Load the key.
2091 VisitForAccumulatorValue(key);
2092
2093 // Swap the name of the function and the receiver on the stack to follow
2094 // the calling convention for call ICs.
2095 __ pop(ecx);
2096 __ push(eax);
2097 __ push(ecx);
2098
2099 // Load the arguments.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002100 ZoneList<Expression*>* args = expr->arguments();
2101 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002102 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002103 for (int i = 0; i < arg_count; i++) {
2104 VisitForStackValue(args->at(i));
2105 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002106 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002107 // Record source position of the IC call.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002108 SetSourcePosition(expr->position());
Ben Murdoch589d6972011-11-30 16:04:58 +00002109 Handle<Code> ic =
2110 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002111 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002112 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002113 RecordJSReturnSite(expr);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002114 // Restore context register.
2115 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002116 context()->DropAndPlug(1, eax); // Drop the key still on the stack.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002117}
2118
2119
Ben Murdoch257744e2011-11-30 15:57:28 +00002120void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
Steve Blockd0582a62009-12-15 09:54:21 +00002121 // Code common for calls using the call stub.
2122 ZoneList<Expression*>* args = expr->arguments();
2123 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002124 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002125 for (int i = 0; i < arg_count; i++) {
2126 VisitForStackValue(args->at(i));
2127 }
Steve Block3ce2e202009-11-05 08:53:23 +00002128 }
Steve Blockd0582a62009-12-15 09:54:21 +00002129 // Record source position for debugger.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002130 SetSourcePosition(expr->position());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002131
2132 // Record call targets in unoptimized code, but not in the snapshot.
2133 bool record_call_target = !Serializer::enabled();
2134 if (record_call_target) {
2135 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
2136 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002137 CallFunctionStub stub(arg_count, flags);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002138 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2139 __ CallStub(&stub, expr->id());
2140 if (record_call_target) {
2141 // There is a one element cache in the instruction stream.
2142#ifdef DEBUG
2143 int return_site_offset = masm()->pc_offset();
2144#endif
2145 Handle<Object> uninitialized =
2146 CallFunctionStub::UninitializedSentinel(isolate());
2147 Handle<JSGlobalPropertyCell> cell =
2148 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
2149 __ test(eax, Immediate(cell));
2150 // Patching code in the stub assumes the opcode is 1 byte and there is
2151 // word for a pointer in the operand.
2152 ASSERT(masm()->pc_offset() - return_site_offset >= 1 + kPointerSize);
2153 }
2154
Ben Murdochb0fe1622011-05-05 13:52:32 +01002155 RecordJSReturnSite(expr);
Steve Blockd0582a62009-12-15 09:54:21 +00002156 // Restore context register.
2157 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002158 context()->DropAndPlug(1, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002159}
2160
2161
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002162void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002163 // Push copy of the first argument or undefined if it doesn't exist.
2164 if (arg_count > 0) {
2165 __ push(Operand(esp, arg_count * kPointerSize));
2166 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002167 __ push(Immediate(isolate()->factory()->undefined_value()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002168 }
2169
2170 // Push the receiver of the enclosing function.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002171 __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002172 // Push the language mode.
2173 __ push(Immediate(Smi::FromInt(language_mode())));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002174
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002175 // Push the start position of the scope the calls resides in.
2176 __ push(Immediate(Smi::FromInt(scope()->start_position())));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002177
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002178 // Do the runtime call.
2179 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002180}
2181
2182
Leon Clarked91b9f72010-01-27 17:25:45 +00002183void FullCodeGenerator::VisitCall(Call* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002184#ifdef DEBUG
2185 // We want to verify that RecordJSReturnSite gets called on all paths
2186 // through this function. Avoid early returns.
2187 expr->return_is_recorded_ = false;
2188#endif
2189
Steve Blockd0582a62009-12-15 09:54:21 +00002190 Comment cmnt(masm_, "[ Call");
Ben Murdoch589d6972011-11-30 16:04:58 +00002191 Expression* callee = expr->expression();
2192 VariableProxy* proxy = callee->AsVariableProxy();
2193 Property* property = callee->AsProperty();
Steve Blockd0582a62009-12-15 09:54:21 +00002194
Ben Murdoch589d6972011-11-30 16:04:58 +00002195 if (proxy != NULL && proxy->var()->is_possibly_eval()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002196 // In a call to eval, we first call %ResolvePossiblyDirectEval to
Ben Murdoch589d6972011-11-30 16:04:58 +00002197 // resolve the function we need to call and the receiver of the call.
2198 // Then we call the resolved function using the given arguments.
Leon Clarkef7060e22010-06-03 12:02:55 +01002199 ZoneList<Expression*>* args = expr->arguments();
2200 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002201 { PreservePositionScope pos_scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002202 VisitForStackValue(callee);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002203 // Reserved receiver slot.
Steve Block44f0eee2011-05-26 01:26:41 +01002204 __ push(Immediate(isolate()->factory()->undefined_value()));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002205 // Push the arguments.
2206 for (int i = 0; i < arg_count; i++) {
2207 VisitForStackValue(args->at(i));
2208 }
2209
Ben Murdoch589d6972011-11-30 16:04:58 +00002210 // Push a copy of the function (found below the arguments) and
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002211 // resolve eval.
2212 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002213 EmitResolvePossiblyDirectEval(arg_count);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002214
2215 // The runtime call returns a pair of values in eax (function) and
2216 // edx (receiver). Touch up the stack with the right values.
2217 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2218 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002219 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002220 // Record source position for debugger.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002221 SetSourcePosition(expr->position());
Ben Murdoch589d6972011-11-30 16:04:58 +00002222 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002223 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
Leon Clarkef7060e22010-06-03 12:02:55 +01002224 __ CallStub(&stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002225 RecordJSReturnSite(expr);
Leon Clarkef7060e22010-06-03 12:02:55 +01002226 // Restore context register.
2227 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002228 context()->DropAndPlug(1, eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00002229
2230 } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
Leon Clarkee46be812010-01-19 14:06:41 +00002231 // Push global object as receiver for the call IC.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002232 __ push(GlobalObjectOperand());
Ben Murdoch589d6972011-11-30 16:04:58 +00002233 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
2234
2235 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Steve Block59151502010-09-22 15:07:15 +01002236 // Call to a lookup slot (dynamically introduced variable).
2237 Label slow, done;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002238 { PreservePositionScope scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002239 // Generate code for loading from variables potentially shadowed by
2240 // eval-introduced variables.
2241 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002242 }
Steve Block59151502010-09-22 15:07:15 +01002243 __ bind(&slow);
Ben Murdoch589d6972011-11-30 16:04:58 +00002244 // Call the runtime to find the function to call (returned in eax) and
2245 // the object holding it (returned in edx).
Leon Clarkef7060e22010-06-03 12:02:55 +01002246 __ push(context_register());
Ben Murdoch589d6972011-11-30 16:04:58 +00002247 __ push(Immediate(proxy->name()));
Leon Clarkef7060e22010-06-03 12:02:55 +01002248 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2249 __ push(eax); // Function.
2250 __ push(edx); // Receiver.
Steve Block59151502010-09-22 15:07:15 +01002251
Ben Murdoch589d6972011-11-30 16:04:58 +00002252 // If fast case code has been generated, emit code to push the function
2253 // and receiver and have the slow path jump around this code.
Steve Block59151502010-09-22 15:07:15 +01002254 if (done.is_linked()) {
2255 Label call;
Ben Murdoch589d6972011-11-30 16:04:58 +00002256 __ jmp(&call, Label::kNear);
Steve Block59151502010-09-22 15:07:15 +01002257 __ bind(&done);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002258 // Push function.
Steve Block59151502010-09-22 15:07:15 +01002259 __ push(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00002260 // The receiver is implicitly the global receiver. Indicate this by
2261 // passing the hole to the call function stub.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002262 __ push(Immediate(isolate()->factory()->the_hole_value()));
Steve Block59151502010-09-22 15:07:15 +01002263 __ bind(&call);
2264 }
2265
Ben Murdoch589d6972011-11-30 16:04:58 +00002266 // The receiver is either the global receiver or an object found by
2267 // LoadContextSlot. That object could be the hole if the receiver is
2268 // implicitly the global object.
Ben Murdoch257744e2011-11-30 15:57:28 +00002269 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
Ben Murdoch589d6972011-11-30 16:04:58 +00002270
2271 } else if (property != NULL) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002272 { PreservePositionScope scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002273 VisitForStackValue(property->obj());
2274 }
2275 if (property->key()->IsPropertyName()) {
2276 EmitCallWithIC(expr,
2277 property->key()->AsLiteral()->handle(),
2278 RelocInfo::CODE_TARGET);
2279 } else {
2280 EmitKeyedCallWithIC(expr, property->key());
2281 }
2282
2283 } else {
2284 // Call to an arbitrary expression not handled specially above.
2285 { PreservePositionScope scope(masm()->positions_recorder());
2286 VisitForStackValue(callee);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002287 }
Steve Blockd0582a62009-12-15 09:54:21 +00002288 // Load global receiver object.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002289 __ mov(ebx, GlobalObjectOperand());
Steve Blockd0582a62009-12-15 09:54:21 +00002290 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2291 // Emit function call.
Ben Murdoch257744e2011-11-30 15:57:28 +00002292 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
Steve Blockd0582a62009-12-15 09:54:21 +00002293 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002294
2295#ifdef DEBUG
2296 // RecordJSReturnSite should have been called.
2297 ASSERT(expr->return_is_recorded_);
2298#endif
Steve Blockd0582a62009-12-15 09:54:21 +00002299}
2300
2301
Leon Clarked91b9f72010-01-27 17:25:45 +00002302void FullCodeGenerator::VisitCallNew(CallNew* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002303 Comment cmnt(masm_, "[ CallNew");
2304 // According to ECMA-262, section 11.2.2, page 44, the function
2305 // expression in new calls must be evaluated before the
2306 // arguments.
Steve Blockd0582a62009-12-15 09:54:21 +00002307
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002308 // Push constructor on the stack. If it's not a function it's used as
2309 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2310 // ignored.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002311 VisitForStackValue(expr->expression());
Steve Blockd0582a62009-12-15 09:54:21 +00002312
2313 // Push the arguments ("left-to-right") on the stack.
2314 ZoneList<Expression*>* args = expr->arguments();
2315 int arg_count = args->length();
2316 for (int i = 0; i < arg_count; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002317 VisitForStackValue(args->at(i));
Steve Blockd0582a62009-12-15 09:54:21 +00002318 }
2319
2320 // Call the construct call builtin that handles allocation and
2321 // constructor invocation.
2322 SetSourcePosition(expr->position());
2323
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002324 // Load function and argument count into edi and eax.
Steve Block053d10c2011-06-13 19:13:29 +01002325 __ SafeSet(eax, Immediate(arg_count));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002326 __ mov(edi, Operand(esp, arg_count * kPointerSize));
Steve Blockd0582a62009-12-15 09:54:21 +00002327
Steve Block44f0eee2011-05-26 01:26:41 +01002328 Handle<Code> construct_builtin =
2329 isolate()->builtins()->JSConstructCall();
Steve Blockd0582a62009-12-15 09:54:21 +00002330 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002331 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00002332}
2333
2334
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002335void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2336 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002337 ASSERT(args->length() == 1);
2338
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002339 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002340
2341 Label materialize_true, materialize_false;
2342 Label* if_true = NULL;
2343 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002344 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002345 context()->PrepareTest(&materialize_true, &materialize_false,
2346 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002347
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002348 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002349 __ test(eax, Immediate(kSmiTagMask));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002350 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002351
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002352 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002353}
2354
2355
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002356void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2357 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002358 ASSERT(args->length() == 1);
2359
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002360 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002361
2362 Label materialize_true, materialize_false;
2363 Label* if_true = NULL;
2364 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002365 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002366 context()->PrepareTest(&materialize_true, &materialize_false,
2367 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002368
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002369 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002370 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002371 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002372
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002373 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002374}
2375
2376
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002377void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2378 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002379 ASSERT(args->length() == 1);
2380
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002381 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002382
2383 Label materialize_true, materialize_false;
2384 Label* if_true = NULL;
2385 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002386 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002387 context()->PrepareTest(&materialize_true, &materialize_false,
2388 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002389
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002390 __ JumpIfSmi(eax, if_false);
Steve Block44f0eee2011-05-26 01:26:41 +01002391 __ cmp(eax, isolate()->factory()->null_value());
Leon Clarkef7060e22010-06-03 12:02:55 +01002392 __ j(equal, if_true);
2393 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2394 // Undetectable objects behave like undefined when tested with typeof.
2395 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2396 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2397 __ j(not_zero, if_false);
2398 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002399 __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
Leon Clarkef7060e22010-06-03 12:02:55 +01002400 __ j(below, if_false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002401 __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002402 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002403 Split(below_equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002404
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002405 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002406}
2407
2408
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002409void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2410 ZoneList<Expression*>* args = expr->arguments();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002411 ASSERT(args->length() == 1);
2412
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002413 VisitForAccumulatorValue(args->at(0));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002414
2415 Label materialize_true, materialize_false;
2416 Label* if_true = NULL;
2417 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002418 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002419 context()->PrepareTest(&materialize_true, &materialize_false,
2420 &if_true, &if_false, &fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002421
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002422 __ JumpIfSmi(eax, if_false);
2423 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002424 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002425 Split(above_equal, if_true, if_false, fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002426
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002427 context()->Plug(if_true, if_false);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002428}
2429
2430
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002431void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2432 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002433 ASSERT(args->length() == 1);
2434
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002435 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002436
2437 Label materialize_true, materialize_false;
2438 Label* if_true = NULL;
2439 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002440 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002441 context()->PrepareTest(&materialize_true, &materialize_false,
2442 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002443
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002444 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002445 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2446 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2447 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002448 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002449 Split(not_zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002450
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002451 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002452}
2453
2454
Iain Merrick75681382010-08-19 15:07:18 +01002455void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002456 CallRuntime* expr) {
2457 ZoneList<Expression*>* args = expr->arguments();
Iain Merrick75681382010-08-19 15:07:18 +01002458 ASSERT(args->length() == 1);
2459
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002460 VisitForAccumulatorValue(args->at(0));
Iain Merrick75681382010-08-19 15:07:18 +01002461
2462 Label materialize_true, materialize_false;
2463 Label* if_true = NULL;
2464 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002465 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002466 context()->PrepareTest(&materialize_true, &materialize_false,
2467 &if_true, &if_false, &fall_through);
Iain Merrick75681382010-08-19 15:07:18 +01002468
Ben Murdoch8b112d22011-06-08 16:22:53 +01002469 if (FLAG_debug_code) __ AbortIfSmi(eax);
2470
2471 // Check whether this map has already been checked to be safe for default
2472 // valueOf.
2473 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2474 __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
2475 1 << Map::kStringWrapperSafeForDefaultValueOf);
2476 __ j(not_zero, if_true);
2477
2478 // Check for fast case object. Return false for slow case objects.
2479 __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
2480 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2481 __ cmp(ecx, FACTORY->hash_table_map());
2482 __ j(equal, if_false);
2483
2484 // Look for valueOf symbol in the descriptor array, and indicate false if
2485 // found. The type is not checked, so if it is a transition it is a false
2486 // negative.
Ben Murdoch257744e2011-11-30 15:57:28 +00002487 __ LoadInstanceDescriptors(ebx, ebx);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002488 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
2489 // ebx: descriptor array
2490 // ecx: length of descriptor array
2491 // Calculate the end of the descriptor array.
2492 STATIC_ASSERT(kSmiTag == 0);
2493 STATIC_ASSERT(kSmiTagSize == 1);
2494 STATIC_ASSERT(kPointerSize == 4);
2495 __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
2496 // Calculate location of the first key name.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002497 __ add(ebx,
2498 Immediate(FixedArray::kHeaderSize +
2499 DescriptorArray::kFirstIndex * kPointerSize));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002500 // Loop through all the keys in the descriptor array. If one of these is the
2501 // symbol valueOf the result is false.
2502 Label entry, loop;
2503 __ jmp(&entry);
2504 __ bind(&loop);
2505 __ mov(edx, FieldOperand(ebx, 0));
2506 __ cmp(edx, FACTORY->value_of_symbol());
2507 __ j(equal, if_false);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002508 __ add(ebx, Immediate(kPointerSize));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002509 __ bind(&entry);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002510 __ cmp(ebx, ecx);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002511 __ j(not_equal, &loop);
2512
2513 // Reload map as register ebx was used as temporary above.
2514 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2515
2516 // If a valueOf property is not found on the object check that it's
2517 // prototype is the un-modified String prototype. If not result is false.
2518 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002519 __ JumpIfSmi(ecx, if_false);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002520 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2521 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2522 __ mov(edx,
2523 FieldOperand(edx, GlobalObject::kGlobalContextOffset));
2524 __ cmp(ecx,
2525 ContextOperand(edx,
2526 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2527 __ j(not_equal, if_false);
2528 // Set the bit in the map to indicate that it has been checked safe for
2529 // default valueOf and set true result.
2530 __ or_(FieldOperand(ebx, Map::kBitField2Offset),
2531 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2532 __ jmp(if_true);
2533
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002534 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002535 context()->Plug(if_true, if_false);
Iain Merrick75681382010-08-19 15:07:18 +01002536}
2537
2538
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002539void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
2540 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002541 ASSERT(args->length() == 1);
2542
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002543 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002544
2545 Label materialize_true, materialize_false;
2546 Label* if_true = NULL;
2547 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002548 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002549 context()->PrepareTest(&materialize_true, &materialize_false,
2550 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002551
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002552 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002553 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002554 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002555 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002556
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002557 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002558}
2559
2560
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002561void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2562 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002563 ASSERT(args->length() == 1);
2564
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002565 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002566
2567 Label materialize_true, materialize_false;
2568 Label* if_true = NULL;
2569 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002570 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002571 context()->PrepareTest(&materialize_true, &materialize_false,
2572 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002573
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002574 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002575 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002576 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002577 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002578
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002579 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002580}
2581
2582
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002583void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2584 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002585 ASSERT(args->length() == 1);
2586
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002587 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002588
2589 Label materialize_true, materialize_false;
2590 Label* if_true = NULL;
2591 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002592 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002593 context()->PrepareTest(&materialize_true, &materialize_false,
2594 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002595
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002596 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002597 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002598 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002599 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002600
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002601 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002602}
2603
2604
2605
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002606void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
2607 ASSERT(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002608
2609 Label materialize_true, materialize_false;
2610 Label* if_true = NULL;
2611 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002612 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002613 context()->PrepareTest(&materialize_true, &materialize_false,
2614 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002615
2616 // Get the frame pointer for the calling frame.
2617 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2618
2619 // Skip the arguments adaptor frame if it exists.
2620 Label check_frame_marker;
2621 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2622 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2623 __ j(not_equal, &check_frame_marker);
2624 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2625
2626 // Check the marker in the calling frame.
2627 __ bind(&check_frame_marker);
2628 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2629 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002630 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002631 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002632
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002633 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002634}
2635
2636
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002637void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
2638 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002639 ASSERT(args->length() == 2);
2640
2641 // Load the two objects into registers and perform the comparison.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002642 VisitForStackValue(args->at(0));
2643 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01002644
2645 Label materialize_true, materialize_false;
2646 Label* if_true = NULL;
2647 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002648 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002649 context()->PrepareTest(&materialize_true, &materialize_false,
2650 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002651
2652 __ pop(ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002653 __ cmp(eax, ebx);
2654 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002655 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002656
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002657 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002658}
2659
2660
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002661void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
2662 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002663 ASSERT(args->length() == 1);
2664
2665 // ArgumentsAccessStub expects the key in edx and the formal
2666 // parameter count in eax.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002667 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002668 __ mov(edx, eax);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002669 __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
Leon Clarkef7060e22010-06-03 12:02:55 +01002670 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2671 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002672 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002673}
2674
2675
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002676void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
2677 ASSERT(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002678
2679 Label exit;
2680 // Get the number of formal parameters.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002681 __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
Leon Clarkef7060e22010-06-03 12:02:55 +01002682
2683 // Check if the calling frame is an arguments adaptor frame.
2684 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2685 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2686 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2687 __ j(not_equal, &exit);
2688
2689 // Arguments adaptor case: Read the arguments length from the
2690 // adaptor frame.
2691 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2692
2693 __ bind(&exit);
2694 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002695 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002696}
2697
2698
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002699void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2700 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002701 ASSERT(args->length() == 1);
2702 Label done, null, function, non_function_constructor;
2703
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002704 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002705
2706 // If the object is a smi, we return null.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002707 __ JumpIfSmi(eax, &null);
Leon Clarkef7060e22010-06-03 12:02:55 +01002708
2709 // Check that the object is a JS object but take special care of JS
2710 // functions to make sure they have 'Function' as their class.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002711 // Assume that there are only two callable types, and one of them is at
2712 // either end of the type range for JS object types. Saves extra comparisons.
2713 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002714 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
2715 // Map is now in eax.
Leon Clarkef7060e22010-06-03 12:02:55 +01002716 __ j(below, &null);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002717 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2718 FIRST_SPEC_OBJECT_TYPE + 1);
2719 __ j(equal, &function);
Leon Clarkef7060e22010-06-03 12:02:55 +01002720
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002721 __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
2722 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2723 LAST_SPEC_OBJECT_TYPE - 1);
2724 __ j(equal, &function);
2725 // Assume that there is no larger type.
2726 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01002727
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002728 // Check if the constructor in the map is a JS function.
Leon Clarkef7060e22010-06-03 12:02:55 +01002729 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2730 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2731 __ j(not_equal, &non_function_constructor);
2732
2733 // eax now contains the constructor function. Grab the
2734 // instance class name from there.
2735 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2736 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2737 __ jmp(&done);
2738
2739 // Functions have class 'Function'.
2740 __ bind(&function);
Steve Block44f0eee2011-05-26 01:26:41 +01002741 __ mov(eax, isolate()->factory()->function_class_symbol());
Leon Clarkef7060e22010-06-03 12:02:55 +01002742 __ jmp(&done);
2743
2744 // Objects with a non-function constructor have class 'Object'.
2745 __ bind(&non_function_constructor);
Steve Block44f0eee2011-05-26 01:26:41 +01002746 __ mov(eax, isolate()->factory()->Object_symbol());
Leon Clarkef7060e22010-06-03 12:02:55 +01002747 __ jmp(&done);
2748
2749 // Non-JS objects have class null.
2750 __ bind(&null);
Steve Block44f0eee2011-05-26 01:26:41 +01002751 __ mov(eax, isolate()->factory()->null_value());
Leon Clarkef7060e22010-06-03 12:02:55 +01002752
2753 // All done.
2754 __ bind(&done);
2755
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002756 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002757}
2758
2759
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002760void FullCodeGenerator::EmitLog(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002761 // Conditionally generate a log call.
2762 // Args:
2763 // 0 (literal string): The type of logging (corresponds to the flags).
2764 // This is used to determine whether or not to generate the log call.
2765 // 1 (string): Format string. Access the string at argument index 2
2766 // with '%2s' (see Logger::LogRuntime for all the formats).
2767 // 2 (array): Arguments to the format string.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002768 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002769 ASSERT_EQ(args->length(), 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01002770 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002771 VisitForStackValue(args->at(1));
2772 VisitForStackValue(args->at(2));
Leon Clarkef7060e22010-06-03 12:02:55 +01002773 __ CallRuntime(Runtime::kLog, 2);
2774 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002775 // Finally, we're expected to leave a value on the top of the stack.
Steve Block44f0eee2011-05-26 01:26:41 +01002776 __ mov(eax, isolate()->factory()->undefined_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002777 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002778}
2779
2780
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002781void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
2782 ASSERT(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002783
2784 Label slow_allocate_heapnumber;
2785 Label heapnumber_allocated;
2786
2787 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2788 __ jmp(&heapnumber_allocated);
2789
2790 __ bind(&slow_allocate_heapnumber);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002791 // Allocate a heap number.
2792 __ CallRuntime(Runtime::kNumberAlloc, 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002793 __ mov(edi, eax);
2794
2795 __ bind(&heapnumber_allocated);
2796
Ben Murdoch8b112d22011-06-08 16:22:53 +01002797 __ PrepareCallCFunction(1, ebx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002798 __ mov(eax, ContextOperand(context_register(), Context::GLOBAL_INDEX));
2799 __ mov(eax, FieldOperand(eax, GlobalObject::kGlobalContextOffset));
2800 __ mov(Operand(esp, 0), eax);
2801 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01002802
2803 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2804 // by computing:
2805 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2806 // This is implemented on both SSE2 and FPU.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002807 if (CpuFeatures::IsSupported(SSE2)) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002808 CpuFeatures::Scope fscope(SSE2);
2809 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002810 __ movd(xmm1, ebx);
2811 __ movd(xmm0, eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002812 __ cvtss2sd(xmm1, xmm1);
Ben Murdoch257744e2011-11-30 15:57:28 +00002813 __ xorps(xmm0, xmm1);
Leon Clarkef7060e22010-06-03 12:02:55 +01002814 __ subsd(xmm0, xmm1);
2815 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2816 } else {
2817 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2818 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2819 Immediate(0x41300000));
2820 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2821 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2822 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2823 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2824 __ fsubp(1);
2825 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2826 }
2827 __ mov(eax, edi);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002828 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002829}
2830
2831
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002832void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002833 // Load the arguments on the stack and call the stub.
2834 SubStringStub stub;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002835 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002836 ASSERT(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002837 VisitForStackValue(args->at(0));
2838 VisitForStackValue(args->at(1));
2839 VisitForStackValue(args->at(2));
Leon Clarkef7060e22010-06-03 12:02:55 +01002840 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002841 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002842}
2843
2844
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002845void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002846 // Load the arguments on the stack and call the stub.
2847 RegExpExecStub stub;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002848 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002849 ASSERT(args->length() == 4);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002850 VisitForStackValue(args->at(0));
2851 VisitForStackValue(args->at(1));
2852 VisitForStackValue(args->at(2));
2853 VisitForStackValue(args->at(3));
Leon Clarkef7060e22010-06-03 12:02:55 +01002854 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002855 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002856}
2857
2858
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002859void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
2860 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002861 ASSERT(args->length() == 1);
2862
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002863 VisitForAccumulatorValue(args->at(0)); // Load the object.
Leon Clarkef7060e22010-06-03 12:02:55 +01002864
Ben Murdoch257744e2011-11-30 15:57:28 +00002865 Label done;
Leon Clarkef7060e22010-06-03 12:02:55 +01002866 // If the object is a smi return the object.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002867 __ JumpIfSmi(eax, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01002868 // If the object is not a value type, return the object.
2869 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
Ben Murdoch257744e2011-11-30 15:57:28 +00002870 __ j(not_equal, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01002871 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2872
2873 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002874 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002875}
2876
2877
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002878void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002879 // Load the arguments on the stack and call the runtime function.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002880 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002881 ASSERT(args->length() == 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002882 VisitForStackValue(args->at(0));
2883 VisitForStackValue(args->at(1));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002884
Ben Murdoch8b112d22011-06-08 16:22:53 +01002885 if (CpuFeatures::IsSupported(SSE2)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00002886 MathPowStub stub(MathPowStub::ON_STACK);
Steve Block44f0eee2011-05-26 01:26:41 +01002887 __ CallStub(&stub);
2888 } else {
2889 __ CallRuntime(Runtime::kMath_pow, 2);
2890 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002891 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002892}
2893
2894
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002895void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
2896 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002897 ASSERT(args->length() == 2);
2898
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002899 VisitForStackValue(args->at(0)); // Load the object.
2900 VisitForAccumulatorValue(args->at(1)); // Load the value.
Leon Clarkef7060e22010-06-03 12:02:55 +01002901 __ pop(ebx); // eax = value. ebx = object.
2902
Ben Murdoch257744e2011-11-30 15:57:28 +00002903 Label done;
Leon Clarkef7060e22010-06-03 12:02:55 +01002904 // If the object is a smi, return the value.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002905 __ JumpIfSmi(ebx, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01002906
2907 // If the object is not a value type, return the value.
2908 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +00002909 __ j(not_equal, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01002910
2911 // Store the value.
2912 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002913
Leon Clarkef7060e22010-06-03 12:02:55 +01002914 // Update the write barrier. Save the value as it will be
2915 // overwritten by the write barrier code and is needed afterward.
2916 __ mov(edx, eax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002917 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
Leon Clarkef7060e22010-06-03 12:02:55 +01002918
2919 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002920 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002921}
2922
2923
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002924void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
2925 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002926 ASSERT_EQ(args->length(), 1);
2927
2928 // Load the argument on the stack and call the stub.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002929 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002930
2931 NumberToStringStub stub;
2932 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002933 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002934}
2935
2936
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002937void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
2938 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01002939 ASSERT(args->length() == 1);
2940
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002941 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002942
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002943 Label done;
2944 StringCharFromCodeGenerator generator(eax, ebx);
2945 generator.GenerateFast(masm_);
Leon Clarkef7060e22010-06-03 12:02:55 +01002946 __ jmp(&done);
2947
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002948 NopRuntimeCallHelper call_helper;
2949 generator.GenerateSlow(masm_, call_helper);
Leon Clarkef7060e22010-06-03 12:02:55 +01002950
2951 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002952 context()->Plug(ebx);
Leon Clarkef7060e22010-06-03 12:02:55 +01002953}
2954
2955
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002956void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
2957 ZoneList<Expression*>* args = expr->arguments();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002958 ASSERT(args->length() == 2);
2959
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002960 VisitForStackValue(args->at(0));
2961 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002962
2963 Register object = ebx;
2964 Register index = eax;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002965 Register result = edx;
2966
2967 __ pop(object);
2968
2969 Label need_conversion;
2970 Label index_out_of_range;
2971 Label done;
2972 StringCharCodeAtGenerator generator(object,
2973 index,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002974 result,
2975 &need_conversion,
2976 &need_conversion,
2977 &index_out_of_range,
2978 STRING_INDEX_IS_NUMBER);
2979 generator.GenerateFast(masm_);
2980 __ jmp(&done);
2981
2982 __ bind(&index_out_of_range);
2983 // When the index is out of range, the spec requires us to return
2984 // NaN.
Steve Block44f0eee2011-05-26 01:26:41 +01002985 __ Set(result, Immediate(isolate()->factory()->nan_value()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002986 __ jmp(&done);
2987
2988 __ bind(&need_conversion);
Leon Clarkef7060e22010-06-03 12:02:55 +01002989 // Move the undefined value into the result register, which will
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002990 // trigger conversion.
Steve Block44f0eee2011-05-26 01:26:41 +01002991 __ Set(result, Immediate(isolate()->factory()->undefined_value()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002992 __ jmp(&done);
2993
2994 NopRuntimeCallHelper call_helper;
2995 generator.GenerateSlow(masm_, call_helper);
2996
2997 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002998 context()->Plug(result);
Leon Clarkef7060e22010-06-03 12:02:55 +01002999}
3000
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003001
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003002void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3003 ZoneList<Expression*>* args = expr->arguments();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003004 ASSERT(args->length() == 2);
3005
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003006 VisitForStackValue(args->at(0));
3007 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003008
3009 Register object = ebx;
3010 Register index = eax;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003011 Register scratch = edx;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003012 Register result = eax;
3013
3014 __ pop(object);
3015
3016 Label need_conversion;
3017 Label index_out_of_range;
3018 Label done;
3019 StringCharAtGenerator generator(object,
3020 index,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003021 scratch,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003022 result,
3023 &need_conversion,
3024 &need_conversion,
3025 &index_out_of_range,
3026 STRING_INDEX_IS_NUMBER);
3027 generator.GenerateFast(masm_);
3028 __ jmp(&done);
3029
3030 __ bind(&index_out_of_range);
3031 // When the index is out of range, the spec requires us to return
3032 // the empty string.
Steve Block44f0eee2011-05-26 01:26:41 +01003033 __ Set(result, Immediate(isolate()->factory()->empty_string()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003034 __ jmp(&done);
3035
3036 __ bind(&need_conversion);
3037 // Move smi zero into the result register, which will trigger
3038 // conversion.
3039 __ Set(result, Immediate(Smi::FromInt(0)));
3040 __ jmp(&done);
3041
3042 NopRuntimeCallHelper call_helper;
3043 generator.GenerateSlow(masm_, call_helper);
3044
3045 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003046 context()->Plug(result);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003047}
3048
3049
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003050void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3051 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003052 ASSERT_EQ(2, args->length());
3053
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003054 VisitForStackValue(args->at(0));
3055 VisitForStackValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003056
3057 StringAddStub stub(NO_STRING_ADD_FLAGS);
3058 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003059 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003060}
3061
3062
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003063void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3064 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003065 ASSERT_EQ(2, args->length());
3066
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003067 VisitForStackValue(args->at(0));
3068 VisitForStackValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003069
3070 StringCompareStub stub;
3071 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003072 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003073}
3074
3075
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003076void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003077 // Load the argument on the stack and call the stub.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003078 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3079 TranscendentalCacheStub::TAGGED);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003080 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003081 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003082 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003083 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003084 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003085}
3086
3087
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003088void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003089 // Load the argument on the stack and call the stub.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003090 TranscendentalCacheStub stub(TranscendentalCache::COS,
3091 TranscendentalCacheStub::TAGGED);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003092 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003093 ASSERT(args->length() == 1);
3094 VisitForStackValue(args->at(0));
3095 __ CallStub(&stub);
3096 context()->Plug(eax);
3097}
3098
3099
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003100void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
3101 // Load the argument on the stack and call the stub.
3102 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3103 TranscendentalCacheStub::TAGGED);
3104 ZoneList<Expression*>* args = expr->arguments();
3105 ASSERT(args->length() == 1);
3106 VisitForStackValue(args->at(0));
3107 __ CallStub(&stub);
3108 context()->Plug(eax);
3109}
3110
3111
3112void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003113 // Load the argument on the stack and call the stub.
3114 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3115 TranscendentalCacheStub::TAGGED);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003116 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003117 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003118 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003119 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003120 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003121}
3122
3123
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003124void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003125 // Load the argument on the stack and call the runtime function.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003126 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003127 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003128 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003129 __ CallRuntime(Runtime::kMath_sqrt, 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003130 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003131}
3132
3133
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003134void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3135 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003136 ASSERT(args->length() >= 2);
3137
Ben Murdoch257744e2011-11-30 15:57:28 +00003138 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3139 for (int i = 0; i < arg_count + 1; ++i) {
3140 VisitForStackValue(args->at(i));
Leon Clarkef7060e22010-06-03 12:02:55 +01003141 }
Ben Murdoch257744e2011-11-30 15:57:28 +00003142 VisitForAccumulatorValue(args->last()); // Function.
Leon Clarkef7060e22010-06-03 12:02:55 +01003143
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003144 // Check for proxy.
3145 Label proxy, done;
3146 __ CmpObjectType(eax, JS_FUNCTION_PROXY_TYPE, ebx);
3147 __ j(equal, &proxy);
3148
Ben Murdoch257744e2011-11-30 15:57:28 +00003149 // InvokeFunction requires the function in edi. Move it in there.
3150 __ mov(edi, result_register());
Leon Clarkef7060e22010-06-03 12:02:55 +01003151 ParameterCount count(arg_count);
Ben Murdoch257744e2011-11-30 15:57:28 +00003152 __ InvokeFunction(edi, count, CALL_FUNCTION,
3153 NullCallWrapper(), CALL_AS_METHOD);
Leon Clarkef7060e22010-06-03 12:02:55 +01003154 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003155 __ jmp(&done);
3156
3157 __ bind(&proxy);
3158 __ push(eax);
3159 __ CallRuntime(Runtime::kCall, args->length());
3160 __ bind(&done);
3161
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003162 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003163}
3164
3165
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003166void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003167 // Load the arguments on the stack and call the stub.
3168 RegExpConstructResultStub stub;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003169 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003170 ASSERT(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003171 VisitForStackValue(args->at(0));
3172 VisitForStackValue(args->at(1));
3173 VisitForStackValue(args->at(2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003174 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003175 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003176}
3177
3178
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003179void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) {
3180 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003181 ASSERT(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003182 VisitForStackValue(args->at(0));
3183 VisitForStackValue(args->at(1));
3184 VisitForStackValue(args->at(2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003185 Label done;
3186 Label slow_case;
3187 Register object = eax;
3188 Register index_1 = ebx;
3189 Register index_2 = ecx;
3190 Register elements = edi;
3191 Register temp = edx;
3192 __ mov(object, Operand(esp, 2 * kPointerSize));
3193 // Fetch the map and check if array is in fast case.
3194 // Check that object doesn't require security checks and
3195 // has no indexed interceptor.
Steve Block44f0eee2011-05-26 01:26:41 +01003196 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3197 __ j(not_equal, &slow_case);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003198 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
3199 KeyedLoadIC::kSlowCaseBitFieldMask);
3200 __ j(not_zero, &slow_case);
3201
3202 // Check the object's elements are in fast case and writable.
3203 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
3204 __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +01003205 Immediate(isolate()->factory()->fixed_array_map()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003206 __ j(not_equal, &slow_case);
3207
3208 // Check that both indices are smis.
3209 __ mov(index_1, Operand(esp, 1 * kPointerSize));
3210 __ mov(index_2, Operand(esp, 0));
3211 __ mov(temp, index_1);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003212 __ or_(temp, index_2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003213 __ JumpIfNotSmi(temp, &slow_case);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003214
3215 // Check that both indices are valid.
3216 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003217 __ cmp(temp, index_1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003218 __ j(below_equal, &slow_case);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003219 __ cmp(temp, index_2);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003220 __ j(below_equal, &slow_case);
3221
3222 // Bring addresses into index1 and index2.
3223 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1));
3224 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2));
3225
3226 // Swap elements. Use object and temp as scratch registers.
3227 __ mov(object, Operand(index_1, 0));
3228 __ mov(temp, Operand(index_2, 0));
3229 __ mov(Operand(index_2, 0), object);
3230 __ mov(Operand(index_1, 0), temp);
3231
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003232 Label no_remembered_set;
3233 __ CheckPageFlag(elements,
3234 temp,
3235 1 << MemoryChunk::SCAN_ON_SCAVENGE,
3236 not_zero,
3237 &no_remembered_set,
3238 Label::kNear);
3239 // Possible optimization: do a check that both values are Smis
3240 // (or them and test against Smi mask.)
Ben Murdochb0fe1622011-05-05 13:52:32 +01003241
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003242 // We are swapping two objects in an array and the incremental marker never
3243 // pauses in the middle of scanning a single object. Therefore the
3244 // incremental marker is not disturbed, so we don't need to call the
3245 // RecordWrite stub that notifies the incremental marker.
3246 __ RememberedSetHelper(elements,
3247 index_1,
3248 temp,
3249 kDontSaveFPRegs,
3250 MacroAssembler::kFallThroughAtEnd);
3251 __ RememberedSetHelper(elements,
3252 index_2,
3253 temp,
3254 kDontSaveFPRegs,
3255 MacroAssembler::kFallThroughAtEnd);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003256
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003257 __ bind(&no_remembered_set);
3258
Ben Murdochb0fe1622011-05-05 13:52:32 +01003259 // We are done. Drop elements from the stack, and return undefined.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003260 __ add(esp, Immediate(3 * kPointerSize));
Steve Block44f0eee2011-05-26 01:26:41 +01003261 __ mov(eax, isolate()->factory()->undefined_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003262 __ jmp(&done);
3263
3264 __ bind(&slow_case);
Leon Clarkef7060e22010-06-03 12:02:55 +01003265 __ CallRuntime(Runtime::kSwapElements, 3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003266
3267 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003268 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003269}
3270
3271
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003272void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3273 ZoneList<Expression*>* args = expr->arguments();
Leon Clarkef7060e22010-06-03 12:02:55 +01003274 ASSERT_EQ(2, args->length());
3275
3276 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3277 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3278
3279 Handle<FixedArray> jsfunction_result_caches(
Steve Block44f0eee2011-05-26 01:26:41 +01003280 isolate()->global_context()->jsfunction_result_caches());
Leon Clarkef7060e22010-06-03 12:02:55 +01003281 if (jsfunction_result_caches->length() <= cache_id) {
3282 __ Abort("Attempt to use undefined cache.");
Steve Block44f0eee2011-05-26 01:26:41 +01003283 __ mov(eax, isolate()->factory()->undefined_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003284 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003285 return;
3286 }
3287
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003288 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003289
3290 Register key = eax;
3291 Register cache = ebx;
3292 Register tmp = ecx;
Steve Block59151502010-09-22 15:07:15 +01003293 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003294 __ mov(cache,
3295 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
Steve Block59151502010-09-22 15:07:15 +01003296 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003297 __ mov(cache,
3298 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3299
3300 Label done, not_found;
3301 // tmp now holds finger offset as a smi.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003302 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003303 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3304 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3305 __ j(not_equal, &not_found);
3306
3307 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3308 __ jmp(&done);
3309
3310 __ bind(&not_found);
3311 // Call runtime to perform the lookup.
3312 __ push(cache);
3313 __ push(key);
3314 __ CallRuntime(Runtime::kGetFromCache, 2);
3315
3316 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003317 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003318}
3319
3320
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003321void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) {
3322 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochbb769b22010-08-11 14:56:33 +01003323 ASSERT_EQ(2, args->length());
3324
3325 Register right = eax;
3326 Register left = ebx;
3327 Register tmp = ecx;
3328
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003329 VisitForStackValue(args->at(0));
3330 VisitForAccumulatorValue(args->at(1));
Ben Murdochbb769b22010-08-11 14:56:33 +01003331 __ pop(left);
3332
3333 Label done, fail, ok;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003334 __ cmp(left, right);
Ben Murdochbb769b22010-08-11 14:56:33 +01003335 __ j(equal, &ok);
3336 // Fail if either is a non-HeapObject.
3337 __ mov(tmp, left);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003338 __ and_(tmp, right);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003339 __ JumpIfSmi(tmp, &fail);
Steve Block44f0eee2011-05-26 01:26:41 +01003340 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
3341 __ CmpInstanceType(tmp, JS_REGEXP_TYPE);
Ben Murdochbb769b22010-08-11 14:56:33 +01003342 __ j(not_equal, &fail);
3343 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3344 __ j(not_equal, &fail);
3345 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3346 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3347 __ j(equal, &ok);
3348 __ bind(&fail);
Steve Block44f0eee2011-05-26 01:26:41 +01003349 __ mov(eax, Immediate(isolate()->factory()->false_value()));
Ben Murdochbb769b22010-08-11 14:56:33 +01003350 __ jmp(&done);
3351 __ bind(&ok);
Steve Block44f0eee2011-05-26 01:26:41 +01003352 __ mov(eax, Immediate(isolate()->factory()->true_value()));
Ben Murdochbb769b22010-08-11 14:56:33 +01003353 __ bind(&done);
3354
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003355 context()->Plug(eax);
Ben Murdochbb769b22010-08-11 14:56:33 +01003356}
3357
3358
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003359void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3360 ZoneList<Expression*>* args = expr->arguments();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003361 ASSERT(args->length() == 1);
3362
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003363 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003364
3365 if (FLAG_debug_code) {
3366 __ AbortIfNotString(eax);
3367 }
3368
3369 Label materialize_true, materialize_false;
3370 Label* if_true = NULL;
3371 Label* if_false = NULL;
3372 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003373 context()->PrepareTest(&materialize_true, &materialize_false,
3374 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003375
3376 __ test(FieldOperand(eax, String::kHashFieldOffset),
3377 Immediate(String::kContainsCachedArrayIndexMask));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003378 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003379 Split(zero, if_true, if_false, fall_through);
3380
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003381 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003382}
3383
3384
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003385void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3386 ZoneList<Expression*>* args = expr->arguments();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003387 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003388 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003389
3390 if (FLAG_debug_code) {
3391 __ AbortIfNotString(eax);
3392 }
3393
3394 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3395 __ IndexFromHash(eax, eax);
3396
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003397 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003398}
3399
3400
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003401void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01003402 Label bailout, done, one_char_separator, long_separator,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003403 non_trivial_array, not_size_one_array, loop,
Ben Murdochb8e0da22011-05-16 14:20:40 +01003404 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003405
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003406 ZoneList<Expression*>* args = expr->arguments();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003407 ASSERT(args->length() == 2);
3408 // We will leave the separator on the stack until the end of the function.
3409 VisitForStackValue(args->at(1));
3410 // Load this to eax (= array)
3411 VisitForAccumulatorValue(args->at(0));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003412 // All aliases of the same register have disjoint lifetimes.
3413 Register array = eax;
Ben Murdochb8e0da22011-05-16 14:20:40 +01003414 Register elements = no_reg; // Will be eax.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003415
Ben Murdochb8e0da22011-05-16 14:20:40 +01003416 Register index = edx;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003417
Ben Murdochb8e0da22011-05-16 14:20:40 +01003418 Register string_length = ecx;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003419
Ben Murdochb8e0da22011-05-16 14:20:40 +01003420 Register string = esi;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003421
3422 Register scratch = ebx;
3423
Ben Murdochb8e0da22011-05-16 14:20:40 +01003424 Register array_length = edi;
3425 Register result_pos = no_reg; // Will be edi.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003426
Ben Murdochb8e0da22011-05-16 14:20:40 +01003427 // Separator operand is already pushed.
3428 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3429 Operand result_operand = Operand(esp, 1 * kPointerSize);
3430 Operand array_length_operand = Operand(esp, 0);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003431 __ sub(esp, Immediate(2 * kPointerSize));
Ben Murdochb8e0da22011-05-16 14:20:40 +01003432 __ cld();
3433 // Check that the array is a JSArray
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003434 __ JumpIfSmi(array, &bailout);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003435 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3436 __ j(not_equal, &bailout);
3437
3438 // Check that the array has fast elements.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003439 __ CheckFastElements(scratch, &bailout);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003440
Ben Murdochb8e0da22011-05-16 14:20:40 +01003441 // If the array has length zero, return the empty string.
3442 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003443 __ SmiUntag(array_length);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003444 __ j(not_zero, &non_trivial_array);
Steve Block44f0eee2011-05-26 01:26:41 +01003445 __ mov(result_operand, isolate()->factory()->empty_string());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003446 __ jmp(&done);
3447
Ben Murdochb8e0da22011-05-16 14:20:40 +01003448 // Save the array length.
3449 __ bind(&non_trivial_array);
3450 __ mov(array_length_operand, array_length);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003451
Ben Murdochb8e0da22011-05-16 14:20:40 +01003452 // Save the FixedArray containing array's elements.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003453 // End of array's live range.
Ben Murdochb8e0da22011-05-16 14:20:40 +01003454 elements = array;
3455 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003456 array = no_reg;
3457
3458
Ben Murdochb8e0da22011-05-16 14:20:40 +01003459 // Check that all array elements are sequential ASCII strings, and
3460 // accumulate the sum of their lengths, as a smi-encoded value.
3461 __ Set(index, Immediate(0));
3462 __ Set(string_length, Immediate(0));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003463 // Loop condition: while (index < length).
Ben Murdochb8e0da22011-05-16 14:20:40 +01003464 // Live loop registers: index, array_length, string,
3465 // scratch, string_length, elements.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003466 if (FLAG_debug_code) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003467 __ cmp(index, array_length);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003468 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
3469 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003470 __ bind(&loop);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003471 __ mov(string, FieldOperand(elements,
3472 index,
3473 times_pointer_size,
3474 FixedArray::kHeaderSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003475 __ JumpIfSmi(string, &bailout);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003476 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3477 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3478 __ and_(scratch, Immediate(
3479 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3480 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3481 __ j(not_equal, &bailout);
3482 __ add(string_length,
3483 FieldOperand(string, SeqAsciiString::kLengthOffset));
3484 __ j(overflow, &bailout);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003485 __ add(index, Immediate(1));
3486 __ cmp(index, array_length);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003487 __ j(less, &loop);
3488
3489 // If array_length is 1, return elements[0], a string.
3490 __ cmp(array_length, 1);
3491 __ j(not_equal, &not_size_one_array);
3492 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3493 __ mov(result_operand, scratch);
3494 __ jmp(&done);
3495
3496 __ bind(&not_size_one_array);
3497
3498 // End of array_length live range.
3499 result_pos = array_length;
3500 array_length = no_reg;
3501
3502 // Live registers:
3503 // string_length: Sum of string lengths, as a smi.
3504 // elements: FixedArray of strings.
3505
3506 // Check that the separator is a flat ASCII string.
3507 __ mov(string, separator_operand);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003508 __ JumpIfSmi(string, &bailout);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003509 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3510 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003511 __ and_(scratch, Immediate(
3512 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003513 __ cmp(scratch, ASCII_STRING_TYPE);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003514 __ j(not_equal, &bailout);
3515
Ben Murdochb8e0da22011-05-16 14:20:40 +01003516 // Add (separator length times array_length) - separator length
3517 // to string_length.
3518 __ mov(scratch, separator_operand);
3519 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003520 __ sub(string_length, scratch); // May be negative, temporarily.
Ben Murdochb8e0da22011-05-16 14:20:40 +01003521 __ imul(scratch, array_length_operand);
3522 __ j(overflow, &bailout);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003523 __ add(string_length, scratch);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003524 __ j(overflow, &bailout);
3525
3526 __ shr(string_length, 1);
3527 // Live registers and stack values:
3528 // string_length
3529 // elements
3530 __ AllocateAsciiString(result_pos, string_length, scratch,
3531 index, string, &bailout);
3532 __ mov(result_operand, result_pos);
3533 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3534
3535
3536 __ mov(string, separator_operand);
3537 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset),
3538 Immediate(Smi::FromInt(1)));
3539 __ j(equal, &one_char_separator);
3540 __ j(greater, &long_separator);
3541
3542
3543 // Empty separator case
3544 __ mov(index, Immediate(0));
3545 __ jmp(&loop_1_condition);
3546 // Loop condition: while (index < length).
3547 __ bind(&loop_1);
3548 // Each iteration of the loop concatenates one string to the result.
3549 // Live values in registers:
3550 // index: which element of the elements array we are adding to the result.
3551 // result_pos: the position to which we are currently copying characters.
3552 // elements: the FixedArray of strings we are joining.
3553
3554 // Get string = array[index].
3555 __ mov(string, FieldOperand(elements, index,
3556 times_pointer_size,
3557 FixedArray::kHeaderSize));
3558 __ mov(string_length,
3559 FieldOperand(string, String::kLengthOffset));
3560 __ shr(string_length, 1);
3561 __ lea(string,
3562 FieldOperand(string, SeqAsciiString::kHeaderSize));
3563 __ CopyBytes(string, result_pos, string_length, scratch);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003564 __ add(index, Immediate(1));
Ben Murdochb8e0da22011-05-16 14:20:40 +01003565 __ bind(&loop_1_condition);
3566 __ cmp(index, array_length_operand);
3567 __ j(less, &loop_1); // End while (index < length).
3568 __ jmp(&done);
3569
3570
3571
3572 // One-character separator case
3573 __ bind(&one_char_separator);
Ben Murdochc7cc0282012-03-05 14:35:55 +00003574 // Replace separator with its ASCII character value.
Ben Murdochb8e0da22011-05-16 14:20:40 +01003575 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3576 __ mov_b(separator_operand, scratch);
3577
3578 __ Set(index, Immediate(0));
3579 // Jump into the loop after the code that copies the separator, so the first
3580 // element is not preceded by a separator
3581 __ jmp(&loop_2_entry);
3582 // Loop condition: while (index < length).
3583 __ bind(&loop_2);
3584 // Each iteration of the loop concatenates one string to the result.
3585 // Live values in registers:
3586 // index: which element of the elements array we are adding to the result.
3587 // result_pos: the position to which we are currently copying characters.
3588
3589 // Copy the separator character to the result.
3590 __ mov_b(scratch, separator_operand);
3591 __ mov_b(Operand(result_pos, 0), scratch);
3592 __ inc(result_pos);
3593
3594 __ bind(&loop_2_entry);
3595 // Get string = array[index].
3596 __ mov(string, FieldOperand(elements, index,
3597 times_pointer_size,
3598 FixedArray::kHeaderSize));
3599 __ mov(string_length,
3600 FieldOperand(string, String::kLengthOffset));
3601 __ shr(string_length, 1);
3602 __ lea(string,
3603 FieldOperand(string, SeqAsciiString::kHeaderSize));
3604 __ CopyBytes(string, result_pos, string_length, scratch);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003605 __ add(index, Immediate(1));
Ben Murdochb8e0da22011-05-16 14:20:40 +01003606
3607 __ cmp(index, array_length_operand);
3608 __ j(less, &loop_2); // End while (index < length).
3609 __ jmp(&done);
3610
3611
3612 // Long separator case (separator is more than one character).
3613 __ bind(&long_separator);
3614
3615 __ Set(index, Immediate(0));
3616 // Jump into the loop after the code that copies the separator, so the first
3617 // element is not preceded by a separator
3618 __ jmp(&loop_3_entry);
3619 // Loop condition: while (index < length).
3620 __ bind(&loop_3);
3621 // Each iteration of the loop concatenates one string to the result.
3622 // Live values in registers:
3623 // index: which element of the elements array we are adding to the result.
3624 // result_pos: the position to which we are currently copying characters.
3625
3626 // Copy the separator to the result.
3627 __ mov(string, separator_operand);
3628 __ mov(string_length,
3629 FieldOperand(string, String::kLengthOffset));
3630 __ shr(string_length, 1);
3631 __ lea(string,
3632 FieldOperand(string, SeqAsciiString::kHeaderSize));
3633 __ CopyBytes(string, result_pos, string_length, scratch);
3634
3635 __ bind(&loop_3_entry);
3636 // Get string = array[index].
3637 __ mov(string, FieldOperand(elements, index,
3638 times_pointer_size,
3639 FixedArray::kHeaderSize));
3640 __ mov(string_length,
3641 FieldOperand(string, String::kLengthOffset));
3642 __ shr(string_length, 1);
3643 __ lea(string,
3644 FieldOperand(string, SeqAsciiString::kHeaderSize));
3645 __ CopyBytes(string, result_pos, string_length, scratch);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003646 __ add(index, Immediate(1));
Ben Murdochb8e0da22011-05-16 14:20:40 +01003647
3648 __ cmp(index, array_length_operand);
3649 __ j(less, &loop_3); // End while (index < length).
3650 __ jmp(&done);
3651
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003652
3653 __ bind(&bailout);
Steve Block44f0eee2011-05-26 01:26:41 +01003654 __ mov(result_operand, isolate()->factory()->undefined_value());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003655 __ bind(&done);
Ben Murdochb8e0da22011-05-16 14:20:40 +01003656 __ mov(eax, result_operand);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003657 // Drop temp values from the stack, and restore context register.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003658 __ add(esp, Immediate(3 * kPointerSize));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003659
3660 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3661 context()->Plug(eax);
3662}
3663
3664
Leon Clarked91b9f72010-01-27 17:25:45 +00003665void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003666 Handle<String> name = expr->name();
3667 if (name->length() > 0 && name->Get(0) == '_') {
3668 Comment cmnt(masm_, "[ InlineRuntimeCall");
3669 EmitInlineRuntimeCall(expr);
3670 return;
3671 }
3672
Steve Block3ce2e202009-11-05 08:53:23 +00003673 Comment cmnt(masm_, "[ CallRuntime");
3674 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00003675
Steve Blockd0582a62009-12-15 09:54:21 +00003676 if (expr->is_jsruntime()) {
3677 // Prepare for calling JS runtime function.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003678 __ mov(eax, GlobalObjectOperand());
Steve Blockd0582a62009-12-15 09:54:21 +00003679 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3680 }
Steve Block3ce2e202009-11-05 08:53:23 +00003681
3682 // Push the arguments ("left-to-right").
3683 int arg_count = args->length();
3684 for (int i = 0; i < arg_count; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003685 VisitForStackValue(args->at(i));
Steve Block3ce2e202009-11-05 08:53:23 +00003686 }
3687
Steve Blockd0582a62009-12-15 09:54:21 +00003688 if (expr->is_jsruntime()) {
Leon Clarkee46be812010-01-19 14:06:41 +00003689 // Call the JS runtime function via a call IC.
3690 __ Set(ecx, Immediate(expr->name()));
Ben Murdoch257744e2011-11-30 15:57:28 +00003691 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Ben Murdoch589d6972011-11-30 16:04:58 +00003692 Handle<Code> ic =
3693 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003694 __ call(ic, mode, expr->id());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003695 // Restore context register.
Steve Blockd0582a62009-12-15 09:54:21 +00003696 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00003697 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00003698 // Call the C runtime function.
3699 __ CallRuntime(expr->function(), arg_count);
Steve Blockd0582a62009-12-15 09:54:21 +00003700 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003701 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003702}
3703
3704
Leon Clarked91b9f72010-01-27 17:25:45 +00003705void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003706 switch (expr->op()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003707 case Token::DELETE: {
3708 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
Ben Murdoch589d6972011-11-30 16:04:58 +00003709 Property* property = expr->expression()->AsProperty();
3710 VariableProxy* proxy = expr->expression()->AsVariableProxy();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003711
Ben Murdoch589d6972011-11-30 16:04:58 +00003712 if (property != NULL) {
3713 VisitForStackValue(property->obj());
3714 VisitForStackValue(property->key());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003715 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
3716 ? kNonStrictMode : kStrictMode;
3717 __ push(Immediate(Smi::FromInt(strict_mode_flag)));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003718 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003719 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00003720 } else if (proxy != NULL) {
3721 Variable* var = proxy->var();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003722 // Delete of an unqualified identifier is disallowed in strict mode
Ben Murdoch589d6972011-11-30 16:04:58 +00003723 // but "delete this" is allowed.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003724 ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
Ben Murdoch589d6972011-11-30 16:04:58 +00003725 if (var->IsUnallocated()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003726 __ push(GlobalObjectOperand());
3727 __ push(Immediate(var->name()));
3728 __ push(Immediate(Smi::FromInt(kNonStrictMode)));
3729 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3730 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00003731 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
3732 // Result of deleting non-global variables is false. 'this' is
3733 // not really a variable, though we implement it as one. The
3734 // subexpression does not have side effects.
3735 context()->Plug(var->is_this());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003736 } else {
3737 // Non-global variable. Call the runtime to try to delete from the
3738 // context where the variable was introduced.
3739 __ push(context_register());
3740 __ push(Immediate(var->name()));
3741 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3742 context()->Plug(eax);
3743 }
Steve Block1e0659c2011-05-24 12:43:12 +01003744 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003745 // Result of deleting non-property, non-variable reference is true.
3746 // The subexpression may have side effects.
3747 VisitForEffect(expr->expression());
3748 context()->Plug(true);
Leon Clarkef7060e22010-06-03 12:02:55 +01003749 }
3750 break;
3751 }
3752
Steve Blockd0582a62009-12-15 09:54:21 +00003753 case Token::VOID: {
3754 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
Leon Clarkee46be812010-01-19 14:06:41 +00003755 VisitForEffect(expr->expression());
Steve Block44f0eee2011-05-26 01:26:41 +01003756 context()->Plug(isolate()->factory()->undefined_value());
Steve Blockd0582a62009-12-15 09:54:21 +00003757 break;
3758 }
3759
3760 case Token::NOT: {
3761 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003762 if (context()->IsEffect()) {
3763 // Unary NOT has no side effects so it's only necessary to visit the
3764 // subexpression. Match the optimizing compiler by not branching.
3765 VisitForEffect(expr->expression());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003766 } else if (context()->IsTest()) {
3767 const TestContext* test = TestContext::cast(context());
3768 // The labels are swapped for the recursive call.
3769 VisitForControl(expr->expression(),
3770 test->false_label(),
3771 test->true_label(),
3772 test->fall_through());
3773 context()->Plug(test->true_label(), test->false_label());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003774 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003775 // We handle value contexts explicitly rather than simply visiting
3776 // for control and plugging the control flow into the context,
3777 // because we need to prepare a pair of extra administrative AST ids
3778 // for the optimizing compiler.
3779 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
3780 Label materialize_true, materialize_false, done;
3781 VisitForControl(expr->expression(),
3782 &materialize_false,
3783 &materialize_true,
3784 &materialize_true);
3785 __ bind(&materialize_true);
3786 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
3787 if (context()->IsAccumulatorValue()) {
3788 __ mov(eax, isolate()->factory()->true_value());
3789 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00003790 __ Push(isolate()->factory()->true_value());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003791 }
3792 __ jmp(&done, Label::kNear);
3793 __ bind(&materialize_false);
3794 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
3795 if (context()->IsAccumulatorValue()) {
3796 __ mov(eax, isolate()->factory()->false_value());
3797 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00003798 __ Push(isolate()->factory()->false_value());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003799 }
3800 __ bind(&done);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003801 }
Steve Blockd0582a62009-12-15 09:54:21 +00003802 break;
3803 }
3804
3805 case Token::TYPEOF: {
3806 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003807 { StackValueContext context(this);
3808 VisitForTypeofValue(expr->expression());
3809 }
Steve Blockd0582a62009-12-15 09:54:21 +00003810 __ CallRuntime(Runtime::kTypeof, 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003811 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003812 break;
3813 }
3814
Leon Clarked91b9f72010-01-27 17:25:45 +00003815 case Token::ADD: {
3816 Comment cmt(masm_, "[ UnaryOperation (ADD)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003817 VisitForAccumulatorValue(expr->expression());
Leon Clarked91b9f72010-01-27 17:25:45 +00003818 Label no_conversion;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003819 __ JumpIfSmi(result_register(), &no_conversion);
Steve Block1e0659c2011-05-24 12:43:12 +01003820 ToNumberStub convert_stub;
3821 __ CallStub(&convert_stub);
Leon Clarked91b9f72010-01-27 17:25:45 +00003822 __ bind(&no_conversion);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003823 context()->Plug(result_register());
Leon Clarked91b9f72010-01-27 17:25:45 +00003824 break;
3825 }
3826
Ben Murdoch257744e2011-11-30 15:57:28 +00003827 case Token::SUB:
3828 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
Leon Clarke4515c472010-02-03 11:58:03 +00003829 break;
Leon Clarke4515c472010-02-03 11:58:03 +00003830
Ben Murdoch257744e2011-11-30 15:57:28 +00003831 case Token::BIT_NOT:
3832 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
Leon Clarke4515c472010-02-03 11:58:03 +00003833 break;
Leon Clarke4515c472010-02-03 11:58:03 +00003834
Steve Blockd0582a62009-12-15 09:54:21 +00003835 default:
3836 UNREACHABLE();
3837 }
3838}
3839
3840
Ben Murdoch257744e2011-11-30 15:57:28 +00003841void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3842 const char* comment) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003843 Comment cmt(masm_, comment);
3844 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3845 UnaryOverwriteMode overwrite =
3846 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
3847 UnaryOpStub stub(expr->op(), overwrite);
3848 // UnaryOpStub expects the argument to be in the
3849 // accumulator register eax.
3850 VisitForAccumulatorValue(expr->expression());
3851 SetSourcePosition(expr->position());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003852 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
Ben Murdoch257744e2011-11-30 15:57:28 +00003853 context()->Plug(eax);
3854}
3855
3856
Leon Clarked91b9f72010-01-27 17:25:45 +00003857void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003858 Comment cmnt(masm_, "[ CountOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003859 SetSourcePosition(expr->position());
3860
Leon Clarkef7060e22010-06-03 12:02:55 +01003861 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3862 // as the left-hand side.
3863 if (!expr->expression()->IsValidLeftHandSide()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003864 VisitForEffect(expr->expression());
Leon Clarkef7060e22010-06-03 12:02:55 +01003865 return;
3866 }
Steve Blockd0582a62009-12-15 09:54:21 +00003867
Leon Clarkee46be812010-01-19 14:06:41 +00003868 // Expression can only be a property, a global or a (parameter or local)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003869 // slot.
Leon Clarkee46be812010-01-19 14:06:41 +00003870 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3871 LhsKind assign_type = VARIABLE;
3872 Property* prop = expr->expression()->AsProperty();
3873 // In case of a property we use the uninitialized expression context
3874 // of the key to detect a named property.
3875 if (prop != NULL) {
3876 assign_type =
3877 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3878 }
3879
3880 // Evaluate expression and get value.
3881 if (assign_type == VARIABLE) {
3882 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003883 AccumulatorValueContext context(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003884 EmitVariableLoad(expr->expression()->AsVariableProxy());
Leon Clarkef7060e22010-06-03 12:02:55 +01003885 } else {
Leon Clarkee46be812010-01-19 14:06:41 +00003886 // Reserve space for result of postfix operation.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003887 if (expr->is_postfix() && !context()->IsEffect()) {
Leon Clarkee46be812010-01-19 14:06:41 +00003888 __ push(Immediate(Smi::FromInt(0)));
3889 }
Leon Clarkee46be812010-01-19 14:06:41 +00003890 if (assign_type == NAMED_PROPERTY) {
Andrei Popescu402d9372010-02-26 13:31:12 +00003891 // Put the object both on the stack and in the accumulator.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003892 VisitForAccumulatorValue(prop->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00003893 __ push(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003894 EmitNamedPropertyLoad(prop);
3895 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003896 VisitForStackValue(prop->obj());
3897 VisitForAccumulatorValue(prop->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00003898 __ mov(edx, Operand(esp, 0));
3899 __ push(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003900 EmitKeyedPropertyLoad(prop);
3901 }
Leon Clarkee46be812010-01-19 14:06:41 +00003902 }
3903
Ben Murdochb0fe1622011-05-05 13:52:32 +01003904 // We need a second deoptimization point after loading the value
3905 // in case evaluating the property load my have a side effect.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003906 if (assign_type == VARIABLE) {
3907 PrepareForBailout(expr->expression(), TOS_REG);
3908 } else {
3909 PrepareForBailoutForId(expr->CountId(), TOS_REG);
3910 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01003911
Leon Clarked91b9f72010-01-27 17:25:45 +00003912 // Call ToNumber only if operand is not a smi.
Ben Murdoch257744e2011-11-30 15:57:28 +00003913 Label no_conversion;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003914 if (ShouldInlineSmiCase(expr->op())) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003915 __ JumpIfSmi(eax, &no_conversion, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003916 }
Steve Block1e0659c2011-05-24 12:43:12 +01003917 ToNumberStub convert_stub;
3918 __ CallStub(&convert_stub);
Leon Clarked91b9f72010-01-27 17:25:45 +00003919 __ bind(&no_conversion);
Steve Blockd0582a62009-12-15 09:54:21 +00003920
Leon Clarkee46be812010-01-19 14:06:41 +00003921 // Save result for postfix expressions.
3922 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003923 if (!context()->IsEffect()) {
3924 // Save the result on the stack. If we have a named or keyed property
3925 // we store the result under the receiver that is currently on top
3926 // of the stack.
3927 switch (assign_type) {
3928 case VARIABLE:
3929 __ push(eax);
3930 break;
3931 case NAMED_PROPERTY:
3932 __ mov(Operand(esp, kPointerSize), eax);
3933 break;
3934 case KEYED_PROPERTY:
3935 __ mov(Operand(esp, 2 * kPointerSize), eax);
3936 break;
3937 }
Leon Clarkee46be812010-01-19 14:06:41 +00003938 }
Steve Blockd0582a62009-12-15 09:54:21 +00003939 }
Leon Clarkee46be812010-01-19 14:06:41 +00003940
Leon Clarked91b9f72010-01-27 17:25:45 +00003941 // Inline smi case if we are in a loop.
Ben Murdoch257744e2011-11-30 15:57:28 +00003942 Label done, stub_call;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003943 JumpPatchSite patch_site(masm_);
3944
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003945 if (ShouldInlineSmiCase(expr->op())) {
Leon Clarked91b9f72010-01-27 17:25:45 +00003946 if (expr->op() == Token::INC) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003947 __ add(eax, Immediate(Smi::FromInt(1)));
Leon Clarked91b9f72010-01-27 17:25:45 +00003948 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003949 __ sub(eax, Immediate(Smi::FromInt(1)));
Leon Clarked91b9f72010-01-27 17:25:45 +00003950 }
Ben Murdoch257744e2011-11-30 15:57:28 +00003951 __ j(overflow, &stub_call, Label::kNear);
Leon Clarked91b9f72010-01-27 17:25:45 +00003952 // We could eliminate this smi check if we split the code at
3953 // the first smi check before calling ToNumber.
Ben Murdoch257744e2011-11-30 15:57:28 +00003954 patch_site.EmitJumpIfSmi(eax, &done, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003955
Leon Clarked91b9f72010-01-27 17:25:45 +00003956 __ bind(&stub_call);
3957 // Call stub. Undo operation first.
3958 if (expr->op() == Token::INC) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003959 __ sub(eax, Immediate(Smi::FromInt(1)));
Leon Clarked91b9f72010-01-27 17:25:45 +00003960 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003961 __ add(eax, Immediate(Smi::FromInt(1)));
Leon Clarked91b9f72010-01-27 17:25:45 +00003962 }
3963 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01003964
3965 // Record position before stub call.
3966 SetSourcePosition(expr->position());
3967
Leon Clarkee46be812010-01-19 14:06:41 +00003968 // Call stub for +1/-1.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003969 __ mov(edx, eax);
3970 __ mov(eax, Immediate(Smi::FromInt(1)));
Ben Murdoch257744e2011-11-30 15:57:28 +00003971 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003972 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
3973 patch_site.EmitPatchInfo();
Leon Clarked91b9f72010-01-27 17:25:45 +00003974 __ bind(&done);
Steve Blockd0582a62009-12-15 09:54:21 +00003975
Leon Clarkee46be812010-01-19 14:06:41 +00003976 // Store the value returned in eax.
3977 switch (assign_type) {
3978 case VARIABLE:
3979 if (expr->is_postfix()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003980 // Perform the assignment as if via '='.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003981 { EffectContext context(this);
3982 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3983 Token::ASSIGN);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003984 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3985 context.Plug(eax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003986 }
3987 // For all contexts except EffectContext We have the result on
Leon Clarkee46be812010-01-19 14:06:41 +00003988 // top of the stack.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003989 if (!context()->IsEffect()) {
3990 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00003991 }
3992 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01003993 // Perform the assignment as if via '='.
Leon Clarkee46be812010-01-19 14:06:41 +00003994 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003995 Token::ASSIGN);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003996 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3997 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003998 }
Steve Blockd0582a62009-12-15 09:54:21 +00003999 break;
Leon Clarkee46be812010-01-19 14:06:41 +00004000 case NAMED_PROPERTY: {
4001 __ mov(ecx, prop->key()->AsLiteral()->handle());
Leon Clarke4515c472010-02-03 11:58:03 +00004002 __ pop(edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004003 Handle<Code> ic = is_classic_mode()
4004 ? isolate()->builtins()->StoreIC_Initialize()
4005 : isolate()->builtins()->StoreIC_Initialize_Strict();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004006 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004007 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00004008 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004009 if (!context()->IsEffect()) {
4010 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004011 }
4012 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004013 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004014 }
Steve Blockd0582a62009-12-15 09:54:21 +00004015 break;
4016 }
Leon Clarkee46be812010-01-19 14:06:41 +00004017 case KEYED_PROPERTY: {
Steve Block6ded16b2010-05-10 14:33:55 +01004018 __ pop(ecx);
4019 __ pop(edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004020 Handle<Code> ic = is_classic_mode()
4021 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4022 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004023 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004024 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00004025 if (expr->is_postfix()) {
Steve Block6ded16b2010-05-10 14:33:55 +01004026 // Result is on the stack
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004027 if (!context()->IsEffect()) {
4028 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004029 }
4030 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004031 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004032 }
Steve Blockd0582a62009-12-15 09:54:21 +00004033 break;
4034 }
Steve Block3ce2e202009-11-05 08:53:23 +00004035 }
4036}
4037
4038
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004039void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004040 VariableProxy* proxy = expr->AsVariableProxy();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004041 ASSERT(!context()->IsEffect());
4042 ASSERT(!context()->IsTest());
4043
Ben Murdoch589d6972011-11-30 16:04:58 +00004044 if (proxy != NULL && proxy->var()->IsUnallocated()) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004045 Comment cmnt(masm_, "Global variable");
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004046 __ mov(eax, GlobalObjectOperand());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004047 __ mov(ecx, Immediate(proxy->name()));
Steve Block44f0eee2011-05-26 01:26:41 +01004048 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004049 // Use a regular load, not a contextual load, to avoid a reference
4050 // error.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004051 __ call(ic);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004052 PrepareForBailout(expr, TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004053 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00004054 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Steve Block59151502010-09-22 15:07:15 +01004055 Label done, slow;
4056
4057 // Generate code for loading from variables potentially shadowed
4058 // by eval-introduced variables.
Ben Murdoch589d6972011-11-30 16:04:58 +00004059 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
Steve Block59151502010-09-22 15:07:15 +01004060
4061 __ bind(&slow);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004062 __ push(esi);
4063 __ push(Immediate(proxy->name()));
4064 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004065 PrepareForBailout(expr, TOS_REG);
Steve Block59151502010-09-22 15:07:15 +01004066 __ bind(&done);
4067
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004068 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004069 } else {
4070 // This expression cannot throw a reference error at the top level.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004071 VisitInDuplicateContext(expr);
Steve Block3ce2e202009-11-05 08:53:23 +00004072 }
Steve Block3ce2e202009-11-05 08:53:23 +00004073}
4074
4075
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004076void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004077 Expression* sub_expr,
4078 Handle<String> check) {
4079 Label materialize_true, materialize_false;
4080 Label* if_true = NULL;
4081 Label* if_false = NULL;
4082 Label* fall_through = NULL;
4083 context()->PrepareTest(&materialize_true, &materialize_false,
4084 &if_true, &if_false, &fall_through);
4085
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004086 { AccumulatorValueContext context(this);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004087 VisitForTypeofValue(sub_expr);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004088 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004089 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004090
Steve Block44f0eee2011-05-26 01:26:41 +01004091 if (check->Equals(isolate()->heap()->number_symbol())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004092 __ JumpIfSmi(eax, if_true);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004093 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +01004094 isolate()->factory()->heap_number_map());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004095 Split(equal, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004096 } else if (check->Equals(isolate()->heap()->string_symbol())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004097 __ JumpIfSmi(eax, if_false);
4098 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
4099 __ j(above_equal, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004100 // Check for undetectable objects => false.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004101 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4102 1 << Map::kIsUndetectable);
4103 Split(zero, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004104 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
4105 __ cmp(eax, isolate()->factory()->true_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004106 __ j(equal, if_true);
Steve Block44f0eee2011-05-26 01:26:41 +01004107 __ cmp(eax, isolate()->factory()->false_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004108 Split(equal, if_true, if_false, fall_through);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004109 } else if (FLAG_harmony_typeof &&
4110 check->Equals(isolate()->heap()->null_symbol())) {
4111 __ cmp(eax, isolate()->factory()->null_value());
4112 Split(equal, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004113 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
4114 __ cmp(eax, isolate()->factory()->undefined_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004115 __ j(equal, if_true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004116 __ JumpIfSmi(eax, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004117 // Check for undetectable objects => true.
4118 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4119 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4120 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4121 Split(not_zero, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004122 } else if (check->Equals(isolate()->heap()->function_symbol())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004123 __ JumpIfSmi(eax, if_false);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004124 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4125 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
4126 __ j(equal, if_true);
4127 __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
4128 Split(equal, if_true, if_false, fall_through);
Steve Block44f0eee2011-05-26 01:26:41 +01004129 } else if (check->Equals(isolate()->heap()->object_symbol())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004130 __ JumpIfSmi(eax, if_false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004131 if (!FLAG_harmony_typeof) {
4132 __ cmp(eax, isolate()->factory()->null_value());
4133 __ j(equal, if_true);
4134 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004135 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004136 __ j(below, if_false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004137 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4138 __ j(above, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004139 // Check for undetectable objects => false.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004140 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4141 1 << Map::kIsUndetectable);
4142 Split(zero, if_true, if_false, fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004143 } else {
4144 if (if_false != fall_through) __ jmp(if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01004145 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004146 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01004147}
4148
4149
Leon Clarked91b9f72010-01-27 17:25:45 +00004150void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004151 Comment cmnt(masm_, "[ CompareOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004152 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00004153
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004154 // First we try a fast inlined version of the compare when one of
4155 // the operands is a literal.
4156 if (TryLiteralCompare(expr)) return;
4157
Leon Clarkee46be812010-01-19 14:06:41 +00004158 // Always perform the comparison for its control flow. Pack the result
4159 // into the expression's context after the comparison is performed.
Leon Clarkef7060e22010-06-03 12:02:55 +01004160 Label materialize_true, materialize_false;
4161 Label* if_true = NULL;
4162 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004163 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004164 context()->PrepareTest(&materialize_true, &materialize_false,
4165 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004166
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004167 Token::Value op = expr->op();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004168 VisitForStackValue(expr->left());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004169 switch (op) {
Leon Clarkee46be812010-01-19 14:06:41 +00004170 case Token::IN:
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004171 VisitForStackValue(expr->right());
Steve Blockd0582a62009-12-15 09:54:21 +00004172 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004173 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01004174 __ cmp(eax, isolate()->factory()->true_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004175 Split(equal, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004176 break;
Steve Blockd0582a62009-12-15 09:54:21 +00004177
4178 case Token::INSTANCEOF: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004179 VisitForStackValue(expr->right());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004180 InstanceofStub stub(InstanceofStub::kNoFlags);
Steve Blockd0582a62009-12-15 09:54:21 +00004181 __ CallStub(&stub);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004182 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4183 __ test(eax, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004184 // The stub returns 0 for true.
4185 Split(zero, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004186 break;
4187 }
4188
4189 default: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004190 VisitForAccumulatorValue(expr->right());
Steve Blockd0582a62009-12-15 09:54:21 +00004191 Condition cc = no_condition;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004192 switch (op) {
Steve Blockd0582a62009-12-15 09:54:21 +00004193 case Token::EQ_STRICT:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004194 case Token::EQ:
Steve Blockd0582a62009-12-15 09:54:21 +00004195 cc = equal;
Steve Blockd0582a62009-12-15 09:54:21 +00004196 break;
4197 case Token::LT:
4198 cc = less;
Steve Blockd0582a62009-12-15 09:54:21 +00004199 break;
4200 case Token::GT:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004201 cc = greater;
Steve Blockd0582a62009-12-15 09:54:21 +00004202 break;
4203 case Token::LTE:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004204 cc = less_equal;
Steve Blockd0582a62009-12-15 09:54:21 +00004205 break;
4206 case Token::GTE:
4207 cc = greater_equal;
Steve Blockd0582a62009-12-15 09:54:21 +00004208 break;
4209 case Token::IN:
4210 case Token::INSTANCEOF:
4211 default:
4212 UNREACHABLE();
4213 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004214 __ pop(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00004215
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004216 bool inline_smi_code = ShouldInlineSmiCase(op);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004217 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004218 if (inline_smi_code) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004219 Label slow_case;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004220 __ mov(ecx, edx);
4221 __ or_(ecx, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00004222 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004223 __ cmp(edx, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004224 Split(cc, if_true, if_false, NULL);
4225 __ bind(&slow_case);
4226 }
Steve Blockd0582a62009-12-15 09:54:21 +00004227
Ben Murdochb0fe1622011-05-05 13:52:32 +01004228 // Record position and call the compare IC.
4229 SetSourcePosition(expr->position());
4230 Handle<Code> ic = CompareIC::GetUninitialized(op);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004231 __ call(ic, RelocInfo::CODE_TARGET, expr->id());
4232 patch_site.EmitPatchInfo();
Ben Murdochb0fe1622011-05-05 13:52:32 +01004233
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004234 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4235 __ test(eax, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004236 Split(cc, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004237 }
4238 }
4239
Leon Clarkee46be812010-01-19 14:06:41 +00004240 // Convert the result of the comparison into one expected for this
4241 // expression's context.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004242 context()->Plug(if_true, if_false);
Steve Blockd0582a62009-12-15 09:54:21 +00004243}
4244
4245
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004246void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4247 Expression* sub_expr,
4248 NilValue nil) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004249 Label materialize_true, materialize_false;
4250 Label* if_true = NULL;
4251 Label* if_false = NULL;
4252 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004253 context()->PrepareTest(&materialize_true, &materialize_false,
4254 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004255
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004256 VisitForAccumulatorValue(sub_expr);
4257 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4258 Handle<Object> nil_value = nil == kNullValue ?
4259 isolate()->factory()->null_value() :
4260 isolate()->factory()->undefined_value();
4261 __ cmp(eax, nil_value);
4262 if (expr->op() == Token::EQ_STRICT) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004263 Split(equal, if_true, if_false, fall_through);
4264 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004265 Handle<Object> other_nil_value = nil == kNullValue ?
4266 isolate()->factory()->undefined_value() :
4267 isolate()->factory()->null_value();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004268 __ j(equal, if_true);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004269 __ cmp(eax, other_nil_value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004270 __ j(equal, if_true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004271 __ JumpIfSmi(eax, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004272 // It can be an undetectable object.
4273 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4274 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
4275 __ test(edx, Immediate(1 << Map::kIsUndetectable));
4276 Split(not_zero, if_true, if_false, fall_through);
4277 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004278 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004279}
4280
4281
Leon Clarked91b9f72010-01-27 17:25:45 +00004282void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004283 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004284 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00004285}
4286
Steve Blockd0582a62009-12-15 09:54:21 +00004287
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004288Register FullCodeGenerator::result_register() {
4289 return eax;
4290}
Leon Clarkee46be812010-01-19 14:06:41 +00004291
4292
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004293Register FullCodeGenerator::context_register() {
4294 return esi;
4295}
4296
4297
Leon Clarked91b9f72010-01-27 17:25:45 +00004298void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
Leon Clarkee46be812010-01-19 14:06:41 +00004299 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4300 __ mov(Operand(ebp, frame_offset), value);
4301}
4302
4303
Leon Clarked91b9f72010-01-27 17:25:45 +00004304void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
Steve Block59151502010-09-22 15:07:15 +01004305 __ mov(dst, ContextOperand(esi, context_index));
Leon Clarkee46be812010-01-19 14:06:41 +00004306}
4307
4308
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004309void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
4310 Scope* declaration_scope = scope()->DeclarationScope();
4311 if (declaration_scope->is_global_scope()) {
4312 // Contexts nested in the global context have a canonical empty function
4313 // as their closure, not the anonymous closure containing the global
4314 // code. Pass a smi sentinel and let the runtime look up the empty
4315 // function.
4316 __ push(Immediate(Smi::FromInt(0)));
4317 } else if (declaration_scope->is_eval_scope()) {
4318 // Contexts nested inside eval code have the same closure as the context
4319 // calling eval, not the anonymous closure containing the eval code.
4320 // Fetch it from the context.
4321 __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
4322 } else {
4323 ASSERT(declaration_scope->is_function_scope());
4324 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4325 }
4326}
4327
4328
Leon Clarkee46be812010-01-19 14:06:41 +00004329// ----------------------------------------------------------------------------
4330// Non-local control flow support.
4331
Leon Clarked91b9f72010-01-27 17:25:45 +00004332void FullCodeGenerator::EnterFinallyBlock() {
Leon Clarkee46be812010-01-19 14:06:41 +00004333 // Cook return address on top of stack (smi encoded Code* delta)
4334 ASSERT(!result_register().is(edx));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004335 __ pop(edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004336 __ sub(edx, Immediate(masm_->CodeObject()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004337 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
4338 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004339 __ SmiTag(edx);
4340 __ push(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00004341 // Store result register while executing finally block.
4342 __ push(result_register());
4343}
4344
4345
Leon Clarked91b9f72010-01-27 17:25:45 +00004346void FullCodeGenerator::ExitFinallyBlock() {
Leon Clarkee46be812010-01-19 14:06:41 +00004347 ASSERT(!result_register().is(edx));
Leon Clarkee46be812010-01-19 14:06:41 +00004348 __ pop(result_register());
4349 // Uncook return address.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004350 __ pop(edx);
4351 __ SmiUntag(edx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004352 __ add(edx, Immediate(masm_->CodeObject()));
4353 __ jmp(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00004354}
4355
4356
4357#undef __
Steve Blockd0582a62009-12-15 09:54:21 +00004358
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004359#define __ ACCESS_MASM(masm())
4360
4361FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4362 int* stack_depth,
4363 int* context_length) {
4364 // The macros used here must preserve the result register.
4365
4366 // Because the handler block contains the context of the finally
4367 // code, we can restore it directly from there for the finally code
4368 // rather than iteratively unwinding contexts via their previous
4369 // links.
4370 __ Drop(*stack_depth); // Down to the handler block.
4371 if (*context_length > 0) {
4372 // Restore the context to its dedicated register and the stack.
4373 __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
4374 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
4375 }
4376 __ PopTryHandler();
4377 __ call(finally_entry_);
4378
4379 *stack_depth = 0;
4380 *context_length = 0;
4381 return previous_;
4382}
4383
4384
4385#undef __
4386
Steve Block3ce2e202009-11-05 08:53:23 +00004387} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01004388
4389#endif // V8_TARGET_ARCH_IA32