blob: 88f204b139604237ab62f45982e2919a2131c1aa [file] [log] [blame]
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001// Copyright 2012 the V8 project authors. All rights reserved.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_IA32)
31
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000032#include "code-stubs.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000034#include "compiler.h"
35#include "debug.h"
36#include "full-codegen.h"
danno@chromium.org88aa0582012-03-23 15:11:57 +000037#include "isolate-inl.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000038#include "parser.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000039#include "scopes.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000040#include "stub-cache.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000041
42namespace v8 {
43namespace internal {
44
45#define __ ACCESS_MASM(masm_)
46
danno@chromium.org40cb8782011-05-25 07:58:50 +000047
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000048class JumpPatchSite BASE_EMBEDDED {
49 public:
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000050 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000051#ifdef DEBUG
52 info_emitted_ = false;
53#endif
54 }
55
56 ~JumpPatchSite() {
57 ASSERT(patch_site_.is_bound() == info_emitted_);
58 }
59
karlklose@chromium.org83a47282011-05-11 11:54:09 +000060 void EmitJumpIfNotSmi(Register reg,
61 Label* target,
62 Label::Distance distance = Label::kFar) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000063 __ test(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000064 EmitJump(not_carry, target, distance); // Always taken before patched.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000065 }
66
karlklose@chromium.org83a47282011-05-11 11:54:09 +000067 void EmitJumpIfSmi(Register reg,
68 Label* target,
69 Label::Distance distance = Label::kFar) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000070 __ test(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000071 EmitJump(carry, target, distance); // Never taken before patched.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000072 }
73
74 void EmitPatchInfo() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000075 if (patch_site_.is_bound()) {
76 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
77 ASSERT(is_int8(delta_to_patch_site));
78 __ test(eax, Immediate(delta_to_patch_site));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000079#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +000080 info_emitted_ = true;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000081#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +000082 } else {
83 __ nop(); // Signals no inlined code.
84 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000085 }
86
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000087 private:
88 // jc will be patched with jz, jnc will become jnz.
karlklose@chromium.org83a47282011-05-11 11:54:09 +000089 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000090 ASSERT(!patch_site_.is_bound() && !info_emitted_);
91 ASSERT(cc == carry || cc == not_carry);
92 __ bind(&patch_site_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +000093 __ j(cc, target, distance);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000094 }
95
96 MacroAssembler* masm_;
97 Label patch_site_;
98#ifdef DEBUG
99 bool info_emitted_;
100#endif
101};
102
103
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000104// Generate code for a JS function. On entry to the function the receiver
105// and arguments have been pushed on the stack left to right, with the
106// return address on top of them. The actual argument count matches the
107// formal parameter count expected by the function.
108//
109// The live registers are:
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000110// o edi: the JS function object being called (i.e. ourselves)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000111// o esi: our context
112// o ebp: our caller's frame pointer
113// o esp: stack pointer (pointing to return address)
114//
115// The function builds a JS frame. Please see JavaScriptFrameConstants in
116// frames-ia32.h for its layout.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000117void FullCodeGenerator::Generate() {
118 CompilationInfo* info = info_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000119 handler_table_ =
120 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
yangguo@chromium.org56454712012-02-16 15:33:53 +0000121 profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000122 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000123 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000124 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000126 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
127
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000128#ifdef DEBUG
129 if (strlen(FLAG_stop_at) > 0 &&
130 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
131 __ int3();
132 }
133#endif
134
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000135 // Strict mode functions and builtins need to replace the receiver
136 // with undefined when called as functions (without an explicit
137 // receiver object). ecx is zero for method calls and non-zero for
138 // function calls.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000139 if (!info->is_classic_mode() || info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000140 Label ok;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000141 Label start;
142 __ bind(&start);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000143 __ test(ecx, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000144 __ j(zero, &ok, Label::kNear);
145 // +1 for return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000146 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000147 __ mov(ecx, Operand(esp, receiver_offset));
148 __ JumpIfSmi(ecx, &ok);
149 __ CmpObjectType(ecx, JS_GLOBAL_PROXY_TYPE, ecx);
150 __ j(not_equal, &ok, Label::kNear);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000151 __ mov(Operand(esp, receiver_offset),
152 Immediate(isolate()->factory()->undefined_value()));
153 __ bind(&ok);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000154 ASSERT(!FLAG_age_code ||
155 (kSizeOfFullCodegenStrictModePrologue == ok.pos() - start.pos()));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000156 }
157
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000158 // Open a frame scope to indicate that there is a frame on the stack. The
159 // MANUAL indicates that the scope shouldn't actually generate code to set up
160 // the frame (that is done below).
161 FrameScope frame_scope(masm_, StackFrame::MANUAL);
162
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000163 __ push(ebp); // Caller's frame pointer.
164 __ mov(ebp, esp);
165 __ push(esi); // Callee's context.
166 __ push(edi); // Callee's JS Function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000167
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000168 { Comment cmnt(masm_, "[ Allocate locals");
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000169 int locals_count = info->scope()->num_stack_slots();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000170 if (locals_count == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000171 __ push(Immediate(isolate()->factory()->undefined_value()));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000172 } else if (locals_count > 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000173 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000174 for (int i = 0; i < locals_count; i++) {
175 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000176 }
177 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000178 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000179
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000180 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000181
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000182 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000183 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000184 if (heap_slots > 0) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000185 Comment cmnt(masm_, "[ Allocate context");
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000186 // Argument to NewContext is the function, which is still in edi.
187 __ push(edi);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000188 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
189 __ Push(info->scope()->GetScopeInfo());
190 __ CallRuntime(Runtime::kNewGlobalContext, 2);
191 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000192 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000193 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000194 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000195 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000196 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000197 function_in_register = false;
198 // Context is returned in both eax and esi. It replaces the context
199 // passed to us. It's saved in the stack and kept live in esi.
200 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
201
202 // Copy parameters into context if necessary.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000203 int num_parameters = info->scope()->num_parameters();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000204 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000205 Variable* var = scope()->parameter(i);
206 if (var->IsContextSlot()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000207 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
208 (num_parameters - 1 - i) * kPointerSize;
209 // Load parameter from stack.
210 __ mov(eax, Operand(ebp, parameter_offset));
211 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000212 int context_offset = Context::SlotOffset(var->index());
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000213 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000214 // Update the write barrier. This clobbers eax and ebx.
215 __ RecordWriteContextSlot(esi,
216 context_offset,
217 eax,
218 ebx,
219 kDontSaveFPRegs);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000220 }
221 }
222 }
223
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000224 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000225 if (arguments != NULL) {
226 // Function uses arguments object.
227 Comment cmnt(masm_, "[ Allocate arguments object");
228 if (function_in_register) {
229 __ push(edi);
230 } else {
231 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
232 }
233 // Receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000234 int num_parameters = info->scope()->num_parameters();
235 int offset = num_parameters * kPointerSize;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000236 __ lea(edx,
237 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
238 __ push(edx);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000239 __ push(Immediate(Smi::FromInt(num_parameters)));
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000240 // Arguments to ArgumentsAccessStub:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000241 // function, receiver address, parameter count.
242 // The stub will rewrite receiver and parameter count if the previous
243 // stack frame was an arguments adapter frame.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000244 ArgumentsAccessStub::Type type;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000245 if (!is_classic_mode()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +0000246 type = ArgumentsAccessStub::NEW_STRICT;
247 } else if (function()->has_duplicate_parameters()) {
248 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
249 } else {
250 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
251 }
252 ArgumentsAccessStub stub(type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000253 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000254
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000255 SetVar(arguments, eax, ebx, edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000256 }
257
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000258 if (FLAG_trace) {
259 __ CallRuntime(Runtime::kTraceEnter, 0);
260 }
261
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000262 // Visit the declarations and body unless there is an illegal
263 // redeclaration.
264 if (scope()->HasIllegalRedeclaration()) {
265 Comment cmnt(masm_, "[ Declarations");
266 scope()->VisitIllegalRedeclaration(this);
267
268 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000269 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000270 { Comment cmnt(masm_, "[ Declarations");
271 // For named function expressions, declare the function name as a
272 // constant.
273 if (scope()->is_function_scope() && scope()->function() != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000274 VariableDeclaration* function = scope()->function();
275 ASSERT(function->proxy()->var()->mode() == CONST ||
276 function->proxy()->var()->mode() == CONST_HARMONY);
277 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
278 VisitVariableDeclaration(function);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000279 }
280 VisitDeclarations(scope()->declarations());
281 }
282
283 { Comment cmnt(masm_, "[ Stack check");
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000284 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000285 Label ok;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000286 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 ExternalReference::address_of_stack_limit(isolate());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000288 __ cmp(esp, Operand::StaticVariable(stack_limit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000289 __ j(above_equal, &ok, Label::kNear);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000290 StackCheckStub stub;
291 __ CallStub(&stub);
292 __ bind(&ok);
293 }
294
295 { Comment cmnt(masm_, "[ Body");
296 ASSERT(loop_depth() == 0);
297 VisitStatements(function()->body());
298 ASSERT(loop_depth() == 0);
299 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000300 }
301
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000302 // Always emit a 'return undefined' in case control fell off the end of
303 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000304 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 __ mov(eax, isolate()->factory()->undefined_value());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000306 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000307 }
308}
309
310
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000311void FullCodeGenerator::ClearAccumulator() {
312 __ Set(eax, Immediate(Smi::FromInt(0)));
313}
314
315
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000316void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
317 __ mov(ebx, Immediate(profiling_counter_));
318 __ sub(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
319 Immediate(Smi::FromInt(delta)));
320}
321
322
323void FullCodeGenerator::EmitProfilingCounterReset() {
324 int reset_value = FLAG_interrupt_budget;
325 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) {
326 // Self-optimization is a one-off thing: if it fails, don't try again.
327 reset_value = Smi::kMaxValue;
328 }
329 __ mov(ebx, Immediate(profiling_counter_));
330 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
331 Immediate(Smi::FromInt(reset_value)));
332}
333
334
yangguo@chromium.org56454712012-02-16 15:33:53 +0000335void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt,
336 Label* back_edge_target) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000337 Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000338 Label ok;
yangguo@chromium.org56454712012-02-16 15:33:53 +0000339
340 if (FLAG_count_based_interrupts) {
341 int weight = 1;
342 if (FLAG_weighted_back_edges) {
343 ASSERT(back_edge_target->is_bound());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000344 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
danno@chromium.org88aa0582012-03-23 15:11:57 +0000345 weight = Min(kMaxBackEdgeWeight,
danno@chromium.org129d3982012-07-25 15:01:47 +0000346 Max(1, distance / kBackEdgeDistanceUnit));
yangguo@chromium.org56454712012-02-16 15:33:53 +0000347 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000348 EmitProfilingCounterDecrement(weight);
yangguo@chromium.org56454712012-02-16 15:33:53 +0000349 __ j(positive, &ok, Label::kNear);
350 InterruptStub stub;
351 __ CallStub(&stub);
352 } else {
353 // Count based interrupts happen often enough when they are enabled
354 // that the additional stack checks are not necessary (they would
355 // only check for interrupts).
356 ExternalReference stack_limit =
357 ExternalReference::address_of_stack_limit(isolate());
358 __ cmp(esp, Operand::StaticVariable(stack_limit));
359 __ j(above_equal, &ok, Label::kNear);
360 StackCheckStub stub;
361 __ CallStub(&stub);
362 }
363
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000364 // Record a mapping of this PC offset to the OSR id. This is used to find
365 // the AST id from the unoptimized code in order to use it as a key into
366 // the deoptimization input data found in the optimized code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000367 RecordStackCheck(stmt->OsrEntryId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000368
369 // Loop stack checks can be patched to perform on-stack replacement. In
370 // order to decide whether or not to perform OSR we embed the loop depth
371 // in a test instruction after the call so we can extract it from the OSR
372 // builtin.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000373 ASSERT(loop_depth() > 0);
374 __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000375
yangguo@chromium.org56454712012-02-16 15:33:53 +0000376 if (FLAG_count_based_interrupts) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000377 EmitProfilingCounterReset();
yangguo@chromium.org56454712012-02-16 15:33:53 +0000378 }
379
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000380 __ bind(&ok);
381 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
382 // Record a mapping of the OSR id to this PC. This is used if the OSR
383 // entry becomes the target of a bailout. We don't expect it to be, but
384 // we want it to work if it is.
385 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000386}
387
388
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000389void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000390 Comment cmnt(masm_, "[ Return sequence");
391 if (return_label_.is_bound()) {
392 __ jmp(&return_label_);
393 } else {
394 // Common return label
395 __ bind(&return_label_);
396 if (FLAG_trace) {
397 __ push(eax);
398 __ CallRuntime(Runtime::kTraceExit, 1);
399 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000400 if (FLAG_interrupt_at_exit || FLAG_self_optimization) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000401 // Pretend that the exit is a backwards jump to the entry.
402 int weight = 1;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000403 if (info_->ShouldSelfOptimize()) {
404 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
405 } else if (FLAG_weighted_back_edges) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000406 int distance = masm_->pc_offset();
danno@chromium.org88aa0582012-03-23 15:11:57 +0000407 weight = Min(kMaxBackEdgeWeight,
danno@chromium.org129d3982012-07-25 15:01:47 +0000408 Max(1, distance / kBackEdgeDistanceUnit));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000409 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000410 EmitProfilingCounterDecrement(weight);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000411 Label ok;
412 __ j(positive, &ok, Label::kNear);
413 __ push(eax);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000414 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) {
415 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
416 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000417 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000418 InterruptStub stub;
419 __ CallStub(&stub);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000420 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000421 __ pop(eax);
422 EmitProfilingCounterReset();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000423 __ bind(&ok);
424 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000425#ifdef DEBUG
426 // Add a label for checking the size of the code used for returning.
427 Label check_exit_codesize;
428 masm_->bind(&check_exit_codesize);
429#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000430 SetSourcePosition(function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000431 __ RecordJSReturn();
432 // Do not use the leave instruction here because it is too short to
433 // patch with the code required by the debugger.
434 __ mov(esp, ebp);
435 __ pop(ebp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000436
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000437 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000438 __ Ret(arguments_bytes, ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000439#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000440 // Check that the size of the code used for returning is large enough
441 // for the debugger's requirements.
442 ASSERT(Assembler::kJSReturnSequenceLength <=
443 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000444#endif
445 }
446}
447
448
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000449void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
450 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000451}
452
453
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000454void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
455 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
456 codegen()->GetVar(result_register(), var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000457}
458
459
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000460void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
461 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
462 MemOperand operand = codegen()->VarOperand(var, result_register());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000463 // Memory operands can be pushed directly.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000464 __ push(operand);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000465}
466
467
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000468void FullCodeGenerator::TestContext::Plug(Variable* var) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000469 // For simplicity we always test the accumulator register.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000470 codegen()->GetVar(result_register(), var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000471 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000472 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000473}
474
475
476void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
477 UNREACHABLE(); // Not used on IA32.
478}
479
480
481void FullCodeGenerator::AccumulatorValueContext::Plug(
482 Heap::RootListIndex index) const {
483 UNREACHABLE(); // Not used on IA32.
484}
485
486
487void FullCodeGenerator::StackValueContext::Plug(
488 Heap::RootListIndex index) const {
489 UNREACHABLE(); // Not used on IA32.
490}
491
492
493void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
494 UNREACHABLE(); // Not used on IA32.
495}
496
497
498void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
499}
500
501
502void FullCodeGenerator::AccumulatorValueContext::Plug(
503 Handle<Object> lit) const {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000504 if (lit->IsSmi()) {
505 __ SafeSet(result_register(), Immediate(lit));
506 } else {
507 __ Set(result_register(), Immediate(lit));
508 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000509}
510
511
512void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000513 if (lit->IsSmi()) {
514 __ SafePush(Immediate(lit));
515 } else {
516 __ push(Immediate(lit));
517 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000518}
519
520
521void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000522 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000523 true,
524 true_label_,
525 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000526 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
527 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000528 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000529 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000530 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000531 } else if (lit->IsString()) {
532 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000533 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000534 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000535 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000536 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000537 } else if (lit->IsSmi()) {
538 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000539 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000540 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000541 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000542 }
543 } else {
544 // For simplicity we always test the accumulator register.
545 __ mov(result_register(), lit);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000546 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000547 }
548}
549
550
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000551void FullCodeGenerator::EffectContext::DropAndPlug(int count,
552 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000553 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000554 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000555}
556
557
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000558void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
559 int count,
560 Register reg) const {
561 ASSERT(count > 0);
562 __ Drop(count);
563 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000564}
565
566
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000567void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
568 Register reg) const {
569 ASSERT(count > 0);
570 if (count > 1) __ Drop(count - 1);
571 __ mov(Operand(esp, 0), reg);
572}
573
574
575void FullCodeGenerator::TestContext::DropAndPlug(int count,
576 Register reg) const {
577 ASSERT(count > 0);
578 // For simplicity we always test the accumulator register.
579 __ Drop(count);
580 __ Move(result_register(), reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000581 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000582 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000583}
584
585
586void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
587 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000588 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000589 __ bind(materialize_true);
590}
591
592
593void FullCodeGenerator::AccumulatorValueContext::Plug(
594 Label* materialize_true,
595 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000596 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000597 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 __ mov(result_register(), isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000599 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000600 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 __ mov(result_register(), isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000602 __ bind(&done);
603}
604
605
606void FullCodeGenerator::StackValueContext::Plug(
607 Label* materialize_true,
608 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000609 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000610 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000611 __ push(Immediate(isolate()->factory()->true_value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000612 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000613 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 __ push(Immediate(isolate()->factory()->false_value()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000615 __ bind(&done);
616}
617
618
619void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
620 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000621 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000622 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000623}
624
625
626void FullCodeGenerator::EffectContext::Plug(bool flag) const {
627}
628
629
630void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 Handle<Object> value = flag
632 ? isolate()->factory()->true_value()
633 : isolate()->factory()->false_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000634 __ mov(result_register(), value);
635}
636
637
638void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 Handle<Object> value = flag
640 ? isolate()->factory()->true_value()
641 : isolate()->factory()->false_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000642 __ push(Immediate(value));
643}
644
645
646void FullCodeGenerator::TestContext::Plug(bool flag) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000647 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000648 true,
649 true_label_,
650 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000651 if (flag) {
652 if (true_label_ != fall_through_) __ jmp(true_label_);
653 } else {
654 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000655 }
656}
657
658
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000659void FullCodeGenerator::DoTest(Expression* condition,
660 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000661 Label* if_false,
662 Label* fall_through) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000663 ToBooleanStub stub(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000664 __ push(result_register());
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000665 __ CallStub(&stub, condition->test_id());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000666 __ test(result_register(), result_register());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000667 // The stub returns nonzero for true.
668 Split(not_zero, if_true, if_false, fall_through);
669}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000670
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000671
ricow@chromium.org65fae842010-08-25 15:26:24 +0000672void FullCodeGenerator::Split(Condition cc,
673 Label* if_true,
674 Label* if_false,
675 Label* fall_through) {
676 if (if_false == fall_through) {
677 __ j(cc, if_true);
678 } else if (if_true == fall_through) {
679 __ j(NegateCondition(cc), if_false);
680 } else {
681 __ j(cc, if_true);
682 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000683 }
684}
685
686
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000687MemOperand FullCodeGenerator::StackOperand(Variable* var) {
688 ASSERT(var->IsStackAllocated());
689 // Offset is negative because higher indexes are at lower addresses.
690 int offset = -var->index() * kPointerSize;
691 // Adjust by a (parameter or local) base offset.
692 if (var->IsParameter()) {
693 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
694 } else {
695 offset += JavaScriptFrameConstants::kLocal0Offset;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000696 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000697 return Operand(ebp, offset);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000698}
699
700
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000701MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
702 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
703 if (var->IsContextSlot()) {
704 int context_chain_length = scope()->ContextChainLength(var->scope());
705 __ LoadContext(scratch, context_chain_length);
706 return ContextOperand(scratch, var->index());
707 } else {
708 return StackOperand(var);
709 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000710}
711
712
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000713void FullCodeGenerator::GetVar(Register dest, Variable* var) {
714 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
715 MemOperand location = VarOperand(var, dest);
716 __ mov(dest, location);
717}
718
719
720void FullCodeGenerator::SetVar(Variable* var,
721 Register src,
722 Register scratch0,
723 Register scratch1) {
724 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
725 ASSERT(!scratch0.is(src));
726 ASSERT(!scratch0.is(scratch1));
727 ASSERT(!scratch1.is(src));
728 MemOperand location = VarOperand(var, scratch0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000729 __ mov(location, src);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000730
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000731 // Emit the write barrier code if the location is in the heap.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000732 if (var->IsContextSlot()) {
733 int offset = Context::SlotOffset(var->index());
734 ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000735 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000736 }
737}
738
739
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000740void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000741 bool should_normalize,
742 Label* if_true,
743 Label* if_false) {
744 // Only prepare for bailouts before splits if we're in a test
745 // context. Otherwise, we let the Visit function deal with the
746 // preparation to avoid preparing with the same AST id twice.
747 if (!context()->IsTest() || !info_->IsOptimizable()) return;
748
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000749 Label skip;
750 if (should_normalize) __ jmp(&skip, Label::kNear);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000751 PrepareForBailout(expr, TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000752 if (should_normalize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000753 __ cmp(eax, isolate()->factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000754 Split(equal, if_true, if_false, NULL);
755 __ bind(&skip);
756 }
757}
758
759
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000760void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000761 // The variable in the declaration always resides in the current context.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000762 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000763 if (generate_debug_code_) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000764 // Check that we're not inside a with or catch context.
765 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
766 __ cmp(ebx, isolate()->factory()->with_context_map());
767 __ Check(not_equal, "Declaration in with context.");
768 __ cmp(ebx, isolate()->factory()->catch_context_map());
769 __ Check(not_equal, "Declaration in catch context.");
770 }
771}
772
773
774void FullCodeGenerator::VisitVariableDeclaration(
775 VariableDeclaration* declaration) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000776 // If it was not possible to allocate the variable at compile time, we
777 // need to "declare" it at runtime to make sure it actually exists in the
778 // local context.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000779 VariableProxy* proxy = declaration->proxy();
780 VariableMode mode = declaration->mode();
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000781 Variable* variable = proxy->var();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000782 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000783 switch (variable->location()) {
784 case Variable::UNALLOCATED:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000785 globals_->Add(variable->name(), zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000786 globals_->Add(variable->binding_needs_init()
787 ? isolate()->factory()->the_hole_value()
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000788 : isolate()->factory()->undefined_value(), zone());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000789 break;
790
791 case Variable::PARAMETER:
792 case Variable::LOCAL:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000793 if (hole_init) {
794 Comment cmnt(masm_, "[ VariableDeclaration");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000795 __ mov(StackOperand(variable),
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000796 Immediate(isolate()->factory()->the_hole_value()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000797 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000798 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000799
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000800 case Variable::CONTEXT:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000801 if (hole_init) {
802 Comment cmnt(masm_, "[ VariableDeclaration");
803 EmitDebugCheckDeclarationContext(variable);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000804 __ mov(ContextOperand(esi, variable->index()),
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000805 Immediate(isolate()->factory()->the_hole_value()));
806 // No write barrier since the hole value is in old space.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000807 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000808 }
809 break;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000810
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000811 case Variable::LOOKUP: {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000812 Comment cmnt(masm_, "[ VariableDeclaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000813 __ push(esi);
814 __ push(Immediate(variable->name()));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000815 // VariableDeclaration nodes are always introduced in one of four modes.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000816 ASSERT(IsDeclaredVariableMode(mode));
817 PropertyAttributes attr =
818 IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000819 __ push(Immediate(Smi::FromInt(attr)));
820 // Push initial value, if any.
821 // Note: For variables we must not push an initial value (such as
822 // 'undefined') because we may have a (legal) redeclaration and we
823 // must not destroy the current value.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000824 if (hole_init) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000825 __ push(Immediate(isolate()->factory()->the_hole_value()));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000826 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000827 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000828 }
829 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000830 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000831 }
832 }
833}
834
835
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000836void FullCodeGenerator::VisitFunctionDeclaration(
837 FunctionDeclaration* declaration) {
838 VariableProxy* proxy = declaration->proxy();
839 Variable* variable = proxy->var();
840 switch (variable->location()) {
841 case Variable::UNALLOCATED: {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000842 globals_->Add(variable->name(), zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000843 Handle<SharedFunctionInfo> function =
844 Compiler::BuildFunctionInfo(declaration->fun(), script());
845 // Check for stack-overflow exception.
846 if (function.is_null()) return SetStackOverflow();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000847 globals_->Add(function, zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000848 break;
849 }
850
851 case Variable::PARAMETER:
852 case Variable::LOCAL: {
853 Comment cmnt(masm_, "[ FunctionDeclaration");
854 VisitForAccumulatorValue(declaration->fun());
855 __ mov(StackOperand(variable), result_register());
856 break;
857 }
858
859 case Variable::CONTEXT: {
860 Comment cmnt(masm_, "[ FunctionDeclaration");
861 EmitDebugCheckDeclarationContext(variable);
862 VisitForAccumulatorValue(declaration->fun());
863 __ mov(ContextOperand(esi, variable->index()), result_register());
864 // We know that we have written a function, which is not a smi.
865 __ RecordWriteContextSlot(esi,
866 Context::SlotOffset(variable->index()),
867 result_register(),
868 ecx,
869 kDontSaveFPRegs,
870 EMIT_REMEMBERED_SET,
871 OMIT_SMI_CHECK);
872 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
873 break;
874 }
875
876 case Variable::LOOKUP: {
877 Comment cmnt(masm_, "[ FunctionDeclaration");
878 __ push(esi);
879 __ push(Immediate(variable->name()));
880 __ push(Immediate(Smi::FromInt(NONE)));
881 VisitForStackValue(declaration->fun());
882 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
883 break;
884 }
885 }
886}
887
888
889void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000890 Variable* variable = declaration->proxy()->var();
891 ASSERT(variable->location() == Variable::CONTEXT);
892 ASSERT(variable->interface()->IsFrozen());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000893
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000894 Comment cmnt(masm_, "[ ModuleDeclaration");
895 EmitDebugCheckDeclarationContext(variable);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000896
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000897 // Load instance object.
898 __ LoadContext(eax, scope_->ContextChainLength(scope_->GlobalScope()));
899 __ mov(eax, ContextOperand(eax, variable->interface()->Index()));
900 __ mov(eax, ContextOperand(eax, Context::EXTENSION_INDEX));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000901
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000902 // Assign it.
903 __ mov(ContextOperand(esi, variable->index()), eax);
904 // We know that we have written a module, which is not a smi.
905 __ RecordWriteContextSlot(esi,
906 Context::SlotOffset(variable->index()),
907 eax,
908 ecx,
909 kDontSaveFPRegs,
910 EMIT_REMEMBERED_SET,
911 OMIT_SMI_CHECK);
912 PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
913
914 // Traverse into body.
915 Visit(declaration->module());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000916}
917
918
919void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
920 VariableProxy* proxy = declaration->proxy();
921 Variable* variable = proxy->var();
922 switch (variable->location()) {
923 case Variable::UNALLOCATED:
924 // TODO(rossberg)
925 break;
926
927 case Variable::CONTEXT: {
928 Comment cmnt(masm_, "[ ImportDeclaration");
929 EmitDebugCheckDeclarationContext(variable);
930 // TODO(rossberg)
931 break;
932 }
933
934 case Variable::PARAMETER:
935 case Variable::LOCAL:
936 case Variable::LOOKUP:
937 UNREACHABLE();
938 }
939}
940
941
942void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
943 // TODO(rossberg)
944}
945
946
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000947void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
948 // Call the runtime to declare the globals.
949 __ push(esi); // The context is the first argument.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000950 __ Push(pairs);
951 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000952 __ CallRuntime(Runtime::kDeclareGlobals, 3);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000953 // Return value is ignored.
954}
955
956
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000957void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
958 // Call the runtime to declare the modules.
959 __ Push(descriptions);
960 __ CallRuntime(Runtime::kDeclareModules, 1);
961 // Return value is ignored.
962}
963
964
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000965void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
966 Comment cmnt(masm_, "[ SwitchStatement");
967 Breakable nested_statement(this, stmt);
968 SetStatementPosition(stmt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000969
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000970 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000971 VisitForStackValue(stmt->tag());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000972 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000973
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000974 ZoneList<CaseClause*>* clauses = stmt->cases();
975 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000976
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000977 Label next_test; // Recycled for each test.
978 // Compile all the tests with branches to their bodies.
979 for (int i = 0; i < clauses->length(); i++) {
980 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000981 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000982
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000983 // The default is not a test, but remember it as final fall through.
984 if (clause->is_default()) {
985 default_clause = clause;
986 continue;
987 }
988
989 Comment cmnt(masm_, "[ Case comparison");
990 __ bind(&next_test);
991 next_test.Unuse();
992
993 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000994 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000995
ricow@chromium.org65fae842010-08-25 15:26:24 +0000996 // Perform the comparison as if via '==='.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000997 __ mov(edx, Operand(esp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000998 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000999 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001000 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001001 Label slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001002 __ mov(ecx, edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001003 __ or_(ecx, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001004 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001005
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001006 __ cmp(edx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001007 __ j(not_equal, &next_test);
1008 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001009 __ jmp(clause->body_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001010 __ bind(&slow_case);
1011 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001012
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001013 // Record position before stub call for type feedback.
1014 SetSourcePosition(clause->position());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001015 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001016 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001017 patch_site.EmitPatchInfo();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001018 __ test(eax, eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001019 __ j(not_equal, &next_test);
1020 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001021 __ jmp(clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001022 }
1023
1024 // Discard the test value and jump to the default if present, otherwise to
1025 // the end of the statement.
1026 __ bind(&next_test);
1027 __ Drop(1); // Switch value is no longer needed.
1028 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001029 __ jmp(nested_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001030 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001031 __ jmp(default_clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001032 }
1033
1034 // Compile all the case bodies.
1035 for (int i = 0; i < clauses->length(); i++) {
1036 Comment cmnt(masm_, "[ Case body");
1037 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001038 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001039 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001040 VisitStatements(clause->statements());
1041 }
1042
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001043 __ bind(nested_statement.break_label());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001044 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001045}
1046
1047
1048void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1049 Comment cmnt(masm_, "[ ForInStatement");
1050 SetStatementPosition(stmt);
1051
1052 Label loop, exit;
1053 ForIn loop_statement(this, stmt);
1054 increment_loop_depth();
1055
1056 // Get the object to enumerate over. Both SpiderMonkey and JSC
1057 // ignore null and undefined in contrast to the specification; see
1058 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001059 VisitForAccumulatorValue(stmt->enumerable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 __ cmp(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001061 __ j(equal, &exit);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001062 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001063 __ j(equal, &exit);
1064
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001065 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1066
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001067 // Convert the object to a JS object.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001068 Label convert, done_convert;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001069 __ JumpIfSmi(eax, &convert, Label::kNear);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001070 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001071 __ j(above_equal, &done_convert, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001072 __ bind(&convert);
1073 __ push(eax);
1074 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1075 __ bind(&done_convert);
1076 __ push(eax);
1077
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001078 // Check for proxies.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001079 Label call_runtime, use_cache, fixed_array;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001080 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1081 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
1082 __ j(below_equal, &call_runtime);
1083
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001084 // Check cache validity in generated code. This is a fast case for
1085 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1086 // guarantee cache validity, call the runtime system to check cache
1087 // validity or get the property names in a fixed array.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001088 __ CheckEnumCache(&call_runtime);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001089
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001090 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001091 __ jmp(&use_cache, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001092
1093 // Get the set of properties to enumerate.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001094 __ bind(&call_runtime);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001095 __ push(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001096 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1098 isolate()->factory()->meta_map());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001099 __ j(not_equal, &fixed_array);
1100
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001101
1102 // We got a map in register eax. Get the enumeration cache from it.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001103 Label no_descriptors;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001104 __ bind(&use_cache);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001105
1106 __ EnumLength(edx, eax);
1107 __ cmp(edx, Immediate(Smi::FromInt(0)));
1108 __ j(equal, &no_descriptors);
1109
danno@chromium.org40cb8782011-05-25 07:58:50 +00001110 __ LoadInstanceDescriptors(eax, ecx);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001111 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001112 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001113
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001114 // Set up the four remaining stack slots.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001115 __ push(eax); // Map.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001116 __ push(ecx); // Enumeration cache.
1117 __ push(edx); // Number of valid entries for the map in the enum cache.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001118 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1119 __ jmp(&loop);
1120
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001121 __ bind(&no_descriptors);
1122 __ add(esp, Immediate(kPointerSize));
1123 __ jmp(&exit);
1124
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001125 // We got a fixed array in register eax. Iterate through that.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001126 Label non_proxy;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001127 __ bind(&fixed_array);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001128
1129 Handle<JSGlobalPropertyCell> cell =
1130 isolate()->factory()->NewJSGlobalPropertyCell(
1131 Handle<Object>(
1132 Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker)));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001133 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001134 __ LoadHeapObject(ebx, cell);
1135 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
1136 Immediate(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker)));
1137
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001138 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
1139 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object
1140 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1141 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx);
1142 __ j(above, &non_proxy);
1143 __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
1144 __ bind(&non_proxy);
1145 __ push(ebx); // Smi
1146 __ push(eax); // Array
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001147 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001148 __ push(eax); // Fixed array length (as smi).
1149 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1150
1151 // Generate code for doing the condition check.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001152 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001153 __ bind(&loop);
1154 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1155 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001156 __ j(above_equal, loop_statement.break_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001157
1158 // Get the current entry of the array into register ebx.
1159 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1160 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1161
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001162 // Get the expected map from the stack or a smi in the
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001163 // permanent slow case into register edx.
1164 __ mov(edx, Operand(esp, 3 * kPointerSize));
1165
1166 // Check if the expected map still matches that of the enumerable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001167 // If not, we may have to filter the key.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001168 Label update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001169 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1170 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001171 __ j(equal, &update_each, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001172
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001173 // For proxies, no filtering is done.
1174 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1175 ASSERT(Smi::FromInt(0) == 0);
1176 __ test(edx, edx);
1177 __ j(zero, &update_each);
1178
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001179 // Convert the entry to a string or null if it isn't a property
1180 // anymore. If the property has been removed while iterating, we
1181 // just skip it.
1182 __ push(ecx); // Enumerable.
1183 __ push(ebx); // Current entry.
1184 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001185 __ test(eax, eax);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001186 __ j(equal, loop_statement.continue_label());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001187 __ mov(ebx, eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001188
1189 // Update the 'each' property or variable from the possibly filtered
1190 // entry in register ebx.
1191 __ bind(&update_each);
1192 __ mov(result_register(), ebx);
1193 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001194 { EffectContext context(this);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001195 EmitAssignment(stmt->each());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001196 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001197
1198 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001199 Visit(stmt->body());
1200
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001201 // Generate code for going to the next element by incrementing the
1202 // index (smi) stored on top of the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001203 __ bind(loop_statement.continue_label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001204 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001205
yangguo@chromium.org56454712012-02-16 15:33:53 +00001206 EmitStackCheck(stmt, &loop);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001207 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001208
1209 // Remove the pointers stored on the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001210 __ bind(loop_statement.break_label());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001211 __ add(esp, Immediate(5 * kPointerSize));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001212
1213 // Exit and decrement the loop depth.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001214 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001215 __ bind(&exit);
1216 decrement_loop_depth();
1217}
1218
1219
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001220void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1221 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001222 // Use the fast case closure allocation code that allocates in new
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001223 // space for nested functions that don't need literals cloning. If
1224 // we're running with the --always-opt or the --prepare-always-opt
1225 // flag, we need to use the runtime function so that the new function
1226 // we are creating here gets a chance to have its code optimized and
1227 // doesn't just get a copy of the existing unoptimized code.
1228 if (!FLAG_always_opt &&
1229 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001230 !pretenure &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001231 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001232 info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001233 FastNewClosureStub stub(info->language_mode());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001234 __ push(Immediate(info));
1235 __ CallStub(&stub);
1236 } else {
1237 __ push(esi);
1238 __ push(Immediate(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001239 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001240 ? isolate()->factory()->true_value()
1241 : isolate()->factory()->false_value()));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001242 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001243 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001244 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001245}
1246
1247
1248void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1249 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001250 EmitVariableLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001251}
1252
1253
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001254void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1255 TypeofState typeof_state,
1256 Label* slow) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001257 Register context = esi;
1258 Register temp = edx;
1259
1260 Scope* s = scope();
1261 while (s != NULL) {
1262 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001263 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001264 // Check that extension is NULL.
1265 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1266 Immediate(0));
1267 __ j(not_equal, slow);
1268 }
1269 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001270 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001271 // Walk the rest of the chain without clobbering esi.
1272 context = temp;
1273 }
1274 // If no outer scope calls eval, we do not need to check more
1275 // context extensions. If we have reached an eval scope, we check
1276 // all extensions from this point.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001277 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001278 s = s->outer_scope();
1279 }
1280
1281 if (s != NULL && s->is_eval_scope()) {
1282 // Loop up the context chain. There is no frame effect so it is
1283 // safe to use raw labels here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001284 Label next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001285 if (!context.is(temp)) {
1286 __ mov(temp, context);
1287 }
1288 __ bind(&next);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001289 // Terminate at native context.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001290 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001291 Immediate(isolate()->factory()->native_context_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001292 __ j(equal, &fast, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001293 // Check that extension is NULL.
1294 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1295 __ j(not_equal, slow);
1296 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001297 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001298 __ jmp(&next);
1299 __ bind(&fast);
1300 }
1301
1302 // All extension objects were empty and it is safe to use a global
1303 // load IC call.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001304 __ mov(edx, GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001305 __ mov(ecx, var->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001306 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001307 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1308 ? RelocInfo::CODE_TARGET
1309 : RelocInfo::CODE_TARGET_CONTEXT;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001310 CallIC(ic, mode);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001311}
1312
1313
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001314MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1315 Label* slow) {
1316 ASSERT(var->IsContextSlot());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001317 Register context = esi;
1318 Register temp = ebx;
1319
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001320 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001321 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001322 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001323 // Check that extension is NULL.
1324 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1325 Immediate(0));
1326 __ j(not_equal, slow);
1327 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001328 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001329 // Walk the rest of the chain without clobbering esi.
1330 context = temp;
1331 }
1332 }
1333 // Check that last extension is NULL.
1334 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1335 __ j(not_equal, slow);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001336
1337 // This function is used only for loads, not stores, so it's safe to
1338 // return an esi-based operand (the write barrier cannot be allowed to
1339 // destroy the esi register).
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001340 return ContextOperand(context, var->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001341}
1342
1343
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001344void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1345 TypeofState typeof_state,
1346 Label* slow,
1347 Label* done) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001348 // Generate fast-case code for variables that might be shadowed by
1349 // eval-introduced variables. Eval is used a lot without
1350 // introducing variables. In those cases, we do not want to
1351 // perform a runtime call for all variables in the scope
1352 // containing the eval.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001353 if (var->mode() == DYNAMIC_GLOBAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001354 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001355 __ jmp(done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001356 } else if (var->mode() == DYNAMIC_LOCAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001357 Variable* local = var->local_if_not_shadowed();
1358 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001359 if (local->mode() == LET ||
1360 local->mode() == CONST ||
1361 local->mode() == CONST_HARMONY) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001362 __ cmp(eax, isolate()->factory()->the_hole_value());
1363 __ j(not_equal, done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001364 if (local->mode() == CONST) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001365 __ mov(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001366 } else { // LET || CONST_HARMONY
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001367 __ push(Immediate(var->name()));
1368 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1369 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001370 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001371 __ jmp(done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001372 }
1373}
1374
1375
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001376void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1377 // Record position before possible IC call.
1378 SetSourcePosition(proxy->position());
1379 Variable* var = proxy->var();
1380
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001381 // Three cases: global variables, lookup variables, and all other types of
1382 // variables.
1383 switch (var->location()) {
1384 case Variable::UNALLOCATED: {
1385 Comment cmnt(masm_, "Global variable");
1386 // Use inline caching. Variable name is passed in ecx and the global
1387 // object in eax.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001388 __ mov(edx, GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001389 __ mov(ecx, var->name());
1390 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001391 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001392 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001393 break;
1394 }
1395
1396 case Variable::PARAMETER:
1397 case Variable::LOCAL:
1398 case Variable::CONTEXT: {
1399 Comment cmnt(masm_, var->IsContextSlot()
1400 ? "Context variable"
1401 : "Stack variable");
danno@chromium.orgc612e022011-11-10 11:38:15 +00001402 if (var->binding_needs_init()) {
1403 // var->scope() may be NULL when the proxy is located in eval code and
1404 // refers to a potential outside binding. Currently those bindings are
1405 // always looked up dynamically, i.e. in that case
1406 // var->location() == LOOKUP.
1407 // always holds.
1408 ASSERT(var->scope() != NULL);
1409
1410 // Check if the binding really needs an initialization check. The check
1411 // can be skipped in the following situation: we have a LET or CONST
1412 // binding in harmony mode, both the Variable and the VariableProxy have
1413 // the same declaration scope (i.e. they are both in global code, in the
1414 // same function or in the same eval code) and the VariableProxy is in
1415 // the source physically located after the initializer of the variable.
1416 //
1417 // We cannot skip any initialization checks for CONST in non-harmony
1418 // mode because const variables may be declared but never initialized:
1419 // if (false) { const x; }; var y = x;
1420 //
1421 // The condition on the declaration scopes is a conservative check for
1422 // nested functions that access a binding and are called before the
1423 // binding is initialized:
1424 // function() { f(); let x = 1; function f() { x = 2; } }
1425 //
1426 bool skip_init_check;
1427 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1428 skip_init_check = false;
jkummerow@chromium.orgac45fed2011-11-07 13:11:02 +00001429 } else {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001430 // Check that we always have valid source position.
1431 ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1432 ASSERT(proxy->position() != RelocInfo::kNoPosition);
1433 skip_init_check = var->mode() != CONST &&
1434 var->initializer_position() < proxy->position();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001435 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001436
1437 if (!skip_init_check) {
1438 // Let and const need a read barrier.
1439 Label done;
1440 GetVar(eax, var);
1441 __ cmp(eax, isolate()->factory()->the_hole_value());
1442 __ j(not_equal, &done, Label::kNear);
1443 if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1444 // Throw a reference error when using an uninitialized let/const
1445 // binding in harmony mode.
1446 __ push(Immediate(var->name()));
1447 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1448 } else {
1449 // Uninitalized const bindings outside of harmony mode are unholed.
1450 ASSERT(var->mode() == CONST);
1451 __ mov(eax, isolate()->factory()->undefined_value());
1452 }
1453 __ bind(&done);
1454 context()->Plug(eax);
1455 break;
1456 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001457 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001458 context()->Plug(var);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001459 break;
1460 }
1461
1462 case Variable::LOOKUP: {
1463 Label done, slow;
1464 // Generate code for loading from variables potentially shadowed
1465 // by eval-introduced variables.
1466 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1467 __ bind(&slow);
1468 Comment cmnt(masm_, "Lookup variable");
1469 __ push(esi); // Context.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001470 __ push(Immediate(var->name()));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001471 __ CallRuntime(Runtime::kLoadContextSlot, 2);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001472 __ bind(&done);
1473 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001474 break;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001475 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001476 }
1477}
1478
1479
1480void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1481 Comment cmnt(masm_, "[ RegExpLiteral");
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001482 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001483 // Registers will be used as follows:
1484 // edi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001485 // ecx = literals array.
1486 // ebx = regexp literal.
1487 // eax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001488 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001489 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001490 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001491 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001492 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001493 __ cmp(ebx, isolate()->factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001494 __ j(not_equal, &materialized, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001495
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001496 // Create regexp literal using runtime function
1497 // Result will be in eax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001498 __ push(ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001499 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1500 __ push(Immediate(expr->pattern()));
1501 __ push(Immediate(expr->flags()));
1502 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001503 __ mov(ebx, eax);
1504
1505 __ bind(&materialized);
1506 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1507 Label allocated, runtime_allocate;
1508 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1509 __ jmp(&allocated);
1510
1511 __ bind(&runtime_allocate);
1512 __ push(ebx);
1513 __ push(Immediate(Smi::FromInt(size)));
1514 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1515 __ pop(ebx);
1516
1517 __ bind(&allocated);
1518 // Copy the content into the newly allocated memory.
1519 // (Unroll copy loop once for better throughput).
1520 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1521 __ mov(edx, FieldOperand(ebx, i));
1522 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1523 __ mov(FieldOperand(eax, i), edx);
1524 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1525 }
1526 if ((size % (2 * kPointerSize)) != 0) {
1527 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1528 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1529 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001530 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001531}
1532
1533
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001534void FullCodeGenerator::EmitAccessor(Expression* expression) {
1535 if (expression == NULL) {
1536 __ push(Immediate(isolate()->factory()->null_value()));
1537 } else {
1538 VisitForStackValue(expression);
1539 }
1540}
1541
1542
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001543void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1544 Comment cmnt(masm_, "[ ObjectLiteral");
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001545 Handle<FixedArray> constant_properties = expr->constant_properties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001546 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1547 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1548 __ push(Immediate(Smi::FromInt(expr->literal_index())));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001549 __ push(Immediate(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001550 int flags = expr->fast_elements()
1551 ? ObjectLiteral::kFastElements
1552 : ObjectLiteral::kNoFlags;
1553 flags |= expr->has_function()
1554 ? ObjectLiteral::kHasFunction
1555 : ObjectLiteral::kNoFlags;
1556 __ push(Immediate(Smi::FromInt(flags)));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001557 int properties_count = constant_properties->length() / 2;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001558 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001559 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001560 } else if (flags != ObjectLiteral::kFastElements ||
1561 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001562 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001563 } else {
1564 FastCloneShallowObjectStub stub(properties_count);
1565 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001566 }
1567
1568 // If result_saved is true the result is on top of the stack. If
1569 // result_saved is false the result is in eax.
1570 bool result_saved = false;
1571
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001572 // Mark all computed expressions that are bound to a key that
1573 // is shadowed by a later occurrence of the same key. For the
1574 // marked expressions, no store code is emitted.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001575 expr->CalculateEmitStore(zone());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001576
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001577 AccessorTable accessor_table(zone());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001578 for (int i = 0; i < expr->properties()->length(); i++) {
1579 ObjectLiteral::Property* property = expr->properties()->at(i);
1580 if (property->IsCompileTimeValue()) continue;
1581
1582 Literal* key = property->key();
1583 Expression* value = property->value();
1584 if (!result_saved) {
1585 __ push(eax); // Save result on the stack
1586 result_saved = true;
1587 }
1588 switch (property->kind()) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001589 case ObjectLiteral::Property::CONSTANT:
1590 UNREACHABLE();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001591 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1592 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1593 // Fall through.
1594 case ObjectLiteral::Property::COMPUTED:
1595 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001596 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001597 VisitForAccumulatorValue(value);
1598 __ mov(ecx, Immediate(key->handle()));
1599 __ mov(edx, Operand(esp, 0));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001600 Handle<Code> ic = is_classic_mode()
1601 ? isolate()->builtins()->StoreIC_Initialize()
1602 : isolate()->builtins()->StoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001603 CallIC(ic, RelocInfo::CODE_TARGET, key->LiteralFeedbackId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001604 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1605 } else {
1606 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001607 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001608 break;
1609 }
1610 // Fall through.
1611 case ObjectLiteral::Property::PROTOTYPE:
1612 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001613 VisitForStackValue(key);
1614 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001615 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001616 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1617 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001618 } else {
1619 __ Drop(3);
1620 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001621 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001622 case ObjectLiteral::Property::GETTER:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001623 accessor_table.lookup(key)->second->getter = value;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001624 break;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001625 case ObjectLiteral::Property::SETTER:
1626 accessor_table.lookup(key)->second->setter = value;
1627 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001628 }
1629 }
1630
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001631 // Emit code to define accessors, using only a single call to the runtime for
1632 // each pair of corresponding getters and setters.
1633 for (AccessorTable::Iterator it = accessor_table.begin();
1634 it != accessor_table.end();
1635 ++it) {
1636 __ push(Operand(esp, 0)); // Duplicate receiver.
1637 VisitForStackValue(it->first);
1638 EmitAccessor(it->second->getter);
1639 EmitAccessor(it->second->setter);
1640 __ push(Immediate(Smi::FromInt(NONE)));
1641 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
1642 }
1643
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 if (expr->has_function()) {
1645 ASSERT(result_saved);
1646 __ push(Operand(esp, 0));
1647 __ CallRuntime(Runtime::kToFastProperties, 1);
1648 }
1649
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001650 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001651 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001652 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001653 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001654 }
1655}
1656
1657
1658void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1659 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001660
1661 ZoneList<Expression*>* subexprs = expr->values();
1662 int length = subexprs->length();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001663 Handle<FixedArray> constant_elements = expr->constant_elements();
1664 ASSERT_EQ(2, constant_elements->length());
1665 ElementsKind constant_elements_kind =
1666 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001667 bool has_constant_fast_elements =
1668 IsFastObjectElementsKind(constant_elements_kind);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001669 Handle<FixedArrayBase> constant_elements_values(
1670 FixedArrayBase::cast(constant_elements->get(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001671
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001672 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1673 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1674 __ push(Immediate(Smi::FromInt(expr->literal_index())));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001675 __ push(Immediate(constant_elements));
erikcorry0ad885c2011-11-21 13:51:57 +00001676 Heap* heap = isolate()->heap();
1677 if (has_constant_fast_elements &&
1678 constant_elements_values->map() == heap->fixed_cow_array_map()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001679 // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
erikcorry0ad885c2011-11-21 13:51:57 +00001680 // change, so it's possible to specialize the stub in advance.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
erikcorry0ad885c2011-11-21 13:51:57 +00001682 FastCloneShallowArrayStub stub(
1683 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
1684 length);
1685 __ CallStub(&stub);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001686 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001687 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001688 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001689 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001690 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001691 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001692 FLAG_smi_only_arrays);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001693 // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
erikcorry0ad885c2011-11-21 13:51:57 +00001694 // change, so it's possible to specialize the stub in advance.
1695 FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
1696 ? FastCloneShallowArrayStub::CLONE_ELEMENTS
1697 : FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001698 FastCloneShallowArrayStub stub(mode, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001699 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001700 }
1701
1702 bool result_saved = false; // Is the result saved to the stack?
1703
1704 // Emit code to evaluate all the non-constant subexpressions and to store
1705 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001706 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001707 Expression* subexpr = subexprs->at(i);
1708 // If the subexpression is a literal or a simple materialized literal it
1709 // is already set in the cloned array.
1710 if (subexpr->AsLiteral() != NULL ||
1711 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1712 continue;
1713 }
1714
1715 if (!result_saved) {
1716 __ push(eax);
1717 result_saved = true;
1718 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001719 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001720
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001721 if (IsFastObjectElementsKind(constant_elements_kind)) {
1722 // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
1723 // cannot transition and don't need to call the runtime stub.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001724 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1725 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1726 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1727 // Store the subexpression value in the array's elements.
1728 __ mov(FieldOperand(ebx, offset), result_register());
1729 // Update the write barrier for the array store.
1730 __ RecordWriteField(ebx, offset, result_register(), ecx,
1731 kDontSaveFPRegs,
1732 EMIT_REMEMBERED_SET,
1733 INLINE_SMI_CHECK);
1734 } else {
1735 // Store the subexpression value in the array's elements.
1736 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1737 __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
1738 __ mov(ecx, Immediate(Smi::FromInt(i)));
1739 __ mov(edx, Immediate(Smi::FromInt(expr->literal_index())));
1740 StoreArrayLiteralElementStub stub;
1741 __ CallStub(&stub);
1742 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001743
1744 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001745 }
1746
1747 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001748 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001749 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001750 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001751 }
1752}
1753
1754
ager@chromium.org5c838252010-02-19 08:53:10 +00001755void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1756 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001757 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1758 // on the left-hand side.
1759 if (!expr->target()->IsValidLeftHandSide()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001760 VisitForEffect(expr->target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001761 return;
1762 }
1763
ager@chromium.org5c838252010-02-19 08:53:10 +00001764 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001765 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001766 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1767 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001768 Property* property = expr->target()->AsProperty();
1769 if (property != NULL) {
1770 assign_type = (property->key()->IsPropertyName())
1771 ? NAMED_PROPERTY
1772 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001773 }
1774
1775 // Evaluate LHS expression.
1776 switch (assign_type) {
1777 case VARIABLE:
1778 // Nothing to do here.
1779 break;
1780 case NAMED_PROPERTY:
1781 if (expr->is_compound()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001782 // We need the receiver both on the stack and in edx.
1783 VisitForStackValue(property->obj());
1784 __ mov(edx, Operand(esp, 0));
ager@chromium.org5c838252010-02-19 08:53:10 +00001785 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001786 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001787 }
1788 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001789 case KEYED_PROPERTY: {
ager@chromium.org5c838252010-02-19 08:53:10 +00001790 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001791 VisitForStackValue(property->obj());
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001792 VisitForStackValue(property->key());
1793 __ mov(edx, Operand(esp, kPointerSize)); // Object.
1794 __ mov(ecx, Operand(esp, 0)); // Key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001795 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001796 VisitForStackValue(property->obj());
1797 VisitForStackValue(property->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00001798 }
1799 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001800 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001801 }
1802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001803 // For compound assignments we need another deoptimization point after the
1804 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001805 if (expr->is_compound()) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001806 AccumulatorValueContext result_context(this);
1807 { AccumulatorValueContext left_operand_context(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001808 switch (assign_type) {
1809 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001810 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001811 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001812 break;
1813 case NAMED_PROPERTY:
1814 EmitNamedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001815 PrepareForBailoutForId(property->LoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001816 break;
1817 case KEYED_PROPERTY:
1818 EmitKeyedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001819 PrepareForBailoutForId(property->LoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001820 break;
1821 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001822 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001823
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001824 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001825 __ push(eax); // Left operand goes on the stack.
1826 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001827
ricow@chromium.org65fae842010-08-25 15:26:24 +00001828 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1829 ? OVERWRITE_RIGHT
1830 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001831 SetSourcePosition(expr->position() + 1);
1832 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001833 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001834 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001835 mode,
1836 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001837 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001838 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001839 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001840 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001841
1842 // Deoptimization point in case the binary operation may have side effects.
1843 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001844 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001845 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001846 }
1847
1848 // Record source position before possible IC call.
1849 SetSourcePosition(expr->position());
1850
1851 // Store the value.
1852 switch (assign_type) {
1853 case VARIABLE:
1854 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001855 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001856 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1857 context()->Plug(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001858 break;
1859 case NAMED_PROPERTY:
1860 EmitNamedPropertyAssignment(expr);
1861 break;
1862 case KEYED_PROPERTY:
1863 EmitKeyedPropertyAssignment(expr);
1864 break;
1865 }
1866}
1867
1868
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001869void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1870 SetSourcePosition(prop->position());
1871 Literal* key = prop->key()->AsLiteral();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001872 ASSERT(!key->handle()->IsSmi());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001873 __ mov(ecx, Immediate(key->handle()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001874 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001875 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001876}
1877
1878
1879void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1880 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001881 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001882 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001883}
1884
1885
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001886void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001887 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001888 OverwriteMode mode,
1889 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001890 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001891 // Do combined smi check of the operands. Left operand is on the
1892 // stack. Right operand is in eax.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001893 Label smi_case, done, stub_call;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001894 __ pop(edx);
1895 __ mov(ecx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001896 __ or_(eax, edx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001897 JumpPatchSite patch_site(masm_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001898 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001899
1900 __ bind(&stub_call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001901 __ mov(eax, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001902 BinaryOpStub stub(op, mode);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001903 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET,
1904 expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001905 patch_site.EmitPatchInfo();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001906 __ jmp(&done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001907
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001908 // Smi case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001909 __ bind(&smi_case);
1910 __ mov(eax, edx); // Copy left operand in case of a stub call.
1911
1912 switch (op) {
1913 case Token::SAR:
1914 __ SmiUntag(eax);
1915 __ SmiUntag(ecx);
1916 __ sar_cl(eax); // No checks of result necessary
1917 __ SmiTag(eax);
1918 break;
1919 case Token::SHL: {
1920 Label result_ok;
1921 __ SmiUntag(eax);
1922 __ SmiUntag(ecx);
1923 __ shl_cl(eax);
1924 // Check that the *signed* result fits in a smi.
1925 __ cmp(eax, 0xc0000000);
1926 __ j(positive, &result_ok);
1927 __ SmiTag(ecx);
1928 __ jmp(&stub_call);
1929 __ bind(&result_ok);
1930 __ SmiTag(eax);
1931 break;
1932 }
1933 case Token::SHR: {
1934 Label result_ok;
1935 __ SmiUntag(eax);
1936 __ SmiUntag(ecx);
1937 __ shr_cl(eax);
1938 __ test(eax, Immediate(0xc0000000));
1939 __ j(zero, &result_ok);
1940 __ SmiTag(ecx);
1941 __ jmp(&stub_call);
1942 __ bind(&result_ok);
1943 __ SmiTag(eax);
1944 break;
1945 }
1946 case Token::ADD:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001947 __ add(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001948 __ j(overflow, &stub_call);
1949 break;
1950 case Token::SUB:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001951 __ sub(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001952 __ j(overflow, &stub_call);
1953 break;
1954 case Token::MUL: {
1955 __ SmiUntag(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001956 __ imul(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001957 __ j(overflow, &stub_call);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001958 __ test(eax, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001959 __ j(not_zero, &done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001960 __ mov(ebx, edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001961 __ or_(ebx, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001962 __ j(negative, &stub_call);
1963 break;
1964 }
1965 case Token::BIT_OR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001966 __ or_(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001967 break;
1968 case Token::BIT_AND:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001969 __ and_(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001970 break;
1971 case Token::BIT_XOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001972 __ xor_(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001973 break;
1974 default:
1975 UNREACHABLE();
1976 }
1977
1978 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001979 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001980}
1981
1982
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001983void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1984 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001985 OverwriteMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001986 __ pop(edx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001987 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001988 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001989 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET,
1990 expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001991 patch_site.EmitPatchInfo();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001992 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001993}
1994
1995
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001996void FullCodeGenerator::EmitAssignment(Expression* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001997 // Invalid left-hand sides are rewritten to have a 'throw
1998 // ReferenceError' on the left-hand side.
1999 if (!expr->IsValidLeftHandSide()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002000 VisitForEffect(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002001 return;
2002 }
2003
2004 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00002005 // slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002006 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2007 LhsKind assign_type = VARIABLE;
2008 Property* prop = expr->AsProperty();
2009 if (prop != NULL) {
2010 assign_type = (prop->key()->IsPropertyName())
2011 ? NAMED_PROPERTY
2012 : KEYED_PROPERTY;
2013 }
2014
2015 switch (assign_type) {
2016 case VARIABLE: {
2017 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002018 EffectContext context(this);
2019 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002020 break;
2021 }
2022 case NAMED_PROPERTY: {
2023 __ push(eax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002024 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002025 __ mov(edx, eax);
2026 __ pop(eax); // Restore value.
2027 __ mov(ecx, prop->key()->AsLiteral()->handle());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002028 Handle<Code> ic = is_classic_mode()
2029 ? isolate()->builtins()->StoreIC_Initialize()
2030 : isolate()->builtins()->StoreIC_Initialize_Strict();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002031 CallIC(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002032 break;
2033 }
2034 case KEYED_PROPERTY: {
2035 __ push(eax); // Preserve value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002036 VisitForStackValue(prop->obj());
2037 VisitForAccumulatorValue(prop->key());
2038 __ mov(ecx, eax);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002039 __ pop(edx); // Receiver.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002040 __ pop(eax); // Restore value.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002041 Handle<Code> ic = is_classic_mode()
2042 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2043 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002044 CallIC(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002045 break;
2046 }
2047 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002048 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002049}
2050
2051
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002052void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002053 Token::Value op) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002054 if (var->IsUnallocated()) {
2055 // Global var, const, or let.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002056 __ mov(ecx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002057 __ mov(edx, GlobalObjectOperand());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002058 Handle<Code> ic = is_classic_mode()
2059 ? isolate()->builtins()->StoreIC_Initialize()
2060 : isolate()->builtins()->StoreIC_Initialize_Strict();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002061 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002062
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002063 } else if (op == Token::INIT_CONST) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002064 // Const initializers need a write barrier.
2065 ASSERT(!var->IsParameter()); // No const parameters.
2066 if (var->IsStackLocal()) {
2067 Label skip;
2068 __ mov(edx, StackOperand(var));
2069 __ cmp(edx, isolate()->factory()->the_hole_value());
2070 __ j(not_equal, &skip);
2071 __ mov(StackOperand(var), eax);
2072 __ bind(&skip);
2073 } else {
2074 ASSERT(var->IsContextSlot() || var->IsLookupSlot());
2075 // Like var declarations, const declarations are hoisted to function
2076 // scope. However, unlike var initializers, const initializers are
2077 // able to drill a hole to that function context, even from inside a
2078 // 'with' context. We thus bypass the normal static scope lookup for
2079 // var->IsContextSlot().
2080 __ push(eax);
2081 __ push(esi);
2082 __ push(Immediate(var->name()));
2083 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002084 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002085
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002086 } else if (var->mode() == LET && op != Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002087 // Non-initializing assignment to let variable needs a write barrier.
2088 if (var->IsLookupSlot()) {
2089 __ push(eax); // Value.
2090 __ push(esi); // Context.
2091 __ push(Immediate(var->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002092 __ push(Immediate(Smi::FromInt(language_mode())));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002093 __ CallRuntime(Runtime::kStoreContextSlot, 4);
2094 } else {
2095 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
2096 Label assign;
2097 MemOperand location = VarOperand(var, ecx);
2098 __ mov(edx, location);
2099 __ cmp(edx, isolate()->factory()->the_hole_value());
2100 __ j(not_equal, &assign, Label::kNear);
2101 __ push(Immediate(var->name()));
2102 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2103 __ bind(&assign);
2104 __ mov(location, eax);
2105 if (var->IsContextSlot()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002106 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002107 int offset = Context::SlotOffset(var->index());
2108 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002109 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002110 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002111
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002112 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
2113 // Assignment to var or initializing assignment to let/const
2114 // in harmony mode.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002115 if (var->IsStackAllocated() || var->IsContextSlot()) {
2116 MemOperand location = VarOperand(var, ecx);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002117 if (generate_debug_code_ && op == Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002118 // Check for an uninitialized let binding.
2119 __ mov(edx, location);
2120 __ cmp(edx, isolate()->factory()->the_hole_value());
2121 __ Check(equal, "Let binding re-initialization.");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002122 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002123 // Perform the assignment.
2124 __ mov(location, eax);
2125 if (var->IsContextSlot()) {
2126 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002127 int offset = Context::SlotOffset(var->index());
2128 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002129 }
2130 } else {
2131 ASSERT(var->IsLookupSlot());
2132 __ push(eax); // Value.
2133 __ push(esi); // Context.
2134 __ push(Immediate(var->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002135 __ push(Immediate(Smi::FromInt(language_mode())));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002136 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002137 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002138 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002139 // Non-initializing assignments to consts are ignored.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002140}
2141
2142
2143void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2144 // Assignment to a property, using a named store IC.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002145 // eax : value
2146 // esp[0] : receiver
2147
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002148 Property* prop = expr->target()->AsProperty();
2149 ASSERT(prop != NULL);
2150 ASSERT(prop->key()->AsLiteral() != NULL);
2151
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002152 // Record source code position before IC call.
2153 SetSourcePosition(expr->position());
2154 __ mov(ecx, prop->key()->AsLiteral()->handle());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002155 __ pop(edx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002156 Handle<Code> ic = is_classic_mode()
2157 ? isolate()->builtins()->StoreIC_Initialize()
2158 : isolate()->builtins()->StoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002159 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002160
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002161 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2162 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002163}
2164
2165
2166void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2167 // Assignment to a property, using a keyed store IC.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002168 // eax : value
2169 // esp[0] : key
2170 // esp[kPointerSize] : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002171
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002172 __ pop(ecx); // Key.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002173 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002174 // Record source code position before IC call.
2175 SetSourcePosition(expr->position());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002176 Handle<Code> ic = is_classic_mode()
2177 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2178 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002179 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002181 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002182 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002183}
2184
2185
2186void FullCodeGenerator::VisitProperty(Property* expr) {
2187 Comment cmnt(masm_, "[ Property");
2188 Expression* key = expr->key();
2189
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002190 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002191 VisitForAccumulatorValue(expr->obj());
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002192 __ mov(edx, result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002193 EmitNamedPropertyLoad(expr);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002194 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002195 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002196 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002197 VisitForStackValue(expr->obj());
2198 VisitForAccumulatorValue(expr->key());
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002199 __ pop(edx); // Object.
2200 __ mov(ecx, result_register()); // Key.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002201 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002202 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002203 }
2204}
2205
2206
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002207void FullCodeGenerator::CallIC(Handle<Code> code,
2208 RelocInfo::Mode rmode,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002209 TypeFeedbackId ast_id) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002210 ic_total_count_++;
2211 __ call(code, rmode, ast_id);
2212}
2213
2214
2215
2216
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002217void FullCodeGenerator::EmitCallWithIC(Call* expr,
2218 Handle<Object> name,
2219 RelocInfo::Mode mode) {
2220 // Code common for calls using the IC.
2221 ZoneList<Expression*>* args = expr->arguments();
2222 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002223 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002224 for (int i = 0; i < arg_count; i++) {
2225 VisitForStackValue(args->at(i));
2226 }
2227 __ Set(ecx, Immediate(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002228 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002229 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002230 SetSourcePosition(expr->position());
danno@chromium.org40cb8782011-05-25 07:58:50 +00002231 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002232 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002233 CallIC(ic, mode, expr->CallFeedbackId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002234 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002235 // Restore context register.
2236 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002237 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002238}
2239
2240
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002242 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002243 // Load the key.
2244 VisitForAccumulatorValue(key);
2245
2246 // Swap the name of the function and the receiver on the stack to follow
2247 // the calling convention for call ICs.
2248 __ pop(ecx);
2249 __ push(eax);
2250 __ push(ecx);
2251
2252 // Load the arguments.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002253 ZoneList<Expression*>* args = expr->arguments();
2254 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002255 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002256 for (int i = 0; i < arg_count; i++) {
2257 VisitForStackValue(args->at(i));
2258 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002259 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002260 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002261 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002262 Handle<Code> ic =
2263 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002264 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002265 CallIC(ic, RelocInfo::CODE_TARGET, expr->CallFeedbackId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002266 RecordJSReturnSite(expr);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002267 // Restore context register.
2268 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002269 context()->DropAndPlug(1, eax); // Drop the key still on the stack.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002270}
2271
2272
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002273void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002274 // Code common for calls using the call stub.
2275 ZoneList<Expression*>* args = expr->arguments();
2276 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002277 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002278 for (int i = 0; i < arg_count; i++) {
2279 VisitForStackValue(args->at(i));
2280 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002281 }
2282 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002283 SetSourcePosition(expr->position());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002284
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002285 // Record call targets in unoptimized code.
2286 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
2287 Handle<Object> uninitialized =
2288 TypeFeedbackCells::UninitializedSentinel(isolate());
2289 Handle<JSGlobalPropertyCell> cell =
2290 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002291 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002292 __ mov(ebx, cell);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002293
lrn@chromium.org34e60782011-09-15 07:25:40 +00002294 CallFunctionStub stub(arg_count, flags);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002295 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002296 __ CallStub(&stub, expr->CallFeedbackId());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002297
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002298 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002299 // Restore context register.
2300 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002301 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002302}
2303
2304
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002305void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002306 // Push copy of the first argument or undefined if it doesn't exist.
2307 if (arg_count > 0) {
2308 __ push(Operand(esp, arg_count * kPointerSize));
2309 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002310 __ push(Immediate(isolate()->factory()->undefined_value()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002311 }
2312
2313 // Push the receiver of the enclosing function.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002314 __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002315 // Push the language mode.
2316 __ push(Immediate(Smi::FromInt(language_mode())));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002317
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002318 // Push the start position of the scope the calls resides in.
2319 __ push(Immediate(Smi::FromInt(scope()->start_position())));
2320
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002321 // Do the runtime call.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002322 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002323}
2324
2325
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002326void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002327#ifdef DEBUG
2328 // We want to verify that RecordJSReturnSite gets called on all paths
2329 // through this function. Avoid early returns.
2330 expr->return_is_recorded_ = false;
2331#endif
2332
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002333 Comment cmnt(masm_, "[ Call");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002334 Expression* callee = expr->expression();
2335 VariableProxy* proxy = callee->AsVariableProxy();
2336 Property* property = callee->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002337
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002338 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002339 // In a call to eval, we first call %ResolvePossiblyDirectEval to
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002340 // resolve the function we need to call and the receiver of the call.
2341 // Then we call the resolved function using the given arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002342 ZoneList<Expression*>* args = expr->arguments();
2343 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002344 { PreservePositionScope pos_scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002345 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002346 // Reserved receiver slot.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002347 __ push(Immediate(isolate()->factory()->undefined_value()));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002348 // Push the arguments.
2349 for (int i = 0; i < arg_count; i++) {
2350 VisitForStackValue(args->at(i));
2351 }
2352
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002353 // Push a copy of the function (found below the arguments) and
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002354 // resolve eval.
2355 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002356 EmitResolvePossiblyDirectEval(arg_count);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002357
2358 // The runtime call returns a pair of values in eax (function) and
2359 // edx (receiver). Touch up the stack with the right values.
2360 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2361 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002362 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002363 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002364 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002365 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002366 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002367 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002368 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002369 // Restore context register.
2370 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002371 context()->DropAndPlug(1, eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002372
2373 } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002374 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002375 __ push(GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002376 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
2377
2378 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002379 // Call to a lookup slot (dynamically introduced variable).
2380 Label slow, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002381 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002382 // Generate code for loading from variables potentially shadowed by
2383 // eval-introduced variables.
2384 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002385 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002386 __ bind(&slow);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002387 // Call the runtime to find the function to call (returned in eax) and
2388 // the object holding it (returned in edx).
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002389 __ push(context_register());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002390 __ push(Immediate(proxy->name()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002391 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2392 __ push(eax); // Function.
2393 __ push(edx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002394
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002395 // If fast case code has been generated, emit code to push the function
2396 // and receiver and have the slow path jump around this code.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002397 if (done.is_linked()) {
2398 Label call;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002399 __ jmp(&call, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002400 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002401 // Push function.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002402 __ push(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002403 // The receiver is implicitly the global receiver. Indicate this by
2404 // passing the hole to the call function stub.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002405 __ push(Immediate(isolate()->factory()->the_hole_value()));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002406 __ bind(&call);
2407 }
2408
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002409 // The receiver is either the global receiver or an object found by
2410 // LoadContextSlot. That object could be the hole if the receiver is
2411 // implicitly the global object.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002412 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002413
2414 } else if (property != NULL) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002415 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002416 VisitForStackValue(property->obj());
2417 }
2418 if (property->key()->IsPropertyName()) {
2419 EmitCallWithIC(expr,
2420 property->key()->AsLiteral()->handle(),
2421 RelocInfo::CODE_TARGET);
2422 } else {
2423 EmitKeyedCallWithIC(expr, property->key());
2424 }
2425
2426 } else {
2427 // Call to an arbitrary expression not handled specially above.
2428 { PreservePositionScope scope(masm()->positions_recorder());
2429 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002430 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002431 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002432 __ mov(ebx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002433 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2434 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002435 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002436 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002437
2438#ifdef DEBUG
2439 // RecordJSReturnSite should have been called.
2440 ASSERT(expr->return_is_recorded_);
2441#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002442}
2443
2444
2445void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2446 Comment cmnt(masm_, "[ CallNew");
2447 // According to ECMA-262, section 11.2.2, page 44, the function
2448 // expression in new calls must be evaluated before the
2449 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002450
ricow@chromium.org65fae842010-08-25 15:26:24 +00002451 // Push constructor on the stack. If it's not a function it's used as
2452 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2453 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002454 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002455
2456 // Push the arguments ("left-to-right") on the stack.
2457 ZoneList<Expression*>* args = expr->arguments();
2458 int arg_count = args->length();
2459 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002460 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002461 }
2462
2463 // Call the construct call builtin that handles allocation and
2464 // constructor invocation.
2465 SetSourcePosition(expr->position());
2466
ricow@chromium.org65fae842010-08-25 15:26:24 +00002467 // Load function and argument count into edi and eax.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002468 __ Set(eax, Immediate(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002469 __ mov(edi, Operand(esp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002470
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002471 // Record call targets in unoptimized code.
2472 Handle<Object> uninitialized =
2473 TypeFeedbackCells::UninitializedSentinel(isolate());
2474 Handle<JSGlobalPropertyCell> cell =
2475 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002476 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002477 __ mov(ebx, cell);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002478
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002479 CallConstructStub stub(RECORD_CALL_TARGET);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002480 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
ulan@chromium.org967e2702012-02-28 09:49:15 +00002481 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002482 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002483}
2484
2485
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002486void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2487 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002488 ASSERT(args->length() == 1);
2489
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002490 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002491
2492 Label materialize_true, materialize_false;
2493 Label* if_true = NULL;
2494 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002495 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002496 context()->PrepareTest(&materialize_true, &materialize_false,
2497 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002498
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002499 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002500 __ test(eax, Immediate(kSmiTagMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002501 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002502
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002503 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002504}
2505
2506
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002507void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2508 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002509 ASSERT(args->length() == 1);
2510
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002511 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002512
2513 Label materialize_true, materialize_false;
2514 Label* if_true = NULL;
2515 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002516 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002517 context()->PrepareTest(&materialize_true, &materialize_false,
2518 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002519
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002520 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002521 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002522 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002523
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002524 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002525}
2526
2527
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002528void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2529 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002530 ASSERT(args->length() == 1);
2531
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002532 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002533
2534 Label materialize_true, materialize_false;
2535 Label* if_true = NULL;
2536 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002537 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002538 context()->PrepareTest(&materialize_true, &materialize_false,
2539 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002540
whesse@chromium.org7b260152011-06-20 15:33:18 +00002541 __ JumpIfSmi(eax, if_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002542 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002543 __ j(equal, if_true);
2544 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2545 // Undetectable objects behave like undefined when tested with typeof.
2546 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2547 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2548 __ j(not_zero, if_false);
2549 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002550 __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002551 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002552 __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002553 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002554 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002555
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002556 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002557}
2558
2559
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002560void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2561 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002562 ASSERT(args->length() == 1);
2563
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002564 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002565
2566 Label materialize_true, materialize_false;
2567 Label* if_true = NULL;
2568 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002569 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002570 context()->PrepareTest(&materialize_true, &materialize_false,
2571 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002572
whesse@chromium.org7b260152011-06-20 15:33:18 +00002573 __ JumpIfSmi(eax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002574 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002575 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002576 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002577
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002578 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002579}
2580
2581
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002582void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2583 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002584 ASSERT(args->length() == 1);
2585
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002586 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002587
2588 Label materialize_true, materialize_false;
2589 Label* if_true = NULL;
2590 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002591 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002592 context()->PrepareTest(&materialize_true, &materialize_false,
2593 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002594
whesse@chromium.org7b260152011-06-20 15:33:18 +00002595 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002596 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2597 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2598 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002599 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002600 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002601
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002602 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002603}
2604
2605
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002606void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002607 CallRuntime* expr) {
2608 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002609 ASSERT(args->length() == 1);
2610
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002611 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002612
2613 Label materialize_true, materialize_false;
2614 Label* if_true = NULL;
2615 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002616 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002617 context()->PrepareTest(&materialize_true, &materialize_false,
2618 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002619
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002620 __ AssertNotSmi(eax);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002621
2622 // Check whether this map has already been checked to be safe for default
2623 // valueOf.
2624 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2625 __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
2626 1 << Map::kStringWrapperSafeForDefaultValueOf);
2627 __ j(not_zero, if_true);
2628
2629 // Check for fast case object. Return false for slow case objects.
2630 __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
2631 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2632 __ cmp(ecx, FACTORY->hash_table_map());
2633 __ j(equal, if_false);
2634
2635 // Look for valueOf symbol in the descriptor array, and indicate false if
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002636 // found. Since we omit an enumeration index check, if it is added via a
2637 // transition that shares its descriptor array, this is a false positive.
2638 Label entry, loop, done;
2639
2640 // Skip loop if no descriptors are valid.
2641 __ NumberOfOwnDescriptors(ecx, ebx);
2642 __ cmp(ecx, 0);
2643 __ j(equal, &done);
2644
danno@chromium.org40cb8782011-05-25 07:58:50 +00002645 __ LoadInstanceDescriptors(ebx, ebx);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002646 // ebx: descriptor array.
2647 // ecx: valid entries in the descriptor array.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002648 // Calculate the end of the descriptor array.
2649 STATIC_ASSERT(kSmiTag == 0);
2650 STATIC_ASSERT(kSmiTagSize == 1);
2651 STATIC_ASSERT(kPointerSize == 4);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002652 __ imul(ecx, ecx, DescriptorArray::kDescriptorSize);
2653 __ lea(ecx, Operand(ebx, ecx, times_2, DescriptorArray::kFirstOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002654 // Calculate location of the first key name.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002655 __ add(ebx, Immediate(DescriptorArray::kFirstOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002656 // Loop through all the keys in the descriptor array. If one of these is the
2657 // symbol valueOf the result is false.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002658 __ jmp(&entry);
2659 __ bind(&loop);
2660 __ mov(edx, FieldOperand(ebx, 0));
2661 __ cmp(edx, FACTORY->value_of_symbol());
2662 __ j(equal, if_false);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002663 __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002664 __ bind(&entry);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002665 __ cmp(ebx, ecx);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002666 __ j(not_equal, &loop);
2667
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002668 __ bind(&done);
2669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002670 // Reload map as register ebx was used as temporary above.
2671 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2672
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002673 // If a valueOf property is not found on the object check that its
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002674 // prototype is the un-modified String prototype. If not result is false.
2675 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002676 __ JumpIfSmi(ecx, if_false);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002677 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002678 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002679 __ mov(edx,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002680 FieldOperand(edx, GlobalObject::kNativeContextOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002681 __ cmp(ecx,
2682 ContextOperand(edx,
2683 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2684 __ j(not_equal, if_false);
2685 // Set the bit in the map to indicate that it has been checked safe for
2686 // default valueOf and set true result.
2687 __ or_(FieldOperand(ebx, Map::kBitField2Offset),
2688 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2689 __ jmp(if_true);
2690
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002691 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002692 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002693}
2694
2695
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002696void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
2697 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002698 ASSERT(args->length() == 1);
2699
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002700 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002701
2702 Label materialize_true, materialize_false;
2703 Label* if_true = NULL;
2704 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002705 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002706 context()->PrepareTest(&materialize_true, &materialize_false,
2707 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002708
whesse@chromium.org7b260152011-06-20 15:33:18 +00002709 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002710 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002711 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002712 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002713
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002714 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002715}
2716
2717
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002718void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2719 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002720 ASSERT(args->length() == 1);
2721
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002722 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002723
2724 Label materialize_true, materialize_false;
2725 Label* if_true = NULL;
2726 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002727 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002728 context()->PrepareTest(&materialize_true, &materialize_false,
2729 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002730
whesse@chromium.org7b260152011-06-20 15:33:18 +00002731 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002732 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002733 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002734 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002735
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002736 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002737}
2738
2739
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002740void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2741 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002742 ASSERT(args->length() == 1);
2743
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002744 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002745
2746 Label materialize_true, materialize_false;
2747 Label* if_true = NULL;
2748 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002749 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002750 context()->PrepareTest(&materialize_true, &materialize_false,
2751 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002752
whesse@chromium.org7b260152011-06-20 15:33:18 +00002753 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002754 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002755 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002756 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002757
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002758 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002759}
2760
2761
2762
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002763void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
2764 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002765
2766 Label materialize_true, materialize_false;
2767 Label* if_true = NULL;
2768 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002769 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002770 context()->PrepareTest(&materialize_true, &materialize_false,
2771 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002772
2773 // Get the frame pointer for the calling frame.
2774 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2775
2776 // Skip the arguments adaptor frame if it exists.
2777 Label check_frame_marker;
2778 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2779 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2780 __ j(not_equal, &check_frame_marker);
2781 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2782
2783 // Check the marker in the calling frame.
2784 __ bind(&check_frame_marker);
2785 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2786 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002787 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002788 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002789
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002790 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002791}
2792
2793
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002794void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
2795 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002796 ASSERT(args->length() == 2);
2797
2798 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002799 VisitForStackValue(args->at(0));
2800 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002801
2802 Label materialize_true, materialize_false;
2803 Label* if_true = NULL;
2804 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002805 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002806 context()->PrepareTest(&materialize_true, &materialize_false,
2807 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002808
2809 __ pop(ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002810 __ cmp(eax, ebx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002811 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002812 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002813
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002814 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002815}
2816
2817
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002818void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
2819 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002820 ASSERT(args->length() == 1);
2821
2822 // ArgumentsAccessStub expects the key in edx and the formal
2823 // parameter count in eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002824 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002825 __ mov(edx, eax);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002826 __ Set(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002827 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2828 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002829 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002830}
2831
2832
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002833void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
2834 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002835
2836 Label exit;
2837 // Get the number of formal parameters.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002838 __ Set(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002839
2840 // Check if the calling frame is an arguments adaptor frame.
2841 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2842 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2843 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2844 __ j(not_equal, &exit);
2845
2846 // Arguments adaptor case: Read the arguments length from the
2847 // adaptor frame.
2848 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2849
2850 __ bind(&exit);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002851 __ AssertSmi(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002852 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002853}
2854
2855
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002856void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2857 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002858 ASSERT(args->length() == 1);
2859 Label done, null, function, non_function_constructor;
2860
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002861 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002862
2863 // If the object is a smi, we return null.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002864 __ JumpIfSmi(eax, &null);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002865
2866 // Check that the object is a JS object but take special care of JS
2867 // functions to make sure they have 'Function' as their class.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002868 // Assume that there are only two callable types, and one of them is at
2869 // either end of the type range for JS object types. Saves extra comparisons.
2870 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002871 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
2872 // Map is now in eax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002873 __ j(below, &null);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002874 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2875 FIRST_SPEC_OBJECT_TYPE + 1);
2876 __ j(equal, &function);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002877
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002878 __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
2879 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2880 LAST_SPEC_OBJECT_TYPE - 1);
2881 __ j(equal, &function);
2882 // Assume that there is no larger type.
2883 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002884
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002885 // Check if the constructor in the map is a JS function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002886 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2887 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2888 __ j(not_equal, &non_function_constructor);
2889
2890 // eax now contains the constructor function. Grab the
2891 // instance class name from there.
2892 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2893 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2894 __ jmp(&done);
2895
2896 // Functions have class 'Function'.
2897 __ bind(&function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002898 __ mov(eax, isolate()->factory()->function_class_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002899 __ jmp(&done);
2900
2901 // Objects with a non-function constructor have class 'Object'.
2902 __ bind(&non_function_constructor);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002903 __ mov(eax, isolate()->factory()->Object_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002904 __ jmp(&done);
2905
2906 // Non-JS objects have class null.
2907 __ bind(&null);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002908 __ mov(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002909
2910 // All done.
2911 __ bind(&done);
2912
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002913 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002914}
2915
2916
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002917void FullCodeGenerator::EmitLog(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002918 // Conditionally generate a log call.
2919 // Args:
2920 // 0 (literal string): The type of logging (corresponds to the flags).
2921 // This is used to determine whether or not to generate the log call.
2922 // 1 (string): Format string. Access the string at argument index 2
2923 // with '%2s' (see Logger::LogRuntime for all the formats).
2924 // 2 (array): Arguments to the format string.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002925 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002926 ASSERT_EQ(args->length(), 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002927 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002928 VisitForStackValue(args->at(1));
2929 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002930 __ CallRuntime(Runtime::kLog, 2);
2931 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002932 // Finally, we're expected to leave a value on the top of the stack.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002933 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002934 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002935}
2936
2937
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002938void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
2939 ASSERT(expr->arguments()->length() == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002940
2941 Label slow_allocate_heapnumber;
2942 Label heapnumber_allocated;
2943
2944 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2945 __ jmp(&heapnumber_allocated);
2946
2947 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002948 // Allocate a heap number.
2949 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002950 __ mov(edi, eax);
2951
2952 __ bind(&heapnumber_allocated);
2953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002954 __ PrepareCallCFunction(1, ebx);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002955 __ mov(eax, ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
2956 __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002957 __ mov(Operand(esp, 0), eax);
2958 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002959
2960 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2961 // by computing:
2962 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2963 // This is implemented on both SSE2 and FPU.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002964 if (CpuFeatures::IsSupported(SSE2)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002965 CpuFeatures::Scope fscope(SSE2);
2966 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002967 __ movd(xmm1, ebx);
2968 __ movd(xmm0, eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002969 __ cvtss2sd(xmm1, xmm1);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002970 __ xorps(xmm0, xmm1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002971 __ subsd(xmm0, xmm1);
2972 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2973 } else {
2974 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2975 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2976 Immediate(0x41300000));
2977 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2978 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2979 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2980 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2981 __ fsubp(1);
2982 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2983 }
2984 __ mov(eax, edi);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002985 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002986}
2987
2988
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002989void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002990 // Load the arguments on the stack and call the stub.
2991 SubStringStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002992 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002993 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002994 VisitForStackValue(args->at(0));
2995 VisitForStackValue(args->at(1));
2996 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002997 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002998 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002999}
3000
3001
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003002void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003003 // Load the arguments on the stack and call the stub.
3004 RegExpExecStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003005 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003006 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003007 VisitForStackValue(args->at(0));
3008 VisitForStackValue(args->at(1));
3009 VisitForStackValue(args->at(2));
3010 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003011 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003012 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003013}
3014
3015
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003016void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3017 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003018 ASSERT(args->length() == 1);
3019
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003020 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003021
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003022 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003023 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003024 __ JumpIfSmi(eax, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003025 // If the object is not a value type, return the object.
3026 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003027 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003028 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
3029
3030 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003031 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003032}
3033
3034
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003035void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3036 ZoneList<Expression*>* args = expr->arguments();
3037 ASSERT(args->length() == 2);
3038 ASSERT_NE(NULL, args->at(1)->AsLiteral());
3039 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->handle()));
3040
3041 VisitForAccumulatorValue(args->at(0)); // Load the object.
3042
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003043 Label runtime, done, not_date_object;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003044 Register object = eax;
3045 Register result = eax;
3046 Register scratch = ecx;
3047
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003048 __ JumpIfSmi(object, &not_date_object);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003049 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003050 __ j(not_equal, &not_date_object);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003051
3052 if (index->value() == 0) {
3053 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003054 __ jmp(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003055 } else {
3056 if (index->value() < JSDate::kFirstUncachedField) {
3057 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3058 __ mov(scratch, Operand::StaticVariable(stamp));
3059 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
3060 __ j(not_equal, &runtime, Label::kNear);
3061 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
3062 kPointerSize * index->value()));
3063 __ jmp(&done);
3064 }
3065 __ bind(&runtime);
3066 __ PrepareCallCFunction(2, scratch);
3067 __ mov(Operand(esp, 0), object);
3068 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
3069 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003070 __ jmp(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003071 }
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003072
3073 __ bind(&not_date_object);
3074 __ CallRuntime(Runtime::kThrowNotDateError, 0);
3075 __ bind(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003076 context()->Plug(result);
3077}
3078
3079
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003080void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003081 // Load the arguments on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003082 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003083 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003084 VisitForStackValue(args->at(0));
3085 VisitForStackValue(args->at(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003087 if (CpuFeatures::IsSupported(SSE2)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003088 MathPowStub stub(MathPowStub::ON_STACK);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003089 __ CallStub(&stub);
3090 } else {
3091 __ CallRuntime(Runtime::kMath_pow, 2);
3092 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003093 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003094}
3095
3096
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003097void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3098 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003099 ASSERT(args->length() == 2);
3100
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003101 VisitForStackValue(args->at(0)); // Load the object.
3102 VisitForAccumulatorValue(args->at(1)); // Load the value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003103 __ pop(ebx); // eax = value. ebx = object.
3104
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003105 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003106 // If the object is a smi, return the value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003107 __ JumpIfSmi(ebx, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003108
3109 // If the object is not a value type, return the value.
3110 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003111 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003112
3113 // Store the value.
3114 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003115
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003116 // Update the write barrier. Save the value as it will be
3117 // overwritten by the write barrier code and is needed afterward.
3118 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003119 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003120
3121 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003122 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003123}
3124
3125
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003126void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3127 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003128 ASSERT_EQ(args->length(), 1);
3129
3130 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003131 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003132
3133 NumberToStringStub stub;
3134 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003135 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003136}
3137
3138
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003139void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3140 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003141 ASSERT(args->length() == 1);
3142
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003143 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003144
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003145 Label done;
3146 StringCharFromCodeGenerator generator(eax, ebx);
3147 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003148 __ jmp(&done);
3149
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003150 NopRuntimeCallHelper call_helper;
3151 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003152
3153 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003154 context()->Plug(ebx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003155}
3156
3157
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003158void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3159 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003160 ASSERT(args->length() == 2);
3161
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003162 VisitForStackValue(args->at(0));
3163 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003164
3165 Register object = ebx;
3166 Register index = eax;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003167 Register result = edx;
3168
3169 __ pop(object);
3170
3171 Label need_conversion;
3172 Label index_out_of_range;
3173 Label done;
3174 StringCharCodeAtGenerator generator(object,
3175 index,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003176 result,
3177 &need_conversion,
3178 &need_conversion,
3179 &index_out_of_range,
3180 STRING_INDEX_IS_NUMBER);
3181 generator.GenerateFast(masm_);
3182 __ jmp(&done);
3183
3184 __ bind(&index_out_of_range);
3185 // When the index is out of range, the spec requires us to return
3186 // NaN.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003187 __ Set(result, Immediate(isolate()->factory()->nan_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003188 __ jmp(&done);
3189
3190 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003191 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003192 // trigger conversion.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003193 __ Set(result, Immediate(isolate()->factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003194 __ jmp(&done);
3195
3196 NopRuntimeCallHelper call_helper;
3197 generator.GenerateSlow(masm_, call_helper);
3198
3199 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003200 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003201}
3202
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003203
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003204void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3205 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003206 ASSERT(args->length() == 2);
3207
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003208 VisitForStackValue(args->at(0));
3209 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003210
3211 Register object = ebx;
3212 Register index = eax;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003213 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003214 Register result = eax;
3215
3216 __ pop(object);
3217
3218 Label need_conversion;
3219 Label index_out_of_range;
3220 Label done;
3221 StringCharAtGenerator generator(object,
3222 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00003223 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003224 result,
3225 &need_conversion,
3226 &need_conversion,
3227 &index_out_of_range,
3228 STRING_INDEX_IS_NUMBER);
3229 generator.GenerateFast(masm_);
3230 __ jmp(&done);
3231
3232 __ bind(&index_out_of_range);
3233 // When the index is out of range, the spec requires us to return
3234 // the empty string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003235 __ Set(result, Immediate(isolate()->factory()->empty_string()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003236 __ jmp(&done);
3237
3238 __ bind(&need_conversion);
3239 // Move smi zero into the result register, which will trigger
3240 // conversion.
3241 __ Set(result, Immediate(Smi::FromInt(0)));
3242 __ jmp(&done);
3243
3244 NopRuntimeCallHelper call_helper;
3245 generator.GenerateSlow(masm_, call_helper);
3246
3247 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003248 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003249}
3250
3251
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003252void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3253 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003254 ASSERT_EQ(2, args->length());
3255
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003256 VisitForStackValue(args->at(0));
3257 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003258
3259 StringAddStub stub(NO_STRING_ADD_FLAGS);
3260 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003261 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003262}
3263
3264
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003265void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3266 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003267 ASSERT_EQ(2, args->length());
3268
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003269 VisitForStackValue(args->at(0));
3270 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003271
3272 StringCompareStub stub;
3273 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003274 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003275}
3276
3277
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003278void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003279 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003280 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3281 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003282 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003283 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003284 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003285 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003286 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003287}
3288
3289
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003290void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003291 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003292 TranscendentalCacheStub stub(TranscendentalCache::COS,
3293 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003294 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003295 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003296 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003297 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003298 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003299}
3300
3301
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003302void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
3303 // Load the argument on the stack and call the stub.
3304 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3305 TranscendentalCacheStub::TAGGED);
3306 ZoneList<Expression*>* args = expr->arguments();
3307 ASSERT(args->length() == 1);
3308 VisitForStackValue(args->at(0));
3309 __ CallStub(&stub);
3310 context()->Plug(eax);
3311}
3312
3313
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003314void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003315 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003316 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3317 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003318 ZoneList<Expression*>* args = expr->arguments();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003319 ASSERT(args->length() == 1);
3320 VisitForStackValue(args->at(0));
3321 __ CallStub(&stub);
3322 context()->Plug(eax);
3323}
3324
3325
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003326void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003327 // Load the argument on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003328 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003329 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003330 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003331 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003332 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003333}
3334
3335
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003336void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3337 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003338 ASSERT(args->length() >= 2);
3339
danno@chromium.org160a7b02011-04-18 15:51:38 +00003340 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3341 for (int i = 0; i < arg_count + 1; ++i) {
3342 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003343 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003344 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003345
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003346 Label runtime, done;
3347 // Check for non-function argument (including proxy).
3348 __ JumpIfSmi(eax, &runtime);
3349 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
3350 __ j(not_equal, &runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003351
danno@chromium.org160a7b02011-04-18 15:51:38 +00003352 // InvokeFunction requires the function in edi. Move it in there.
3353 __ mov(edi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003354 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003355 __ InvokeFunction(edi, count, CALL_FUNCTION,
3356 NullCallWrapper(), CALL_AS_METHOD);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003357 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003358 __ jmp(&done);
3359
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003360 __ bind(&runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003361 __ push(eax);
3362 __ CallRuntime(Runtime::kCall, args->length());
3363 __ bind(&done);
3364
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003365 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003366}
3367
3368
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003369void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003370 // Load the arguments on the stack and call the stub.
3371 RegExpConstructResultStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003372 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003373 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003374 VisitForStackValue(args->at(0));
3375 VisitForStackValue(args->at(1));
3376 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003377 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003378 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003379}
3380
3381
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003382void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3383 ZoneList<Expression*>* args = expr->arguments();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003384 ASSERT_EQ(2, args->length());
3385
3386 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3387 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3388
3389 Handle<FixedArray> jsfunction_result_caches(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003390 isolate()->native_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003391 if (jsfunction_result_caches->length() <= cache_id) {
3392 __ Abort("Attempt to use undefined cache.");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003394 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003395 return;
3396 }
3397
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003398 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003399
3400 Register key = eax;
3401 Register cache = ebx;
3402 Register tmp = ecx;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003403 __ mov(cache, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003404 __ mov(cache,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003405 FieldOperand(cache, GlobalObject::kNativeContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003406 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003407 __ mov(cache,
3408 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3409
3410 Label done, not_found;
3411 // tmp now holds finger offset as a smi.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003412 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003413 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3414 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3415 __ j(not_equal, &not_found);
3416
3417 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3418 __ jmp(&done);
3419
3420 __ bind(&not_found);
3421 // Call runtime to perform the lookup.
3422 __ push(cache);
3423 __ push(key);
3424 __ CallRuntime(Runtime::kGetFromCache, 2);
3425
3426 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003427 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003428}
3429
3430
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003431void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) {
3432 ZoneList<Expression*>* args = expr->arguments();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003433 ASSERT_EQ(2, args->length());
3434
3435 Register right = eax;
3436 Register left = ebx;
3437 Register tmp = ecx;
3438
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003439 VisitForStackValue(args->at(0));
3440 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003441 __ pop(left);
3442
3443 Label done, fail, ok;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003444 __ cmp(left, right);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003445 __ j(equal, &ok);
3446 // Fail if either is a non-HeapObject.
3447 __ mov(tmp, left);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003448 __ and_(tmp, right);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003449 __ JumpIfSmi(tmp, &fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003450 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
3451 __ CmpInstanceType(tmp, JS_REGEXP_TYPE);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003452 __ j(not_equal, &fail);
3453 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3454 __ j(not_equal, &fail);
3455 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3456 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3457 __ j(equal, &ok);
3458 __ bind(&fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003459 __ mov(eax, Immediate(isolate()->factory()->false_value()));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003460 __ jmp(&done);
3461 __ bind(&ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003462 __ mov(eax, Immediate(isolate()->factory()->true_value()));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003463 __ bind(&done);
3464
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003465 context()->Plug(eax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003466}
3467
3468
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003469void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3470 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003471 ASSERT(args->length() == 1);
3472
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003473 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003474
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003475 __ AssertString(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003476
3477 Label materialize_true, materialize_false;
3478 Label* if_true = NULL;
3479 Label* if_false = NULL;
3480 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003481 context()->PrepareTest(&materialize_true, &materialize_false,
3482 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003483
3484 __ test(FieldOperand(eax, String::kHashFieldOffset),
3485 Immediate(String::kContainsCachedArrayIndexMask));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003486 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003487 Split(zero, if_true, if_false, fall_through);
3488
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003489 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003490}
3491
3492
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003493void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3494 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003495 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003496 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003497
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003498 __ AssertString(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003499
3500 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3501 __ IndexFromHash(eax, eax);
3502
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003503 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003504}
3505
3506
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003507void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003508 Label bailout, done, one_char_separator, long_separator,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003509 non_trivial_array, not_size_one_array, loop,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003510 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003511
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003512 ZoneList<Expression*>* args = expr->arguments();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003513 ASSERT(args->length() == 2);
3514 // We will leave the separator on the stack until the end of the function.
3515 VisitForStackValue(args->at(1));
3516 // Load this to eax (= array)
3517 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003518 // All aliases of the same register have disjoint lifetimes.
3519 Register array = eax;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003520 Register elements = no_reg; // Will be eax.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003521
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003522 Register index = edx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003523
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003524 Register string_length = ecx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003525
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003526 Register string = esi;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003527
3528 Register scratch = ebx;
3529
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003530 Register array_length = edi;
3531 Register result_pos = no_reg; // Will be edi.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003532
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003533 // Separator operand is already pushed.
3534 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3535 Operand result_operand = Operand(esp, 1 * kPointerSize);
3536 Operand array_length_operand = Operand(esp, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003537 __ sub(esp, Immediate(2 * kPointerSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003538 __ cld();
3539 // Check that the array is a JSArray
whesse@chromium.org7b260152011-06-20 15:33:18 +00003540 __ JumpIfSmi(array, &bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003541 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3542 __ j(not_equal, &bailout);
3543
3544 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003545 __ CheckFastElements(scratch, &bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003546
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003547 // If the array has length zero, return the empty string.
3548 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003549 __ SmiUntag(array_length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003550 __ j(not_zero, &non_trivial_array);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003551 __ mov(result_operand, isolate()->factory()->empty_string());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003552 __ jmp(&done);
3553
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003554 // Save the array length.
3555 __ bind(&non_trivial_array);
3556 __ mov(array_length_operand, array_length);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003557
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003558 // Save the FixedArray containing array's elements.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003559 // End of array's live range.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003560 elements = array;
3561 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003562 array = no_reg;
3563
3564
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003565 // Check that all array elements are sequential ASCII strings, and
3566 // accumulate the sum of their lengths, as a smi-encoded value.
3567 __ Set(index, Immediate(0));
3568 __ Set(string_length, Immediate(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003569 // Loop condition: while (index < length).
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003570 // Live loop registers: index, array_length, string,
3571 // scratch, string_length, elements.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003572 if (generate_debug_code_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003573 __ cmp(index, array_length);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003574 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
3575 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003576 __ bind(&loop);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003577 __ mov(string, FieldOperand(elements,
3578 index,
3579 times_pointer_size,
3580 FixedArray::kHeaderSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003581 __ JumpIfSmi(string, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003582 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3583 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3584 __ and_(scratch, Immediate(
3585 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003586 __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003587 __ j(not_equal, &bailout);
3588 __ add(string_length,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003589 FieldOperand(string, SeqOneByteString::kLengthOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003590 __ j(overflow, &bailout);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003591 __ add(index, Immediate(1));
3592 __ cmp(index, array_length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003593 __ j(less, &loop);
3594
3595 // If array_length is 1, return elements[0], a string.
3596 __ cmp(array_length, 1);
3597 __ j(not_equal, &not_size_one_array);
3598 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3599 __ mov(result_operand, scratch);
3600 __ jmp(&done);
3601
3602 __ bind(&not_size_one_array);
3603
3604 // End of array_length live range.
3605 result_pos = array_length;
3606 array_length = no_reg;
3607
3608 // Live registers:
3609 // string_length: Sum of string lengths, as a smi.
3610 // elements: FixedArray of strings.
3611
3612 // Check that the separator is a flat ASCII string.
3613 __ mov(string, separator_operand);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003614 __ JumpIfSmi(string, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003615 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3616 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003617 __ and_(scratch, Immediate(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003618 kIsNotStringMask | kStringEncodingMask | kAsciiDataHintMask |
3619 kStringRepresentationMask));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003620 __ cmp(scratch, ASCII_STRING_TYPE);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003621 __ j(not_equal, &bailout);
3622
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003623 // Add (separator length times array_length) - separator length
3624 // to string_length.
3625 __ mov(scratch, separator_operand);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003626 __ mov(scratch, FieldOperand(scratch, SeqOneByteString::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003627 __ sub(string_length, scratch); // May be negative, temporarily.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003628 __ imul(scratch, array_length_operand);
3629 __ j(overflow, &bailout);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003630 __ add(string_length, scratch);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003631 __ j(overflow, &bailout);
3632
3633 __ shr(string_length, 1);
3634 // Live registers and stack values:
3635 // string_length
3636 // elements
3637 __ AllocateAsciiString(result_pos, string_length, scratch,
3638 index, string, &bailout);
3639 __ mov(result_operand, result_pos);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003640 __ lea(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003641
3642
3643 __ mov(string, separator_operand);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003644 __ cmp(FieldOperand(string, SeqOneByteString::kLengthOffset),
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003645 Immediate(Smi::FromInt(1)));
3646 __ j(equal, &one_char_separator);
3647 __ j(greater, &long_separator);
3648
3649
3650 // Empty separator case
3651 __ mov(index, Immediate(0));
3652 __ jmp(&loop_1_condition);
3653 // Loop condition: while (index < length).
3654 __ bind(&loop_1);
3655 // Each iteration of the loop concatenates one string to the result.
3656 // Live values in registers:
3657 // index: which element of the elements array we are adding to the result.
3658 // result_pos: the position to which we are currently copying characters.
3659 // elements: the FixedArray of strings we are joining.
3660
3661 // Get string = array[index].
3662 __ mov(string, FieldOperand(elements, index,
3663 times_pointer_size,
3664 FixedArray::kHeaderSize));
3665 __ mov(string_length,
3666 FieldOperand(string, String::kLengthOffset));
3667 __ shr(string_length, 1);
3668 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003669 FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003670 __ CopyBytes(string, result_pos, string_length, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003671 __ add(index, Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003672 __ bind(&loop_1_condition);
3673 __ cmp(index, array_length_operand);
3674 __ j(less, &loop_1); // End while (index < length).
3675 __ jmp(&done);
3676
3677
3678
3679 // One-character separator case
3680 __ bind(&one_char_separator);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003681 // Replace separator with its ASCII character value.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003682 __ mov_b(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003683 __ mov_b(separator_operand, scratch);
3684
3685 __ Set(index, Immediate(0));
3686 // Jump into the loop after the code that copies the separator, so the first
3687 // element is not preceded by a separator
3688 __ jmp(&loop_2_entry);
3689 // Loop condition: while (index < length).
3690 __ bind(&loop_2);
3691 // Each iteration of the loop concatenates one string to the result.
3692 // Live values in registers:
3693 // index: which element of the elements array we are adding to the result.
3694 // result_pos: the position to which we are currently copying characters.
3695
3696 // Copy the separator character to the result.
3697 __ mov_b(scratch, separator_operand);
3698 __ mov_b(Operand(result_pos, 0), scratch);
3699 __ inc(result_pos);
3700
3701 __ bind(&loop_2_entry);
3702 // Get string = array[index].
3703 __ mov(string, FieldOperand(elements, index,
3704 times_pointer_size,
3705 FixedArray::kHeaderSize));
3706 __ mov(string_length,
3707 FieldOperand(string, String::kLengthOffset));
3708 __ shr(string_length, 1);
3709 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003710 FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003711 __ CopyBytes(string, result_pos, string_length, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003712 __ add(index, Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003713
3714 __ cmp(index, array_length_operand);
3715 __ j(less, &loop_2); // End while (index < length).
3716 __ jmp(&done);
3717
3718
3719 // Long separator case (separator is more than one character).
3720 __ bind(&long_separator);
3721
3722 __ Set(index, Immediate(0));
3723 // Jump into the loop after the code that copies the separator, so the first
3724 // element is not preceded by a separator
3725 __ jmp(&loop_3_entry);
3726 // Loop condition: while (index < length).
3727 __ bind(&loop_3);
3728 // Each iteration of the loop concatenates one string to the result.
3729 // Live values in registers:
3730 // index: which element of the elements array we are adding to the result.
3731 // result_pos: the position to which we are currently copying characters.
3732
3733 // Copy the separator to the result.
3734 __ mov(string, separator_operand);
3735 __ mov(string_length,
3736 FieldOperand(string, String::kLengthOffset));
3737 __ shr(string_length, 1);
3738 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003739 FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003740 __ CopyBytes(string, result_pos, string_length, scratch);
3741
3742 __ bind(&loop_3_entry);
3743 // Get string = array[index].
3744 __ mov(string, FieldOperand(elements, index,
3745 times_pointer_size,
3746 FixedArray::kHeaderSize));
3747 __ mov(string_length,
3748 FieldOperand(string, String::kLengthOffset));
3749 __ shr(string_length, 1);
3750 __ lea(string,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003751 FieldOperand(string, SeqOneByteString::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003752 __ CopyBytes(string, result_pos, string_length, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003753 __ add(index, Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003754
3755 __ cmp(index, array_length_operand);
3756 __ j(less, &loop_3); // End while (index < length).
3757 __ jmp(&done);
3758
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003759
3760 __ bind(&bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003761 __ mov(result_operand, isolate()->factory()->undefined_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003762 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003763 __ mov(eax, result_operand);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003764 // Drop temp values from the stack, and restore context register.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003765 __ add(esp, Immediate(3 * kPointerSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003766
3767 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3768 context()->Plug(eax);
3769}
3770
3771
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003772void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003773 Handle<String> name = expr->name();
3774 if (name->length() > 0 && name->Get(0) == '_') {
3775 Comment cmnt(masm_, "[ InlineRuntimeCall");
3776 EmitInlineRuntimeCall(expr);
3777 return;
3778 }
3779
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003780 Comment cmnt(masm_, "[ CallRuntime");
3781 ZoneList<Expression*>* args = expr->arguments();
3782
3783 if (expr->is_jsruntime()) {
3784 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003785 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003786 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3787 }
3788
3789 // Push the arguments ("left-to-right").
3790 int arg_count = args->length();
3791 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003792 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003793 }
3794
3795 if (expr->is_jsruntime()) {
3796 // Call the JS runtime function via a call IC.
3797 __ Set(ecx, Immediate(expr->name()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003798 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
lrn@chromium.org34e60782011-09-15 07:25:40 +00003799 Handle<Code> ic =
3800 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00003801 CallIC(ic, mode, expr->CallRuntimeFeedbackId());
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003802 // Restore context register.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003803 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3804 } else {
3805 // Call the C runtime function.
3806 __ CallRuntime(expr->function(), arg_count);
3807 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003808 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003809}
3810
3811
3812void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3813 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003814 case Token::DELETE: {
3815 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003816 Property* property = expr->expression()->AsProperty();
3817 VariableProxy* proxy = expr->expression()->AsVariableProxy();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003818
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003819 if (property != NULL) {
3820 VisitForStackValue(property->obj());
3821 VisitForStackValue(property->key());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003822 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
3823 ? kNonStrictMode : kStrictMode;
3824 __ push(Immediate(Smi::FromInt(strict_mode_flag)));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003825 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003826 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003827 } else if (proxy != NULL) {
3828 Variable* var = proxy->var();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003829 // Delete of an unqualified identifier is disallowed in strict mode
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003830 // but "delete this" is allowed.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003831 ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003832 if (var->IsUnallocated()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003833 __ push(GlobalObjectOperand());
3834 __ push(Immediate(var->name()));
3835 __ push(Immediate(Smi::FromInt(kNonStrictMode)));
3836 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3837 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003838 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
3839 // Result of deleting non-global variables is false. 'this' is
3840 // not really a variable, though we implement it as one. The
3841 // subexpression does not have side effects.
3842 context()->Plug(var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003843 } else {
3844 // Non-global variable. Call the runtime to try to delete from the
3845 // context where the variable was introduced.
3846 __ push(context_register());
3847 __ push(Immediate(var->name()));
3848 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3849 context()->Plug(eax);
3850 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003851 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003852 // Result of deleting non-property, non-variable reference is true.
3853 // The subexpression may have side effects.
3854 VisitForEffect(expr->expression());
3855 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003856 }
3857 break;
3858 }
3859
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003860 case Token::VOID: {
3861 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3862 VisitForEffect(expr->expression());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003863 context()->Plug(isolate()->factory()->undefined_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003864 break;
3865 }
3866
3867 case Token::NOT: {
3868 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003869 if (context()->IsEffect()) {
3870 // Unary NOT has no side effects so it's only necessary to visit the
3871 // subexpression. Match the optimizing compiler by not branching.
3872 VisitForEffect(expr->expression());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003873 } else if (context()->IsTest()) {
3874 const TestContext* test = TestContext::cast(context());
3875 // The labels are swapped for the recursive call.
3876 VisitForControl(expr->expression(),
3877 test->false_label(),
3878 test->true_label(),
3879 test->fall_through());
3880 context()->Plug(test->true_label(), test->false_label());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003881 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003882 // We handle value contexts explicitly rather than simply visiting
3883 // for control and plugging the control flow into the context,
3884 // because we need to prepare a pair of extra administrative AST ids
3885 // for the optimizing compiler.
3886 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
3887 Label materialize_true, materialize_false, done;
3888 VisitForControl(expr->expression(),
3889 &materialize_false,
3890 &materialize_true,
3891 &materialize_true);
3892 __ bind(&materialize_true);
3893 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
3894 if (context()->IsAccumulatorValue()) {
3895 __ mov(eax, isolate()->factory()->true_value());
3896 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003897 __ Push(isolate()->factory()->true_value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003898 }
3899 __ jmp(&done, Label::kNear);
3900 __ bind(&materialize_false);
3901 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
3902 if (context()->IsAccumulatorValue()) {
3903 __ mov(eax, isolate()->factory()->false_value());
3904 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003905 __ Push(isolate()->factory()->false_value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003906 }
3907 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003908 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003909 break;
3910 }
3911
3912 case Token::TYPEOF: {
3913 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003914 { StackValueContext context(this);
3915 VisitForTypeofValue(expr->expression());
3916 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003917 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003918 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003919 break;
3920 }
3921
3922 case Token::ADD: {
3923 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003924 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003925 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003926 __ JumpIfSmi(result_register(), &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003927 ToNumberStub convert_stub;
3928 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003929 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003930 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003931 break;
3932 }
3933
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003934 case Token::SUB:
3935 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003936 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003937
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003938 case Token::BIT_NOT:
3939 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003940 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003941
3942 default:
3943 UNREACHABLE();
3944 }
3945}
3946
3947
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003948void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3949 const char* comment) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003950 Comment cmt(masm_, comment);
3951 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3952 UnaryOverwriteMode overwrite =
3953 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003954 UnaryOpStub stub(expr->op(), overwrite);
3955 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003956 // accumulator register eax.
3957 VisitForAccumulatorValue(expr->expression());
3958 SetSourcePosition(expr->position());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00003959 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET,
3960 expr->UnaryOperationFeedbackId());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003961 context()->Plug(eax);
3962}
3963
3964
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003965void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3966 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003967 SetSourcePosition(expr->position());
3968
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003969 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3970 // as the left-hand side.
3971 if (!expr->expression()->IsValidLeftHandSide()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003972 VisitForEffect(expr->expression());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003973 return;
3974 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003975
3976 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00003977 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003978 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3979 LhsKind assign_type = VARIABLE;
3980 Property* prop = expr->expression()->AsProperty();
3981 // In case of a property we use the uninitialized expression context
3982 // of the key to detect a named property.
3983 if (prop != NULL) {
3984 assign_type =
3985 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3986 }
3987
3988 // Evaluate expression and get value.
3989 if (assign_type == VARIABLE) {
3990 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003991 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003992 EmitVariableLoad(expr->expression()->AsVariableProxy());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003993 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003994 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003995 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003996 __ push(Immediate(Smi::FromInt(0)));
3997 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003998 if (assign_type == NAMED_PROPERTY) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003999 // Put the object both on the stack and in edx.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004000 VisitForAccumulatorValue(prop->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00004001 __ push(eax);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004002 __ mov(edx, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004003 EmitNamedPropertyLoad(prop);
4004 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004005 VisitForStackValue(prop->obj());
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004006 VisitForStackValue(prop->key());
4007 __ mov(edx, Operand(esp, kPointerSize)); // Object.
4008 __ mov(ecx, Operand(esp, 0)); // Key.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004009 EmitKeyedPropertyLoad(prop);
4010 }
4011 }
4012
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004013 // We need a second deoptimization point after loading the value
4014 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004015 if (assign_type == VARIABLE) {
4016 PrepareForBailout(expr->expression(), TOS_REG);
4017 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004018 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004019 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004020
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004021 // Call ToNumber only if operand is not a smi.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004022 Label no_conversion;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004023 if (ShouldInlineSmiCase(expr->op())) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004024 __ JumpIfSmi(eax, &no_conversion, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004025 }
whesse@chromium.org7a392b32011-01-31 11:30:36 +00004026 ToNumberStub convert_stub;
4027 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004028 __ bind(&no_conversion);
4029
4030 // Save result for postfix expressions.
4031 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004032 if (!context()->IsEffect()) {
4033 // Save the result on the stack. If we have a named or keyed property
4034 // we store the result under the receiver that is currently on top
4035 // of the stack.
4036 switch (assign_type) {
4037 case VARIABLE:
4038 __ push(eax);
4039 break;
4040 case NAMED_PROPERTY:
4041 __ mov(Operand(esp, kPointerSize), eax);
4042 break;
4043 case KEYED_PROPERTY:
4044 __ mov(Operand(esp, 2 * kPointerSize), eax);
4045 break;
4046 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004047 }
4048 }
4049
4050 // Inline smi case if we are in a loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004051 Label done, stub_call;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004052 JumpPatchSite patch_site(masm_);
4053
ricow@chromium.org65fae842010-08-25 15:26:24 +00004054 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004055 if (expr->op() == Token::INC) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004056 __ add(eax, Immediate(Smi::FromInt(1)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004057 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004058 __ sub(eax, Immediate(Smi::FromInt(1)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004059 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004060 __ j(overflow, &stub_call, Label::kNear);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004061 // We could eliminate this smi check if we split the code at
4062 // the first smi check before calling ToNumber.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004063 patch_site.EmitJumpIfSmi(eax, &done, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004064
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004065 __ bind(&stub_call);
4066 // Call stub. Undo operation first.
4067 if (expr->op() == Token::INC) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004068 __ sub(eax, Immediate(Smi::FromInt(1)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004069 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004070 __ add(eax, Immediate(Smi::FromInt(1)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004071 }
4072 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004073
4074 // Record position before stub call.
4075 SetSourcePosition(expr->position());
4076
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004077 // Call stub for +1/-1.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004078 __ mov(edx, eax);
4079 __ mov(eax, Immediate(Smi::FromInt(1)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004080 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004081 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountBinOpFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004082 patch_site.EmitPatchInfo();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004083 __ bind(&done);
4084
4085 // Store the value returned in eax.
4086 switch (assign_type) {
4087 case VARIABLE:
4088 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004089 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004090 { EffectContext context(this);
4091 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4092 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004093 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4094 context.Plug(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004095 }
4096 // For all contexts except EffectContext We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004097 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004098 if (!context()->IsEffect()) {
4099 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004100 }
4101 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004102 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004103 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004104 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004105 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4106 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004107 }
4108 break;
4109 case NAMED_PROPERTY: {
4110 __ mov(ecx, prop->key()->AsLiteral()->handle());
4111 __ pop(edx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004112 Handle<Code> ic = is_classic_mode()
4113 ? isolate()->builtins()->StoreIC_Initialize()
4114 : isolate()->builtins()->StoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004115 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004116 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004117 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004118 if (!context()->IsEffect()) {
4119 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004120 }
4121 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004122 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004123 }
4124 break;
4125 }
4126 case KEYED_PROPERTY: {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004127 __ pop(ecx);
4128 __ pop(edx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004129 Handle<Code> ic = is_classic_mode()
4130 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4131 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004132 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004133 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004134 if (expr->is_postfix()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004135 // Result is on the stack
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004136 if (!context()->IsEffect()) {
4137 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004138 }
4139 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004140 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004141 }
4142 break;
4143 }
4144 }
4145}
4146
4147
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004148void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004149 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004150 ASSERT(!context()->IsEffect());
4151 ASSERT(!context()->IsTest());
4152
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004153 if (proxy != NULL && proxy->var()->IsUnallocated()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004154 Comment cmnt(masm_, "Global variable");
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004155 __ mov(edx, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004156 __ mov(ecx, Immediate(proxy->name()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004157 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004158 // Use a regular load, not a contextual load, to avoid a reference
4159 // error.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004160 CallIC(ic);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004161 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004162 context()->Plug(eax);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004163 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004164 Label done, slow;
4165
4166 // Generate code for loading from variables potentially shadowed
4167 // by eval-introduced variables.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004168 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004169
4170 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004171 __ push(esi);
4172 __ push(Immediate(proxy->name()));
4173 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004174 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004175 __ bind(&done);
4176
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004177 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004178 } else {
4179 // This expression cannot throw a reference error at the top level.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004180 VisitInDuplicateContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004181 }
4182}
4183
4184
ager@chromium.org04921a82011-06-27 13:21:41 +00004185void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004186 Expression* sub_expr,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004187 Handle<String> check) {
4188 Label materialize_true, materialize_false;
4189 Label* if_true = NULL;
4190 Label* if_false = NULL;
4191 Label* fall_through = NULL;
4192 context()->PrepareTest(&materialize_true, &materialize_false,
4193 &if_true, &if_false, &fall_through);
4194
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004195 { AccumulatorValueContext context(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004196 VisitForTypeofValue(sub_expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004197 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004198 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004200 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004201 __ JumpIfSmi(eax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004202 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004203 isolate()->factory()->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004204 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004205 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004206 __ JumpIfSmi(eax, if_false);
4207 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
4208 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004209 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004210 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4211 1 << Map::kIsUndetectable);
4212 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004213 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
4214 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004215 __ j(equal, if_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 __ cmp(eax, isolate()->factory()->false_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004217 Split(equal, if_true, if_false, fall_through);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004218 } else if (FLAG_harmony_typeof &&
4219 check->Equals(isolate()->heap()->null_symbol())) {
4220 __ cmp(eax, isolate()->factory()->null_value());
4221 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004222 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
4223 __ cmp(eax, isolate()->factory()->undefined_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004224 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004225 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004226 // Check for undetectable objects => true.
4227 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4228 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4229 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4230 Split(not_zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004232 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004233 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4234 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
4235 __ j(equal, if_true);
4236 __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
4237 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004238 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004239 __ JumpIfSmi(eax, if_false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004240 if (!FLAG_harmony_typeof) {
4241 __ cmp(eax, isolate()->factory()->null_value());
4242 __ j(equal, if_true);
4243 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004244 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004245 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004246 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4247 __ j(above, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004248 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004249 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4250 1 << Map::kIsUndetectable);
4251 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004252 } else {
4253 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004254 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004255 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004256}
4257
4258
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004259void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4260 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004261 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004262
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004263 // First we try a fast inlined version of the compare when one of
4264 // the operands is a literal.
4265 if (TryLiteralCompare(expr)) return;
4266
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004267 // Always perform the comparison for its control flow. Pack the result
4268 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004269 Label materialize_true, materialize_false;
4270 Label* if_true = NULL;
4271 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004272 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004273 context()->PrepareTest(&materialize_true, &materialize_false,
4274 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004275
ager@chromium.org04921a82011-06-27 13:21:41 +00004276 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004277 VisitForStackValue(expr->left());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004278 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004279 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004280 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004281 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004282 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004283 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004284 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004285 break;
4286
4287 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004288 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004289 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004290 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004291 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004292 __ test(eax, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004293 // The stub returns 0 for true.
4294 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004295 break;
4296 }
4297
4298 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004299 VisitForAccumulatorValue(expr->right());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004300 Condition cc = CompareIC::ComputeCondition(op);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004301 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004302
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004303 bool inline_smi_code = ShouldInlineSmiCase(op);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004304 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004305 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004306 Label slow_case;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004307 __ mov(ecx, edx);
4308 __ or_(ecx, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004309 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004310 __ cmp(edx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004311 Split(cc, if_true, if_false, NULL);
4312 __ bind(&slow_case);
4313 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004314
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004315 // Record position and call the compare IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004316 SetSourcePosition(expr->position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004317 Handle<Code> ic = CompareIC::GetUninitialized(op);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004318 CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004319 patch_site.EmitPatchInfo();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004320
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004321 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004322 __ test(eax, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004323 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004324 }
4325 }
4326
4327 // Convert the result of the comparison into one expected for this
4328 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004329 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004330}
4331
4332
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004333void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4334 Expression* sub_expr,
4335 NilValue nil) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004336 Label materialize_true, materialize_false;
4337 Label* if_true = NULL;
4338 Label* if_false = NULL;
4339 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004340 context()->PrepareTest(&materialize_true, &materialize_false,
4341 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004342
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004343 VisitForAccumulatorValue(sub_expr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004344 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004345 Handle<Object> nil_value = nil == kNullValue ?
4346 isolate()->factory()->null_value() :
4347 isolate()->factory()->undefined_value();
4348 __ cmp(eax, nil_value);
4349 if (expr->op() == Token::EQ_STRICT) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004350 Split(equal, if_true, if_false, fall_through);
4351 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004352 Handle<Object> other_nil_value = nil == kNullValue ?
4353 isolate()->factory()->undefined_value() :
4354 isolate()->factory()->null_value();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004355 __ j(equal, if_true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004356 __ cmp(eax, other_nil_value);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004357 __ j(equal, if_true);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004358 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004359 // It can be an undetectable object.
4360 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4361 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
4362 __ test(edx, Immediate(1 << Map::kIsUndetectable));
4363 Split(not_zero, if_true, if_false, fall_through);
4364 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004365 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004366}
4367
4368
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004369void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4370 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004371 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004372}
4373
4374
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004375Register FullCodeGenerator::result_register() {
4376 return eax;
4377}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004378
4379
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004380Register FullCodeGenerator::context_register() {
4381 return esi;
4382}
4383
4384
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004385void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4386 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4387 __ mov(Operand(ebp, frame_offset), value);
4388}
4389
4390
4391void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004392 __ mov(dst, ContextOperand(esi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004393}
4394
4395
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004396void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004397 Scope* declaration_scope = scope()->DeclarationScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004398 if (declaration_scope->is_global_scope() ||
4399 declaration_scope->is_module_scope()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004400 // Contexts nested in the native context have a canonical empty function
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004401 // as their closure, not the anonymous closure containing the global
4402 // code. Pass a smi sentinel and let the runtime look up the empty
4403 // function.
4404 __ push(Immediate(Smi::FromInt(0)));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004405 } else if (declaration_scope->is_eval_scope()) {
4406 // Contexts nested inside eval code have the same closure as the context
4407 // calling eval, not the anonymous closure containing the eval code.
4408 // Fetch it from the context.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004409 __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
4410 } else {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004411 ASSERT(declaration_scope->is_function_scope());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004412 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4413 }
4414}
4415
4416
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004417// ----------------------------------------------------------------------------
4418// Non-local control flow support.
4419
4420void FullCodeGenerator::EnterFinallyBlock() {
4421 // Cook return address on top of stack (smi encoded Code* delta)
4422 ASSERT(!result_register().is(edx));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004423 __ pop(edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004424 __ sub(edx, Immediate(masm_->CodeObject()));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00004425 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
4426 STATIC_ASSERT(kSmiTag == 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004427 __ SmiTag(edx);
4428 __ push(edx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004429
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004430 // Store result register while executing finally block.
4431 __ push(result_register());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004432
4433 // Store pending message while executing finally block.
4434 ExternalReference pending_message_obj =
4435 ExternalReference::address_of_pending_message_obj(isolate());
4436 __ mov(edx, Operand::StaticVariable(pending_message_obj));
4437 __ push(edx);
4438
4439 ExternalReference has_pending_message =
4440 ExternalReference::address_of_has_pending_message(isolate());
4441 __ mov(edx, Operand::StaticVariable(has_pending_message));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004442 __ SmiTag(edx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004443 __ push(edx);
4444
4445 ExternalReference pending_message_script =
4446 ExternalReference::address_of_pending_message_script(isolate());
4447 __ mov(edx, Operand::StaticVariable(pending_message_script));
4448 __ push(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004449}
4450
4451
4452void FullCodeGenerator::ExitFinallyBlock() {
4453 ASSERT(!result_register().is(edx));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004454 // Restore pending message from stack.
4455 __ pop(edx);
4456 ExternalReference pending_message_script =
4457 ExternalReference::address_of_pending_message_script(isolate());
4458 __ mov(Operand::StaticVariable(pending_message_script), edx);
4459
4460 __ pop(edx);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004461 __ SmiUntag(edx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004462 ExternalReference has_pending_message =
4463 ExternalReference::address_of_has_pending_message(isolate());
4464 __ mov(Operand::StaticVariable(has_pending_message), edx);
4465
4466 __ pop(edx);
4467 ExternalReference pending_message_obj =
4468 ExternalReference::address_of_pending_message_obj(isolate());
4469 __ mov(Operand::StaticVariable(pending_message_obj), edx);
4470
4471 // Restore result register from stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004472 __ pop(result_register());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004473
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004474 // Uncook return address.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004475 __ pop(edx);
4476 __ SmiUntag(edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004477 __ add(edx, Immediate(masm_->CodeObject()));
4478 __ jmp(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004479}
4480
4481
4482#undef __
4483
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004484#define __ ACCESS_MASM(masm())
4485
4486FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4487 int* stack_depth,
4488 int* context_length) {
4489 // The macros used here must preserve the result register.
4490
4491 // Because the handler block contains the context of the finally
4492 // code, we can restore it directly from there for the finally code
4493 // rather than iteratively unwinding contexts via their previous
4494 // links.
4495 __ Drop(*stack_depth); // Down to the handler block.
4496 if (*context_length > 0) {
4497 // Restore the context to its dedicated register and the stack.
4498 __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
4499 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
4500 }
4501 __ PopTryHandler();
4502 __ call(finally_entry_);
4503
4504 *stack_depth = 0;
4505 *context_length = 0;
4506 return previous_;
4507}
4508
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004509#undef __
4510
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004511} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004512
4513#endif // V8_TARGET_ARCH_IA32