blob: f46a30a5e29ff2e03008ddb204d2df391cda85ae [file] [log] [blame]
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001// Copyright 2011 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"
37#include "parser.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000038#include "scopes.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000039#include "stub-cache.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000040
41namespace v8 {
42namespace internal {
43
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000044
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000045#define __ ACCESS_MASM(masm_)
46
danno@chromium.org40cb8782011-05-25 07:58:50 +000047
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000048static unsigned GetPropertyId(Property* property) {
49 if (property->is_synthetic()) return AstNode::kNoNumber;
50 return property->id();
51}
52
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000053
54class JumpPatchSite BASE_EMBEDDED {
55 public:
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000056 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000057#ifdef DEBUG
58 info_emitted_ = false;
59#endif
60 }
61
62 ~JumpPatchSite() {
63 ASSERT(patch_site_.is_bound() == info_emitted_);
64 }
65
karlklose@chromium.org83a47282011-05-11 11:54:09 +000066 void EmitJumpIfNotSmi(Register reg,
67 Label* target,
68 Label::Distance distance = Label::kFar) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000069 __ test(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000070 EmitJump(not_carry, target, distance); // Always taken before patched.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000071 }
72
karlklose@chromium.org83a47282011-05-11 11:54:09 +000073 void EmitJumpIfSmi(Register reg,
74 Label* target,
75 Label::Distance distance = Label::kFar) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000076 __ test(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +000077 EmitJump(carry, target, distance); // Never taken before patched.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000078 }
79
80 void EmitPatchInfo() {
81 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
82 ASSERT(is_int8(delta_to_patch_site));
83 __ test(eax, Immediate(delta_to_patch_site));
84#ifdef DEBUG
85 info_emitted_ = true;
86#endif
87 }
88
89 bool is_bound() const { return patch_site_.is_bound(); }
90
91 private:
92 // jc will be patched with jz, jnc will become jnz.
karlklose@chromium.org83a47282011-05-11 11:54:09 +000093 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000094 ASSERT(!patch_site_.is_bound() && !info_emitted_);
95 ASSERT(cc == carry || cc == not_carry);
96 __ bind(&patch_site_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +000097 __ j(cc, target, distance);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000098 }
99
100 MacroAssembler* masm_;
101 Label patch_site_;
102#ifdef DEBUG
103 bool info_emitted_;
104#endif
105};
106
107
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000108// Generate code for a JS function. On entry to the function the receiver
109// and arguments have been pushed on the stack left to right, with the
110// return address on top of them. The actual argument count matches the
111// formal parameter count expected by the function.
112//
113// The live registers are:
114// o edi: the JS function object being called (ie, ourselves)
115// o esi: our context
116// o ebp: our caller's frame pointer
117// o esp: stack pointer (pointing to return address)
118//
119// The function builds a JS frame. Please see JavaScriptFrameConstants in
120// frames-ia32.h for its layout.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000121void FullCodeGenerator::Generate(CompilationInfo* info) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000122 ASSERT(info_ == NULL);
123 info_ = info;
124 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000125 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126
vegorov@chromium.org42841962010-10-18 11:18:59 +0000127#ifdef DEBUG
128 if (strlen(FLAG_stop_at) > 0 &&
129 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
130 __ int3();
131 }
132#endif
133
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000134 // Strict mode functions and builtins need to replace the receiver
135 // with undefined when called as functions (without an explicit
136 // receiver object). ecx is zero for method calls and non-zero for
137 // function calls.
138 if (info->is_strict_mode() || info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000139 Label ok;
140 __ test(ecx, Operand(ecx));
141 __ j(zero, &ok, Label::kNear);
142 // +1 for return address.
143 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
144 __ mov(Operand(esp, receiver_offset),
145 Immediate(isolate()->factory()->undefined_value()));
146 __ bind(&ok);
147 }
148
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000149 __ push(ebp); // Caller's frame pointer.
150 __ mov(ebp, esp);
151 __ push(esi); // Callee's context.
152 __ push(edi); // Callee's JS Function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000154 { Comment cmnt(masm_, "[ Allocate locals");
155 int locals_count = scope()->num_stack_slots();
156 if (locals_count == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 __ push(Immediate(isolate()->factory()->undefined_value()));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000158 } else if (locals_count > 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000159 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000160 for (int i = 0; i < locals_count; i++) {
161 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000162 }
163 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000164 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000165
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000166 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000167
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000168 // Possibly allocate a local context.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000169 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000170 if (heap_slots > 0) {
171 Comment cmnt(masm_, "[ Allocate local context");
172 // Argument to NewContext is the function, which is still in edi.
173 __ push(edi);
174 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
175 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000176 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000177 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000178 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000179 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000180 function_in_register = false;
181 // Context is returned in both eax and esi. It replaces the context
182 // passed to us. It's saved in the stack and kept live in esi.
183 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
184
185 // Copy parameters into context if necessary.
186 int num_parameters = scope()->num_parameters();
187 for (int i = 0; i < num_parameters; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000188 Slot* slot = scope()->parameter(i)->AsSlot();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000189 if (slot != NULL && slot->type() == Slot::CONTEXT) {
190 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
191 (num_parameters - 1 - i) * kPointerSize;
192 // Load parameter from stack.
193 __ mov(eax, Operand(ebp, parameter_offset));
194 // Store it in the context.
195 int context_offset = Context::SlotOffset(slot->index());
196 __ mov(Operand(esi, context_offset), eax);
197 // Update the write barrier. This clobbers all involved
198 // registers, so we have use a third register to avoid
199 // clobbering esi.
200 __ mov(ecx, esi);
201 __ RecordWrite(ecx, context_offset, eax, ebx);
202 }
203 }
204 }
205
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000206 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000207 if (arguments != NULL) {
208 // Function uses arguments object.
209 Comment cmnt(masm_, "[ Allocate arguments object");
210 if (function_in_register) {
211 __ push(edi);
212 } else {
213 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
214 }
215 // Receiver is just before the parameters on the caller's stack.
216 int offset = scope()->num_parameters() * kPointerSize;
217 __ lea(edx,
218 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
219 __ push(edx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000220 __ SafePush(Immediate(Smi::FromInt(scope()->num_parameters())));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000221 // Arguments to ArgumentsAccessStub and/or New...:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000222 // function, receiver address, parameter count.
223 // The stub will rewrite receiver and parameter count if the previous
224 // stack frame was an arguments adapter frame.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000225 ArgumentsAccessStub::Type type;
226 if (is_strict_mode()) {
227 type = ArgumentsAccessStub::NEW_STRICT;
228 } else if (function()->has_duplicate_parameters()) {
229 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
230 } else {
231 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
232 }
233 ArgumentsAccessStub stub(type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000234 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000235
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000236 Move(arguments->AsSlot(), eax, ebx, edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000237 }
238
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000239 if (FLAG_trace) {
240 __ CallRuntime(Runtime::kTraceEnter, 0);
241 }
242
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000243 // Visit the declarations and body unless there is an illegal
244 // redeclaration.
245 if (scope()->HasIllegalRedeclaration()) {
246 Comment cmnt(masm_, "[ Declarations");
247 scope()->VisitIllegalRedeclaration(this);
248
249 } else {
250 { Comment cmnt(masm_, "[ Declarations");
251 // For named function expressions, declare the function name as a
252 // constant.
253 if (scope()->is_function_scope() && scope()->function() != NULL) {
254 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
255 }
256 VisitDeclarations(scope()->declarations());
257 }
258
259 { Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000260 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000261 Label ok;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000262 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000263 ExternalReference::address_of_stack_limit(isolate());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000264 __ cmp(esp, Operand::StaticVariable(stack_limit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000265 __ j(above_equal, &ok, Label::kNear);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000266 StackCheckStub stub;
267 __ CallStub(&stub);
268 __ bind(&ok);
269 }
270
271 { Comment cmnt(masm_, "[ Body");
272 ASSERT(loop_depth() == 0);
273 VisitStatements(function()->body());
274 ASSERT(loop_depth() == 0);
275 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000276 }
277
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000278 // Always emit a 'return undefined' in case control fell off the end of
279 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000280 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 __ mov(eax, isolate()->factory()->undefined_value());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000282 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000283 }
284}
285
286
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000287void FullCodeGenerator::ClearAccumulator() {
288 __ Set(eax, Immediate(Smi::FromInt(0)));
289}
290
291
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000292void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
293 Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000294 Label ok;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000295 ExternalReference stack_limit =
296 ExternalReference::address_of_stack_limit(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000297 __ cmp(esp, Operand::StaticVariable(stack_limit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000298 __ j(above_equal, &ok, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000299 StackCheckStub stub;
300 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000301 // Record a mapping of this PC offset to the OSR id. This is used to find
302 // the AST id from the unoptimized code in order to use it as a key into
303 // the deoptimization input data found in the optimized code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000304 RecordStackCheck(stmt->OsrEntryId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000305
306 // Loop stack checks can be patched to perform on-stack replacement. In
307 // order to decide whether or not to perform OSR we embed the loop depth
308 // in a test instruction after the call so we can extract it from the OSR
309 // builtin.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000310 ASSERT(loop_depth() > 0);
311 __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000312
313 __ bind(&ok);
314 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
315 // Record a mapping of the OSR id to this PC. This is used if the OSR
316 // entry becomes the target of a bailout. We don't expect it to be, but
317 // we want it to work if it is.
318 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000319}
320
321
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000322void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000323 Comment cmnt(masm_, "[ Return sequence");
324 if (return_label_.is_bound()) {
325 __ jmp(&return_label_);
326 } else {
327 // Common return label
328 __ bind(&return_label_);
329 if (FLAG_trace) {
330 __ push(eax);
331 __ CallRuntime(Runtime::kTraceExit, 1);
332 }
333#ifdef DEBUG
334 // Add a label for checking the size of the code used for returning.
335 Label check_exit_codesize;
336 masm_->bind(&check_exit_codesize);
337#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000338 SetSourcePosition(function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000339 __ RecordJSReturn();
340 // Do not use the leave instruction here because it is too short to
341 // patch with the code required by the debugger.
342 __ mov(esp, ebp);
343 __ pop(ebp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000344
345 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize;
346 __ Ret(arguments_bytes, ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000347#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000348 // Check that the size of the code used for returning is large enough
349 // for the debugger's requirements.
350 ASSERT(Assembler::kJSReturnSequenceLength <=
351 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000352#endif
353 }
354}
355
356
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000357void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000358}
359
360
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000361void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
362 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
363 __ mov(result_register(), slot_operand);
364}
365
366
367void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
368 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
369 // Memory operands can be pushed directly.
370 __ push(slot_operand);
371}
372
373
374void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
375 // For simplicity we always test the accumulator register.
376 codegen()->Move(result_register(), slot);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000377 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000378 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000379}
380
381
382void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
383 UNREACHABLE(); // Not used on IA32.
384}
385
386
387void FullCodeGenerator::AccumulatorValueContext::Plug(
388 Heap::RootListIndex index) const {
389 UNREACHABLE(); // Not used on IA32.
390}
391
392
393void FullCodeGenerator::StackValueContext::Plug(
394 Heap::RootListIndex index) const {
395 UNREACHABLE(); // Not used on IA32.
396}
397
398
399void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
400 UNREACHABLE(); // Not used on IA32.
401}
402
403
404void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
405}
406
407
408void FullCodeGenerator::AccumulatorValueContext::Plug(
409 Handle<Object> lit) const {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000410 if (lit->IsSmi()) {
411 __ SafeSet(result_register(), Immediate(lit));
412 } else {
413 __ Set(result_register(), Immediate(lit));
414 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000415}
416
417
418void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000419 if (lit->IsSmi()) {
420 __ SafePush(Immediate(lit));
421 } else {
422 __ push(Immediate(lit));
423 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000424}
425
426
427void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000428 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
429 true,
430 true_label_,
431 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000432 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
433 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000434 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000435 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000436 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000437 } else if (lit->IsString()) {
438 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000439 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000440 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000441 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000442 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000443 } else if (lit->IsSmi()) {
444 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000445 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000446 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000447 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000448 }
449 } else {
450 // For simplicity we always test the accumulator register.
451 __ mov(result_register(), lit);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000452 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000453 }
454}
455
456
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000457void FullCodeGenerator::EffectContext::DropAndPlug(int count,
458 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000459 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000460 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000461}
462
463
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000464void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
465 int count,
466 Register reg) const {
467 ASSERT(count > 0);
468 __ Drop(count);
469 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000470}
471
472
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000473void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
474 Register reg) const {
475 ASSERT(count > 0);
476 if (count > 1) __ Drop(count - 1);
477 __ mov(Operand(esp, 0), reg);
478}
479
480
481void FullCodeGenerator::TestContext::DropAndPlug(int count,
482 Register reg) const {
483 ASSERT(count > 0);
484 // For simplicity we always test the accumulator register.
485 __ Drop(count);
486 __ Move(result_register(), reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000487 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000488 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000489}
490
491
492void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
493 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000494 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000495 __ bind(materialize_true);
496}
497
498
499void FullCodeGenerator::AccumulatorValueContext::Plug(
500 Label* materialize_true,
501 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000502 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000503 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000504 __ mov(result_register(), isolate()->factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000505 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000506 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000507 __ mov(result_register(), isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000508 __ bind(&done);
509}
510
511
512void FullCodeGenerator::StackValueContext::Plug(
513 Label* materialize_true,
514 Label* materialize_false) const {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000515 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000516 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 __ push(Immediate(isolate()->factory()->true_value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000518 __ jmp(&done, Label::kNear);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000519 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 __ push(Immediate(isolate()->factory()->false_value()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000521 __ bind(&done);
522}
523
524
525void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
526 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000527 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000528 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000529}
530
531
532void FullCodeGenerator::EffectContext::Plug(bool flag) const {
533}
534
535
536void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 Handle<Object> value = flag
538 ? isolate()->factory()->true_value()
539 : isolate()->factory()->false_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000540 __ mov(result_register(), value);
541}
542
543
544void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 Handle<Object> value = flag
546 ? isolate()->factory()->true_value()
547 : isolate()->factory()->false_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000548 __ push(Immediate(value));
549}
550
551
552void FullCodeGenerator::TestContext::Plug(bool flag) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000553 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
554 true,
555 true_label_,
556 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000557 if (flag) {
558 if (true_label_ != fall_through_) __ jmp(true_label_);
559 } else {
560 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000561 }
562}
563
564
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000565void FullCodeGenerator::DoTest(Expression* condition,
566 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000567 Label* if_false,
568 Label* fall_through) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000569 ToBooleanStub stub;
570 __ push(result_register());
571 __ CallStub(&stub);
572 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000573 // The stub returns nonzero for true.
574 Split(not_zero, if_true, if_false, fall_through);
575}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000576
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000577
ricow@chromium.org65fae842010-08-25 15:26:24 +0000578void FullCodeGenerator::Split(Condition cc,
579 Label* if_true,
580 Label* if_false,
581 Label* fall_through) {
582 if (if_false == fall_through) {
583 __ j(cc, if_true);
584 } else if (if_true == fall_through) {
585 __ j(NegateCondition(cc), if_false);
586 } else {
587 __ j(cc, if_true);
588 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000589 }
590}
591
592
593MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
594 switch (slot->type()) {
595 case Slot::PARAMETER:
596 case Slot::LOCAL:
597 return Operand(ebp, SlotOffset(slot));
598 case Slot::CONTEXT: {
599 int context_chain_length =
ager@chromium.org5c838252010-02-19 08:53:10 +0000600 scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000601 __ LoadContext(scratch, context_chain_length);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000602 return ContextOperand(scratch, slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000603 }
604 case Slot::LOOKUP:
605 UNREACHABLE();
606 }
607 UNREACHABLE();
608 return Operand(eax, 0);
609}
610
611
612void FullCodeGenerator::Move(Register destination, Slot* source) {
613 MemOperand location = EmitSlotSearch(source, destination);
614 __ mov(destination, location);
615}
616
617
618void FullCodeGenerator::Move(Slot* dst,
619 Register src,
620 Register scratch1,
621 Register scratch2) {
622 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
623 ASSERT(!scratch1.is(src) && !scratch2.is(src));
624 MemOperand location = EmitSlotSearch(dst, scratch1);
625 __ mov(location, src);
626 // Emit the write barrier code if the location is in the heap.
627 if (dst->type() == Slot::CONTEXT) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000628 int offset = Context::SlotOffset(dst->index());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000629 ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000630 __ RecordWrite(scratch1, offset, src, scratch2);
631 }
632}
633
634
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000635void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
636 bool should_normalize,
637 Label* if_true,
638 Label* if_false) {
639 // Only prepare for bailouts before splits if we're in a test
640 // context. Otherwise, we let the Visit function deal with the
641 // preparation to avoid preparing with the same AST id twice.
642 if (!context()->IsTest() || !info_->IsOptimizable()) return;
643
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000644 Label skip;
645 if (should_normalize) __ jmp(&skip, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000646
647 ForwardBailoutStack* current = forward_bailout_stack_;
648 while (current != NULL) {
649 PrepareForBailout(current->expr(), state);
650 current = current->parent();
651 }
652
653 if (should_normalize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000654 __ cmp(eax, isolate()->factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000655 Split(equal, if_true, if_false, NULL);
656 __ bind(&skip);
657 }
658}
659
660
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000661void FullCodeGenerator::EmitDeclaration(Variable* variable,
662 Variable::Mode mode,
663 FunctionLiteral* function) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000664 Comment cmnt(masm_, "[ Declaration");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000665 ASSERT(variable != NULL); // Must have been resolved.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000666 Slot* slot = variable->AsSlot();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000667 Property* prop = variable->AsProperty();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000668
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000669 if (slot != NULL) {
670 switch (slot->type()) {
671 case Slot::PARAMETER:
672 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000673 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000674 __ mov(Operand(ebp, SlotOffset(slot)),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000675 Immediate(isolate()->factory()->the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000676 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000677 VisitForAccumulatorValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000678 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
679 }
680 break;
681
682 case Slot::CONTEXT:
683 // We bypass the general EmitSlotSearch because we know more about
684 // this specific context.
685
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000686 // The variable in the decl always resides in the current function
687 // context.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000688 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000689 if (FLAG_debug_code) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000690 // Check that we're not inside a 'with'.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000691 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000692 __ cmp(ebx, Operand(esi));
693 __ Check(equal, "Unexpected declaration in current context.");
694 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000695 if (mode == Variable::CONST) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000696 __ mov(ContextOperand(esi, slot->index()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000697 Immediate(isolate()->factory()->the_hole_value()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000698 // No write barrier since the hole value is in old space.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000699 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000700 VisitForAccumulatorValue(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000701 __ mov(ContextOperand(esi, slot->index()), result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000702 int offset = Context::SlotOffset(slot->index());
703 __ mov(ebx, esi);
704 __ RecordWrite(ebx, offset, result_register(), ecx);
705 }
706 break;
707
708 case Slot::LOOKUP: {
709 __ push(esi);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000710 __ push(Immediate(variable->name()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000711 // Declaration nodes are always introduced in one of two modes.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000712 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
713 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000714 __ push(Immediate(Smi::FromInt(attr)));
715 // Push initial value, if any.
716 // Note: For variables we must not push an initial value (such as
717 // 'undefined') because we may have a (legal) redeclaration and we
718 // must not destroy the current value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000719 if (mode == Variable::CONST) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000720 __ push(Immediate(isolate()->factory()->the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000721 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000722 VisitForStackValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000723 } else {
724 __ push(Immediate(Smi::FromInt(0))); // No initial value!
725 }
726 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
727 break;
728 }
729 }
730
731 } else if (prop != NULL) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000732 // A const declaration aliasing a parameter is an illegal redeclaration.
733 ASSERT(mode != Variable::CONST);
734 if (function != NULL) {
735 // We are declaring a function that rewrites to a property.
736 // Use (keyed) IC to set the initial value. We cannot visit the
737 // rewrite because it's shared and we risk recording duplicate AST
738 // IDs for bailouts from optimized code.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000739 ASSERT(prop->obj()->AsVariableProxy() != NULL);
740 { AccumulatorValueContext for_object(this);
741 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000742 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000743
danno@chromium.org40cb8782011-05-25 07:58:50 +0000744 __ push(eax);
745 VisitForAccumulatorValue(function);
746 __ pop(edx);
747
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000748 ASSERT(prop->key()->AsLiteral() != NULL &&
749 prop->key()->AsLiteral()->handle()->IsSmi());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000750 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000751
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000752 Handle<Code> ic = is_strict_mode()
753 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
754 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000755 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000756 }
757 }
758}
759
760
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000761void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
762 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
763}
764
765
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000766void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
767 // Call the runtime to declare the globals.
768 __ push(esi); // The context is the first argument.
769 __ push(Immediate(pairs));
ager@chromium.org5c838252010-02-19 08:53:10 +0000770 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000771 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
772 __ CallRuntime(Runtime::kDeclareGlobals, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000773 // Return value is ignored.
774}
775
776
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000777void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
778 Comment cmnt(masm_, "[ SwitchStatement");
779 Breakable nested_statement(this, stmt);
780 SetStatementPosition(stmt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000781
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000782 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000783 VisitForStackValue(stmt->tag());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000784 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000785
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000786 ZoneList<CaseClause*>* clauses = stmt->cases();
787 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000788
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000789 Label next_test; // Recycled for each test.
790 // Compile all the tests with branches to their bodies.
791 for (int i = 0; i < clauses->length(); i++) {
792 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000793 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000794
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000795 // The default is not a test, but remember it as final fall through.
796 if (clause->is_default()) {
797 default_clause = clause;
798 continue;
799 }
800
801 Comment cmnt(masm_, "[ Case comparison");
802 __ bind(&next_test);
803 next_test.Unuse();
804
805 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000806 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000807
ricow@chromium.org65fae842010-08-25 15:26:24 +0000808 // Perform the comparison as if via '==='.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000809 __ mov(edx, Operand(esp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000810 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000811 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000812 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000813 Label slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000814 __ mov(ecx, edx);
815 __ or_(ecx, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000816 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000817
ricow@chromium.org65fae842010-08-25 15:26:24 +0000818 __ cmp(edx, Operand(eax));
819 __ j(not_equal, &next_test);
820 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000821 __ jmp(clause->body_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000822 __ bind(&slow_case);
823 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000824
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000825 // Record position before stub call for type feedback.
826 SetSourcePosition(clause->position());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000827 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000828 EmitCallIC(ic, &patch_site, clause->CompareId());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000829 __ test(eax, Operand(eax));
830 __ j(not_equal, &next_test);
831 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000832 __ jmp(clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000833 }
834
835 // Discard the test value and jump to the default if present, otherwise to
836 // the end of the statement.
837 __ bind(&next_test);
838 __ Drop(1); // Switch value is no longer needed.
839 if (default_clause == NULL) {
840 __ jmp(nested_statement.break_target());
841 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000842 __ jmp(default_clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000843 }
844
845 // Compile all the case bodies.
846 for (int i = 0; i < clauses->length(); i++) {
847 Comment cmnt(masm_, "[ Case body");
848 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000849 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000850 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000851 VisitStatements(clause->statements());
852 }
853
854 __ bind(nested_statement.break_target());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000855 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000856}
857
858
859void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
860 Comment cmnt(masm_, "[ ForInStatement");
861 SetStatementPosition(stmt);
862
863 Label loop, exit;
864 ForIn loop_statement(this, stmt);
865 increment_loop_depth();
866
867 // Get the object to enumerate over. Both SpiderMonkey and JSC
868 // ignore null and undefined in contrast to the specification; see
869 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000870 VisitForAccumulatorValue(stmt->enumerable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000871 __ cmp(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000872 __ j(equal, &exit);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000874 __ j(equal, &exit);
875
876 // Convert the object to a JS object.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000877 Label convert, done_convert;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000878 __ JumpIfSmi(eax, &convert, Label::kNear);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000879 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000880 __ j(above_equal, &done_convert, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000881 __ bind(&convert);
882 __ push(eax);
883 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
884 __ bind(&done_convert);
885 __ push(eax);
886
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000887 // Check cache validity in generated code. This is a fast case for
888 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
889 // guarantee cache validity, call the runtime system to check cache
890 // validity or get the property names in a fixed array.
891 Label next, call_runtime;
892 __ mov(ecx, eax);
893 __ bind(&next);
894
895 // Check that there are no elements. Register ecx contains the
896 // current JS object we've reached through the prototype chain.
897 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000898 isolate()->factory()->empty_fixed_array());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000899 __ j(not_equal, &call_runtime);
900
901 // Check that instance descriptors are not empty so that we can
902 // check for an enum cache. Leave the map in ebx for the subsequent
903 // prototype load.
904 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000905 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset));
906 __ JumpIfSmi(edx, &call_runtime);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000907
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000908 // Check that there is an enum cache in the non-empty instance
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000909 // descriptors (edx). This is the case if the next enumeration
910 // index field does not contain a smi.
911 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000912 __ JumpIfSmi(edx, &call_runtime);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000913
914 // For all objects but the receiver, check that the cache is empty.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000915 Label check_prototype;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000916 __ cmp(ecx, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000917 __ j(equal, &check_prototype, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000918 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 __ cmp(edx, isolate()->factory()->empty_fixed_array());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000920 __ j(not_equal, &call_runtime);
921
922 // Load the prototype from the map and loop if non-null.
923 __ bind(&check_prototype);
924 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 __ cmp(ecx, isolate()->factory()->null_value());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000926 __ j(not_equal, &next);
927
928 // The enum cache is valid. Load the map of the object being
929 // iterated over and use the cache for the iteration.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000930 Label use_cache;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000931 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000932 __ jmp(&use_cache, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000933
934 // Get the set of properties to enumerate.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000935 __ bind(&call_runtime);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000936 __ push(eax); // Duplicate the enumerable object on the stack.
937 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
938
939 // If we got a map from the runtime call, we can do a fast
940 // modification check. Otherwise, we got a fixed array, and we have
941 // to do a slow check.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000942 Label fixed_array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000943 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
944 isolate()->factory()->meta_map());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000945 __ j(not_equal, &fixed_array, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000946
947 // We got a map in register eax. Get the enumeration cache from it.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000948 __ bind(&use_cache);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000949 __ LoadInstanceDescriptors(eax, ecx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000950 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
951 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
952
953 // Setup the four remaining stack slots.
954 __ push(eax); // Map.
955 __ push(edx); // Enumeration cache.
956 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000957 __ push(eax); // Enumeration cache length (as smi).
958 __ push(Immediate(Smi::FromInt(0))); // Initial index.
959 __ jmp(&loop);
960
961 // We got a fixed array in register eax. Iterate through that.
962 __ bind(&fixed_array);
963 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
964 __ push(eax);
965 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000966 __ push(eax); // Fixed array length (as smi).
967 __ push(Immediate(Smi::FromInt(0))); // Initial index.
968
969 // Generate code for doing the condition check.
970 __ bind(&loop);
971 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
972 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
973 __ j(above_equal, loop_statement.break_target());
974
975 // Get the current entry of the array into register ebx.
976 __ mov(ebx, Operand(esp, 2 * kPointerSize));
977 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
978
979 // Get the expected map from the stack or a zero map in the
980 // permanent slow case into register edx.
981 __ mov(edx, Operand(esp, 3 * kPointerSize));
982
983 // Check if the expected map still matches that of the enumerable.
984 // If not, we have to filter the key.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000985 Label update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000986 __ mov(ecx, Operand(esp, 4 * kPointerSize));
987 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000988 __ j(equal, &update_each, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000989
990 // Convert the entry to a string or null if it isn't a property
991 // anymore. If the property has been removed while iterating, we
992 // just skip it.
993 __ push(ecx); // Enumerable.
994 __ push(ebx); // Current entry.
995 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000996 __ test(eax, Operand(eax));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000997 __ j(equal, loop_statement.continue_target());
998 __ mov(ebx, Operand(eax));
999
1000 // Update the 'each' property or variable from the possibly filtered
1001 // entry in register ebx.
1002 __ bind(&update_each);
1003 __ mov(result_register(), ebx);
1004 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001005 { EffectContext context(this);
1006 EmitAssignment(stmt->each(), stmt->AssignmentId());
1007 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001008
1009 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001010 Visit(stmt->body());
1011
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001012 // Generate code for going to the next element by incrementing the
1013 // index (smi) stored on top of the stack.
1014 __ bind(loop_statement.continue_target());
1015 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001016
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001017 EmitStackCheck(stmt);
1018 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001019
1020 // Remove the pointers stored on the stack.
1021 __ bind(loop_statement.break_target());
1022 __ add(Operand(esp), Immediate(5 * kPointerSize));
1023
1024 // Exit and decrement the loop depth.
1025 __ bind(&exit);
1026 decrement_loop_depth();
1027}
1028
1029
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001030void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1031 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001032 // Use the fast case closure allocation code that allocates in new
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001033 // space for nested functions that don't need literals cloning. If
1034 // we're running with the --always-opt or the --prepare-always-opt
1035 // flag, we need to use the runtime function so that the new function
1036 // we are creating here gets a chance to have its code optimized and
1037 // doesn't just get a copy of the existing unoptimized code.
1038 if (!FLAG_always_opt &&
1039 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001040 !pretenure &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001041 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 info->num_literals() == 0) {
1043 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001044 __ push(Immediate(info));
1045 __ CallStub(&stub);
1046 } else {
1047 __ push(esi);
1048 __ push(Immediate(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001049 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001050 ? isolate()->factory()->true_value()
1051 : isolate()->factory()->false_value()));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001052 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001053 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001054 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001055}
1056
1057
1058void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1059 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001060 EmitVariableLoad(expr->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001061}
1062
1063
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001064void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
1065 Slot* slot,
1066 TypeofState typeof_state,
1067 Label* slow) {
1068 Register context = esi;
1069 Register temp = edx;
1070
1071 Scope* s = scope();
1072 while (s != NULL) {
1073 if (s->num_heap_slots() > 0) {
1074 if (s->calls_eval()) {
1075 // Check that extension is NULL.
1076 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1077 Immediate(0));
1078 __ j(not_equal, slow);
1079 }
1080 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001081 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001082 // Walk the rest of the chain without clobbering esi.
1083 context = temp;
1084 }
1085 // If no outer scope calls eval, we do not need to check more
1086 // context extensions. If we have reached an eval scope, we check
1087 // all extensions from this point.
1088 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1089 s = s->outer_scope();
1090 }
1091
1092 if (s != NULL && s->is_eval_scope()) {
1093 // Loop up the context chain. There is no frame effect so it is
1094 // safe to use raw labels here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001095 Label next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001096 if (!context.is(temp)) {
1097 __ mov(temp, context);
1098 }
1099 __ bind(&next);
1100 // Terminate at global context.
1101 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 Immediate(isolate()->factory()->global_context_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001103 __ j(equal, &fast, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001104 // Check that extension is NULL.
1105 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1106 __ j(not_equal, slow);
1107 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001108 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001109 __ jmp(&next);
1110 __ bind(&fast);
1111 }
1112
1113 // All extension objects were empty and it is safe to use a global
1114 // load IC call.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001115 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001116 __ mov(ecx, slot->var()->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001117 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001118 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1119 ? RelocInfo::CODE_TARGET
1120 : RelocInfo::CODE_TARGET_CONTEXT;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001121 EmitCallIC(ic, mode, AstNode::kNoNumber);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001122}
1123
1124
1125MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1126 Slot* slot,
1127 Label* slow) {
1128 ASSERT(slot->type() == Slot::CONTEXT);
1129 Register context = esi;
1130 Register temp = ebx;
1131
1132 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1133 if (s->num_heap_slots() > 0) {
1134 if (s->calls_eval()) {
1135 // Check that extension is NULL.
1136 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1137 Immediate(0));
1138 __ j(not_equal, slow);
1139 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001140 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001141 // Walk the rest of the chain without clobbering esi.
1142 context = temp;
1143 }
1144 }
1145 // Check that last extension is NULL.
1146 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1147 __ j(not_equal, slow);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001148
1149 // This function is used only for loads, not stores, so it's safe to
1150 // return an esi-based operand (the write barrier cannot be allowed to
1151 // destroy the esi register).
1152 return ContextOperand(context, slot->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001153}
1154
1155
1156void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1157 Slot* slot,
1158 TypeofState typeof_state,
1159 Label* slow,
1160 Label* done) {
1161 // Generate fast-case code for variables that might be shadowed by
1162 // eval-introduced variables. Eval is used a lot without
1163 // introducing variables. In those cases, we do not want to
1164 // perform a runtime call for all variables in the scope
1165 // containing the eval.
1166 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1167 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1168 __ jmp(done);
1169 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001170 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001171 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1172 if (potential_slot != NULL) {
1173 // Generate fast case for locals that rewrite to slots.
1174 __ mov(eax,
1175 ContextSlotOperandCheckExtensions(potential_slot, slow));
1176 if (potential_slot->var()->mode() == Variable::CONST) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 __ cmp(eax, isolate()->factory()->the_hole_value());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001178 __ j(not_equal, done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001179 __ mov(eax, isolate()->factory()->undefined_value());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001180 }
1181 __ jmp(done);
1182 } else if (rewrite != NULL) {
1183 // Generate fast case for calls of an argument function.
1184 Property* property = rewrite->AsProperty();
1185 if (property != NULL) {
1186 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1187 Literal* key_literal = property->key()->AsLiteral();
1188 if (obj_proxy != NULL &&
1189 key_literal != NULL &&
1190 obj_proxy->IsArguments() &&
1191 key_literal->handle()->IsSmi()) {
1192 // Load arguments object if there are no eval-introduced
1193 // variables. Then load the argument from the arguments
1194 // object using keyed load.
1195 __ mov(edx,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001196 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001197 slow));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001198 __ SafeSet(eax, Immediate(key_literal->handle()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001199 Handle<Code> ic =
1200 isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001201 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001202 __ jmp(done);
1203 }
1204 }
1205 }
1206 }
1207}
1208
1209
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001210void FullCodeGenerator::EmitVariableLoad(Variable* var) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001211 // Three cases: non-this global variables, lookup slots, and all other
1212 // types of slots.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001213 Slot* slot = var->AsSlot();
whesse@chromium.org7b260152011-06-20 15:33:18 +00001214 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001215
whesse@chromium.org7b260152011-06-20 15:33:18 +00001216 if (slot == NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001217 Comment cmnt(masm_, "Global variable");
1218 // Use inline caching. Variable name is passed in ecx and the global
1219 // object on the stack.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001220 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001221 __ mov(ecx, var->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001222 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001223 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001224 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001225
whesse@chromium.org7b260152011-06-20 15:33:18 +00001226 } else if (slot->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001227 Label done, slow;
1228
1229 // Generate code for loading from variables potentially shadowed
1230 // by eval-introduced variables.
1231 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1232
1233 __ bind(&slow);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001234 Comment cmnt(masm_, "Lookup slot");
1235 __ push(esi); // Context.
1236 __ push(Immediate(var->name()));
1237 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001238 __ bind(&done);
1239
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001240 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001241
whesse@chromium.org7b260152011-06-20 15:33:18 +00001242 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001243 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1244 ? "Context slot"
1245 : "Stack slot");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001246 if (var->mode() == Variable::CONST) {
1247 // Constants may be the hole value if they have not been initialized.
1248 // Unhole them.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001249 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001250 MemOperand slot_operand = EmitSlotSearch(slot, eax);
1251 __ mov(eax, slot_operand);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001252 __ cmp(eax, isolate()->factory()->the_hole_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001253 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001254 __ mov(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001255 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001256 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001257 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001258 context()->Plug(slot);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001259 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001260 }
1261}
1262
1263
1264void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1265 Comment cmnt(masm_, "[ RegExpLiteral");
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001266 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001267 // Registers will be used as follows:
1268 // edi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001269 // ecx = literals array.
1270 // ebx = regexp literal.
1271 // eax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001272 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001273 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001274 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001275 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001276 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 __ cmp(ebx, isolate()->factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001278 __ j(not_equal, &materialized, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001279
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001280 // Create regexp literal using runtime function
1281 // Result will be in eax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001282 __ push(ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001283 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1284 __ push(Immediate(expr->pattern()));
1285 __ push(Immediate(expr->flags()));
1286 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001287 __ mov(ebx, eax);
1288
1289 __ bind(&materialized);
1290 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1291 Label allocated, runtime_allocate;
1292 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1293 __ jmp(&allocated);
1294
1295 __ bind(&runtime_allocate);
1296 __ push(ebx);
1297 __ push(Immediate(Smi::FromInt(size)));
1298 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1299 __ pop(ebx);
1300
1301 __ bind(&allocated);
1302 // Copy the content into the newly allocated memory.
1303 // (Unroll copy loop once for better throughput).
1304 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1305 __ mov(edx, FieldOperand(ebx, i));
1306 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1307 __ mov(FieldOperand(eax, i), edx);
1308 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1309 }
1310 if ((size % (2 * kPointerSize)) != 0) {
1311 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1312 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1313 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001314 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001315}
1316
1317
1318void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1319 Comment cmnt(masm_, "[ ObjectLiteral");
1320 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1321 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1322 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1323 __ push(Immediate(expr->constant_properties()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001324 int flags = expr->fast_elements()
1325 ? ObjectLiteral::kFastElements
1326 : ObjectLiteral::kNoFlags;
1327 flags |= expr->has_function()
1328 ? ObjectLiteral::kHasFunction
1329 : ObjectLiteral::kNoFlags;
1330 __ push(Immediate(Smi::FromInt(flags)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001331 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001332 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001333 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001334 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001335 }
1336
1337 // If result_saved is true the result is on top of the stack. If
1338 // result_saved is false the result is in eax.
1339 bool result_saved = false;
1340
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001341 // Mark all computed expressions that are bound to a key that
1342 // is shadowed by a later occurrence of the same key. For the
1343 // marked expressions, no store code is emitted.
1344 expr->CalculateEmitStore();
1345
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001346 for (int i = 0; i < expr->properties()->length(); i++) {
1347 ObjectLiteral::Property* property = expr->properties()->at(i);
1348 if (property->IsCompileTimeValue()) continue;
1349
1350 Literal* key = property->key();
1351 Expression* value = property->value();
1352 if (!result_saved) {
1353 __ push(eax); // Save result on the stack
1354 result_saved = true;
1355 }
1356 switch (property->kind()) {
1357 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1358 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1359 // Fall through.
1360 case ObjectLiteral::Property::COMPUTED:
1361 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001362 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001363 VisitForAccumulatorValue(value);
1364 __ mov(ecx, Immediate(key->handle()));
1365 __ mov(edx, Operand(esp, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001366 Handle<Code> ic = is_strict_mode()
1367 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1368 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001369 EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001370 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1371 } else {
1372 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001373 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001374 break;
1375 }
1376 // Fall through.
1377 case ObjectLiteral::Property::PROTOTYPE:
1378 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001379 VisitForStackValue(key);
1380 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001381 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001382 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1383 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001384 } else {
1385 __ Drop(3);
1386 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001387 break;
1388 case ObjectLiteral::Property::SETTER:
1389 case ObjectLiteral::Property::GETTER:
1390 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001391 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001392 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
1393 Smi::FromInt(1) :
1394 Smi::FromInt(0)));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001395 VisitForStackValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001396 __ CallRuntime(Runtime::kDefineAccessor, 4);
1397 break;
1398 default: UNREACHABLE();
1399 }
1400 }
1401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 if (expr->has_function()) {
1403 ASSERT(result_saved);
1404 __ push(Operand(esp, 0));
1405 __ CallRuntime(Runtime::kToFastProperties, 1);
1406 }
1407
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001408 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001409 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001410 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001411 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001412 }
1413}
1414
1415
1416void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1417 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001418
1419 ZoneList<Expression*>* subexprs = expr->values();
1420 int length = subexprs->length();
1421
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001422 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1423 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1424 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1425 __ push(Immediate(expr->constant_elements()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001426 if (expr->constant_elements()->map() ==
1427 isolate()->heap()->fixed_cow_array_map()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001428 ASSERT(expr->depth() == 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001429 FastCloneShallowArrayStub stub(
1430 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1431 __ CallStub(&stub);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001432 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001433 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001434 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001435 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001436 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001437 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001438 FastCloneShallowArrayStub stub(
1439 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001440 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001441 }
1442
1443 bool result_saved = false; // Is the result saved to the stack?
1444
1445 // Emit code to evaluate all the non-constant subexpressions and to store
1446 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001447 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001448 Expression* subexpr = subexprs->at(i);
1449 // If the subexpression is a literal or a simple materialized literal it
1450 // is already set in the cloned array.
1451 if (subexpr->AsLiteral() != NULL ||
1452 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1453 continue;
1454 }
1455
1456 if (!result_saved) {
1457 __ push(eax);
1458 result_saved = true;
1459 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001460 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001461
1462 // Store the subexpression value in the array's elements.
1463 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1464 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1465 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1466 __ mov(FieldOperand(ebx, offset), result_register());
1467
1468 // Update the write barrier for the array store.
1469 __ RecordWrite(ebx, offset, result_register(), ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001470
1471 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001472 }
1473
1474 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001475 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001476 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001477 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001478 }
1479}
1480
1481
ager@chromium.org5c838252010-02-19 08:53:10 +00001482void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1483 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001484 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1485 // on the left-hand side.
1486 if (!expr->target()->IsValidLeftHandSide()) {
1487 VisitForEffect(expr->target());
1488 return;
1489 }
1490
ager@chromium.org5c838252010-02-19 08:53:10 +00001491 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001492 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001493 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1494 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001495 Property* property = expr->target()->AsProperty();
1496 if (property != NULL) {
1497 assign_type = (property->key()->IsPropertyName())
1498 ? NAMED_PROPERTY
1499 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001500 }
1501
1502 // Evaluate LHS expression.
1503 switch (assign_type) {
1504 case VARIABLE:
1505 // Nothing to do here.
1506 break;
1507 case NAMED_PROPERTY:
1508 if (expr->is_compound()) {
1509 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001510 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001511 __ push(result_register());
1512 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001513 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001514 }
1515 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001516 case KEYED_PROPERTY: {
ager@chromium.org5c838252010-02-19 08:53:10 +00001517 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001518 VisitForStackValue(property->obj());
1519 VisitForAccumulatorValue(property->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00001520 __ mov(edx, Operand(esp, 0));
1521 __ push(eax);
1522 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001523 VisitForStackValue(property->obj());
1524 VisitForStackValue(property->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00001525 }
1526 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001527 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001528 }
1529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001530 // For compound assignments we need another deoptimization point after the
1531 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001532 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001533 { AccumulatorValueContext context(this);
1534 switch (assign_type) {
1535 case VARIABLE:
1536 EmitVariableLoad(expr->target()->AsVariableProxy()->var());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001537 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001538 break;
1539 case NAMED_PROPERTY:
1540 EmitNamedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001541 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001542 break;
1543 case KEYED_PROPERTY:
1544 EmitKeyedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001545 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001546 break;
1547 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001548 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001549
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001550 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001551 __ push(eax); // Left operand goes on the stack.
1552 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001553
ricow@chromium.org65fae842010-08-25 15:26:24 +00001554 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1555 ? OVERWRITE_RIGHT
1556 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001557 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001558 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001559 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001560 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001561 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001562 mode,
1563 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001564 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001565 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001566 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001567 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001568
1569 // Deoptimization point in case the binary operation may have side effects.
1570 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001571 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001572 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001573 }
1574
1575 // Record source position before possible IC call.
1576 SetSourcePosition(expr->position());
1577
1578 // Store the value.
1579 switch (assign_type) {
1580 case VARIABLE:
1581 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001582 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001583 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1584 context()->Plug(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001585 break;
1586 case NAMED_PROPERTY:
1587 EmitNamedPropertyAssignment(expr);
1588 break;
1589 case KEYED_PROPERTY:
1590 EmitKeyedPropertyAssignment(expr);
1591 break;
1592 }
1593}
1594
1595
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001596void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1597 SetSourcePosition(prop->position());
1598 Literal* key = prop->key()->AsLiteral();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001599 ASSERT(!key->handle()->IsSmi());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001600 __ mov(ecx, Immediate(key->handle()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001601 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001602 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001603}
1604
1605
1606void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1607 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001608 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001609 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001610}
1611
1612
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001613void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001614 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001615 OverwriteMode mode,
1616 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001617 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001618 // Do combined smi check of the operands. Left operand is on the
1619 // stack. Right operand is in eax.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001620 Label smi_case, done, stub_call;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001621 __ pop(edx);
1622 __ mov(ecx, eax);
1623 __ or_(eax, Operand(edx));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001624 JumpPatchSite patch_site(masm_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001625 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001626
1627 __ bind(&stub_call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001628 __ mov(eax, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001629 BinaryOpStub stub(op, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001630 EmitCallIC(stub.GetCode(), &patch_site, expr->id());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001631 __ jmp(&done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001632
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001633 // Smi case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001634 __ bind(&smi_case);
1635 __ mov(eax, edx); // Copy left operand in case of a stub call.
1636
1637 switch (op) {
1638 case Token::SAR:
1639 __ SmiUntag(eax);
1640 __ SmiUntag(ecx);
1641 __ sar_cl(eax); // No checks of result necessary
1642 __ SmiTag(eax);
1643 break;
1644 case Token::SHL: {
1645 Label result_ok;
1646 __ SmiUntag(eax);
1647 __ SmiUntag(ecx);
1648 __ shl_cl(eax);
1649 // Check that the *signed* result fits in a smi.
1650 __ cmp(eax, 0xc0000000);
1651 __ j(positive, &result_ok);
1652 __ SmiTag(ecx);
1653 __ jmp(&stub_call);
1654 __ bind(&result_ok);
1655 __ SmiTag(eax);
1656 break;
1657 }
1658 case Token::SHR: {
1659 Label result_ok;
1660 __ SmiUntag(eax);
1661 __ SmiUntag(ecx);
1662 __ shr_cl(eax);
1663 __ test(eax, Immediate(0xc0000000));
1664 __ j(zero, &result_ok);
1665 __ SmiTag(ecx);
1666 __ jmp(&stub_call);
1667 __ bind(&result_ok);
1668 __ SmiTag(eax);
1669 break;
1670 }
1671 case Token::ADD:
1672 __ add(eax, Operand(ecx));
1673 __ j(overflow, &stub_call);
1674 break;
1675 case Token::SUB:
1676 __ sub(eax, Operand(ecx));
1677 __ j(overflow, &stub_call);
1678 break;
1679 case Token::MUL: {
1680 __ SmiUntag(eax);
1681 __ imul(eax, Operand(ecx));
1682 __ j(overflow, &stub_call);
1683 __ test(eax, Operand(eax));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001684 __ j(not_zero, &done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001685 __ mov(ebx, edx);
1686 __ or_(ebx, Operand(ecx));
1687 __ j(negative, &stub_call);
1688 break;
1689 }
1690 case Token::BIT_OR:
1691 __ or_(eax, Operand(ecx));
1692 break;
1693 case Token::BIT_AND:
1694 __ and_(eax, Operand(ecx));
1695 break;
1696 case Token::BIT_XOR:
1697 __ xor_(eax, Operand(ecx));
1698 break;
1699 default:
1700 UNREACHABLE();
1701 }
1702
1703 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001704 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001705}
1706
1707
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001708void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1709 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001710 OverwriteMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001711 __ pop(edx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001712 BinaryOpStub stub(op, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001713 // NULL signals no inlined smi code.
1714 EmitCallIC(stub.GetCode(), NULL, expr->id());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001715 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001716}
1717
1718
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001719void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001720 // Invalid left-hand sides are rewritten to have a 'throw
1721 // ReferenceError' on the left-hand side.
1722 if (!expr->IsValidLeftHandSide()) {
1723 VisitForEffect(expr);
1724 return;
1725 }
1726
1727 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001728 // slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001729 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1730 LhsKind assign_type = VARIABLE;
1731 Property* prop = expr->AsProperty();
1732 if (prop != NULL) {
1733 assign_type = (prop->key()->IsPropertyName())
1734 ? NAMED_PROPERTY
1735 : KEYED_PROPERTY;
1736 }
1737
1738 switch (assign_type) {
1739 case VARIABLE: {
1740 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001741 EffectContext context(this);
1742 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001743 break;
1744 }
1745 case NAMED_PROPERTY: {
1746 __ push(eax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001747 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001748 __ mov(edx, eax);
1749 __ pop(eax); // Restore value.
1750 __ mov(ecx, prop->key()->AsLiteral()->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001751 Handle<Code> ic = is_strict_mode()
1752 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1753 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001754 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001755 break;
1756 }
1757 case KEYED_PROPERTY: {
1758 __ push(eax); // Preserve value.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001759 if (prop->is_synthetic()) {
1760 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1761 ASSERT(prop->key()->AsLiteral() != NULL);
1762 { AccumulatorValueContext for_object(this);
1763 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1764 }
1765 __ mov(edx, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001766 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001767 } else {
1768 VisitForStackValue(prop->obj());
1769 VisitForAccumulatorValue(prop->key());
1770 __ mov(ecx, eax);
1771 __ pop(edx);
1772 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001773 __ pop(eax); // Restore value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001774 Handle<Code> ic = is_strict_mode()
1775 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1776 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001777 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001778 break;
1779 }
1780 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001781 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1782 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001783}
1784
1785
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001786void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001787 Token::Value op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001788 ASSERT(var != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001789 ASSERT(var->is_global() || var->AsSlot() != NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001790
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001791 if (var->is_global()) {
1792 ASSERT(!var->is_this());
1793 // Assignment to a global variable. Use inline caching for the
1794 // assignment. Right-hand-side value is passed in eax, variable name in
1795 // ecx, and the global object on the stack.
1796 __ mov(ecx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001797 __ mov(edx, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001798 Handle<Code> ic = is_strict_mode()
1799 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1800 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001801 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001802
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001803 } else if (op == Token::INIT_CONST) {
1804 // Like var declarations, const declarations are hoisted to function
1805 // scope. However, unlike var initializers, const initializers are able
1806 // to drill a hole to that function context, even from inside a 'with'
1807 // context. We thus bypass the normal static scope lookup.
1808 Slot* slot = var->AsSlot();
1809 Label skip;
1810 switch (slot->type()) {
1811 case Slot::PARAMETER:
1812 // No const parameters.
1813 UNREACHABLE();
1814 break;
1815 case Slot::LOCAL:
1816 __ mov(edx, Operand(ebp, SlotOffset(slot)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 __ cmp(edx, isolate()->factory()->the_hole_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001818 __ j(not_equal, &skip);
1819 __ mov(Operand(ebp, SlotOffset(slot)), eax);
1820 break;
1821 case Slot::CONTEXT: {
1822 __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX));
1823 __ mov(edx, ContextOperand(ecx, slot->index()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001824 __ cmp(edx, isolate()->factory()->the_hole_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001825 __ j(not_equal, &skip);
1826 __ mov(ContextOperand(ecx, slot->index()), eax);
1827 int offset = Context::SlotOffset(slot->index());
1828 __ mov(edx, eax); // Preserve the stored value in eax.
1829 __ RecordWrite(ecx, offset, edx, ebx);
1830 break;
1831 }
1832 case Slot::LOOKUP:
1833 __ push(eax);
1834 __ push(esi);
1835 __ push(Immediate(var->name()));
1836 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1837 break;
1838 }
1839 __ bind(&skip);
1840
1841 } else if (var->mode() != Variable::CONST) {
1842 // Perform the assignment for non-const variables. Const assignments
1843 // are simply skipped.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001844 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001845 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001846 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001847 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001848 // Perform the assignment.
1849 __ mov(Operand(ebp, SlotOffset(slot)), eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001850 break;
1851
1852 case Slot::CONTEXT: {
1853 MemOperand target = EmitSlotSearch(slot, ecx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001854 // Perform the assignment and issue the write barrier.
1855 __ mov(target, eax);
1856 // The value of the assignment is in eax. RecordWrite clobbers its
1857 // register arguments.
1858 __ mov(edx, eax);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001859 int offset = Context::SlotOffset(slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001860 __ RecordWrite(ecx, offset, edx, ebx);
1861 break;
1862 }
1863
1864 case Slot::LOOKUP:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001865 // Call the runtime for the assignment.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001866 __ push(eax); // Value.
1867 __ push(esi); // Context.
1868 __ push(Immediate(var->name()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001869 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
1870 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001871 break;
1872 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001873 }
1874}
1875
1876
1877void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1878 // Assignment to a property, using a named store IC.
1879 Property* prop = expr->target()->AsProperty();
1880 ASSERT(prop != NULL);
1881 ASSERT(prop->key()->AsLiteral() != NULL);
1882
1883 // If the assignment starts a block of assignments to the same object,
1884 // change to slow case to avoid the quadratic behavior of repeatedly
1885 // adding fast properties.
1886 if (expr->starts_initialization_block()) {
1887 __ push(result_register());
1888 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
1889 __ CallRuntime(Runtime::kToSlowProperties, 1);
1890 __ pop(result_register());
1891 }
1892
1893 // Record source code position before IC call.
1894 SetSourcePosition(expr->position());
1895 __ mov(ecx, prop->key()->AsLiteral()->handle());
1896 if (expr->ends_initialization_block()) {
1897 __ mov(edx, Operand(esp, 0));
1898 } else {
1899 __ pop(edx);
1900 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001901 Handle<Code> ic = is_strict_mode()
1902 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1903 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001904 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001905
1906 // If the assignment ends an initialization block, revert to fast case.
1907 if (expr->ends_initialization_block()) {
1908 __ push(eax); // Result of assignment, saved even if not needed.
1909 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
1910 __ CallRuntime(Runtime::kToFastProperties, 1);
1911 __ pop(eax);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001912 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001913 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001914 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1915 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001916}
1917
1918
1919void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1920 // Assignment to a property, using a keyed store IC.
1921
1922 // If the assignment starts a block of assignments to the same object,
1923 // change to slow case to avoid the quadratic behavior of repeatedly
1924 // adding fast properties.
1925 if (expr->starts_initialization_block()) {
1926 __ push(result_register());
1927 // Receiver is now under the key and value.
1928 __ push(Operand(esp, 2 * kPointerSize));
1929 __ CallRuntime(Runtime::kToSlowProperties, 1);
1930 __ pop(result_register());
1931 }
1932
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001933 __ pop(ecx);
1934 if (expr->ends_initialization_block()) {
1935 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
1936 } else {
1937 __ pop(edx);
1938 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001939 // Record source code position before IC call.
1940 SetSourcePosition(expr->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001941 Handle<Code> ic = is_strict_mode()
1942 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1943 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001944 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001945
1946 // If the assignment ends an initialization block, revert to fast case.
1947 if (expr->ends_initialization_block()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001948 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001949 __ push(eax); // Result of assignment, saved even if not needed.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001950 __ push(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001951 __ CallRuntime(Runtime::kToFastProperties, 1);
1952 __ pop(eax);
1953 }
1954
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001955 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001956 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001957}
1958
1959
1960void FullCodeGenerator::VisitProperty(Property* expr) {
1961 Comment cmnt(masm_, "[ Property");
1962 Expression* key = expr->key();
1963
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001964 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001965 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001966 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001967 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001968 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001969 VisitForStackValue(expr->obj());
1970 VisitForAccumulatorValue(expr->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00001971 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001972 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001973 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001974 }
1975}
1976
1977
1978void FullCodeGenerator::EmitCallWithIC(Call* expr,
1979 Handle<Object> name,
1980 RelocInfo::Mode mode) {
1981 // Code common for calls using the IC.
1982 ZoneList<Expression*>* args = expr->arguments();
1983 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001984 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001985 for (int i = 0; i < arg_count; i++) {
1986 VisitForStackValue(args->at(i));
1987 }
1988 __ Set(ecx, Immediate(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001989 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001990 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001991 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001992 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001993 Handle<Code> ic =
1994 isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001995 EmitCallIC(ic, mode, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001996 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001997 // Restore context register.
1998 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001999 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002000}
2001
2002
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002003void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002004 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002005 // Load the key.
2006 VisitForAccumulatorValue(key);
2007
2008 // Swap the name of the function and the receiver on the stack to follow
2009 // the calling convention for call ICs.
2010 __ pop(ecx);
2011 __ push(eax);
2012 __ push(ecx);
2013
2014 // Load the arguments.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002015 ZoneList<Expression*>* args = expr->arguments();
2016 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002017 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002018 for (int i = 0; i < arg_count; i++) {
2019 VisitForStackValue(args->at(i));
2020 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002021 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002022 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002023 SetSourcePosition(expr->position());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002024 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002025 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
2026 arg_count, in_loop);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002027 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002028 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002029 RecordJSReturnSite(expr);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002030 // Restore context register.
2031 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002032 context()->DropAndPlug(1, eax); // Drop the key still on the stack.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002033}
2034
2035
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002036void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002037 // Code common for calls using the call stub.
2038 ZoneList<Expression*>* args = expr->arguments();
2039 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002040 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002041 for (int i = 0; i < arg_count; i++) {
2042 VisitForStackValue(args->at(i));
2043 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002044 }
2045 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002046 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002047 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002048 CallFunctionStub stub(arg_count, in_loop, flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002049 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002050 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002051 // Restore context register.
2052 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002053 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002054}
2055
2056
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002057void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2058 int arg_count) {
2059 // Push copy of the first argument or undefined if it doesn't exist.
2060 if (arg_count > 0) {
2061 __ push(Operand(esp, arg_count * kPointerSize));
2062 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002063 __ push(Immediate(isolate()->factory()->undefined_value()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002064 }
2065
2066 // Push the receiver of the enclosing function.
2067 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
2068
2069 // Push the strict mode flag.
2070 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
2071
2072 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2073 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2074 : Runtime::kResolvePossiblyDirectEval, 4);
2075}
2076
2077
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002078void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002079#ifdef DEBUG
2080 // We want to verify that RecordJSReturnSite gets called on all paths
2081 // through this function. Avoid early returns.
2082 expr->return_is_recorded_ = false;
2083#endif
2084
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002085 Comment cmnt(masm_, "[ Call");
2086 Expression* fun = expr->expression();
2087 Variable* var = fun->AsVariableProxy()->AsVariable();
2088
2089 if (var != NULL && var->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002090 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2091 // resolve the function we need to call and the receiver of the
2092 // call. Then we call the resolved function using the given
2093 // arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002094 ZoneList<Expression*>* args = expr->arguments();
2095 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002096 { PreservePositionScope pos_scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002097 VisitForStackValue(fun);
2098 // Reserved receiver slot.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002099 __ push(Immediate(isolate()->factory()->undefined_value()));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002100
2101 // Push the arguments.
2102 for (int i = 0; i < arg_count; i++) {
2103 VisitForStackValue(args->at(i));
2104 }
2105
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002106 // If we know that eval can only be shadowed by eval-introduced
2107 // variables we attempt to load the global eval function directly
2108 // in generated code. If we succeed, there is no need to perform a
2109 // context lookup in the runtime system.
2110 Label done;
2111 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2112 Label slow;
2113 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2114 NOT_INSIDE_TYPEOF,
2115 &slow);
2116 // Push the function and resolve eval.
2117 __ push(eax);
2118 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2119 __ jmp(&done);
2120 __ bind(&slow);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002121 }
2122
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002123 // Push copy of the function (found below the arguments) and
2124 // resolve eval.
2125 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2126 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2127 if (done.is_linked()) {
2128 __ bind(&done);
2129 }
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002130
2131 // The runtime call returns a pair of values in eax (function) and
2132 // edx (receiver). Touch up the stack with the right values.
2133 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2134 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002135 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002136 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002137 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002138 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002139 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002140 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002141 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002142 // Restore context register.
2143 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002144 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002145 } else if (var != NULL && !var->is_this() && var->is_global()) {
2146 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002147 __ push(GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002148 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002149 } else if (var != NULL && var->AsSlot() != NULL &&
2150 var->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002151 // Call to a lookup slot (dynamically introduced variable).
2152 Label slow, done;
2153
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002154 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002155 // Generate code for loading from variables potentially shadowed
2156 // by eval-introduced variables.
2157 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
2158 NOT_INSIDE_TYPEOF,
2159 &slow,
2160 &done);
2161 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002162
2163 __ bind(&slow);
2164 // Call the runtime to find the function to call (returned in eax)
2165 // and the object holding it (returned in edx).
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002166 __ push(context_register());
2167 __ push(Immediate(var->name()));
2168 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2169 __ push(eax); // Function.
2170 __ push(edx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002171
2172 // If fast case code has been generated, emit code to push the
2173 // function and receiver and have the slow path jump around this
2174 // code.
2175 if (done.is_linked()) {
2176 Label call;
2177 __ jmp(&call);
2178 __ bind(&done);
2179 // Push function.
2180 __ push(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002181 // The receiver is implicitly the global receiver. Indicate this
2182 // by passing the hole to the call function stub.
2183 __ push(Immediate(isolate()->factory()->the_hole_value()));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002184 __ bind(&call);
2185 }
2186
danno@chromium.org40cb8782011-05-25 07:58:50 +00002187 // The receiver is either the global receiver or an object found
2188 // by LoadContextSlot. That object could be the hole if the
2189 // receiver is implicitly the global object.
2190 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002191 } else if (fun->AsProperty() != NULL) {
2192 // Call to an object property.
2193 Property* prop = fun->AsProperty();
2194 Literal* key = prop->key()->AsLiteral();
2195 if (key != NULL && key->handle()->IsSymbol()) {
2196 // Call to a named property, use call IC.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002197 { PreservePositionScope scope(masm()->positions_recorder());
2198 VisitForStackValue(prop->obj());
2199 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002200 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
2201 } else {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002202 // Call to a keyed property.
2203 // For a synthetic property use keyed load IC followed by function call,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002204 // for a regular property use keyed EmitCallIC.
ager@chromium.org5c838252010-02-19 08:53:10 +00002205 if (prop->is_synthetic()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002206 // Do not visit the object and key subexpressions (they are shared
2207 // by all occurrences of the same rewritten parameter).
2208 ASSERT(prop->obj()->AsVariableProxy() != NULL);
2209 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
2210 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
2211 MemOperand operand = EmitSlotSearch(slot, edx);
2212 __ mov(edx, operand);
2213
2214 ASSERT(prop->key()->AsLiteral() != NULL);
2215 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
2216 __ mov(eax, prop->key()->AsLiteral()->handle());
2217
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002218 // Record source code position for IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002219 SetSourcePosition(prop->position());
ager@chromium.org5c838252010-02-19 08:53:10 +00002220
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002221 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002222 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
ager@chromium.org5c838252010-02-19 08:53:10 +00002223 // Push result (function).
2224 __ push(eax);
2225 // Push Global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002226 __ mov(ecx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002227 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002228 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002229 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002230 { PreservePositionScope scope(masm()->positions_recorder());
2231 VisitForStackValue(prop->obj());
2232 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002233 EmitKeyedCallWithIC(expr, prop->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002234 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002235 }
2236 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002237 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002238 VisitForStackValue(fun);
2239 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002240 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002241 __ mov(ebx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002242 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2243 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002244 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002245 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002246
2247#ifdef DEBUG
2248 // RecordJSReturnSite should have been called.
2249 ASSERT(expr->return_is_recorded_);
2250#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002251}
2252
2253
2254void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2255 Comment cmnt(masm_, "[ CallNew");
2256 // According to ECMA-262, section 11.2.2, page 44, the function
2257 // expression in new calls must be evaluated before the
2258 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002259
ricow@chromium.org65fae842010-08-25 15:26:24 +00002260 // Push constructor on the stack. If it's not a function it's used as
2261 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2262 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002263 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002264
2265 // Push the arguments ("left-to-right") on the stack.
2266 ZoneList<Expression*>* args = expr->arguments();
2267 int arg_count = args->length();
2268 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002269 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002270 }
2271
2272 // Call the construct call builtin that handles allocation and
2273 // constructor invocation.
2274 SetSourcePosition(expr->position());
2275
ricow@chromium.org65fae842010-08-25 15:26:24 +00002276 // Load function and argument count into edi and eax.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002277 __ SafeSet(eax, Immediate(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002278 __ mov(edi, Operand(esp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002279
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002280 Handle<Code> construct_builtin =
2281 isolate()->builtins()->JSConstructCall();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002282 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002283 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002284}
2285
2286
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002287void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2288 ASSERT(args->length() == 1);
2289
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002290 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002291
2292 Label materialize_true, materialize_false;
2293 Label* if_true = NULL;
2294 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002295 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002296 context()->PrepareTest(&materialize_true, &materialize_false,
2297 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002298
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002299 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002300 __ test(eax, Immediate(kSmiTagMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002301 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002302
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002303 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002304}
2305
2306
2307void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2308 ASSERT(args->length() == 1);
2309
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002310 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002311
2312 Label materialize_true, materialize_false;
2313 Label* if_true = NULL;
2314 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002315 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002316 context()->PrepareTest(&materialize_true, &materialize_false,
2317 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002318
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002319 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002320 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002321 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002322
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002323 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002324}
2325
2326
2327void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2328 ASSERT(args->length() == 1);
2329
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002330 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002331
2332 Label materialize_true, materialize_false;
2333 Label* if_true = NULL;
2334 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002335 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002336 context()->PrepareTest(&materialize_true, &materialize_false,
2337 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002338
whesse@chromium.org7b260152011-06-20 15:33:18 +00002339 __ JumpIfSmi(eax, if_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002340 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002341 __ j(equal, if_true);
2342 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2343 // Undetectable objects behave like undefined when tested with typeof.
2344 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2345 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2346 __ j(not_zero, if_false);
2347 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002348 __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002349 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002350 __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002351 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002352 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002353
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002354 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002355}
2356
2357
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002358void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2359 ASSERT(args->length() == 1);
2360
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002361 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002362
2363 Label materialize_true, materialize_false;
2364 Label* if_true = NULL;
2365 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002366 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002367 context()->PrepareTest(&materialize_true, &materialize_false,
2368 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002369
whesse@chromium.org7b260152011-06-20 15:33:18 +00002370 __ JumpIfSmi(eax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002371 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002372 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002373 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002374
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002375 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002376}
2377
2378
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002379void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2380 ASSERT(args->length() == 1);
2381
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002382 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002383
2384 Label materialize_true, materialize_false;
2385 Label* if_true = NULL;
2386 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002387 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002388 context()->PrepareTest(&materialize_true, &materialize_false,
2389 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002390
whesse@chromium.org7b260152011-06-20 15:33:18 +00002391 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002392 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2393 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2394 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002395 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002396 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002397
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002398 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002399}
2400
2401
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002402void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2403 ZoneList<Expression*>* args) {
2404 ASSERT(args->length() == 1);
2405
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002406 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002407
2408 Label materialize_true, materialize_false;
2409 Label* if_true = NULL;
2410 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002411 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002412 context()->PrepareTest(&materialize_true, &materialize_false,
2413 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002414
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002415 if (FLAG_debug_code) __ AbortIfSmi(eax);
2416
2417 // Check whether this map has already been checked to be safe for default
2418 // valueOf.
2419 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2420 __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
2421 1 << Map::kStringWrapperSafeForDefaultValueOf);
2422 __ j(not_zero, if_true);
2423
2424 // Check for fast case object. Return false for slow case objects.
2425 __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
2426 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2427 __ cmp(ecx, FACTORY->hash_table_map());
2428 __ j(equal, if_false);
2429
2430 // Look for valueOf symbol in the descriptor array, and indicate false if
2431 // found. The type is not checked, so if it is a transition it is a false
2432 // negative.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002433 __ LoadInstanceDescriptors(ebx, ebx);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002434 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
2435 // ebx: descriptor array
2436 // ecx: length of descriptor array
2437 // Calculate the end of the descriptor array.
2438 STATIC_ASSERT(kSmiTag == 0);
2439 STATIC_ASSERT(kSmiTagSize == 1);
2440 STATIC_ASSERT(kPointerSize == 4);
2441 __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
2442 // Calculate location of the first key name.
2443 __ add(Operand(ebx),
2444 Immediate(FixedArray::kHeaderSize +
2445 DescriptorArray::kFirstIndex * kPointerSize));
2446 // Loop through all the keys in the descriptor array. If one of these is the
2447 // symbol valueOf the result is false.
2448 Label entry, loop;
2449 __ jmp(&entry);
2450 __ bind(&loop);
2451 __ mov(edx, FieldOperand(ebx, 0));
2452 __ cmp(edx, FACTORY->value_of_symbol());
2453 __ j(equal, if_false);
2454 __ add(Operand(ebx), Immediate(kPointerSize));
2455 __ bind(&entry);
2456 __ cmp(ebx, Operand(ecx));
2457 __ j(not_equal, &loop);
2458
2459 // Reload map as register ebx was used as temporary above.
2460 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2461
2462 // If a valueOf property is not found on the object check that it's
2463 // prototype is the un-modified String prototype. If not result is false.
2464 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002465 __ JumpIfSmi(ecx, if_false);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002466 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2467 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2468 __ mov(edx,
2469 FieldOperand(edx, GlobalObject::kGlobalContextOffset));
2470 __ cmp(ecx,
2471 ContextOperand(edx,
2472 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2473 __ j(not_equal, if_false);
2474 // Set the bit in the map to indicate that it has been checked safe for
2475 // default valueOf and set true result.
2476 __ or_(FieldOperand(ebx, Map::kBitField2Offset),
2477 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2478 __ jmp(if_true);
2479
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002480 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002481 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002482}
2483
2484
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002485void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2486 ASSERT(args->length() == 1);
2487
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002488 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002489
2490 Label materialize_true, materialize_false;
2491 Label* if_true = NULL;
2492 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002493 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002494 context()->PrepareTest(&materialize_true, &materialize_false,
2495 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002496
whesse@chromium.org7b260152011-06-20 15:33:18 +00002497 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002498 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002499 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002500 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002501
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002502 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002503}
2504
2505
2506void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2507 ASSERT(args->length() == 1);
2508
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002509 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002510
2511 Label materialize_true, materialize_false;
2512 Label* if_true = NULL;
2513 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002514 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002515 context()->PrepareTest(&materialize_true, &materialize_false,
2516 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002517
whesse@chromium.org7b260152011-06-20 15:33:18 +00002518 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002519 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002520 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002521 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002522
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002523 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002524}
2525
2526
2527void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2528 ASSERT(args->length() == 1);
2529
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002530 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002531
2532 Label materialize_true, materialize_false;
2533 Label* if_true = NULL;
2534 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002535 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002536 context()->PrepareTest(&materialize_true, &materialize_false,
2537 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002538
whesse@chromium.org7b260152011-06-20 15:33:18 +00002539 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002540 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002541 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002542 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002543
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002544 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002545}
2546
2547
2548
2549void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2550 ASSERT(args->length() == 0);
2551
2552 Label materialize_true, materialize_false;
2553 Label* if_true = NULL;
2554 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002555 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002556 context()->PrepareTest(&materialize_true, &materialize_false,
2557 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002558
2559 // Get the frame pointer for the calling frame.
2560 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2561
2562 // Skip the arguments adaptor frame if it exists.
2563 Label check_frame_marker;
2564 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2565 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2566 __ j(not_equal, &check_frame_marker);
2567 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2568
2569 // Check the marker in the calling frame.
2570 __ bind(&check_frame_marker);
2571 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2572 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002573 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002574 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002575
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002576 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002577}
2578
2579
2580void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2581 ASSERT(args->length() == 2);
2582
2583 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002584 VisitForStackValue(args->at(0));
2585 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002586
2587 Label materialize_true, materialize_false;
2588 Label* if_true = NULL;
2589 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002590 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002591 context()->PrepareTest(&materialize_true, &materialize_false,
2592 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002593
2594 __ pop(ebx);
2595 __ cmp(eax, Operand(ebx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002596 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002597 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002598
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002599 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002600}
2601
2602
2603void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2604 ASSERT(args->length() == 1);
2605
2606 // ArgumentsAccessStub expects the key in edx and the formal
2607 // parameter count in eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002608 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002609 __ mov(edx, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002610 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002611 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2612 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002613 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002614}
2615
2616
2617void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2618 ASSERT(args->length() == 0);
2619
2620 Label exit;
2621 // Get the number of formal parameters.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002622 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002623
2624 // Check if the calling frame is an arguments adaptor frame.
2625 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2626 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2627 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2628 __ j(not_equal, &exit);
2629
2630 // Arguments adaptor case: Read the arguments length from the
2631 // adaptor frame.
2632 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2633
2634 __ bind(&exit);
2635 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002636 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002637}
2638
2639
2640void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2641 ASSERT(args->length() == 1);
2642 Label done, null, function, non_function_constructor;
2643
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002644 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002645
2646 // If the object is a smi, we return null.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002647 __ JumpIfSmi(eax, &null);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002648
2649 // Check that the object is a JS object but take special care of JS
2650 // functions to make sure they have 'Function' as their class.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002651 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
2652 // Map is now in eax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002653 __ j(below, &null);
2654
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002655 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
2656 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
2657 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
2658 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
2659 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
2660 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
2661 __ CmpInstanceType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
2662 __ j(above_equal, &function);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002663
2664 // Check if the constructor in the map is a function.
2665 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2666 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2667 __ j(not_equal, &non_function_constructor);
2668
2669 // eax now contains the constructor function. Grab the
2670 // instance class name from there.
2671 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2672 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2673 __ jmp(&done);
2674
2675 // Functions have class 'Function'.
2676 __ bind(&function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002677 __ mov(eax, isolate()->factory()->function_class_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002678 __ jmp(&done);
2679
2680 // Objects with a non-function constructor have class 'Object'.
2681 __ bind(&non_function_constructor);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002682 __ mov(eax, isolate()->factory()->Object_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002683 __ jmp(&done);
2684
2685 // Non-JS objects have class null.
2686 __ bind(&null);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002687 __ mov(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002688
2689 // All done.
2690 __ bind(&done);
2691
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002692 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002693}
2694
2695
2696void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2697 // Conditionally generate a log call.
2698 // Args:
2699 // 0 (literal string): The type of logging (corresponds to the flags).
2700 // This is used to determine whether or not to generate the log call.
2701 // 1 (string): Format string. Access the string at argument index 2
2702 // with '%2s' (see Logger::LogRuntime for all the formats).
2703 // 2 (array): Arguments to the format string.
2704 ASSERT_EQ(args->length(), 3);
2705#ifdef ENABLE_LOGGING_AND_PROFILING
2706 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002707 VisitForStackValue(args->at(1));
2708 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002709 __ CallRuntime(Runtime::kLog, 2);
2710 }
2711#endif
2712 // Finally, we're expected to leave a value on the top of the stack.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002713 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002714 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002715}
2716
2717
2718void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2719 ASSERT(args->length() == 0);
2720
2721 Label slow_allocate_heapnumber;
2722 Label heapnumber_allocated;
2723
2724 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2725 __ jmp(&heapnumber_allocated);
2726
2727 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002728 // Allocate a heap number.
2729 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002730 __ mov(edi, eax);
2731
2732 __ bind(&heapnumber_allocated);
2733
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002734 __ PrepareCallCFunction(1, ebx);
2735 __ mov(Operand(esp, 0), Immediate(ExternalReference::isolate_address()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002736 __ CallCFunction(ExternalReference::random_uint32_function(isolate()),
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002737 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002738
2739 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2740 // by computing:
2741 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2742 // This is implemented on both SSE2 and FPU.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002743 if (CpuFeatures::IsSupported(SSE2)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002744 CpuFeatures::Scope fscope(SSE2);
2745 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2746 __ movd(xmm1, Operand(ebx));
2747 __ movd(xmm0, Operand(eax));
2748 __ cvtss2sd(xmm1, xmm1);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002749 __ xorps(xmm0, xmm1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002750 __ subsd(xmm0, xmm1);
2751 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2752 } else {
2753 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2754 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2755 Immediate(0x41300000));
2756 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2757 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2758 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2759 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2760 __ fsubp(1);
2761 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2762 }
2763 __ mov(eax, edi);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002764 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002765}
2766
2767
2768void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2769 // Load the arguments on the stack and call the stub.
2770 SubStringStub stub;
2771 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002772 VisitForStackValue(args->at(0));
2773 VisitForStackValue(args->at(1));
2774 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002775 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002776 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002777}
2778
2779
2780void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2781 // Load the arguments on the stack and call the stub.
2782 RegExpExecStub stub;
2783 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002784 VisitForStackValue(args->at(0));
2785 VisitForStackValue(args->at(1));
2786 VisitForStackValue(args->at(2));
2787 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002788 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002789 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002790}
2791
2792
2793void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2794 ASSERT(args->length() == 1);
2795
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002796 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002797
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002798 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002799 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002800 __ JumpIfSmi(eax, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002801 // If the object is not a value type, return the object.
2802 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002803 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002804 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2805
2806 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002807 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002808}
2809
2810
2811void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2812 // Load the arguments on the stack and call the runtime function.
2813 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002814 VisitForStackValue(args->at(0));
2815 VisitForStackValue(args->at(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002817 if (CpuFeatures::IsSupported(SSE2)) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002818 MathPowStub stub;
2819 __ CallStub(&stub);
2820 } else {
2821 __ CallRuntime(Runtime::kMath_pow, 2);
2822 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002823 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002824}
2825
2826
2827void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2828 ASSERT(args->length() == 2);
2829
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002830 VisitForStackValue(args->at(0)); // Load the object.
2831 VisitForAccumulatorValue(args->at(1)); // Load the value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002832 __ pop(ebx); // eax = value. ebx = object.
2833
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002834 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002835 // If the object is a smi, return the value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002836 __ JumpIfSmi(ebx, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002837
2838 // If the object is not a value type, return the value.
2839 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002840 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002841
2842 // Store the value.
2843 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
2844 // Update the write barrier. Save the value as it will be
2845 // overwritten by the write barrier code and is needed afterward.
2846 __ mov(edx, eax);
2847 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
2848
2849 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002850 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002851}
2852
2853
2854void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2855 ASSERT_EQ(args->length(), 1);
2856
2857 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002858 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002859
2860 NumberToStringStub stub;
2861 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002862 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002863}
2864
2865
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002866void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002867 ASSERT(args->length() == 1);
2868
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002869 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002870
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002871 Label done;
2872 StringCharFromCodeGenerator generator(eax, ebx);
2873 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002874 __ jmp(&done);
2875
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002876 NopRuntimeCallHelper call_helper;
2877 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002878
2879 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002880 context()->Plug(ebx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002881}
2882
2883
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002884void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2885 ASSERT(args->length() == 2);
2886
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002887 VisitForStackValue(args->at(0));
2888 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002889
2890 Register object = ebx;
2891 Register index = eax;
2892 Register scratch = ecx;
2893 Register result = edx;
2894
2895 __ pop(object);
2896
2897 Label need_conversion;
2898 Label index_out_of_range;
2899 Label done;
2900 StringCharCodeAtGenerator generator(object,
2901 index,
2902 scratch,
2903 result,
2904 &need_conversion,
2905 &need_conversion,
2906 &index_out_of_range,
2907 STRING_INDEX_IS_NUMBER);
2908 generator.GenerateFast(masm_);
2909 __ jmp(&done);
2910
2911 __ bind(&index_out_of_range);
2912 // When the index is out of range, the spec requires us to return
2913 // NaN.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002914 __ Set(result, Immediate(isolate()->factory()->nan_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002915 __ jmp(&done);
2916
2917 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002918 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002919 // trigger conversion.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002920 __ Set(result, Immediate(isolate()->factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002921 __ jmp(&done);
2922
2923 NopRuntimeCallHelper call_helper;
2924 generator.GenerateSlow(masm_, call_helper);
2925
2926 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002927 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002928}
2929
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002930
2931void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2932 ASSERT(args->length() == 2);
2933
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002934 VisitForStackValue(args->at(0));
2935 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002936
2937 Register object = ebx;
2938 Register index = eax;
2939 Register scratch1 = ecx;
2940 Register scratch2 = edx;
2941 Register result = eax;
2942
2943 __ pop(object);
2944
2945 Label need_conversion;
2946 Label index_out_of_range;
2947 Label done;
2948 StringCharAtGenerator generator(object,
2949 index,
2950 scratch1,
2951 scratch2,
2952 result,
2953 &need_conversion,
2954 &need_conversion,
2955 &index_out_of_range,
2956 STRING_INDEX_IS_NUMBER);
2957 generator.GenerateFast(masm_);
2958 __ jmp(&done);
2959
2960 __ bind(&index_out_of_range);
2961 // When the index is out of range, the spec requires us to return
2962 // the empty string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002963 __ Set(result, Immediate(isolate()->factory()->empty_string()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002964 __ jmp(&done);
2965
2966 __ bind(&need_conversion);
2967 // Move smi zero into the result register, which will trigger
2968 // conversion.
2969 __ Set(result, Immediate(Smi::FromInt(0)));
2970 __ jmp(&done);
2971
2972 NopRuntimeCallHelper call_helper;
2973 generator.GenerateSlow(masm_, call_helper);
2974
2975 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002976 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002977}
2978
2979
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002980void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2981 ASSERT_EQ(2, args->length());
2982
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002983 VisitForStackValue(args->at(0));
2984 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002985
2986 StringAddStub stub(NO_STRING_ADD_FLAGS);
2987 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002988 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002989}
2990
2991
2992void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2993 ASSERT_EQ(2, args->length());
2994
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002995 VisitForStackValue(args->at(0));
2996 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002997
2998 StringCompareStub stub;
2999 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003000 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003001}
3002
3003
3004void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
3005 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003006 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3007 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003008 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003009 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003010 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003011 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003012}
3013
3014
3015void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
3016 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003017 TranscendentalCacheStub stub(TranscendentalCache::COS,
3018 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003019 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003020 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003021 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003022 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003023}
3024
3025
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003026void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3027 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003028 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3029 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003030 ASSERT(args->length() == 1);
3031 VisitForStackValue(args->at(0));
3032 __ CallStub(&stub);
3033 context()->Plug(eax);
3034}
3035
3036
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003037void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
3038 // Load the argument on the stack and call the runtime function.
3039 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003040 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003041 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003042 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003043}
3044
3045
3046void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
3047 ASSERT(args->length() >= 2);
3048
danno@chromium.org160a7b02011-04-18 15:51:38 +00003049 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3050 for (int i = 0; i < arg_count + 1; ++i) {
3051 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003052 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003053 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003054
danno@chromium.org160a7b02011-04-18 15:51:38 +00003055 // InvokeFunction requires the function in edi. Move it in there.
3056 __ mov(edi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003057 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003058 __ InvokeFunction(edi, count, CALL_FUNCTION,
3059 NullCallWrapper(), CALL_AS_METHOD);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003060 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003061 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003062}
3063
3064
3065void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003066 // Load the arguments on the stack and call the stub.
3067 RegExpConstructResultStub stub;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003068 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003069 VisitForStackValue(args->at(0));
3070 VisitForStackValue(args->at(1));
3071 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003072 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003073 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003074}
3075
3076
3077void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
3078 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003079 VisitForStackValue(args->at(0));
3080 VisitForStackValue(args->at(1));
3081 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003082 Label done;
3083 Label slow_case;
3084 Register object = eax;
3085 Register index_1 = ebx;
3086 Register index_2 = ecx;
3087 Register elements = edi;
3088 Register temp = edx;
3089 __ mov(object, Operand(esp, 2 * kPointerSize));
3090 // Fetch the map and check if array is in fast case.
3091 // Check that object doesn't require security checks and
3092 // has no indexed interceptor.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003093 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3094 __ j(not_equal, &slow_case);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003095 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
3096 KeyedLoadIC::kSlowCaseBitFieldMask);
3097 __ j(not_zero, &slow_case);
3098
3099 // Check the object's elements are in fast case and writable.
3100 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
3101 __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003102 Immediate(isolate()->factory()->fixed_array_map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003103 __ j(not_equal, &slow_case);
3104
3105 // Check that both indices are smis.
3106 __ mov(index_1, Operand(esp, 1 * kPointerSize));
3107 __ mov(index_2, Operand(esp, 0));
3108 __ mov(temp, index_1);
3109 __ or_(temp, Operand(index_2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003110 __ JumpIfNotSmi(temp, &slow_case);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003111
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003112 // Check that both indices are valid.
3113 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
3114 __ cmp(temp, Operand(index_1));
3115 __ j(below_equal, &slow_case);
3116 __ cmp(temp, Operand(index_2));
3117 __ j(below_equal, &slow_case);
3118
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003119 // Bring addresses into index1 and index2.
3120 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1));
3121 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2));
3122
3123 // Swap elements. Use object and temp as scratch registers.
3124 __ mov(object, Operand(index_1, 0));
3125 __ mov(temp, Operand(index_2, 0));
3126 __ mov(Operand(index_2, 0), object);
3127 __ mov(Operand(index_1, 0), temp);
3128
3129 Label new_space;
3130 __ InNewSpace(elements, temp, equal, &new_space);
3131
3132 __ mov(object, elements);
3133 __ RecordWriteHelper(object, index_1, temp);
3134 __ RecordWriteHelper(elements, index_2, temp);
3135
3136 __ bind(&new_space);
3137 // We are done. Drop elements from the stack, and return undefined.
3138 __ add(Operand(esp), Immediate(3 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003139 __ mov(eax, isolate()->factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003140 __ jmp(&done);
3141
3142 __ bind(&slow_case);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003143 __ CallRuntime(Runtime::kSwapElements, 3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003144
3145 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003146 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003147}
3148
3149
3150void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3151 ASSERT_EQ(2, args->length());
3152
3153 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3154 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3155
3156 Handle<FixedArray> jsfunction_result_caches(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003157 isolate()->global_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003158 if (jsfunction_result_caches->length() <= cache_id) {
3159 __ Abort("Attempt to use undefined cache.");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003160 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003161 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003162 return;
3163 }
3164
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003165 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003166
3167 Register key = eax;
3168 Register cache = ebx;
3169 Register tmp = ecx;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003170 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003171 __ mov(cache,
3172 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003173 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003174 __ mov(cache,
3175 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3176
3177 Label done, not_found;
3178 // tmp now holds finger offset as a smi.
3179 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3180 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3181 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3182 __ j(not_equal, &not_found);
3183
3184 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3185 __ jmp(&done);
3186
3187 __ bind(&not_found);
3188 // Call runtime to perform the lookup.
3189 __ push(cache);
3190 __ push(key);
3191 __ CallRuntime(Runtime::kGetFromCache, 2);
3192
3193 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003194 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003195}
3196
3197
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003198void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3199 ASSERT_EQ(2, args->length());
3200
3201 Register right = eax;
3202 Register left = ebx;
3203 Register tmp = ecx;
3204
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003205 VisitForStackValue(args->at(0));
3206 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003207 __ pop(left);
3208
3209 Label done, fail, ok;
3210 __ cmp(left, Operand(right));
3211 __ j(equal, &ok);
3212 // Fail if either is a non-HeapObject.
3213 __ mov(tmp, left);
3214 __ and_(Operand(tmp), right);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003215 __ JumpIfSmi(tmp, &fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003216 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
3217 __ CmpInstanceType(tmp, JS_REGEXP_TYPE);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003218 __ j(not_equal, &fail);
3219 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3220 __ j(not_equal, &fail);
3221 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3222 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3223 __ j(equal, &ok);
3224 __ bind(&fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003225 __ mov(eax, Immediate(isolate()->factory()->false_value()));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003226 __ jmp(&done);
3227 __ bind(&ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003228 __ mov(eax, Immediate(isolate()->factory()->true_value()));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003229 __ bind(&done);
3230
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003231 context()->Plug(eax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003232}
3233
3234
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003235void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
3236 ASSERT(args->length() == 1);
3237
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003238 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003239
3240 if (FLAG_debug_code) {
3241 __ AbortIfNotString(eax);
3242 }
3243
3244 Label materialize_true, materialize_false;
3245 Label* if_true = NULL;
3246 Label* if_false = NULL;
3247 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003248 context()->PrepareTest(&materialize_true, &materialize_false,
3249 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003250
3251 __ test(FieldOperand(eax, String::kHashFieldOffset),
3252 Immediate(String::kContainsCachedArrayIndexMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003253 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003254 Split(zero, if_true, if_false, fall_through);
3255
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003256 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003257}
3258
3259
3260void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3261 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003262 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003263
3264 if (FLAG_debug_code) {
3265 __ AbortIfNotString(eax);
3266 }
3267
3268 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3269 __ IndexFromHash(eax, eax);
3270
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003271 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003272}
3273
3274
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003275void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003276 Label bailout, done, one_char_separator, long_separator,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003277 non_trivial_array, not_size_one_array, loop,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003278 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003279
3280 ASSERT(args->length() == 2);
3281 // We will leave the separator on the stack until the end of the function.
3282 VisitForStackValue(args->at(1));
3283 // Load this to eax (= array)
3284 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003285 // All aliases of the same register have disjoint lifetimes.
3286 Register array = eax;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003287 Register elements = no_reg; // Will be eax.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003288
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003289 Register index = edx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003290
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003291 Register string_length = ecx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003292
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003293 Register string = esi;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003294
3295 Register scratch = ebx;
3296
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003297 Register array_length = edi;
3298 Register result_pos = no_reg; // Will be edi.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003299
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003300 // Separator operand is already pushed.
3301 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3302 Operand result_operand = Operand(esp, 1 * kPointerSize);
3303 Operand array_length_operand = Operand(esp, 0);
3304 __ sub(Operand(esp), Immediate(2 * kPointerSize));
3305 __ cld();
3306 // Check that the array is a JSArray
whesse@chromium.org7b260152011-06-20 15:33:18 +00003307 __ JumpIfSmi(array, &bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003308 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3309 __ j(not_equal, &bailout);
3310
3311 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003312 __ CheckFastElements(scratch, &bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003313
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003314 // If the array has length zero, return the empty string.
3315 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003316 __ SmiUntag(array_length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003317 __ j(not_zero, &non_trivial_array);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003318 __ mov(result_operand, isolate()->factory()->empty_string());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003319 __ jmp(&done);
3320
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003321 // Save the array length.
3322 __ bind(&non_trivial_array);
3323 __ mov(array_length_operand, array_length);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003324
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003325 // Save the FixedArray containing array's elements.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003326 // End of array's live range.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003327 elements = array;
3328 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003329 array = no_reg;
3330
3331
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003332 // Check that all array elements are sequential ASCII strings, and
3333 // accumulate the sum of their lengths, as a smi-encoded value.
3334 __ Set(index, Immediate(0));
3335 __ Set(string_length, Immediate(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003336 // Loop condition: while (index < length).
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003337 // Live loop registers: index, array_length, string,
3338 // scratch, string_length, elements.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003339 if (FLAG_debug_code) {
3340 __ cmp(index, Operand(array_length));
3341 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
3342 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003343 __ bind(&loop);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003344 __ mov(string, FieldOperand(elements,
3345 index,
3346 times_pointer_size,
3347 FixedArray::kHeaderSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003348 __ JumpIfSmi(string, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003349 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3350 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3351 __ and_(scratch, Immediate(
3352 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3353 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3354 __ j(not_equal, &bailout);
3355 __ add(string_length,
3356 FieldOperand(string, SeqAsciiString::kLengthOffset));
3357 __ j(overflow, &bailout);
3358 __ add(Operand(index), Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003359 __ cmp(index, Operand(array_length));
3360 __ j(less, &loop);
3361
3362 // If array_length is 1, return elements[0], a string.
3363 __ cmp(array_length, 1);
3364 __ j(not_equal, &not_size_one_array);
3365 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3366 __ mov(result_operand, scratch);
3367 __ jmp(&done);
3368
3369 __ bind(&not_size_one_array);
3370
3371 // End of array_length live range.
3372 result_pos = array_length;
3373 array_length = no_reg;
3374
3375 // Live registers:
3376 // string_length: Sum of string lengths, as a smi.
3377 // elements: FixedArray of strings.
3378
3379 // Check that the separator is a flat ASCII string.
3380 __ mov(string, separator_operand);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003381 __ JumpIfSmi(string, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003382 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3383 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003384 __ and_(scratch, Immediate(
3385 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003386 __ cmp(scratch, ASCII_STRING_TYPE);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003387 __ j(not_equal, &bailout);
3388
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003389 // Add (separator length times array_length) - separator length
3390 // to string_length.
3391 __ mov(scratch, separator_operand);
3392 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset));
3393 __ sub(string_length, Operand(scratch)); // May be negative, temporarily.
3394 __ imul(scratch, array_length_operand);
3395 __ j(overflow, &bailout);
3396 __ add(string_length, Operand(scratch));
3397 __ j(overflow, &bailout);
3398
3399 __ shr(string_length, 1);
3400 // Live registers and stack values:
3401 // string_length
3402 // elements
3403 __ AllocateAsciiString(result_pos, string_length, scratch,
3404 index, string, &bailout);
3405 __ mov(result_operand, result_pos);
3406 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3407
3408
3409 __ mov(string, separator_operand);
3410 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset),
3411 Immediate(Smi::FromInt(1)));
3412 __ j(equal, &one_char_separator);
3413 __ j(greater, &long_separator);
3414
3415
3416 // Empty separator case
3417 __ mov(index, Immediate(0));
3418 __ jmp(&loop_1_condition);
3419 // Loop condition: while (index < length).
3420 __ bind(&loop_1);
3421 // Each iteration of the loop concatenates one string to the result.
3422 // Live values in registers:
3423 // index: which element of the elements array we are adding to the result.
3424 // result_pos: the position to which we are currently copying characters.
3425 // elements: the FixedArray of strings we are joining.
3426
3427 // Get string = array[index].
3428 __ mov(string, FieldOperand(elements, index,
3429 times_pointer_size,
3430 FixedArray::kHeaderSize));
3431 __ mov(string_length,
3432 FieldOperand(string, String::kLengthOffset));
3433 __ shr(string_length, 1);
3434 __ lea(string,
3435 FieldOperand(string, SeqAsciiString::kHeaderSize));
3436 __ CopyBytes(string, result_pos, string_length, scratch);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003437 __ add(Operand(index), Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003438 __ bind(&loop_1_condition);
3439 __ cmp(index, array_length_operand);
3440 __ j(less, &loop_1); // End while (index < length).
3441 __ jmp(&done);
3442
3443
3444
3445 // One-character separator case
3446 __ bind(&one_char_separator);
3447 // Replace separator with its ascii character value.
3448 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3449 __ mov_b(separator_operand, scratch);
3450
3451 __ Set(index, Immediate(0));
3452 // Jump into the loop after the code that copies the separator, so the first
3453 // element is not preceded by a separator
3454 __ jmp(&loop_2_entry);
3455 // Loop condition: while (index < length).
3456 __ bind(&loop_2);
3457 // Each iteration of the loop concatenates one string to the result.
3458 // Live values in registers:
3459 // index: which element of the elements array we are adding to the result.
3460 // result_pos: the position to which we are currently copying characters.
3461
3462 // Copy the separator character to the result.
3463 __ mov_b(scratch, separator_operand);
3464 __ mov_b(Operand(result_pos, 0), scratch);
3465 __ inc(result_pos);
3466
3467 __ bind(&loop_2_entry);
3468 // Get string = array[index].
3469 __ mov(string, FieldOperand(elements, index,
3470 times_pointer_size,
3471 FixedArray::kHeaderSize));
3472 __ mov(string_length,
3473 FieldOperand(string, String::kLengthOffset));
3474 __ shr(string_length, 1);
3475 __ lea(string,
3476 FieldOperand(string, SeqAsciiString::kHeaderSize));
3477 __ CopyBytes(string, result_pos, string_length, scratch);
3478 __ add(Operand(index), Immediate(1));
3479
3480 __ cmp(index, array_length_operand);
3481 __ j(less, &loop_2); // End while (index < length).
3482 __ jmp(&done);
3483
3484
3485 // Long separator case (separator is more than one character).
3486 __ bind(&long_separator);
3487
3488 __ Set(index, Immediate(0));
3489 // Jump into the loop after the code that copies the separator, so the first
3490 // element is not preceded by a separator
3491 __ jmp(&loop_3_entry);
3492 // Loop condition: while (index < length).
3493 __ bind(&loop_3);
3494 // Each iteration of the loop concatenates one string to the result.
3495 // Live values in registers:
3496 // index: which element of the elements array we are adding to the result.
3497 // result_pos: the position to which we are currently copying characters.
3498
3499 // Copy the separator to the result.
3500 __ mov(string, separator_operand);
3501 __ mov(string_length,
3502 FieldOperand(string, String::kLengthOffset));
3503 __ shr(string_length, 1);
3504 __ lea(string,
3505 FieldOperand(string, SeqAsciiString::kHeaderSize));
3506 __ CopyBytes(string, result_pos, string_length, scratch);
3507
3508 __ bind(&loop_3_entry);
3509 // Get string = array[index].
3510 __ mov(string, FieldOperand(elements, index,
3511 times_pointer_size,
3512 FixedArray::kHeaderSize));
3513 __ mov(string_length,
3514 FieldOperand(string, String::kLengthOffset));
3515 __ shr(string_length, 1);
3516 __ lea(string,
3517 FieldOperand(string, SeqAsciiString::kHeaderSize));
3518 __ CopyBytes(string, result_pos, string_length, scratch);
3519 __ add(Operand(index), Immediate(1));
3520
3521 __ cmp(index, array_length_operand);
3522 __ j(less, &loop_3); // End while (index < length).
3523 __ jmp(&done);
3524
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003525
3526 __ bind(&bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003527 __ mov(result_operand, isolate()->factory()->undefined_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003528 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003529 __ mov(eax, result_operand);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003530 // Drop temp values from the stack, and restore context register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003531 __ add(Operand(esp), Immediate(3 * kPointerSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003532
3533 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3534 context()->Plug(eax);
3535}
3536
3537
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003538void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003539 Handle<String> name = expr->name();
3540 if (name->length() > 0 && name->Get(0) == '_') {
3541 Comment cmnt(masm_, "[ InlineRuntimeCall");
3542 EmitInlineRuntimeCall(expr);
3543 return;
3544 }
3545
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003546 Comment cmnt(masm_, "[ CallRuntime");
3547 ZoneList<Expression*>* args = expr->arguments();
3548
3549 if (expr->is_jsruntime()) {
3550 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003551 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003552 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3553 }
3554
3555 // Push the arguments ("left-to-right").
3556 int arg_count = args->length();
3557 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003558 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003559 }
3560
3561 if (expr->is_jsruntime()) {
3562 // Call the JS runtime function via a call IC.
3563 __ Set(ecx, Immediate(expr->name()));
3564 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003565 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003567 arg_count, in_loop, mode);
3568 EmitCallIC(ic, mode, expr->id());
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003569 // Restore context register.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003570 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3571 } else {
3572 // Call the C runtime function.
3573 __ CallRuntime(expr->function(), arg_count);
3574 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003575 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003576}
3577
3578
3579void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3580 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003581 case Token::DELETE: {
3582 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3583 Property* prop = expr->expression()->AsProperty();
3584 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003585
3586 if (prop != NULL) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003587 if (prop->is_synthetic()) {
3588 // Result of deleting parameters is false, even when they rewrite
3589 // to accesses on the arguments object.
3590 context()->Plug(false);
3591 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003592 VisitForStackValue(prop->obj());
3593 VisitForStackValue(prop->key());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003594 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003595 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003596 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003597 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003598 } else if (var != NULL) {
3599 // Delete of an unqualified identifier is disallowed in strict mode
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003600 // but "delete this" is.
3601 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003602 if (var->is_global()) {
3603 __ push(GlobalObjectOperand());
3604 __ push(Immediate(var->name()));
3605 __ push(Immediate(Smi::FromInt(kNonStrictMode)));
3606 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3607 context()->Plug(eax);
3608 } else if (var->AsSlot() != NULL &&
3609 var->AsSlot()->type() != Slot::LOOKUP) {
3610 // Result of deleting non-global, non-dynamic variables is false.
3611 // The subexpression does not have side effects.
3612 context()->Plug(false);
3613 } else {
3614 // Non-global variable. Call the runtime to try to delete from the
3615 // context where the variable was introduced.
3616 __ push(context_register());
3617 __ push(Immediate(var->name()));
3618 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3619 context()->Plug(eax);
3620 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003621 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003622 // Result of deleting non-property, non-variable reference is true.
3623 // The subexpression may have side effects.
3624 VisitForEffect(expr->expression());
3625 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003626 }
3627 break;
3628 }
3629
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003630 case Token::VOID: {
3631 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3632 VisitForEffect(expr->expression());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633 context()->Plug(isolate()->factory()->undefined_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003634 break;
3635 }
3636
3637 case Token::NOT: {
3638 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003639 if (context()->IsEffect()) {
3640 // Unary NOT has no side effects so it's only necessary to visit the
3641 // subexpression. Match the optimizing compiler by not branching.
3642 VisitForEffect(expr->expression());
3643 } else {
3644 Label materialize_true, materialize_false;
3645 Label* if_true = NULL;
3646 Label* if_false = NULL;
3647 Label* fall_through = NULL;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003648
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003649 // Notice that the labels are swapped.
3650 context()->PrepareTest(&materialize_true, &materialize_false,
3651 &if_false, &if_true, &fall_through);
3652 if (context()->IsTest()) ForwardBailoutToChild(expr);
3653 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3654 context()->Plug(if_false, if_true); // Labels swapped.
3655 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003656 break;
3657 }
3658
3659 case Token::TYPEOF: {
3660 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003661 { StackValueContext context(this);
3662 VisitForTypeofValue(expr->expression());
3663 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003664 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003665 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003666 break;
3667 }
3668
3669 case Token::ADD: {
3670 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003671 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003672 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003673 __ JumpIfSmi(result_register(), &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003674 ToNumberStub convert_stub;
3675 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003676 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003677 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003678 break;
3679 }
3680
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003681 case Token::SUB:
3682 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003683 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003684
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003685 case Token::BIT_NOT:
3686 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003687 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003688
3689 default:
3690 UNREACHABLE();
3691 }
3692}
3693
3694
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003695void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3696 const char* comment) {
3697 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
3698 Comment cmt(masm_, comment);
3699 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3700 UnaryOverwriteMode overwrite =
3701 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003702 UnaryOpStub stub(expr->op(), overwrite);
3703 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003704 // accumulator register eax.
3705 VisitForAccumulatorValue(expr->expression());
3706 SetSourcePosition(expr->position());
3707 EmitCallIC(stub.GetCode(), NULL, expr->id());
3708 context()->Plug(eax);
3709}
3710
3711
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003712void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3713 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003714 SetSourcePosition(expr->position());
3715
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003716 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3717 // as the left-hand side.
3718 if (!expr->expression()->IsValidLeftHandSide()) {
3719 VisitForEffect(expr->expression());
3720 return;
3721 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003722
3723 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00003724 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003725 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3726 LhsKind assign_type = VARIABLE;
3727 Property* prop = expr->expression()->AsProperty();
3728 // In case of a property we use the uninitialized expression context
3729 // of the key to detect a named property.
3730 if (prop != NULL) {
3731 assign_type =
3732 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3733 }
3734
3735 // Evaluate expression and get value.
3736 if (assign_type == VARIABLE) {
3737 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003738 AccumulatorValueContext context(this);
3739 EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003740 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003741 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003742 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003743 __ push(Immediate(Smi::FromInt(0)));
3744 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003745 if (assign_type == NAMED_PROPERTY) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003746 // Put the object both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003747 VisitForAccumulatorValue(prop->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00003748 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003749 EmitNamedPropertyLoad(prop);
3750 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003751 VisitForStackValue(prop->obj());
3752 VisitForAccumulatorValue(prop->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00003753 __ mov(edx, Operand(esp, 0));
3754 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003755 EmitKeyedPropertyLoad(prop);
3756 }
3757 }
3758
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003759 // We need a second deoptimization point after loading the value
3760 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003761 if (assign_type == VARIABLE) {
3762 PrepareForBailout(expr->expression(), TOS_REG);
3763 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003764 PrepareForBailoutForId(expr->CountId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003765 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003766
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003767 // Call ToNumber only if operand is not a smi.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003768 Label no_conversion;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003769 if (ShouldInlineSmiCase(expr->op())) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003770 __ JumpIfSmi(eax, &no_conversion, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003771 }
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003772 ToNumberStub convert_stub;
3773 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003774 __ bind(&no_conversion);
3775
3776 // Save result for postfix expressions.
3777 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003778 if (!context()->IsEffect()) {
3779 // Save the result on the stack. If we have a named or keyed property
3780 // we store the result under the receiver that is currently on top
3781 // of the stack.
3782 switch (assign_type) {
3783 case VARIABLE:
3784 __ push(eax);
3785 break;
3786 case NAMED_PROPERTY:
3787 __ mov(Operand(esp, kPointerSize), eax);
3788 break;
3789 case KEYED_PROPERTY:
3790 __ mov(Operand(esp, 2 * kPointerSize), eax);
3791 break;
3792 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003793 }
3794 }
3795
3796 // Inline smi case if we are in a loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003797 Label done, stub_call;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003798 JumpPatchSite patch_site(masm_);
3799
ricow@chromium.org65fae842010-08-25 15:26:24 +00003800 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003801 if (expr->op() == Token::INC) {
3802 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3803 } else {
3804 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3805 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003806 __ j(overflow, &stub_call, Label::kNear);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003807 // We could eliminate this smi check if we split the code at
3808 // the first smi check before calling ToNumber.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003809 patch_site.EmitJumpIfSmi(eax, &done, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003810
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003811 __ bind(&stub_call);
3812 // Call stub. Undo operation first.
3813 if (expr->op() == Token::INC) {
3814 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3815 } else {
3816 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3817 }
3818 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003819
3820 // Record position before stub call.
3821 SetSourcePosition(expr->position());
3822
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003823 // Call stub for +1/-1.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003824 __ mov(edx, eax);
3825 __ mov(eax, Immediate(Smi::FromInt(1)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003826 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003827 EmitCallIC(stub.GetCode(), &patch_site, expr->CountId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003828 __ bind(&done);
3829
3830 // Store the value returned in eax.
3831 switch (assign_type) {
3832 case VARIABLE:
3833 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003834 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003835 { EffectContext context(this);
3836 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3837 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003838 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3839 context.Plug(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003840 }
3841 // For all contexts except EffectContext We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003842 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003843 if (!context()->IsEffect()) {
3844 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003845 }
3846 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003847 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003848 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003849 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003850 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3851 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003852 }
3853 break;
3854 case NAMED_PROPERTY: {
3855 __ mov(ecx, prop->key()->AsLiteral()->handle());
3856 __ pop(edx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003857 Handle<Code> ic = is_strict_mode()
3858 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3859 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003860 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003861 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003862 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003863 if (!context()->IsEffect()) {
3864 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003865 }
3866 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003867 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003868 }
3869 break;
3870 }
3871 case KEYED_PROPERTY: {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003872 __ pop(ecx);
3873 __ pop(edx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003874 Handle<Code> ic = is_strict_mode()
3875 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3876 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003877 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003878 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003879 if (expr->is_postfix()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003880 // Result is on the stack
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003881 if (!context()->IsEffect()) {
3882 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003883 }
3884 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003885 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003886 }
3887 break;
3888 }
3889 }
3890}
3891
3892
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003893void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003894 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003895 ASSERT(!context()->IsEffect());
3896 ASSERT(!context()->IsTest());
3897
ricow@chromium.org65fae842010-08-25 15:26:24 +00003898 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3899 Comment cmnt(masm_, "Global variable");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003900 __ mov(eax, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003901 __ mov(ecx, Immediate(proxy->name()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003902 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003903 // Use a regular load, not a contextual load, to avoid a reference
3904 // error.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003905 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003906 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003907 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003908 } else if (proxy != NULL &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003909 proxy->var()->AsSlot() != NULL &&
3910 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003911 Label done, slow;
3912
3913 // Generate code for loading from variables potentially shadowed
3914 // by eval-introduced variables.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003915 Slot* slot = proxy->var()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003916 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3917
3918 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003919 __ push(esi);
3920 __ push(Immediate(proxy->name()));
3921 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003922 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003923 __ bind(&done);
3924
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003925 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003926 } else {
3927 // This expression cannot throw a reference error at the top level.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003928 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003929 }
3930}
3931
3932
ricow@chromium.org65fae842010-08-25 15:26:24 +00003933bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
3934 Expression* left,
3935 Expression* right,
3936 Label* if_true,
3937 Label* if_false,
3938 Label* fall_through) {
3939 if (op != Token::EQ && op != Token::EQ_STRICT) return false;
3940
3941 // Check for the pattern: typeof <expression> == <string literal>.
3942 Literal* right_literal = right->AsLiteral();
3943 if (right_literal == NULL) return false;
3944 Handle<Object> right_literal_value = right_literal->handle();
3945 if (!right_literal_value->IsString()) return false;
3946 UnaryOperation* left_unary = left->AsUnaryOperation();
3947 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
3948 Handle<String> check = Handle<String>::cast(right_literal_value);
3949
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003950 { AccumulatorValueContext context(this);
3951 VisitForTypeofValue(left_unary->expression());
3952 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003953 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003955 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003956 __ JumpIfSmi(eax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003957 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003958 isolate()->factory()->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003959 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003960 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003961 __ JumpIfSmi(eax, if_false);
3962 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
3963 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003964 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003965 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
3966 1 << Map::kIsUndetectable);
3967 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003968 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
3969 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003970 __ j(equal, if_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003971 __ cmp(eax, isolate()->factory()->false_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003972 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003973 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
3974 __ cmp(eax, isolate()->factory()->undefined_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003975 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003976 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003977 // Check for undetectable objects => true.
3978 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3979 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3980 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3981 Split(not_zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003983 __ JumpIfSmi(eax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003984 __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003985 Split(above_equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003986 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003987 __ JumpIfSmi(eax, if_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 __ cmp(eax, isolate()->factory()->null_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003989 __ j(equal, if_true);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003990 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003991 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003992 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
3993 __ j(above, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003994 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003995 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
3996 1 << Map::kIsUndetectable);
3997 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003998 } else {
3999 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004000 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004001
4002 return true;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004003}
4004
4005
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004006void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4007 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004008 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004009
4010 // Always perform the comparison for its control flow. Pack the result
4011 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004012
4013 Label materialize_true, materialize_false;
4014 Label* if_true = NULL;
4015 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004016 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004017 context()->PrepareTest(&materialize_true, &materialize_false,
4018 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004019
4020 // First we try a fast inlined version of the compare when one of
4021 // the operands is a literal.
4022 Token::Value op = expr->op();
4023 Expression* left = expr->left();
4024 Expression* right = expr->right();
4025 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004026 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004027 return;
4028 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004029
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004030 VisitForStackValue(expr->left());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004031 switch (expr->op()) {
4032 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004033 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004034 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004035 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004036 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004037 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004038 break;
4039
4040 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004041 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004042 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004043 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004044 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004045 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004046 // The stub returns 0 for true.
4047 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004048 break;
4049 }
4050
4051 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004052 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004053 Condition cc = no_condition;
4054 bool strict = false;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004055 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004056 case Token::EQ_STRICT:
4057 strict = true;
4058 // Fall through
ricow@chromium.org65fae842010-08-25 15:26:24 +00004059 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004060 cc = equal;
4061 __ pop(edx);
4062 break;
4063 case Token::LT:
4064 cc = less;
4065 __ pop(edx);
4066 break;
4067 case Token::GT:
4068 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4069 cc = less;
4070 __ mov(edx, result_register());
4071 __ pop(eax);
4072 break;
4073 case Token::LTE:
4074 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4075 cc = greater_equal;
4076 __ mov(edx, result_register());
4077 __ pop(eax);
4078 break;
4079 case Token::GTE:
4080 cc = greater_equal;
4081 __ pop(edx);
4082 break;
4083 case Token::IN:
4084 case Token::INSTANCEOF:
4085 default:
4086 UNREACHABLE();
4087 }
4088
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004089 bool inline_smi_code = ShouldInlineSmiCase(op);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004090 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004091 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004092 Label slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004093 __ mov(ecx, Operand(edx));
4094 __ or_(ecx, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004095 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004096 __ cmp(edx, Operand(eax));
4097 Split(cc, if_true, if_false, NULL);
4098 __ bind(&slow_case);
4099 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004100
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004101 // Record position and call the compare IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004102 SetSourcePosition(expr->position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004103 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004104 EmitCallIC(ic, &patch_site, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004105
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004106 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004107 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004108 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004109 }
4110 }
4111
4112 // Convert the result of the comparison into one expected for this
4113 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004114 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004115}
4116
4117
ricow@chromium.org65fae842010-08-25 15:26:24 +00004118void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4119 Label materialize_true, materialize_false;
4120 Label* if_true = NULL;
4121 Label* if_false = NULL;
4122 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004123 context()->PrepareTest(&materialize_true, &materialize_false,
4124 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004125
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004126 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004127 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004129 __ cmp(eax, isolate()->factory()->null_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004130 if (expr->is_strict()) {
4131 Split(equal, if_true, if_false, fall_through);
4132 } else {
4133 __ j(equal, if_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004134 __ cmp(eax, isolate()->factory()->undefined_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004135 __ j(equal, if_true);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004136 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004137 // It can be an undetectable object.
4138 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4139 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
4140 __ test(edx, Immediate(1 << Map::kIsUndetectable));
4141 Split(not_zero, if_true, if_false, fall_through);
4142 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004143 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004144}
4145
4146
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004147void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4148 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004149 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004150}
4151
4152
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004153Register FullCodeGenerator::result_register() {
4154 return eax;
4155}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004156
4157
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004158Register FullCodeGenerator::context_register() {
4159 return esi;
4160}
4161
4162
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004163void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
4164 RelocInfo::Mode mode,
4165 unsigned ast_id) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004166 ASSERT(mode == RelocInfo::CODE_TARGET ||
4167 mode == RelocInfo::CODE_TARGET_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004168 switch (ic->kind()) {
4169 case Code::LOAD_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004170 __ IncrementCounter(isolate()->counters()->named_load_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004171 break;
4172 case Code::KEYED_LOAD_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173 __ IncrementCounter(isolate()->counters()->keyed_load_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004174 break;
4175 case Code::STORE_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 __ IncrementCounter(isolate()->counters()->named_store_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004177 break;
4178 case Code::KEYED_STORE_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004179 __ IncrementCounter(isolate()->counters()->keyed_store_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004180 default:
4181 break;
4182 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004183 __ call(ic, mode, ast_id);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004184}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004185
4186
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004187void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
4188 JumpPatchSite* patch_site,
4189 unsigned ast_id) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004190 Counters* counters = isolate()->counters();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004191 switch (ic->kind()) {
4192 case Code::LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004193 __ IncrementCounter(counters->named_load_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004194 break;
4195 case Code::KEYED_LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004196 __ IncrementCounter(counters->keyed_load_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004197 break;
4198 case Code::STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004199 __ IncrementCounter(counters->named_store_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004200 break;
4201 case Code::KEYED_STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004202 __ IncrementCounter(counters->keyed_store_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004203 default:
4204 break;
4205 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004206 __ call(ic, RelocInfo::CODE_TARGET, ast_id);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004207 if (patch_site != NULL && patch_site->is_bound()) {
4208 patch_site->EmitPatchInfo();
4209 } else {
4210 __ nop(); // Signals no inlined code.
4211 }
4212}
4213
4214
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004215void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4216 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4217 __ mov(Operand(ebp, frame_offset), value);
4218}
4219
4220
4221void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004222 __ mov(dst, ContextOperand(esi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004223}
4224
4225
4226// ----------------------------------------------------------------------------
4227// Non-local control flow support.
4228
4229void FullCodeGenerator::EnterFinallyBlock() {
4230 // Cook return address on top of stack (smi encoded Code* delta)
4231 ASSERT(!result_register().is(edx));
4232 __ mov(edx, Operand(esp, 0));
4233 __ sub(Operand(edx), Immediate(masm_->CodeObject()));
4234 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4235 ASSERT_EQ(0, kSmiTag);
4236 __ add(edx, Operand(edx)); // Convert to smi.
4237 __ mov(Operand(esp, 0), edx);
4238 // Store result register while executing finally block.
4239 __ push(result_register());
4240}
4241
4242
4243void FullCodeGenerator::ExitFinallyBlock() {
4244 ASSERT(!result_register().is(edx));
4245 // Restore result register from stack.
4246 __ pop(result_register());
4247 // Uncook return address.
4248 __ mov(edx, Operand(esp, 0));
4249 __ sar(edx, 1); // Convert smi to int.
4250 __ add(Operand(edx), Immediate(masm_->CodeObject()));
4251 __ mov(Operand(esp, 0), edx);
4252 // And return.
4253 __ ret(0);
4254}
4255
4256
4257#undef __
4258
4259} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004260
4261#endif // V8_TARGET_ARCH_IA32