blob: c341b084ce3db2c938f9cc32e51a2aedd4b6fbdd [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) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000569 ToBooleanStub stub(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000570 __ push(result_register());
571 __ CallStub(&stub);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000572 __ test(result_register(), Operand(result_register()));
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) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000690 // Check that we're not inside a with or catch context.
691 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
692 __ cmp(ebx, isolate()->factory()->with_context_map());
693 __ Check(not_equal, "Declaration in with context.");
694 __ cmp(ebx, isolate()->factory()->catch_context_map());
695 __ Check(not_equal, "Declaration in catch context.");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000696 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000697 if (mode == Variable::CONST) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000698 __ mov(ContextOperand(esi, slot->index()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000699 Immediate(isolate()->factory()->the_hole_value()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000700 // No write barrier since the hole value is in old space.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000701 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000702 VisitForAccumulatorValue(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000703 __ mov(ContextOperand(esi, slot->index()), result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000704 int offset = Context::SlotOffset(slot->index());
705 __ mov(ebx, esi);
706 __ RecordWrite(ebx, offset, result_register(), ecx);
707 }
708 break;
709
710 case Slot::LOOKUP: {
711 __ push(esi);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000712 __ push(Immediate(variable->name()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000713 // Declaration nodes are always introduced in one of two modes.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000714 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
715 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000716 __ push(Immediate(Smi::FromInt(attr)));
717 // Push initial value, if any.
718 // Note: For variables we must not push an initial value (such as
719 // 'undefined') because we may have a (legal) redeclaration and we
720 // must not destroy the current value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000721 if (mode == Variable::CONST) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000722 __ push(Immediate(isolate()->factory()->the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000723 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000724 VisitForStackValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000725 } else {
726 __ push(Immediate(Smi::FromInt(0))); // No initial value!
727 }
728 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
729 break;
730 }
731 }
732
733 } else if (prop != NULL) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000734 // A const declaration aliasing a parameter is an illegal redeclaration.
735 ASSERT(mode != Variable::CONST);
736 if (function != NULL) {
737 // We are declaring a function that rewrites to a property.
738 // Use (keyed) IC to set the initial value. We cannot visit the
739 // rewrite because it's shared and we risk recording duplicate AST
740 // IDs for bailouts from optimized code.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000741 ASSERT(prop->obj()->AsVariableProxy() != NULL);
742 { AccumulatorValueContext for_object(this);
743 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000744 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000745
danno@chromium.org40cb8782011-05-25 07:58:50 +0000746 __ push(eax);
747 VisitForAccumulatorValue(function);
748 __ pop(edx);
749
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000750 ASSERT(prop->key()->AsLiteral() != NULL &&
751 prop->key()->AsLiteral()->handle()->IsSmi());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000752 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000753
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000754 Handle<Code> ic = is_strict_mode()
755 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
756 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000757 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000758 }
759 }
760}
761
762
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000763void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
764 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
765}
766
767
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000768void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
769 // Call the runtime to declare the globals.
770 __ push(esi); // The context is the first argument.
771 __ push(Immediate(pairs));
ager@chromium.org5c838252010-02-19 08:53:10 +0000772 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000773 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
774 __ CallRuntime(Runtime::kDeclareGlobals, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000775 // Return value is ignored.
776}
777
778
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000779void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
780 Comment cmnt(masm_, "[ SwitchStatement");
781 Breakable nested_statement(this, stmt);
782 SetStatementPosition(stmt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000783
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000784 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000785 VisitForStackValue(stmt->tag());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000786 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000787
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000788 ZoneList<CaseClause*>* clauses = stmt->cases();
789 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000790
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000791 Label next_test; // Recycled for each test.
792 // Compile all the tests with branches to their bodies.
793 for (int i = 0; i < clauses->length(); i++) {
794 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000795 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000796
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000797 // The default is not a test, but remember it as final fall through.
798 if (clause->is_default()) {
799 default_clause = clause;
800 continue;
801 }
802
803 Comment cmnt(masm_, "[ Case comparison");
804 __ bind(&next_test);
805 next_test.Unuse();
806
807 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000808 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000809
ricow@chromium.org65fae842010-08-25 15:26:24 +0000810 // Perform the comparison as if via '==='.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000811 __ mov(edx, Operand(esp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000812 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000813 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000814 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000815 Label slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000816 __ mov(ecx, edx);
817 __ or_(ecx, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000818 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000819
ricow@chromium.org65fae842010-08-25 15:26:24 +0000820 __ cmp(edx, Operand(eax));
821 __ j(not_equal, &next_test);
822 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000823 __ jmp(clause->body_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000824 __ bind(&slow_case);
825 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000826
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000827 // Record position before stub call for type feedback.
828 SetSourcePosition(clause->position());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000829 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000830 EmitCallIC(ic, &patch_site, clause->CompareId());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000831 __ test(eax, Operand(eax));
832 __ j(not_equal, &next_test);
833 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000834 __ jmp(clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000835 }
836
837 // Discard the test value and jump to the default if present, otherwise to
838 // the end of the statement.
839 __ bind(&next_test);
840 __ Drop(1); // Switch value is no longer needed.
841 if (default_clause == NULL) {
842 __ jmp(nested_statement.break_target());
843 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000844 __ jmp(default_clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000845 }
846
847 // Compile all the case bodies.
848 for (int i = 0; i < clauses->length(); i++) {
849 Comment cmnt(masm_, "[ Case body");
850 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000851 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000852 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000853 VisitStatements(clause->statements());
854 }
855
856 __ bind(nested_statement.break_target());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000857 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000858}
859
860
861void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
862 Comment cmnt(masm_, "[ ForInStatement");
863 SetStatementPosition(stmt);
864
865 Label loop, exit;
866 ForIn loop_statement(this, stmt);
867 increment_loop_depth();
868
869 // Get the object to enumerate over. Both SpiderMonkey and JSC
870 // ignore null and undefined in contrast to the specification; see
871 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000872 VisitForAccumulatorValue(stmt->enumerable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 __ cmp(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000874 __ j(equal, &exit);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000875 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000876 __ j(equal, &exit);
877
878 // Convert the object to a JS object.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000879 Label convert, done_convert;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000880 __ JumpIfSmi(eax, &convert, Label::kNear);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000881 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000882 __ j(above_equal, &done_convert, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000883 __ bind(&convert);
884 __ push(eax);
885 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
886 __ bind(&done_convert);
887 __ push(eax);
888
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000889 // Check cache validity in generated code. This is a fast case for
890 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
891 // guarantee cache validity, call the runtime system to check cache
892 // validity or get the property names in a fixed array.
893 Label next, call_runtime;
894 __ mov(ecx, eax);
895 __ bind(&next);
896
897 // Check that there are no elements. Register ecx contains the
898 // current JS object we've reached through the prototype chain.
899 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000900 isolate()->factory()->empty_fixed_array());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000901 __ j(not_equal, &call_runtime);
902
903 // Check that instance descriptors are not empty so that we can
904 // check for an enum cache. Leave the map in ebx for the subsequent
905 // prototype load.
906 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000907 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset));
908 __ JumpIfSmi(edx, &call_runtime);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000909
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000910 // Check that there is an enum cache in the non-empty instance
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000911 // descriptors (edx). This is the case if the next enumeration
912 // index field does not contain a smi.
913 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000914 __ JumpIfSmi(edx, &call_runtime);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000915
916 // For all objects but the receiver, check that the cache is empty.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000917 Label check_prototype;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000918 __ cmp(ecx, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000919 __ j(equal, &check_prototype, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000920 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 __ cmp(edx, isolate()->factory()->empty_fixed_array());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000922 __ j(not_equal, &call_runtime);
923
924 // Load the prototype from the map and loop if non-null.
925 __ bind(&check_prototype);
926 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 __ cmp(ecx, isolate()->factory()->null_value());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000928 __ j(not_equal, &next);
929
930 // The enum cache is valid. Load the map of the object being
931 // iterated over and use the cache for the iteration.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000932 Label use_cache;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000933 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000934 __ jmp(&use_cache, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000935
936 // Get the set of properties to enumerate.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000937 __ bind(&call_runtime);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000938 __ push(eax); // Duplicate the enumerable object on the stack.
939 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
940
941 // If we got a map from the runtime call, we can do a fast
942 // modification check. Otherwise, we got a fixed array, and we have
943 // to do a slow check.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000944 Label fixed_array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000945 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
946 isolate()->factory()->meta_map());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000947 __ j(not_equal, &fixed_array, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000948
949 // We got a map in register eax. Get the enumeration cache from it.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000950 __ bind(&use_cache);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000951 __ LoadInstanceDescriptors(eax, ecx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000952 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
953 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
954
955 // Setup the four remaining stack slots.
956 __ push(eax); // Map.
957 __ push(edx); // Enumeration cache.
958 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000959 __ push(eax); // Enumeration cache length (as smi).
960 __ push(Immediate(Smi::FromInt(0))); // Initial index.
961 __ jmp(&loop);
962
963 // We got a fixed array in register eax. Iterate through that.
964 __ bind(&fixed_array);
965 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
966 __ push(eax);
967 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000968 __ push(eax); // Fixed array length (as smi).
969 __ push(Immediate(Smi::FromInt(0))); // Initial index.
970
971 // Generate code for doing the condition check.
972 __ bind(&loop);
973 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
974 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
975 __ j(above_equal, loop_statement.break_target());
976
977 // Get the current entry of the array into register ebx.
978 __ mov(ebx, Operand(esp, 2 * kPointerSize));
979 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
980
981 // Get the expected map from the stack or a zero map in the
982 // permanent slow case into register edx.
983 __ mov(edx, Operand(esp, 3 * kPointerSize));
984
985 // Check if the expected map still matches that of the enumerable.
986 // If not, we have to filter the key.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000987 Label update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000988 __ mov(ecx, Operand(esp, 4 * kPointerSize));
989 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000990 __ j(equal, &update_each, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000991
992 // Convert the entry to a string or null if it isn't a property
993 // anymore. If the property has been removed while iterating, we
994 // just skip it.
995 __ push(ecx); // Enumerable.
996 __ push(ebx); // Current entry.
997 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000998 __ test(eax, Operand(eax));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000999 __ j(equal, loop_statement.continue_target());
1000 __ mov(ebx, Operand(eax));
1001
1002 // Update the 'each' property or variable from the possibly filtered
1003 // entry in register ebx.
1004 __ bind(&update_each);
1005 __ mov(result_register(), ebx);
1006 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001007 { EffectContext context(this);
1008 EmitAssignment(stmt->each(), stmt->AssignmentId());
1009 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001010
1011 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001012 Visit(stmt->body());
1013
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001014 // Generate code for going to the next element by incrementing the
1015 // index (smi) stored on top of the stack.
1016 __ bind(loop_statement.continue_target());
1017 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001018
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019 EmitStackCheck(stmt);
1020 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001021
1022 // Remove the pointers stored on the stack.
1023 __ bind(loop_statement.break_target());
1024 __ add(Operand(esp), Immediate(5 * kPointerSize));
1025
1026 // Exit and decrement the loop depth.
1027 __ bind(&exit);
1028 decrement_loop_depth();
1029}
1030
1031
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001032void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1033 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001034 // Use the fast case closure allocation code that allocates in new
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001035 // space for nested functions that don't need literals cloning. If
1036 // we're running with the --always-opt or the --prepare-always-opt
1037 // flag, we need to use the runtime function so that the new function
1038 // we are creating here gets a chance to have its code optimized and
1039 // doesn't just get a copy of the existing unoptimized code.
1040 if (!FLAG_always_opt &&
1041 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 !pretenure &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001043 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001044 info->num_literals() == 0) {
1045 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001046 __ push(Immediate(info));
1047 __ CallStub(&stub);
1048 } else {
1049 __ push(esi);
1050 __ push(Immediate(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001051 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052 ? isolate()->factory()->true_value()
1053 : isolate()->factory()->false_value()));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001054 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001055 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001056 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001057}
1058
1059
1060void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1061 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001062 EmitVariableLoad(expr->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001063}
1064
1065
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001066void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
1067 Slot* slot,
1068 TypeofState typeof_state,
1069 Label* slow) {
1070 Register context = esi;
1071 Register temp = edx;
1072
1073 Scope* s = scope();
1074 while (s != NULL) {
1075 if (s->num_heap_slots() > 0) {
1076 if (s->calls_eval()) {
1077 // Check that extension is NULL.
1078 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1079 Immediate(0));
1080 __ j(not_equal, slow);
1081 }
1082 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001083 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001084 // Walk the rest of the chain without clobbering esi.
1085 context = temp;
1086 }
1087 // If no outer scope calls eval, we do not need to check more
1088 // context extensions. If we have reached an eval scope, we check
1089 // all extensions from this point.
1090 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1091 s = s->outer_scope();
1092 }
1093
1094 if (s != NULL && s->is_eval_scope()) {
1095 // Loop up the context chain. There is no frame effect so it is
1096 // safe to use raw labels here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001097 Label next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001098 if (!context.is(temp)) {
1099 __ mov(temp, context);
1100 }
1101 __ bind(&next);
1102 // Terminate at global context.
1103 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001104 Immediate(isolate()->factory()->global_context_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001105 __ j(equal, &fast, Label::kNear);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001106 // Check that extension is NULL.
1107 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1108 __ j(not_equal, slow);
1109 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001110 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001111 __ jmp(&next);
1112 __ bind(&fast);
1113 }
1114
1115 // All extension objects were empty and it is safe to use a global
1116 // load IC call.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001117 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001118 __ mov(ecx, slot->var()->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001119 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001120 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1121 ? RelocInfo::CODE_TARGET
1122 : RelocInfo::CODE_TARGET_CONTEXT;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001123 EmitCallIC(ic, mode, AstNode::kNoNumber);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001124}
1125
1126
1127MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1128 Slot* slot,
1129 Label* slow) {
1130 ASSERT(slot->type() == Slot::CONTEXT);
1131 Register context = esi;
1132 Register temp = ebx;
1133
1134 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1135 if (s->num_heap_slots() > 0) {
1136 if (s->calls_eval()) {
1137 // Check that extension is NULL.
1138 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1139 Immediate(0));
1140 __ j(not_equal, slow);
1141 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001142 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001143 // Walk the rest of the chain without clobbering esi.
1144 context = temp;
1145 }
1146 }
1147 // Check that last extension is NULL.
1148 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1149 __ j(not_equal, slow);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001150
1151 // This function is used only for loads, not stores, so it's safe to
1152 // return an esi-based operand (the write barrier cannot be allowed to
1153 // destroy the esi register).
1154 return ContextOperand(context, slot->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001155}
1156
1157
1158void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1159 Slot* slot,
1160 TypeofState typeof_state,
1161 Label* slow,
1162 Label* done) {
1163 // Generate fast-case code for variables that might be shadowed by
1164 // eval-introduced variables. Eval is used a lot without
1165 // introducing variables. In those cases, we do not want to
1166 // perform a runtime call for all variables in the scope
1167 // containing the eval.
1168 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1169 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1170 __ jmp(done);
1171 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001172 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001173 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1174 if (potential_slot != NULL) {
1175 // Generate fast case for locals that rewrite to slots.
1176 __ mov(eax,
1177 ContextSlotOperandCheckExtensions(potential_slot, slow));
1178 if (potential_slot->var()->mode() == Variable::CONST) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001179 __ cmp(eax, isolate()->factory()->the_hole_value());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001180 __ j(not_equal, done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001181 __ mov(eax, isolate()->factory()->undefined_value());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001182 }
1183 __ jmp(done);
1184 } else if (rewrite != NULL) {
1185 // Generate fast case for calls of an argument function.
1186 Property* property = rewrite->AsProperty();
1187 if (property != NULL) {
1188 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1189 Literal* key_literal = property->key()->AsLiteral();
1190 if (obj_proxy != NULL &&
1191 key_literal != NULL &&
1192 obj_proxy->IsArguments() &&
1193 key_literal->handle()->IsSmi()) {
1194 // Load arguments object if there are no eval-introduced
1195 // variables. Then load the argument from the arguments
1196 // object using keyed load.
1197 __ mov(edx,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001198 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001199 slow));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001200 __ SafeSet(eax, Immediate(key_literal->handle()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001201 Handle<Code> ic =
1202 isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001203 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001204 __ jmp(done);
1205 }
1206 }
1207 }
1208 }
1209}
1210
1211
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001212void FullCodeGenerator::EmitVariableLoad(Variable* var) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001213 // Three cases: non-this global variables, lookup slots, and all other
1214 // types of slots.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001215 Slot* slot = var->AsSlot();
whesse@chromium.org7b260152011-06-20 15:33:18 +00001216 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001217
whesse@chromium.org7b260152011-06-20 15:33:18 +00001218 if (slot == NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001219 Comment cmnt(masm_, "Global variable");
1220 // Use inline caching. Variable name is passed in ecx and the global
1221 // object on the stack.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001222 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001223 __ mov(ecx, var->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001224 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001225 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001226 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001227
whesse@chromium.org7b260152011-06-20 15:33:18 +00001228 } else if (slot->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001229 Label done, slow;
1230
1231 // Generate code for loading from variables potentially shadowed
1232 // by eval-introduced variables.
1233 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1234
1235 __ bind(&slow);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001236 Comment cmnt(masm_, "Lookup slot");
1237 __ push(esi); // Context.
1238 __ push(Immediate(var->name()));
1239 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001240 __ bind(&done);
1241
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001242 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001243
whesse@chromium.org7b260152011-06-20 15:33:18 +00001244 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001245 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1246 ? "Context slot"
1247 : "Stack slot");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001248 if (var->mode() == Variable::CONST) {
1249 // Constants may be the hole value if they have not been initialized.
1250 // Unhole them.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001251 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001252 MemOperand slot_operand = EmitSlotSearch(slot, eax);
1253 __ mov(eax, slot_operand);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001254 __ cmp(eax, isolate()->factory()->the_hole_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001255 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001256 __ mov(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001257 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001258 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001259 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001260 context()->Plug(slot);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001261 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001262 }
1263}
1264
1265
1266void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1267 Comment cmnt(masm_, "[ RegExpLiteral");
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001268 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001269 // Registers will be used as follows:
1270 // edi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001271 // ecx = literals array.
1272 // ebx = regexp literal.
1273 // eax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001274 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001275 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001276 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001277 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001278 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001279 __ cmp(ebx, isolate()->factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001280 __ j(not_equal, &materialized, Label::kNear);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001281
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001282 // Create regexp literal using runtime function
1283 // Result will be in eax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001284 __ push(ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001285 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1286 __ push(Immediate(expr->pattern()));
1287 __ push(Immediate(expr->flags()));
1288 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001289 __ mov(ebx, eax);
1290
1291 __ bind(&materialized);
1292 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1293 Label allocated, runtime_allocate;
1294 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1295 __ jmp(&allocated);
1296
1297 __ bind(&runtime_allocate);
1298 __ push(ebx);
1299 __ push(Immediate(Smi::FromInt(size)));
1300 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1301 __ pop(ebx);
1302
1303 __ bind(&allocated);
1304 // Copy the content into the newly allocated memory.
1305 // (Unroll copy loop once for better throughput).
1306 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1307 __ mov(edx, FieldOperand(ebx, i));
1308 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1309 __ mov(FieldOperand(eax, i), edx);
1310 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1311 }
1312 if ((size % (2 * kPointerSize)) != 0) {
1313 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1314 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1315 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001316 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001317}
1318
1319
1320void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1321 Comment cmnt(masm_, "[ ObjectLiteral");
1322 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1323 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1324 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1325 __ push(Immediate(expr->constant_properties()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 int flags = expr->fast_elements()
1327 ? ObjectLiteral::kFastElements
1328 : ObjectLiteral::kNoFlags;
1329 flags |= expr->has_function()
1330 ? ObjectLiteral::kHasFunction
1331 : ObjectLiteral::kNoFlags;
1332 __ push(Immediate(Smi::FromInt(flags)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001333 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001334 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001335 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001336 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001337 }
1338
1339 // If result_saved is true the result is on top of the stack. If
1340 // result_saved is false the result is in eax.
1341 bool result_saved = false;
1342
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001343 // Mark all computed expressions that are bound to a key that
1344 // is shadowed by a later occurrence of the same key. For the
1345 // marked expressions, no store code is emitted.
1346 expr->CalculateEmitStore();
1347
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001348 for (int i = 0; i < expr->properties()->length(); i++) {
1349 ObjectLiteral::Property* property = expr->properties()->at(i);
1350 if (property->IsCompileTimeValue()) continue;
1351
1352 Literal* key = property->key();
1353 Expression* value = property->value();
1354 if (!result_saved) {
1355 __ push(eax); // Save result on the stack
1356 result_saved = true;
1357 }
1358 switch (property->kind()) {
1359 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1360 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1361 // Fall through.
1362 case ObjectLiteral::Property::COMPUTED:
1363 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001364 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001365 VisitForAccumulatorValue(value);
1366 __ mov(ecx, Immediate(key->handle()));
1367 __ mov(edx, Operand(esp, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001368 Handle<Code> ic = is_strict_mode()
1369 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1370 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001371 EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001372 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1373 } else {
1374 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001375 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001376 break;
1377 }
1378 // Fall through.
1379 case ObjectLiteral::Property::PROTOTYPE:
1380 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001381 VisitForStackValue(key);
1382 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001383 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001384 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1385 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001386 } else {
1387 __ Drop(3);
1388 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001389 break;
1390 case ObjectLiteral::Property::SETTER:
1391 case ObjectLiteral::Property::GETTER:
1392 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001393 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001394 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
1395 Smi::FromInt(1) :
1396 Smi::FromInt(0)));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001397 VisitForStackValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001398 __ CallRuntime(Runtime::kDefineAccessor, 4);
1399 break;
1400 default: UNREACHABLE();
1401 }
1402 }
1403
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001404 if (expr->has_function()) {
1405 ASSERT(result_saved);
1406 __ push(Operand(esp, 0));
1407 __ CallRuntime(Runtime::kToFastProperties, 1);
1408 }
1409
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001410 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001411 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001412 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001413 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001414 }
1415}
1416
1417
1418void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1419 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001420
1421 ZoneList<Expression*>* subexprs = expr->values();
1422 int length = subexprs->length();
1423
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001424 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1425 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1426 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1427 __ push(Immediate(expr->constant_elements()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 if (expr->constant_elements()->map() ==
1429 isolate()->heap()->fixed_cow_array_map()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001430 ASSERT(expr->depth() == 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001431 FastCloneShallowArrayStub stub(
1432 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1433 __ CallStub(&stub);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001434 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001435 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001436 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001437 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001438 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001439 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001440 FastCloneShallowArrayStub stub(
1441 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001442 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001443 }
1444
1445 bool result_saved = false; // Is the result saved to the stack?
1446
1447 // Emit code to evaluate all the non-constant subexpressions and to store
1448 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001449 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001450 Expression* subexpr = subexprs->at(i);
1451 // If the subexpression is a literal or a simple materialized literal it
1452 // is already set in the cloned array.
1453 if (subexpr->AsLiteral() != NULL ||
1454 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1455 continue;
1456 }
1457
1458 if (!result_saved) {
1459 __ push(eax);
1460 result_saved = true;
1461 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001462 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001463
1464 // Store the subexpression value in the array's elements.
1465 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1466 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1467 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1468 __ mov(FieldOperand(ebx, offset), result_register());
1469
1470 // Update the write barrier for the array store.
1471 __ RecordWrite(ebx, offset, result_register(), ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001472
1473 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001474 }
1475
1476 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001477 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001478 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001479 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001480 }
1481}
1482
1483
ager@chromium.org5c838252010-02-19 08:53:10 +00001484void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1485 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001486 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1487 // on the left-hand side.
1488 if (!expr->target()->IsValidLeftHandSide()) {
1489 VisitForEffect(expr->target());
1490 return;
1491 }
1492
ager@chromium.org5c838252010-02-19 08:53:10 +00001493 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001494 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001495 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1496 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001497 Property* property = expr->target()->AsProperty();
1498 if (property != NULL) {
1499 assign_type = (property->key()->IsPropertyName())
1500 ? NAMED_PROPERTY
1501 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001502 }
1503
1504 // Evaluate LHS expression.
1505 switch (assign_type) {
1506 case VARIABLE:
1507 // Nothing to do here.
1508 break;
1509 case NAMED_PROPERTY:
1510 if (expr->is_compound()) {
1511 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001512 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001513 __ push(result_register());
1514 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001515 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001516 }
1517 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001518 case KEYED_PROPERTY: {
ager@chromium.org5c838252010-02-19 08:53:10 +00001519 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001520 VisitForStackValue(property->obj());
1521 VisitForAccumulatorValue(property->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00001522 __ mov(edx, Operand(esp, 0));
1523 __ push(eax);
1524 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001525 VisitForStackValue(property->obj());
1526 VisitForStackValue(property->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00001527 }
1528 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001529 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001530 }
1531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001532 // For compound assignments we need another deoptimization point after the
1533 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001534 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001535 { AccumulatorValueContext context(this);
1536 switch (assign_type) {
1537 case VARIABLE:
1538 EmitVariableLoad(expr->target()->AsVariableProxy()->var());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001539 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001540 break;
1541 case NAMED_PROPERTY:
1542 EmitNamedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001543 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001544 break;
1545 case KEYED_PROPERTY:
1546 EmitKeyedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001547 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001548 break;
1549 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001550 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001551
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001552 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001553 __ push(eax); // Left operand goes on the stack.
1554 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001555
ricow@chromium.org65fae842010-08-25 15:26:24 +00001556 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1557 ? OVERWRITE_RIGHT
1558 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001559 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001560 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001561 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001562 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001563 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001564 mode,
1565 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001566 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001567 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001568 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001569 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001570
1571 // Deoptimization point in case the binary operation may have side effects.
1572 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001573 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001574 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001575 }
1576
1577 // Record source position before possible IC call.
1578 SetSourcePosition(expr->position());
1579
1580 // Store the value.
1581 switch (assign_type) {
1582 case VARIABLE:
1583 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001584 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001585 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1586 context()->Plug(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001587 break;
1588 case NAMED_PROPERTY:
1589 EmitNamedPropertyAssignment(expr);
1590 break;
1591 case KEYED_PROPERTY:
1592 EmitKeyedPropertyAssignment(expr);
1593 break;
1594 }
1595}
1596
1597
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001598void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1599 SetSourcePosition(prop->position());
1600 Literal* key = prop->key()->AsLiteral();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001601 ASSERT(!key->handle()->IsSmi());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001602 __ mov(ecx, Immediate(key->handle()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001603 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001604 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001605}
1606
1607
1608void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1609 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001610 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001611 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001612}
1613
1614
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001615void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001616 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001617 OverwriteMode mode,
1618 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001619 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001620 // Do combined smi check of the operands. Left operand is on the
1621 // stack. Right operand is in eax.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001622 Label smi_case, done, stub_call;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001623 __ pop(edx);
1624 __ mov(ecx, eax);
1625 __ or_(eax, Operand(edx));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001626 JumpPatchSite patch_site(masm_);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001627 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001628
1629 __ bind(&stub_call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001630 __ mov(eax, ecx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001631 BinaryOpStub stub(op, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001632 EmitCallIC(stub.GetCode(), &patch_site, expr->id());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001633 __ jmp(&done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001634
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001635 // Smi case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001636 __ bind(&smi_case);
1637 __ mov(eax, edx); // Copy left operand in case of a stub call.
1638
1639 switch (op) {
1640 case Token::SAR:
1641 __ SmiUntag(eax);
1642 __ SmiUntag(ecx);
1643 __ sar_cl(eax); // No checks of result necessary
1644 __ SmiTag(eax);
1645 break;
1646 case Token::SHL: {
1647 Label result_ok;
1648 __ SmiUntag(eax);
1649 __ SmiUntag(ecx);
1650 __ shl_cl(eax);
1651 // Check that the *signed* result fits in a smi.
1652 __ cmp(eax, 0xc0000000);
1653 __ j(positive, &result_ok);
1654 __ SmiTag(ecx);
1655 __ jmp(&stub_call);
1656 __ bind(&result_ok);
1657 __ SmiTag(eax);
1658 break;
1659 }
1660 case Token::SHR: {
1661 Label result_ok;
1662 __ SmiUntag(eax);
1663 __ SmiUntag(ecx);
1664 __ shr_cl(eax);
1665 __ test(eax, Immediate(0xc0000000));
1666 __ j(zero, &result_ok);
1667 __ SmiTag(ecx);
1668 __ jmp(&stub_call);
1669 __ bind(&result_ok);
1670 __ SmiTag(eax);
1671 break;
1672 }
1673 case Token::ADD:
1674 __ add(eax, Operand(ecx));
1675 __ j(overflow, &stub_call);
1676 break;
1677 case Token::SUB:
1678 __ sub(eax, Operand(ecx));
1679 __ j(overflow, &stub_call);
1680 break;
1681 case Token::MUL: {
1682 __ SmiUntag(eax);
1683 __ imul(eax, Operand(ecx));
1684 __ j(overflow, &stub_call);
1685 __ test(eax, Operand(eax));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001686 __ j(not_zero, &done, Label::kNear);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001687 __ mov(ebx, edx);
1688 __ or_(ebx, Operand(ecx));
1689 __ j(negative, &stub_call);
1690 break;
1691 }
1692 case Token::BIT_OR:
1693 __ or_(eax, Operand(ecx));
1694 break;
1695 case Token::BIT_AND:
1696 __ and_(eax, Operand(ecx));
1697 break;
1698 case Token::BIT_XOR:
1699 __ xor_(eax, Operand(ecx));
1700 break;
1701 default:
1702 UNREACHABLE();
1703 }
1704
1705 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001706 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001707}
1708
1709
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001710void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1711 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001712 OverwriteMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001713 __ pop(edx);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001714 BinaryOpStub stub(op, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001715 // NULL signals no inlined smi code.
1716 EmitCallIC(stub.GetCode(), NULL, expr->id());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001717 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001718}
1719
1720
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001721void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001722 // Invalid left-hand sides are rewritten to have a 'throw
1723 // ReferenceError' on the left-hand side.
1724 if (!expr->IsValidLeftHandSide()) {
1725 VisitForEffect(expr);
1726 return;
1727 }
1728
1729 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001730 // slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001731 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1732 LhsKind assign_type = VARIABLE;
1733 Property* prop = expr->AsProperty();
1734 if (prop != NULL) {
1735 assign_type = (prop->key()->IsPropertyName())
1736 ? NAMED_PROPERTY
1737 : KEYED_PROPERTY;
1738 }
1739
1740 switch (assign_type) {
1741 case VARIABLE: {
1742 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001743 EffectContext context(this);
1744 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001745 break;
1746 }
1747 case NAMED_PROPERTY: {
1748 __ push(eax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001749 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001750 __ mov(edx, eax);
1751 __ pop(eax); // Restore value.
1752 __ mov(ecx, prop->key()->AsLiteral()->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001753 Handle<Code> ic = is_strict_mode()
1754 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1755 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001756 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001757 break;
1758 }
1759 case KEYED_PROPERTY: {
1760 __ push(eax); // Preserve value.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001761 if (prop->is_synthetic()) {
1762 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1763 ASSERT(prop->key()->AsLiteral() != NULL);
1764 { AccumulatorValueContext for_object(this);
1765 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1766 }
1767 __ mov(edx, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001768 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001769 } else {
1770 VisitForStackValue(prop->obj());
1771 VisitForAccumulatorValue(prop->key());
1772 __ mov(ecx, eax);
1773 __ pop(edx);
1774 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001775 __ pop(eax); // Restore value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001776 Handle<Code> ic = is_strict_mode()
1777 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1778 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001779 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001780 break;
1781 }
1782 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001783 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1784 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001785}
1786
1787
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001788void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001789 Token::Value op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001790 ASSERT(var != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001791 ASSERT(var->is_global() || var->AsSlot() != NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001792
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001793 if (var->is_global()) {
1794 ASSERT(!var->is_this());
1795 // Assignment to a global variable. Use inline caching for the
1796 // assignment. Right-hand-side value is passed in eax, variable name in
1797 // ecx, and the global object on the stack.
1798 __ mov(ecx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001799 __ mov(edx, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001800 Handle<Code> ic = is_strict_mode()
1801 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1802 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001803 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001804
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001805 } else if (op == Token::INIT_CONST) {
1806 // Like var declarations, const declarations are hoisted to function
1807 // scope. However, unlike var initializers, const initializers are able
1808 // to drill a hole to that function context, even from inside a 'with'
1809 // context. We thus bypass the normal static scope lookup.
1810 Slot* slot = var->AsSlot();
1811 Label skip;
1812 switch (slot->type()) {
1813 case Slot::PARAMETER:
1814 // No const parameters.
1815 UNREACHABLE();
1816 break;
1817 case Slot::LOCAL:
1818 __ mov(edx, Operand(ebp, SlotOffset(slot)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001819 __ cmp(edx, isolate()->factory()->the_hole_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001820 __ j(not_equal, &skip);
1821 __ mov(Operand(ebp, SlotOffset(slot)), eax);
1822 break;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001823 case Slot::CONTEXT:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001824 case Slot::LOOKUP:
1825 __ push(eax);
1826 __ push(esi);
1827 __ push(Immediate(var->name()));
1828 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1829 break;
1830 }
1831 __ bind(&skip);
1832
1833 } else if (var->mode() != Variable::CONST) {
1834 // Perform the assignment for non-const variables. Const assignments
1835 // are simply skipped.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001836 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001837 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001838 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001839 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001840 // Perform the assignment.
1841 __ mov(Operand(ebp, SlotOffset(slot)), eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001842 break;
1843
1844 case Slot::CONTEXT: {
1845 MemOperand target = EmitSlotSearch(slot, ecx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001846 // Perform the assignment and issue the write barrier.
1847 __ mov(target, eax);
1848 // The value of the assignment is in eax. RecordWrite clobbers its
1849 // register arguments.
1850 __ mov(edx, eax);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001851 int offset = Context::SlotOffset(slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001852 __ RecordWrite(ecx, offset, edx, ebx);
1853 break;
1854 }
1855
1856 case Slot::LOOKUP:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001857 // Call the runtime for the assignment.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001858 __ push(eax); // Value.
1859 __ push(esi); // Context.
1860 __ push(Immediate(var->name()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001861 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
1862 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001863 break;
1864 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001865 }
1866}
1867
1868
1869void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1870 // Assignment to a property, using a named store IC.
1871 Property* prop = expr->target()->AsProperty();
1872 ASSERT(prop != NULL);
1873 ASSERT(prop->key()->AsLiteral() != NULL);
1874
1875 // If the assignment starts a block of assignments to the same object,
1876 // change to slow case to avoid the quadratic behavior of repeatedly
1877 // adding fast properties.
1878 if (expr->starts_initialization_block()) {
1879 __ push(result_register());
1880 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
1881 __ CallRuntime(Runtime::kToSlowProperties, 1);
1882 __ pop(result_register());
1883 }
1884
1885 // Record source code position before IC call.
1886 SetSourcePosition(expr->position());
1887 __ mov(ecx, prop->key()->AsLiteral()->handle());
1888 if (expr->ends_initialization_block()) {
1889 __ mov(edx, Operand(esp, 0));
1890 } else {
1891 __ pop(edx);
1892 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001893 Handle<Code> ic = is_strict_mode()
1894 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1895 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001896 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001897
1898 // If the assignment ends an initialization block, revert to fast case.
1899 if (expr->ends_initialization_block()) {
1900 __ push(eax); // Result of assignment, saved even if not needed.
1901 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
1902 __ CallRuntime(Runtime::kToFastProperties, 1);
1903 __ pop(eax);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001904 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001905 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001906 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1907 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001908}
1909
1910
1911void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1912 // Assignment to a property, using a keyed store IC.
1913
1914 // If the assignment starts a block of assignments to the same object,
1915 // change to slow case to avoid the quadratic behavior of repeatedly
1916 // adding fast properties.
1917 if (expr->starts_initialization_block()) {
1918 __ push(result_register());
1919 // Receiver is now under the key and value.
1920 __ push(Operand(esp, 2 * kPointerSize));
1921 __ CallRuntime(Runtime::kToSlowProperties, 1);
1922 __ pop(result_register());
1923 }
1924
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001925 __ pop(ecx);
1926 if (expr->ends_initialization_block()) {
1927 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
1928 } else {
1929 __ pop(edx);
1930 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001931 // Record source code position before IC call.
1932 SetSourcePosition(expr->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001933 Handle<Code> ic = is_strict_mode()
1934 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1935 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001936 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001937
1938 // If the assignment ends an initialization block, revert to fast case.
1939 if (expr->ends_initialization_block()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001940 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001941 __ push(eax); // Result of assignment, saved even if not needed.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001942 __ push(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001943 __ CallRuntime(Runtime::kToFastProperties, 1);
1944 __ pop(eax);
1945 }
1946
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001947 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001948 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001949}
1950
1951
1952void FullCodeGenerator::VisitProperty(Property* expr) {
1953 Comment cmnt(masm_, "[ Property");
1954 Expression* key = expr->key();
1955
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001956 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001957 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001958 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001959 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001960 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001961 VisitForStackValue(expr->obj());
1962 VisitForAccumulatorValue(expr->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00001963 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001964 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001965 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001966 }
1967}
1968
1969
1970void FullCodeGenerator::EmitCallWithIC(Call* expr,
1971 Handle<Object> name,
1972 RelocInfo::Mode mode) {
1973 // Code common for calls using the IC.
1974 ZoneList<Expression*>* args = expr->arguments();
1975 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001976 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001977 for (int i = 0; i < arg_count; i++) {
1978 VisitForStackValue(args->at(i));
1979 }
1980 __ Set(ecx, Immediate(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001981 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001982 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001983 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001984 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001985 Handle<Code> ic =
1986 isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001987 EmitCallIC(ic, mode, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001988 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001989 // Restore context register.
1990 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001991 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001992}
1993
1994
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001995void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00001996 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001997 // Load the key.
1998 VisitForAccumulatorValue(key);
1999
2000 // Swap the name of the function and the receiver on the stack to follow
2001 // the calling convention for call ICs.
2002 __ pop(ecx);
2003 __ push(eax);
2004 __ push(ecx);
2005
2006 // Load the arguments.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002007 ZoneList<Expression*>* args = expr->arguments();
2008 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002009 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002010 for (int i = 0; i < arg_count; i++) {
2011 VisitForStackValue(args->at(i));
2012 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002013 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002014 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002015 SetSourcePosition(expr->position());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002016 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002017 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
2018 arg_count, in_loop);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002019 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002020 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002021 RecordJSReturnSite(expr);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002022 // Restore context register.
2023 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002024 context()->DropAndPlug(1, eax); // Drop the key still on the stack.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002025}
2026
2027
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002028void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002029 // Code common for calls using the call stub.
2030 ZoneList<Expression*>* args = expr->arguments();
2031 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002032 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002033 for (int i = 0; i < arg_count; i++) {
2034 VisitForStackValue(args->at(i));
2035 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002036 }
2037 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002038 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002039 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002040 CallFunctionStub stub(arg_count, in_loop, flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002041 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002042 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002043 // Restore context register.
2044 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002045 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002046}
2047
2048
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002049void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2050 int arg_count) {
2051 // Push copy of the first argument or undefined if it doesn't exist.
2052 if (arg_count > 0) {
2053 __ push(Operand(esp, arg_count * kPointerSize));
2054 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002055 __ push(Immediate(isolate()->factory()->undefined_value()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002056 }
2057
2058 // Push the receiver of the enclosing function.
2059 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
2060
2061 // Push the strict mode flag.
2062 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
2063
2064 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2065 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2066 : Runtime::kResolvePossiblyDirectEval, 4);
2067}
2068
2069
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002070void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002071#ifdef DEBUG
2072 // We want to verify that RecordJSReturnSite gets called on all paths
2073 // through this function. Avoid early returns.
2074 expr->return_is_recorded_ = false;
2075#endif
2076
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002077 Comment cmnt(masm_, "[ Call");
2078 Expression* fun = expr->expression();
2079 Variable* var = fun->AsVariableProxy()->AsVariable();
2080
2081 if (var != NULL && var->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002082 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2083 // resolve the function we need to call and the receiver of the
2084 // call. Then we call the resolved function using the given
2085 // arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002086 ZoneList<Expression*>* args = expr->arguments();
2087 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002088 { PreservePositionScope pos_scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002089 VisitForStackValue(fun);
2090 // Reserved receiver slot.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002091 __ push(Immediate(isolate()->factory()->undefined_value()));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002092
2093 // Push the arguments.
2094 for (int i = 0; i < arg_count; i++) {
2095 VisitForStackValue(args->at(i));
2096 }
2097
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002098 // If we know that eval can only be shadowed by eval-introduced
2099 // variables we attempt to load the global eval function directly
2100 // in generated code. If we succeed, there is no need to perform a
2101 // context lookup in the runtime system.
2102 Label done;
2103 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2104 Label slow;
2105 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2106 NOT_INSIDE_TYPEOF,
2107 &slow);
2108 // Push the function and resolve eval.
2109 __ push(eax);
2110 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2111 __ jmp(&done);
2112 __ bind(&slow);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002113 }
2114
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002115 // Push copy of the function (found below the arguments) and
2116 // resolve eval.
2117 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2118 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2119 if (done.is_linked()) {
2120 __ bind(&done);
2121 }
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002122
2123 // The runtime call returns a pair of values in eax (function) and
2124 // edx (receiver). Touch up the stack with the right values.
2125 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2126 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002127 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002128 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002129 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002130 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002131 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002132 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002133 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002134 // Restore context register.
2135 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002136 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002137 } else if (var != NULL && !var->is_this() && var->is_global()) {
2138 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002139 __ push(GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002140 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002141 } else if (var != NULL && var->AsSlot() != NULL &&
2142 var->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002143 // Call to a lookup slot (dynamically introduced variable).
2144 Label slow, done;
2145
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002146 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002147 // Generate code for loading from variables potentially shadowed
2148 // by eval-introduced variables.
2149 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
2150 NOT_INSIDE_TYPEOF,
2151 &slow,
2152 &done);
2153 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002154
2155 __ bind(&slow);
2156 // Call the runtime to find the function to call (returned in eax)
2157 // and the object holding it (returned in edx).
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002158 __ push(context_register());
2159 __ push(Immediate(var->name()));
2160 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2161 __ push(eax); // Function.
2162 __ push(edx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002163
2164 // If fast case code has been generated, emit code to push the
2165 // function and receiver and have the slow path jump around this
2166 // code.
2167 if (done.is_linked()) {
2168 Label call;
2169 __ jmp(&call);
2170 __ bind(&done);
2171 // Push function.
2172 __ push(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002173 // The receiver is implicitly the global receiver. Indicate this
2174 // by passing the hole to the call function stub.
2175 __ push(Immediate(isolate()->factory()->the_hole_value()));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002176 __ bind(&call);
2177 }
2178
danno@chromium.org40cb8782011-05-25 07:58:50 +00002179 // The receiver is either the global receiver or an object found
2180 // by LoadContextSlot. That object could be the hole if the
2181 // receiver is implicitly the global object.
2182 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002183 } else if (fun->AsProperty() != NULL) {
2184 // Call to an object property.
2185 Property* prop = fun->AsProperty();
2186 Literal* key = prop->key()->AsLiteral();
2187 if (key != NULL && key->handle()->IsSymbol()) {
2188 // Call to a named property, use call IC.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002189 { PreservePositionScope scope(masm()->positions_recorder());
2190 VisitForStackValue(prop->obj());
2191 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002192 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
2193 } else {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002194 // Call to a keyed property.
2195 // For a synthetic property use keyed load IC followed by function call,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002196 // for a regular property use keyed EmitCallIC.
ager@chromium.org5c838252010-02-19 08:53:10 +00002197 if (prop->is_synthetic()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002198 // Do not visit the object and key subexpressions (they are shared
2199 // by all occurrences of the same rewritten parameter).
2200 ASSERT(prop->obj()->AsVariableProxy() != NULL);
2201 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
2202 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
2203 MemOperand operand = EmitSlotSearch(slot, edx);
2204 __ mov(edx, operand);
2205
2206 ASSERT(prop->key()->AsLiteral() != NULL);
2207 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
2208 __ mov(eax, prop->key()->AsLiteral()->handle());
2209
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002210 // Record source code position for IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002211 SetSourcePosition(prop->position());
ager@chromium.org5c838252010-02-19 08:53:10 +00002212
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002213 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002214 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
ager@chromium.org5c838252010-02-19 08:53:10 +00002215 // Push result (function).
2216 __ push(eax);
2217 // Push Global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002218 __ mov(ecx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002219 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002220 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002221 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002222 { PreservePositionScope scope(masm()->positions_recorder());
2223 VisitForStackValue(prop->obj());
2224 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002225 EmitKeyedCallWithIC(expr, prop->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002226 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002227 }
2228 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002229 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002230 VisitForStackValue(fun);
2231 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002232 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002233 __ mov(ebx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002234 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2235 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002236 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002237 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002238
2239#ifdef DEBUG
2240 // RecordJSReturnSite should have been called.
2241 ASSERT(expr->return_is_recorded_);
2242#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002243}
2244
2245
2246void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2247 Comment cmnt(masm_, "[ CallNew");
2248 // According to ECMA-262, section 11.2.2, page 44, the function
2249 // expression in new calls must be evaluated before the
2250 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002251
ricow@chromium.org65fae842010-08-25 15:26:24 +00002252 // Push constructor on the stack. If it's not a function it's used as
2253 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2254 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002255 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002256
2257 // Push the arguments ("left-to-right") on the stack.
2258 ZoneList<Expression*>* args = expr->arguments();
2259 int arg_count = args->length();
2260 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002261 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002262 }
2263
2264 // Call the construct call builtin that handles allocation and
2265 // constructor invocation.
2266 SetSourcePosition(expr->position());
2267
ricow@chromium.org65fae842010-08-25 15:26:24 +00002268 // Load function and argument count into edi and eax.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002269 __ SafeSet(eax, Immediate(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002270 __ mov(edi, Operand(esp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002271
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002272 Handle<Code> construct_builtin =
2273 isolate()->builtins()->JSConstructCall();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002274 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002275 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002276}
2277
2278
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002279void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2280 ASSERT(args->length() == 1);
2281
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002282 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002283
2284 Label materialize_true, materialize_false;
2285 Label* if_true = NULL;
2286 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002287 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002288 context()->PrepareTest(&materialize_true, &materialize_false,
2289 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002290
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002291 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002292 __ test(eax, Immediate(kSmiTagMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002293 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002294
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002295 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002296}
2297
2298
2299void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2300 ASSERT(args->length() == 1);
2301
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002302 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002303
2304 Label materialize_true, materialize_false;
2305 Label* if_true = NULL;
2306 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002307 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002308 context()->PrepareTest(&materialize_true, &materialize_false,
2309 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002310
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002311 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002312 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002313 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002314
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002315 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002316}
2317
2318
2319void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2320 ASSERT(args->length() == 1);
2321
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002322 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002323
2324 Label materialize_true, materialize_false;
2325 Label* if_true = NULL;
2326 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002327 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002328 context()->PrepareTest(&materialize_true, &materialize_false,
2329 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002330
whesse@chromium.org7b260152011-06-20 15:33:18 +00002331 __ JumpIfSmi(eax, if_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002332 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002333 __ j(equal, if_true);
2334 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2335 // Undetectable objects behave like undefined when tested with typeof.
2336 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2337 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2338 __ j(not_zero, if_false);
2339 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002340 __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002341 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002342 __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002343 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002344 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002345
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002346 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002347}
2348
2349
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002350void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2351 ASSERT(args->length() == 1);
2352
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002353 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002354
2355 Label materialize_true, materialize_false;
2356 Label* if_true = NULL;
2357 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002358 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002359 context()->PrepareTest(&materialize_true, &materialize_false,
2360 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002361
whesse@chromium.org7b260152011-06-20 15:33:18 +00002362 __ JumpIfSmi(eax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002363 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002364 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002365 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002366
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002367 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002368}
2369
2370
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002371void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2372 ASSERT(args->length() == 1);
2373
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002374 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002375
2376 Label materialize_true, materialize_false;
2377 Label* if_true = NULL;
2378 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002379 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002380 context()->PrepareTest(&materialize_true, &materialize_false,
2381 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002382
whesse@chromium.org7b260152011-06-20 15:33:18 +00002383 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002384 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2385 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2386 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002387 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002388 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002389
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002390 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002391}
2392
2393
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002394void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2395 ZoneList<Expression*>* args) {
2396 ASSERT(args->length() == 1);
2397
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002398 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002399
2400 Label materialize_true, materialize_false;
2401 Label* if_true = NULL;
2402 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002403 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002404 context()->PrepareTest(&materialize_true, &materialize_false,
2405 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002407 if (FLAG_debug_code) __ AbortIfSmi(eax);
2408
2409 // Check whether this map has already been checked to be safe for default
2410 // valueOf.
2411 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2412 __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
2413 1 << Map::kStringWrapperSafeForDefaultValueOf);
2414 __ j(not_zero, if_true);
2415
2416 // Check for fast case object. Return false for slow case objects.
2417 __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
2418 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2419 __ cmp(ecx, FACTORY->hash_table_map());
2420 __ j(equal, if_false);
2421
2422 // Look for valueOf symbol in the descriptor array, and indicate false if
2423 // found. The type is not checked, so if it is a transition it is a false
2424 // negative.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002425 __ LoadInstanceDescriptors(ebx, ebx);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002426 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
2427 // ebx: descriptor array
2428 // ecx: length of descriptor array
2429 // Calculate the end of the descriptor array.
2430 STATIC_ASSERT(kSmiTag == 0);
2431 STATIC_ASSERT(kSmiTagSize == 1);
2432 STATIC_ASSERT(kPointerSize == 4);
2433 __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
2434 // Calculate location of the first key name.
2435 __ add(Operand(ebx),
2436 Immediate(FixedArray::kHeaderSize +
2437 DescriptorArray::kFirstIndex * kPointerSize));
2438 // Loop through all the keys in the descriptor array. If one of these is the
2439 // symbol valueOf the result is false.
2440 Label entry, loop;
2441 __ jmp(&entry);
2442 __ bind(&loop);
2443 __ mov(edx, FieldOperand(ebx, 0));
2444 __ cmp(edx, FACTORY->value_of_symbol());
2445 __ j(equal, if_false);
2446 __ add(Operand(ebx), Immediate(kPointerSize));
2447 __ bind(&entry);
2448 __ cmp(ebx, Operand(ecx));
2449 __ j(not_equal, &loop);
2450
2451 // Reload map as register ebx was used as temporary above.
2452 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2453
2454 // If a valueOf property is not found on the object check that it's
2455 // prototype is the un-modified String prototype. If not result is false.
2456 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002457 __ JumpIfSmi(ecx, if_false);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002458 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2459 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2460 __ mov(edx,
2461 FieldOperand(edx, GlobalObject::kGlobalContextOffset));
2462 __ cmp(ecx,
2463 ContextOperand(edx,
2464 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2465 __ j(not_equal, if_false);
2466 // Set the bit in the map to indicate that it has been checked safe for
2467 // default valueOf and set true result.
2468 __ or_(FieldOperand(ebx, Map::kBitField2Offset),
2469 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2470 __ jmp(if_true);
2471
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002472 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002473 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002474}
2475
2476
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002477void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2478 ASSERT(args->length() == 1);
2479
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002480 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002481
2482 Label materialize_true, materialize_false;
2483 Label* if_true = NULL;
2484 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002485 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002486 context()->PrepareTest(&materialize_true, &materialize_false,
2487 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002488
whesse@chromium.org7b260152011-06-20 15:33:18 +00002489 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002490 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002491 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002492 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002493
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002494 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002495}
2496
2497
2498void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2499 ASSERT(args->length() == 1);
2500
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002501 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002502
2503 Label materialize_true, materialize_false;
2504 Label* if_true = NULL;
2505 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002506 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002507 context()->PrepareTest(&materialize_true, &materialize_false,
2508 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002509
whesse@chromium.org7b260152011-06-20 15:33:18 +00002510 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002511 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002512 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002513 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002514
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002515 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002516}
2517
2518
2519void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2520 ASSERT(args->length() == 1);
2521
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002522 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002523
2524 Label materialize_true, materialize_false;
2525 Label* if_true = NULL;
2526 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002527 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002528 context()->PrepareTest(&materialize_true, &materialize_false,
2529 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002530
whesse@chromium.org7b260152011-06-20 15:33:18 +00002531 __ JumpIfSmi(eax, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002532 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002533 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002534 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002535
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002536 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002537}
2538
2539
2540
2541void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2542 ASSERT(args->length() == 0);
2543
2544 Label materialize_true, materialize_false;
2545 Label* if_true = NULL;
2546 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002547 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002548 context()->PrepareTest(&materialize_true, &materialize_false,
2549 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002550
2551 // Get the frame pointer for the calling frame.
2552 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2553
2554 // Skip the arguments adaptor frame if it exists.
2555 Label check_frame_marker;
2556 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2557 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2558 __ j(not_equal, &check_frame_marker);
2559 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2560
2561 // Check the marker in the calling frame.
2562 __ bind(&check_frame_marker);
2563 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2564 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002565 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002566 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002567
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002568 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002569}
2570
2571
2572void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2573 ASSERT(args->length() == 2);
2574
2575 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002576 VisitForStackValue(args->at(0));
2577 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002578
2579 Label materialize_true, materialize_false;
2580 Label* if_true = NULL;
2581 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002582 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002583 context()->PrepareTest(&materialize_true, &materialize_false,
2584 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002585
2586 __ pop(ebx);
2587 __ cmp(eax, Operand(ebx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002588 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002589 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002590
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002591 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002592}
2593
2594
2595void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2596 ASSERT(args->length() == 1);
2597
2598 // ArgumentsAccessStub expects the key in edx and the formal
2599 // parameter count in eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002600 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002601 __ mov(edx, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002602 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002603 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2604 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002605 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002606}
2607
2608
2609void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2610 ASSERT(args->length() == 0);
2611
2612 Label exit;
2613 // Get the number of formal parameters.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002614 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002615
2616 // Check if the calling frame is an arguments adaptor frame.
2617 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2618 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2619 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2620 __ j(not_equal, &exit);
2621
2622 // Arguments adaptor case: Read the arguments length from the
2623 // adaptor frame.
2624 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2625
2626 __ bind(&exit);
2627 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002628 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002629}
2630
2631
2632void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2633 ASSERT(args->length() == 1);
2634 Label done, null, function, non_function_constructor;
2635
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002636 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002637
2638 // If the object is a smi, we return null.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002639 __ JumpIfSmi(eax, &null);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002640
2641 // Check that the object is a JS object but take special care of JS
2642 // functions to make sure they have 'Function' as their class.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002643 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
2644 // Map is now in eax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002645 __ j(below, &null);
2646
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002647 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
2648 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
2649 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
2650 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
2651 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
2652 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
2653 __ CmpInstanceType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
2654 __ j(above_equal, &function);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002655
2656 // Check if the constructor in the map is a function.
2657 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2658 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2659 __ j(not_equal, &non_function_constructor);
2660
2661 // eax now contains the constructor function. Grab the
2662 // instance class name from there.
2663 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2664 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2665 __ jmp(&done);
2666
2667 // Functions have class 'Function'.
2668 __ bind(&function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002669 __ mov(eax, isolate()->factory()->function_class_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002670 __ jmp(&done);
2671
2672 // Objects with a non-function constructor have class 'Object'.
2673 __ bind(&non_function_constructor);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002674 __ mov(eax, isolate()->factory()->Object_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002675 __ jmp(&done);
2676
2677 // Non-JS objects have class null.
2678 __ bind(&null);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002679 __ mov(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002680
2681 // All done.
2682 __ bind(&done);
2683
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002684 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002685}
2686
2687
2688void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2689 // Conditionally generate a log call.
2690 // Args:
2691 // 0 (literal string): The type of logging (corresponds to the flags).
2692 // This is used to determine whether or not to generate the log call.
2693 // 1 (string): Format string. Access the string at argument index 2
2694 // with '%2s' (see Logger::LogRuntime for all the formats).
2695 // 2 (array): Arguments to the format string.
2696 ASSERT_EQ(args->length(), 3);
2697#ifdef ENABLE_LOGGING_AND_PROFILING
2698 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002699 VisitForStackValue(args->at(1));
2700 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002701 __ CallRuntime(Runtime::kLog, 2);
2702 }
2703#endif
2704 // Finally, we're expected to leave a value on the top of the stack.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002705 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002706 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002707}
2708
2709
2710void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2711 ASSERT(args->length() == 0);
2712
2713 Label slow_allocate_heapnumber;
2714 Label heapnumber_allocated;
2715
2716 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2717 __ jmp(&heapnumber_allocated);
2718
2719 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002720 // Allocate a heap number.
2721 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002722 __ mov(edi, eax);
2723
2724 __ bind(&heapnumber_allocated);
2725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002726 __ PrepareCallCFunction(1, ebx);
2727 __ mov(Operand(esp, 0), Immediate(ExternalReference::isolate_address()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002728 __ CallCFunction(ExternalReference::random_uint32_function(isolate()),
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002729 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002730
2731 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2732 // by computing:
2733 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2734 // This is implemented on both SSE2 and FPU.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002735 if (CpuFeatures::IsSupported(SSE2)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002736 CpuFeatures::Scope fscope(SSE2);
2737 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2738 __ movd(xmm1, Operand(ebx));
2739 __ movd(xmm0, Operand(eax));
2740 __ cvtss2sd(xmm1, xmm1);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002741 __ xorps(xmm0, xmm1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002742 __ subsd(xmm0, xmm1);
2743 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2744 } else {
2745 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2746 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2747 Immediate(0x41300000));
2748 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2749 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2750 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2751 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2752 __ fsubp(1);
2753 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2754 }
2755 __ mov(eax, edi);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002756 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002757}
2758
2759
2760void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2761 // Load the arguments on the stack and call the stub.
2762 SubStringStub stub;
2763 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002764 VisitForStackValue(args->at(0));
2765 VisitForStackValue(args->at(1));
2766 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002767 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002768 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002769}
2770
2771
2772void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2773 // Load the arguments on the stack and call the stub.
2774 RegExpExecStub stub;
2775 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002776 VisitForStackValue(args->at(0));
2777 VisitForStackValue(args->at(1));
2778 VisitForStackValue(args->at(2));
2779 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002780 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002781 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002782}
2783
2784
2785void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2786 ASSERT(args->length() == 1);
2787
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002788 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002789
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002790 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002791 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002792 __ JumpIfSmi(eax, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002793 // If the object is not a value type, return the object.
2794 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002795 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002796 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2797
2798 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002799 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002800}
2801
2802
2803void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2804 // Load the arguments on the stack and call the runtime function.
2805 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002806 VisitForStackValue(args->at(0));
2807 VisitForStackValue(args->at(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002808
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002809 if (CpuFeatures::IsSupported(SSE2)) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002810 MathPowStub stub;
2811 __ CallStub(&stub);
2812 } else {
2813 __ CallRuntime(Runtime::kMath_pow, 2);
2814 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002815 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002816}
2817
2818
2819void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2820 ASSERT(args->length() == 2);
2821
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002822 VisitForStackValue(args->at(0)); // Load the object.
2823 VisitForAccumulatorValue(args->at(1)); // Load the value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002824 __ pop(ebx); // eax = value. ebx = object.
2825
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002826 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002827 // If the object is a smi, return the value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002828 __ JumpIfSmi(ebx, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002829
2830 // If the object is not a value type, return the value.
2831 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002832 __ j(not_equal, &done, Label::kNear);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002833
2834 // Store the value.
2835 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
2836 // Update the write barrier. Save the value as it will be
2837 // overwritten by the write barrier code and is needed afterward.
2838 __ mov(edx, eax);
2839 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
2840
2841 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002842 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002843}
2844
2845
2846void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2847 ASSERT_EQ(args->length(), 1);
2848
2849 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002850 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002851
2852 NumberToStringStub stub;
2853 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002854 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002855}
2856
2857
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002858void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002859 ASSERT(args->length() == 1);
2860
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002861 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002862
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002863 Label done;
2864 StringCharFromCodeGenerator generator(eax, ebx);
2865 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002866 __ jmp(&done);
2867
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002868 NopRuntimeCallHelper call_helper;
2869 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002870
2871 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002872 context()->Plug(ebx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002873}
2874
2875
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002876void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2877 ASSERT(args->length() == 2);
2878
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002879 VisitForStackValue(args->at(0));
2880 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002881
2882 Register object = ebx;
2883 Register index = eax;
2884 Register scratch = ecx;
2885 Register result = edx;
2886
2887 __ pop(object);
2888
2889 Label need_conversion;
2890 Label index_out_of_range;
2891 Label done;
2892 StringCharCodeAtGenerator generator(object,
2893 index,
2894 scratch,
2895 result,
2896 &need_conversion,
2897 &need_conversion,
2898 &index_out_of_range,
2899 STRING_INDEX_IS_NUMBER);
2900 generator.GenerateFast(masm_);
2901 __ jmp(&done);
2902
2903 __ bind(&index_out_of_range);
2904 // When the index is out of range, the spec requires us to return
2905 // NaN.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002906 __ Set(result, Immediate(isolate()->factory()->nan_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002907 __ jmp(&done);
2908
2909 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002910 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002911 // trigger conversion.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002912 __ Set(result, Immediate(isolate()->factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002913 __ jmp(&done);
2914
2915 NopRuntimeCallHelper call_helper;
2916 generator.GenerateSlow(masm_, call_helper);
2917
2918 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002919 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002920}
2921
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002922
2923void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2924 ASSERT(args->length() == 2);
2925
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002926 VisitForStackValue(args->at(0));
2927 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002928
2929 Register object = ebx;
2930 Register index = eax;
2931 Register scratch1 = ecx;
2932 Register scratch2 = edx;
2933 Register result = eax;
2934
2935 __ pop(object);
2936
2937 Label need_conversion;
2938 Label index_out_of_range;
2939 Label done;
2940 StringCharAtGenerator generator(object,
2941 index,
2942 scratch1,
2943 scratch2,
2944 result,
2945 &need_conversion,
2946 &need_conversion,
2947 &index_out_of_range,
2948 STRING_INDEX_IS_NUMBER);
2949 generator.GenerateFast(masm_);
2950 __ jmp(&done);
2951
2952 __ bind(&index_out_of_range);
2953 // When the index is out of range, the spec requires us to return
2954 // the empty string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002955 __ Set(result, Immediate(isolate()->factory()->empty_string()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002956 __ jmp(&done);
2957
2958 __ bind(&need_conversion);
2959 // Move smi zero into the result register, which will trigger
2960 // conversion.
2961 __ Set(result, Immediate(Smi::FromInt(0)));
2962 __ jmp(&done);
2963
2964 NopRuntimeCallHelper call_helper;
2965 generator.GenerateSlow(masm_, call_helper);
2966
2967 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002968 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002969}
2970
2971
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002972void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2973 ASSERT_EQ(2, args->length());
2974
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002975 VisitForStackValue(args->at(0));
2976 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002977
2978 StringAddStub stub(NO_STRING_ADD_FLAGS);
2979 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002980 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002981}
2982
2983
2984void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2985 ASSERT_EQ(2, args->length());
2986
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002987 VisitForStackValue(args->at(0));
2988 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002989
2990 StringCompareStub stub;
2991 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002992 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002993}
2994
2995
2996void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2997 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00002998 TranscendentalCacheStub stub(TranscendentalCache::SIN,
2999 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003000 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003001 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003002 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003003 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003004}
3005
3006
3007void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
3008 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003009 TranscendentalCacheStub stub(TranscendentalCache::COS,
3010 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003011 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003012 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003013 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003014 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003015}
3016
3017
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003018void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3019 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003020 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3021 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003022 ASSERT(args->length() == 1);
3023 VisitForStackValue(args->at(0));
3024 __ CallStub(&stub);
3025 context()->Plug(eax);
3026}
3027
3028
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003029void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
3030 // Load the argument on the stack and call the runtime function.
3031 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003032 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003033 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003034 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003035}
3036
3037
3038void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
3039 ASSERT(args->length() >= 2);
3040
danno@chromium.org160a7b02011-04-18 15:51:38 +00003041 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3042 for (int i = 0; i < arg_count + 1; ++i) {
3043 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003044 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003045 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003046
danno@chromium.org160a7b02011-04-18 15:51:38 +00003047 // InvokeFunction requires the function in edi. Move it in there.
3048 __ mov(edi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003049 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003050 __ InvokeFunction(edi, count, CALL_FUNCTION,
3051 NullCallWrapper(), CALL_AS_METHOD);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003052 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003053 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003054}
3055
3056
3057void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003058 // Load the arguments on the stack and call the stub.
3059 RegExpConstructResultStub stub;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003060 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003061 VisitForStackValue(args->at(0));
3062 VisitForStackValue(args->at(1));
3063 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003064 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003065 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003066}
3067
3068
3069void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
3070 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003071 VisitForStackValue(args->at(0));
3072 VisitForStackValue(args->at(1));
3073 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003074 Label done;
3075 Label slow_case;
3076 Register object = eax;
3077 Register index_1 = ebx;
3078 Register index_2 = ecx;
3079 Register elements = edi;
3080 Register temp = edx;
3081 __ mov(object, Operand(esp, 2 * kPointerSize));
3082 // Fetch the map and check if array is in fast case.
3083 // Check that object doesn't require security checks and
3084 // has no indexed interceptor.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003085 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3086 __ j(not_equal, &slow_case);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003087 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
3088 KeyedLoadIC::kSlowCaseBitFieldMask);
3089 __ j(not_zero, &slow_case);
3090
3091 // Check the object's elements are in fast case and writable.
3092 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
3093 __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003094 Immediate(isolate()->factory()->fixed_array_map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003095 __ j(not_equal, &slow_case);
3096
3097 // Check that both indices are smis.
3098 __ mov(index_1, Operand(esp, 1 * kPointerSize));
3099 __ mov(index_2, Operand(esp, 0));
3100 __ mov(temp, index_1);
3101 __ or_(temp, Operand(index_2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003102 __ JumpIfNotSmi(temp, &slow_case);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003103
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003104 // Check that both indices are valid.
3105 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
3106 __ cmp(temp, Operand(index_1));
3107 __ j(below_equal, &slow_case);
3108 __ cmp(temp, Operand(index_2));
3109 __ j(below_equal, &slow_case);
3110
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003111 // Bring addresses into index1 and index2.
3112 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1));
3113 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2));
3114
3115 // Swap elements. Use object and temp as scratch registers.
3116 __ mov(object, Operand(index_1, 0));
3117 __ mov(temp, Operand(index_2, 0));
3118 __ mov(Operand(index_2, 0), object);
3119 __ mov(Operand(index_1, 0), temp);
3120
3121 Label new_space;
3122 __ InNewSpace(elements, temp, equal, &new_space);
3123
3124 __ mov(object, elements);
3125 __ RecordWriteHelper(object, index_1, temp);
3126 __ RecordWriteHelper(elements, index_2, temp);
3127
3128 __ bind(&new_space);
3129 // We are done. Drop elements from the stack, and return undefined.
3130 __ add(Operand(esp), Immediate(3 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003131 __ mov(eax, isolate()->factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003132 __ jmp(&done);
3133
3134 __ bind(&slow_case);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003135 __ CallRuntime(Runtime::kSwapElements, 3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003136
3137 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003138 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003139}
3140
3141
3142void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3143 ASSERT_EQ(2, args->length());
3144
3145 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3146 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3147
3148 Handle<FixedArray> jsfunction_result_caches(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003149 isolate()->global_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003150 if (jsfunction_result_caches->length() <= cache_id) {
3151 __ Abort("Attempt to use undefined cache.");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003152 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003153 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003154 return;
3155 }
3156
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003157 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003158
3159 Register key = eax;
3160 Register cache = ebx;
3161 Register tmp = ecx;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003162 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003163 __ mov(cache,
3164 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003165 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003166 __ mov(cache,
3167 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3168
3169 Label done, not_found;
3170 // tmp now holds finger offset as a smi.
3171 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3172 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3173 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3174 __ j(not_equal, &not_found);
3175
3176 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3177 __ jmp(&done);
3178
3179 __ bind(&not_found);
3180 // Call runtime to perform the lookup.
3181 __ push(cache);
3182 __ push(key);
3183 __ CallRuntime(Runtime::kGetFromCache, 2);
3184
3185 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003186 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003187}
3188
3189
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003190void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3191 ASSERT_EQ(2, args->length());
3192
3193 Register right = eax;
3194 Register left = ebx;
3195 Register tmp = ecx;
3196
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003197 VisitForStackValue(args->at(0));
3198 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003199 __ pop(left);
3200
3201 Label done, fail, ok;
3202 __ cmp(left, Operand(right));
3203 __ j(equal, &ok);
3204 // Fail if either is a non-HeapObject.
3205 __ mov(tmp, left);
3206 __ and_(Operand(tmp), right);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003207 __ JumpIfSmi(tmp, &fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003208 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
3209 __ CmpInstanceType(tmp, JS_REGEXP_TYPE);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003210 __ j(not_equal, &fail);
3211 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3212 __ j(not_equal, &fail);
3213 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3214 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3215 __ j(equal, &ok);
3216 __ bind(&fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003217 __ mov(eax, Immediate(isolate()->factory()->false_value()));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003218 __ jmp(&done);
3219 __ bind(&ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003220 __ mov(eax, Immediate(isolate()->factory()->true_value()));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003221 __ bind(&done);
3222
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003223 context()->Plug(eax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003224}
3225
3226
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003227void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
3228 ASSERT(args->length() == 1);
3229
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003230 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003231
3232 if (FLAG_debug_code) {
3233 __ AbortIfNotString(eax);
3234 }
3235
3236 Label materialize_true, materialize_false;
3237 Label* if_true = NULL;
3238 Label* if_false = NULL;
3239 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003240 context()->PrepareTest(&materialize_true, &materialize_false,
3241 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003242
3243 __ test(FieldOperand(eax, String::kHashFieldOffset),
3244 Immediate(String::kContainsCachedArrayIndexMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003245 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003246 Split(zero, if_true, if_false, fall_through);
3247
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003248 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003249}
3250
3251
3252void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3253 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003254 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003255
3256 if (FLAG_debug_code) {
3257 __ AbortIfNotString(eax);
3258 }
3259
3260 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3261 __ IndexFromHash(eax, eax);
3262
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003263 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003264}
3265
3266
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003267void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003268 Label bailout, done, one_char_separator, long_separator,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003269 non_trivial_array, not_size_one_array, loop,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003270 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003271
3272 ASSERT(args->length() == 2);
3273 // We will leave the separator on the stack until the end of the function.
3274 VisitForStackValue(args->at(1));
3275 // Load this to eax (= array)
3276 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003277 // All aliases of the same register have disjoint lifetimes.
3278 Register array = eax;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003279 Register elements = no_reg; // Will be eax.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003280
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003281 Register index = edx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003282
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003283 Register string_length = ecx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003284
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003285 Register string = esi;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003286
3287 Register scratch = ebx;
3288
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003289 Register array_length = edi;
3290 Register result_pos = no_reg; // Will be edi.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003291
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003292 // Separator operand is already pushed.
3293 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3294 Operand result_operand = Operand(esp, 1 * kPointerSize);
3295 Operand array_length_operand = Operand(esp, 0);
3296 __ sub(Operand(esp), Immediate(2 * kPointerSize));
3297 __ cld();
3298 // Check that the array is a JSArray
whesse@chromium.org7b260152011-06-20 15:33:18 +00003299 __ JumpIfSmi(array, &bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003300 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3301 __ j(not_equal, &bailout);
3302
3303 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003304 __ CheckFastElements(scratch, &bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003305
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003306 // If the array has length zero, return the empty string.
3307 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003308 __ SmiUntag(array_length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003309 __ j(not_zero, &non_trivial_array);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003310 __ mov(result_operand, isolate()->factory()->empty_string());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003311 __ jmp(&done);
3312
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003313 // Save the array length.
3314 __ bind(&non_trivial_array);
3315 __ mov(array_length_operand, array_length);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003316
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003317 // Save the FixedArray containing array's elements.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003318 // End of array's live range.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003319 elements = array;
3320 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003321 array = no_reg;
3322
3323
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003324 // Check that all array elements are sequential ASCII strings, and
3325 // accumulate the sum of their lengths, as a smi-encoded value.
3326 __ Set(index, Immediate(0));
3327 __ Set(string_length, Immediate(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003328 // Loop condition: while (index < length).
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003329 // Live loop registers: index, array_length, string,
3330 // scratch, string_length, elements.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003331 if (FLAG_debug_code) {
3332 __ cmp(index, Operand(array_length));
3333 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
3334 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003335 __ bind(&loop);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003336 __ mov(string, FieldOperand(elements,
3337 index,
3338 times_pointer_size,
3339 FixedArray::kHeaderSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003340 __ JumpIfSmi(string, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003341 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3342 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3343 __ and_(scratch, Immediate(
3344 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3345 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3346 __ j(not_equal, &bailout);
3347 __ add(string_length,
3348 FieldOperand(string, SeqAsciiString::kLengthOffset));
3349 __ j(overflow, &bailout);
3350 __ add(Operand(index), Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003351 __ cmp(index, Operand(array_length));
3352 __ j(less, &loop);
3353
3354 // If array_length is 1, return elements[0], a string.
3355 __ cmp(array_length, 1);
3356 __ j(not_equal, &not_size_one_array);
3357 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3358 __ mov(result_operand, scratch);
3359 __ jmp(&done);
3360
3361 __ bind(&not_size_one_array);
3362
3363 // End of array_length live range.
3364 result_pos = array_length;
3365 array_length = no_reg;
3366
3367 // Live registers:
3368 // string_length: Sum of string lengths, as a smi.
3369 // elements: FixedArray of strings.
3370
3371 // Check that the separator is a flat ASCII string.
3372 __ mov(string, separator_operand);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003373 __ JumpIfSmi(string, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003374 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3375 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003376 __ and_(scratch, Immediate(
3377 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003378 __ cmp(scratch, ASCII_STRING_TYPE);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003379 __ j(not_equal, &bailout);
3380
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003381 // Add (separator length times array_length) - separator length
3382 // to string_length.
3383 __ mov(scratch, separator_operand);
3384 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset));
3385 __ sub(string_length, Operand(scratch)); // May be negative, temporarily.
3386 __ imul(scratch, array_length_operand);
3387 __ j(overflow, &bailout);
3388 __ add(string_length, Operand(scratch));
3389 __ j(overflow, &bailout);
3390
3391 __ shr(string_length, 1);
3392 // Live registers and stack values:
3393 // string_length
3394 // elements
3395 __ AllocateAsciiString(result_pos, string_length, scratch,
3396 index, string, &bailout);
3397 __ mov(result_operand, result_pos);
3398 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3399
3400
3401 __ mov(string, separator_operand);
3402 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset),
3403 Immediate(Smi::FromInt(1)));
3404 __ j(equal, &one_char_separator);
3405 __ j(greater, &long_separator);
3406
3407
3408 // Empty separator case
3409 __ mov(index, Immediate(0));
3410 __ jmp(&loop_1_condition);
3411 // Loop condition: while (index < length).
3412 __ bind(&loop_1);
3413 // Each iteration of the loop concatenates one string to the result.
3414 // Live values in registers:
3415 // index: which element of the elements array we are adding to the result.
3416 // result_pos: the position to which we are currently copying characters.
3417 // elements: the FixedArray of strings we are joining.
3418
3419 // Get string = array[index].
3420 __ mov(string, FieldOperand(elements, index,
3421 times_pointer_size,
3422 FixedArray::kHeaderSize));
3423 __ mov(string_length,
3424 FieldOperand(string, String::kLengthOffset));
3425 __ shr(string_length, 1);
3426 __ lea(string,
3427 FieldOperand(string, SeqAsciiString::kHeaderSize));
3428 __ CopyBytes(string, result_pos, string_length, scratch);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003429 __ add(Operand(index), Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003430 __ bind(&loop_1_condition);
3431 __ cmp(index, array_length_operand);
3432 __ j(less, &loop_1); // End while (index < length).
3433 __ jmp(&done);
3434
3435
3436
3437 // One-character separator case
3438 __ bind(&one_char_separator);
3439 // Replace separator with its ascii character value.
3440 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3441 __ mov_b(separator_operand, scratch);
3442
3443 __ Set(index, Immediate(0));
3444 // Jump into the loop after the code that copies the separator, so the first
3445 // element is not preceded by a separator
3446 __ jmp(&loop_2_entry);
3447 // Loop condition: while (index < length).
3448 __ bind(&loop_2);
3449 // Each iteration of the loop concatenates one string to the result.
3450 // Live values in registers:
3451 // index: which element of the elements array we are adding to the result.
3452 // result_pos: the position to which we are currently copying characters.
3453
3454 // Copy the separator character to the result.
3455 __ mov_b(scratch, separator_operand);
3456 __ mov_b(Operand(result_pos, 0), scratch);
3457 __ inc(result_pos);
3458
3459 __ bind(&loop_2_entry);
3460 // Get string = array[index].
3461 __ mov(string, FieldOperand(elements, index,
3462 times_pointer_size,
3463 FixedArray::kHeaderSize));
3464 __ mov(string_length,
3465 FieldOperand(string, String::kLengthOffset));
3466 __ shr(string_length, 1);
3467 __ lea(string,
3468 FieldOperand(string, SeqAsciiString::kHeaderSize));
3469 __ CopyBytes(string, result_pos, string_length, scratch);
3470 __ add(Operand(index), Immediate(1));
3471
3472 __ cmp(index, array_length_operand);
3473 __ j(less, &loop_2); // End while (index < length).
3474 __ jmp(&done);
3475
3476
3477 // Long separator case (separator is more than one character).
3478 __ bind(&long_separator);
3479
3480 __ Set(index, Immediate(0));
3481 // Jump into the loop after the code that copies the separator, so the first
3482 // element is not preceded by a separator
3483 __ jmp(&loop_3_entry);
3484 // Loop condition: while (index < length).
3485 __ bind(&loop_3);
3486 // Each iteration of the loop concatenates one string to the result.
3487 // Live values in registers:
3488 // index: which element of the elements array we are adding to the result.
3489 // result_pos: the position to which we are currently copying characters.
3490
3491 // Copy the separator to the result.
3492 __ mov(string, separator_operand);
3493 __ mov(string_length,
3494 FieldOperand(string, String::kLengthOffset));
3495 __ shr(string_length, 1);
3496 __ lea(string,
3497 FieldOperand(string, SeqAsciiString::kHeaderSize));
3498 __ CopyBytes(string, result_pos, string_length, scratch);
3499
3500 __ bind(&loop_3_entry);
3501 // Get string = array[index].
3502 __ mov(string, FieldOperand(elements, index,
3503 times_pointer_size,
3504 FixedArray::kHeaderSize));
3505 __ mov(string_length,
3506 FieldOperand(string, String::kLengthOffset));
3507 __ shr(string_length, 1);
3508 __ lea(string,
3509 FieldOperand(string, SeqAsciiString::kHeaderSize));
3510 __ CopyBytes(string, result_pos, string_length, scratch);
3511 __ add(Operand(index), Immediate(1));
3512
3513 __ cmp(index, array_length_operand);
3514 __ j(less, &loop_3); // End while (index < length).
3515 __ jmp(&done);
3516
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003517
3518 __ bind(&bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003519 __ mov(result_operand, isolate()->factory()->undefined_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003520 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003521 __ mov(eax, result_operand);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003522 // Drop temp values from the stack, and restore context register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003523 __ add(Operand(esp), Immediate(3 * kPointerSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003524
3525 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3526 context()->Plug(eax);
3527}
3528
3529
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003530void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003531 Handle<String> name = expr->name();
3532 if (name->length() > 0 && name->Get(0) == '_') {
3533 Comment cmnt(masm_, "[ InlineRuntimeCall");
3534 EmitInlineRuntimeCall(expr);
3535 return;
3536 }
3537
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003538 Comment cmnt(masm_, "[ CallRuntime");
3539 ZoneList<Expression*>* args = expr->arguments();
3540
3541 if (expr->is_jsruntime()) {
3542 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003543 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003544 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3545 }
3546
3547 // Push the arguments ("left-to-right").
3548 int arg_count = args->length();
3549 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003550 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003551 }
3552
3553 if (expr->is_jsruntime()) {
3554 // Call the JS runtime function via a call IC.
3555 __ Set(ecx, Immediate(expr->name()));
3556 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003557 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003558 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003559 arg_count, in_loop, mode);
3560 EmitCallIC(ic, mode, expr->id());
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003561 // Restore context register.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003562 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3563 } else {
3564 // Call the C runtime function.
3565 __ CallRuntime(expr->function(), arg_count);
3566 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003567 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003568}
3569
3570
3571void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3572 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003573 case Token::DELETE: {
3574 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3575 Property* prop = expr->expression()->AsProperty();
3576 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003577
3578 if (prop != NULL) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003579 if (prop->is_synthetic()) {
3580 // Result of deleting parameters is false, even when they rewrite
3581 // to accesses on the arguments object.
3582 context()->Plug(false);
3583 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003584 VisitForStackValue(prop->obj());
3585 VisitForStackValue(prop->key());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003586 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003587 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003588 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003589 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003590 } else if (var != NULL) {
3591 // Delete of an unqualified identifier is disallowed in strict mode
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003592 // but "delete this" is.
3593 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003594 if (var->is_global()) {
3595 __ push(GlobalObjectOperand());
3596 __ push(Immediate(var->name()));
3597 __ push(Immediate(Smi::FromInt(kNonStrictMode)));
3598 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3599 context()->Plug(eax);
3600 } else if (var->AsSlot() != NULL &&
3601 var->AsSlot()->type() != Slot::LOOKUP) {
3602 // Result of deleting non-global, non-dynamic variables is false.
3603 // The subexpression does not have side effects.
3604 context()->Plug(false);
3605 } else {
3606 // Non-global variable. Call the runtime to try to delete from the
3607 // context where the variable was introduced.
3608 __ push(context_register());
3609 __ push(Immediate(var->name()));
3610 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3611 context()->Plug(eax);
3612 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003613 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003614 // Result of deleting non-property, non-variable reference is true.
3615 // The subexpression may have side effects.
3616 VisitForEffect(expr->expression());
3617 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003618 }
3619 break;
3620 }
3621
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003622 case Token::VOID: {
3623 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3624 VisitForEffect(expr->expression());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 context()->Plug(isolate()->factory()->undefined_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003626 break;
3627 }
3628
3629 case Token::NOT: {
3630 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003631 if (context()->IsEffect()) {
3632 // Unary NOT has no side effects so it's only necessary to visit the
3633 // subexpression. Match the optimizing compiler by not branching.
3634 VisitForEffect(expr->expression());
3635 } else {
3636 Label materialize_true, materialize_false;
3637 Label* if_true = NULL;
3638 Label* if_false = NULL;
3639 Label* fall_through = NULL;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003640
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003641 // Notice that the labels are swapped.
3642 context()->PrepareTest(&materialize_true, &materialize_false,
3643 &if_false, &if_true, &fall_through);
3644 if (context()->IsTest()) ForwardBailoutToChild(expr);
3645 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3646 context()->Plug(if_false, if_true); // Labels swapped.
3647 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003648 break;
3649 }
3650
3651 case Token::TYPEOF: {
3652 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003653 { StackValueContext context(this);
3654 VisitForTypeofValue(expr->expression());
3655 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003656 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003657 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003658 break;
3659 }
3660
3661 case Token::ADD: {
3662 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003663 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003664 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003665 __ JumpIfSmi(result_register(), &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003666 ToNumberStub convert_stub;
3667 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003668 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003669 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003670 break;
3671 }
3672
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003673 case Token::SUB:
3674 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003675 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003676
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003677 case Token::BIT_NOT:
3678 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003679 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003680
3681 default:
3682 UNREACHABLE();
3683 }
3684}
3685
3686
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003687void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3688 const char* comment) {
3689 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
3690 Comment cmt(masm_, comment);
3691 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3692 UnaryOverwriteMode overwrite =
3693 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003694 UnaryOpStub stub(expr->op(), overwrite);
3695 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003696 // accumulator register eax.
3697 VisitForAccumulatorValue(expr->expression());
3698 SetSourcePosition(expr->position());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00003699 EmitCallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003700 context()->Plug(eax);
3701}
3702
3703
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003704void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3705 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003706 SetSourcePosition(expr->position());
3707
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003708 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3709 // as the left-hand side.
3710 if (!expr->expression()->IsValidLeftHandSide()) {
3711 VisitForEffect(expr->expression());
3712 return;
3713 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003714
3715 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00003716 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003717 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3718 LhsKind assign_type = VARIABLE;
3719 Property* prop = expr->expression()->AsProperty();
3720 // In case of a property we use the uninitialized expression context
3721 // of the key to detect a named property.
3722 if (prop != NULL) {
3723 assign_type =
3724 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3725 }
3726
3727 // Evaluate expression and get value.
3728 if (assign_type == VARIABLE) {
3729 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003730 AccumulatorValueContext context(this);
3731 EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003732 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003733 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003734 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003735 __ push(Immediate(Smi::FromInt(0)));
3736 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003737 if (assign_type == NAMED_PROPERTY) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003738 // Put the object both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003739 VisitForAccumulatorValue(prop->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00003740 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003741 EmitNamedPropertyLoad(prop);
3742 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003743 VisitForStackValue(prop->obj());
3744 VisitForAccumulatorValue(prop->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00003745 __ mov(edx, Operand(esp, 0));
3746 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003747 EmitKeyedPropertyLoad(prop);
3748 }
3749 }
3750
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003751 // We need a second deoptimization point after loading the value
3752 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003753 if (assign_type == VARIABLE) {
3754 PrepareForBailout(expr->expression(), TOS_REG);
3755 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003756 PrepareForBailoutForId(expr->CountId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003757 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003758
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003759 // Call ToNumber only if operand is not a smi.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003760 Label no_conversion;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003761 if (ShouldInlineSmiCase(expr->op())) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003762 __ JumpIfSmi(eax, &no_conversion, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003763 }
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003764 ToNumberStub convert_stub;
3765 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003766 __ bind(&no_conversion);
3767
3768 // Save result for postfix expressions.
3769 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003770 if (!context()->IsEffect()) {
3771 // Save the result on the stack. If we have a named or keyed property
3772 // we store the result under the receiver that is currently on top
3773 // of the stack.
3774 switch (assign_type) {
3775 case VARIABLE:
3776 __ push(eax);
3777 break;
3778 case NAMED_PROPERTY:
3779 __ mov(Operand(esp, kPointerSize), eax);
3780 break;
3781 case KEYED_PROPERTY:
3782 __ mov(Operand(esp, 2 * kPointerSize), eax);
3783 break;
3784 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003785 }
3786 }
3787
3788 // Inline smi case if we are in a loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003789 Label done, stub_call;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003790 JumpPatchSite patch_site(masm_);
3791
ricow@chromium.org65fae842010-08-25 15:26:24 +00003792 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003793 if (expr->op() == Token::INC) {
3794 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3795 } else {
3796 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3797 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003798 __ j(overflow, &stub_call, Label::kNear);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003799 // We could eliminate this smi check if we split the code at
3800 // the first smi check before calling ToNumber.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003801 patch_site.EmitJumpIfSmi(eax, &done, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003802
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003803 __ bind(&stub_call);
3804 // Call stub. Undo operation first.
3805 if (expr->op() == Token::INC) {
3806 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3807 } else {
3808 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3809 }
3810 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003811
3812 // Record position before stub call.
3813 SetSourcePosition(expr->position());
3814
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003815 // Call stub for +1/-1.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003816 __ mov(edx, eax);
3817 __ mov(eax, Immediate(Smi::FromInt(1)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003818 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003819 EmitCallIC(stub.GetCode(), &patch_site, expr->CountId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003820 __ bind(&done);
3821
3822 // Store the value returned in eax.
3823 switch (assign_type) {
3824 case VARIABLE:
3825 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003826 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003827 { EffectContext context(this);
3828 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3829 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003830 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3831 context.Plug(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003832 }
3833 // For all contexts except EffectContext We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003834 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003835 if (!context()->IsEffect()) {
3836 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003837 }
3838 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003839 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003840 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003841 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003842 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3843 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003844 }
3845 break;
3846 case NAMED_PROPERTY: {
3847 __ mov(ecx, prop->key()->AsLiteral()->handle());
3848 __ pop(edx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003849 Handle<Code> ic = is_strict_mode()
3850 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3851 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003852 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003853 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003854 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003855 if (!context()->IsEffect()) {
3856 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003857 }
3858 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003859 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003860 }
3861 break;
3862 }
3863 case KEYED_PROPERTY: {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003864 __ pop(ecx);
3865 __ pop(edx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003866 Handle<Code> ic = is_strict_mode()
3867 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3868 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003869 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003870 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003871 if (expr->is_postfix()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003872 // Result is on the stack
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003873 if (!context()->IsEffect()) {
3874 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003875 }
3876 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003877 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003878 }
3879 break;
3880 }
3881 }
3882}
3883
3884
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003885void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003886 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003887 ASSERT(!context()->IsEffect());
3888 ASSERT(!context()->IsTest());
3889
ricow@chromium.org65fae842010-08-25 15:26:24 +00003890 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3891 Comment cmnt(masm_, "Global variable");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003892 __ mov(eax, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003893 __ mov(ecx, Immediate(proxy->name()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003894 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003895 // Use a regular load, not a contextual load, to avoid a reference
3896 // error.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003897 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003898 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003899 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003900 } else if (proxy != NULL &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003901 proxy->var()->AsSlot() != NULL &&
3902 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003903 Label done, slow;
3904
3905 // Generate code for loading from variables potentially shadowed
3906 // by eval-introduced variables.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003907 Slot* slot = proxy->var()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003908 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3909
3910 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003911 __ push(esi);
3912 __ push(Immediate(proxy->name()));
3913 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003914 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003915 __ bind(&done);
3916
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003917 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003918 } else {
3919 // This expression cannot throw a reference error at the top level.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003920 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003921 }
3922}
3923
3924
ager@chromium.org04921a82011-06-27 13:21:41 +00003925void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3926 Handle<String> check,
3927 Label* if_true,
3928 Label* if_false,
3929 Label* fall_through) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003930 { AccumulatorValueContext context(this);
ager@chromium.org04921a82011-06-27 13:21:41 +00003931 VisitForTypeofValue(expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003932 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003933 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003934
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003936 __ JumpIfSmi(eax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003937 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003938 isolate()->factory()->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003939 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003940 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003941 __ JumpIfSmi(eax, if_false);
3942 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
3943 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003944 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003945 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
3946 1 << Map::kIsUndetectable);
3947 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003948 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
3949 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003950 __ j(equal, if_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003951 __ cmp(eax, isolate()->factory()->false_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003952 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003953 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
3954 __ cmp(eax, isolate()->factory()->undefined_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003955 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003956 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003957 // Check for undetectable objects => true.
3958 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3959 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3960 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3961 Split(not_zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003962 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003963 __ JumpIfSmi(eax, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003964 __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003965 Split(above_equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003966 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003967 __ JumpIfSmi(eax, if_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003968 __ cmp(eax, isolate()->factory()->null_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003969 __ j(equal, if_true);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003970 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003971 __ j(below, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003972 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
3973 __ j(above, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003974 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003975 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
3976 1 << Map::kIsUndetectable);
3977 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003978 } else {
3979 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003980 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003981}
ricow@chromium.org65fae842010-08-25 15:26:24 +00003982
ager@chromium.org04921a82011-06-27 13:21:41 +00003983
3984void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
3985 Label* if_true,
3986 Label* if_false,
3987 Label* fall_through) {
3988 VisitForAccumulatorValue(expr);
3989 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3990
3991 __ cmp(eax, isolate()->factory()->undefined_value());
3992 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003993}
3994
3995
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003996void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3997 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003998 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003999
4000 // Always perform the comparison for its control flow. Pack the result
4001 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004002
4003 Label materialize_true, materialize_false;
4004 Label* if_true = NULL;
4005 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004006 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004007 context()->PrepareTest(&materialize_true, &materialize_false,
4008 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004009
4010 // First we try a fast inlined version of the compare when one of
4011 // the operands is a literal.
ager@chromium.org04921a82011-06-27 13:21:41 +00004012 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004013 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004014 return;
4015 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004016
ager@chromium.org04921a82011-06-27 13:21:41 +00004017 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004018 VisitForStackValue(expr->left());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004019 switch (expr->op()) {
4020 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004021 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004022 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004023 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004024 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004025 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004026 break;
4027
4028 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004029 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004030 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004031 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004032 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004033 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004034 // The stub returns 0 for true.
4035 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004036 break;
4037 }
4038
4039 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004040 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004041 Condition cc = no_condition;
4042 bool strict = false;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004043 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004044 case Token::EQ_STRICT:
4045 strict = true;
4046 // Fall through
ricow@chromium.org65fae842010-08-25 15:26:24 +00004047 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004048 cc = equal;
4049 __ pop(edx);
4050 break;
4051 case Token::LT:
4052 cc = less;
4053 __ pop(edx);
4054 break;
4055 case Token::GT:
4056 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4057 cc = less;
4058 __ mov(edx, result_register());
4059 __ pop(eax);
4060 break;
4061 case Token::LTE:
4062 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4063 cc = greater_equal;
4064 __ mov(edx, result_register());
4065 __ pop(eax);
4066 break;
4067 case Token::GTE:
4068 cc = greater_equal;
4069 __ pop(edx);
4070 break;
4071 case Token::IN:
4072 case Token::INSTANCEOF:
4073 default:
4074 UNREACHABLE();
4075 }
4076
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004077 bool inline_smi_code = ShouldInlineSmiCase(op);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004078 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004079 if (inline_smi_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004080 Label slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004081 __ mov(ecx, Operand(edx));
4082 __ or_(ecx, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004083 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004084 __ cmp(edx, Operand(eax));
4085 Split(cc, if_true, if_false, NULL);
4086 __ bind(&slow_case);
4087 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004088
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004089 // Record position and call the compare IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004090 SetSourcePosition(expr->position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004091 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004092 EmitCallIC(ic, &patch_site, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004093
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004094 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004095 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004096 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004097 }
4098 }
4099
4100 // Convert the result of the comparison into one expected for this
4101 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004102 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004103}
4104
4105
ricow@chromium.org65fae842010-08-25 15:26:24 +00004106void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4107 Label materialize_true, materialize_false;
4108 Label* if_true = NULL;
4109 Label* if_false = NULL;
4110 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004111 context()->PrepareTest(&materialize_true, &materialize_false,
4112 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004113
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004114 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004115 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4116
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004117 __ cmp(eax, isolate()->factory()->null_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004118 if (expr->is_strict()) {
4119 Split(equal, if_true, if_false, fall_through);
4120 } else {
4121 __ j(equal, if_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004122 __ cmp(eax, isolate()->factory()->undefined_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004123 __ j(equal, if_true);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004124 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004125 // It can be an undetectable object.
4126 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4127 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
4128 __ test(edx, Immediate(1 << Map::kIsUndetectable));
4129 Split(not_zero, if_true, if_false, fall_through);
4130 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004131 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004132}
4133
4134
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004135void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4136 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004137 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004138}
4139
4140
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004141Register FullCodeGenerator::result_register() {
4142 return eax;
4143}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004144
4145
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004146Register FullCodeGenerator::context_register() {
4147 return esi;
4148}
4149
4150
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004151void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
4152 RelocInfo::Mode mode,
4153 unsigned ast_id) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004154 ASSERT(mode == RelocInfo::CODE_TARGET ||
4155 mode == RelocInfo::CODE_TARGET_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004156 switch (ic->kind()) {
4157 case Code::LOAD_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004158 __ IncrementCounter(isolate()->counters()->named_load_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004159 break;
4160 case Code::KEYED_LOAD_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004161 __ IncrementCounter(isolate()->counters()->keyed_load_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004162 break;
4163 case Code::STORE_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004164 __ IncrementCounter(isolate()->counters()->named_store_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004165 break;
4166 case Code::KEYED_STORE_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004167 __ IncrementCounter(isolate()->counters()->keyed_store_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004168 default:
4169 break;
4170 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004171 __ call(ic, mode, ast_id);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004172}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004173
4174
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004175void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
4176 JumpPatchSite* patch_site,
4177 unsigned ast_id) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004178 Counters* counters = isolate()->counters();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004179 switch (ic->kind()) {
4180 case Code::LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004181 __ IncrementCounter(counters->named_load_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004182 break;
4183 case Code::KEYED_LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004184 __ IncrementCounter(counters->keyed_load_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004185 break;
4186 case Code::STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004187 __ IncrementCounter(counters->named_store_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004188 break;
4189 case Code::KEYED_STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004190 __ IncrementCounter(counters->keyed_store_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004191 default:
4192 break;
4193 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004194 __ call(ic, RelocInfo::CODE_TARGET, ast_id);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004195 if (patch_site != NULL && patch_site->is_bound()) {
4196 patch_site->EmitPatchInfo();
4197 } else {
4198 __ nop(); // Signals no inlined code.
4199 }
4200}
4201
4202
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004203void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4204 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4205 __ mov(Operand(ebp, frame_offset), value);
4206}
4207
4208
4209void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004210 __ mov(dst, ContextOperand(esi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004211}
4212
4213
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004214void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
4215 if (scope()->is_global_scope()) {
4216 // Contexts nested in the global context have a canonical empty function
4217 // as their closure, not the anonymous closure containing the global
4218 // code. Pass a smi sentinel and let the runtime look up the empty
4219 // function.
4220 __ push(Immediate(Smi::FromInt(0)));
4221 } else if (scope()->is_eval_scope()) {
4222 // Contexts created by a call to eval have the same closure as the
4223 // context calling eval, not the anonymous closure containing the eval
4224 // code. Fetch it from the context.
4225 __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
4226 } else {
4227 ASSERT(scope()->is_function_scope());
4228 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4229 }
4230}
4231
4232
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004233// ----------------------------------------------------------------------------
4234// Non-local control flow support.
4235
4236void FullCodeGenerator::EnterFinallyBlock() {
4237 // Cook return address on top of stack (smi encoded Code* delta)
4238 ASSERT(!result_register().is(edx));
4239 __ mov(edx, Operand(esp, 0));
4240 __ sub(Operand(edx), Immediate(masm_->CodeObject()));
4241 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4242 ASSERT_EQ(0, kSmiTag);
4243 __ add(edx, Operand(edx)); // Convert to smi.
4244 __ mov(Operand(esp, 0), edx);
4245 // Store result register while executing finally block.
4246 __ push(result_register());
4247}
4248
4249
4250void FullCodeGenerator::ExitFinallyBlock() {
4251 ASSERT(!result_register().is(edx));
4252 // Restore result register from stack.
4253 __ pop(result_register());
4254 // Uncook return address.
4255 __ mov(edx, Operand(esp, 0));
4256 __ sar(edx, 1); // Convert smi to int.
4257 __ add(Operand(edx), Immediate(masm_->CodeObject()));
4258 __ mov(Operand(esp, 0), edx);
4259 // And return.
4260 __ ret(0);
4261}
4262
4263
4264#undef __
4265
4266} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004267
4268#endif // V8_TARGET_ARCH_IA32