blob: c46a869f3f5800ae94a457db9f338dc110d701f6 [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
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000047static unsigned GetPropertyId(Property* property) {
48 if (property->is_synthetic()) return AstNode::kNoNumber;
49 return property->id();
50}
51
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000052
53class JumpPatchSite BASE_EMBEDDED {
54 public:
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000055 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000056#ifdef DEBUG
57 info_emitted_ = false;
58#endif
59 }
60
61 ~JumpPatchSite() {
62 ASSERT(patch_site_.is_bound() == info_emitted_);
63 }
64
65 void EmitJumpIfNotSmi(Register reg, NearLabel* target) {
66 __ test(reg, Immediate(kSmiTagMask));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000067 EmitJump(not_carry, target); // Always taken before patched.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000068 }
69
70 void EmitJumpIfSmi(Register reg, NearLabel* target) {
71 __ test(reg, Immediate(kSmiTagMask));
72 EmitJump(carry, target); // Never taken before patched.
73 }
74
75 void EmitPatchInfo() {
76 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
77 ASSERT(is_int8(delta_to_patch_site));
78 __ test(eax, Immediate(delta_to_patch_site));
79#ifdef DEBUG
80 info_emitted_ = true;
81#endif
82 }
83
84 bool is_bound() const { return patch_site_.is_bound(); }
85
86 private:
87 // jc will be patched with jz, jnc will become jnz.
88 void EmitJump(Condition cc, NearLabel* target) {
89 ASSERT(!patch_site_.is_bound() && !info_emitted_);
90 ASSERT(cc == carry || cc == not_carry);
91 __ bind(&patch_site_);
92 __ j(cc, target);
93 }
94
95 MacroAssembler* masm_;
96 Label patch_site_;
97#ifdef DEBUG
98 bool info_emitted_;
99#endif
100};
101
102
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000103// Generate code for a JS function. On entry to the function the receiver
104// and arguments have been pushed on the stack left to right, with the
105// return address on top of them. The actual argument count matches the
106// formal parameter count expected by the function.
107//
108// The live registers are:
109// o edi: the JS function object being called (ie, ourselves)
110// o esi: our context
111// o ebp: our caller's frame pointer
112// o esp: stack pointer (pointing to return address)
113//
114// The function builds a JS frame. Please see JavaScriptFrameConstants in
115// frames-ia32.h for its layout.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000116void FullCodeGenerator::Generate(CompilationInfo* info) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000117 ASSERT(info_ == NULL);
118 info_ = info;
119 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000120 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121
vegorov@chromium.org42841962010-10-18 11:18:59 +0000122#ifdef DEBUG
123 if (strlen(FLAG_stop_at) > 0 &&
124 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
125 __ int3();
126 }
127#endif
128
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000129 __ push(ebp); // Caller's frame pointer.
130 __ mov(ebp, esp);
131 __ push(esi); // Callee's context.
132 __ push(edi); // Callee's JS Function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000133
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000134 { Comment cmnt(masm_, "[ Allocate locals");
135 int locals_count = scope()->num_stack_slots();
136 if (locals_count == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 __ push(Immediate(isolate()->factory()->undefined_value()));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000138 } else if (locals_count > 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000140 for (int i = 0; i < locals_count; i++) {
141 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000142 }
143 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000144 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000145
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000146 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000147
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000148 // Possibly allocate a local context.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000149 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000150 if (heap_slots > 0) {
151 Comment cmnt(masm_, "[ Allocate local context");
152 // Argument to NewContext is the function, which is still in edi.
153 __ push(edi);
154 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
155 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000157 } else {
158 __ CallRuntime(Runtime::kNewContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000160 function_in_register = false;
161 // Context is returned in both eax and esi. It replaces the context
162 // passed to us. It's saved in the stack and kept live in esi.
163 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
164
165 // Copy parameters into context if necessary.
166 int num_parameters = scope()->num_parameters();
167 for (int i = 0; i < num_parameters; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000168 Slot* slot = scope()->parameter(i)->AsSlot();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000169 if (slot != NULL && slot->type() == Slot::CONTEXT) {
170 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
171 (num_parameters - 1 - i) * kPointerSize;
172 // Load parameter from stack.
173 __ mov(eax, Operand(ebp, parameter_offset));
174 // Store it in the context.
175 int context_offset = Context::SlotOffset(slot->index());
176 __ mov(Operand(esi, context_offset), eax);
177 // Update the write barrier. This clobbers all involved
178 // registers, so we have use a third register to avoid
179 // clobbering esi.
180 __ mov(ecx, esi);
181 __ RecordWrite(ecx, context_offset, eax, ebx);
182 }
183 }
184 }
185
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000186 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000187 if (arguments != NULL) {
188 // Function uses arguments object.
189 Comment cmnt(masm_, "[ Allocate arguments object");
190 if (function_in_register) {
191 __ push(edi);
192 } else {
193 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
194 }
195 // Receiver is just before the parameters on the caller's stack.
196 int offset = scope()->num_parameters() * kPointerSize;
197 __ lea(edx,
198 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
199 __ push(edx);
200 __ push(Immediate(Smi::FromInt(scope()->num_parameters())));
201 // Arguments to ArgumentsAccessStub:
202 // function, receiver address, parameter count.
203 // The stub will rewrite receiver and parameter count if the previous
204 // stack frame was an arguments adapter frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 ArgumentsAccessStub stub(
206 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
207 : ArgumentsAccessStub::NEW_NON_STRICT);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000208 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000209
210 Variable* arguments_shadow = scope()->arguments_shadow();
211 if (arguments_shadow != NULL) {
212 __ mov(ecx, eax); // Duplicate result.
213 Move(arguments_shadow->AsSlot(), ecx, ebx, edx);
214 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000215 Move(arguments->AsSlot(), eax, ebx, edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000216 }
217
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000218 if (FLAG_trace) {
219 __ CallRuntime(Runtime::kTraceEnter, 0);
220 }
221
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000222 // Visit the declarations and body unless there is an illegal
223 // redeclaration.
224 if (scope()->HasIllegalRedeclaration()) {
225 Comment cmnt(masm_, "[ Declarations");
226 scope()->VisitIllegalRedeclaration(this);
227
228 } else {
229 { Comment cmnt(masm_, "[ Declarations");
230 // For named function expressions, declare the function name as a
231 // constant.
232 if (scope()->is_function_scope() && scope()->function() != NULL) {
233 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
234 }
235 VisitDeclarations(scope()->declarations());
236 }
237
238 { Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000239 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000240 NearLabel ok;
241 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000242 ExternalReference::address_of_stack_limit(isolate());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000243 __ cmp(esp, Operand::StaticVariable(stack_limit));
244 __ j(above_equal, &ok, taken);
245 StackCheckStub stub;
246 __ CallStub(&stub);
247 __ bind(&ok);
248 }
249
250 { Comment cmnt(masm_, "[ Body");
251 ASSERT(loop_depth() == 0);
252 VisitStatements(function()->body());
253 ASSERT(loop_depth() == 0);
254 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000255 }
256
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000257 // Always emit a 'return undefined' in case control fell off the end of
258 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000259 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 __ mov(eax, isolate()->factory()->undefined_value());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000261 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000262 }
263}
264
265
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000266void FullCodeGenerator::ClearAccumulator() {
267 __ Set(eax, Immediate(Smi::FromInt(0)));
268}
269
270
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000271void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
272 Comment cmnt(masm_, "[ Stack check");
273 NearLabel ok;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 ExternalReference stack_limit =
275 ExternalReference::address_of_stack_limit(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000276 __ cmp(esp, Operand::StaticVariable(stack_limit));
277 __ j(above_equal, &ok, taken);
278 StackCheckStub stub;
279 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000280 // Record a mapping of this PC offset to the OSR id. This is used to find
281 // the AST id from the unoptimized code in order to use it as a key into
282 // the deoptimization input data found in the optimized code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000283 RecordStackCheck(stmt->OsrEntryId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000284
285 // Loop stack checks can be patched to perform on-stack replacement. In
286 // order to decide whether or not to perform OSR we embed the loop depth
287 // in a test instruction after the call so we can extract it from the OSR
288 // builtin.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000289 ASSERT(loop_depth() > 0);
290 __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000291
292 __ bind(&ok);
293 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
294 // Record a mapping of the OSR id to this PC. This is used if the OSR
295 // entry becomes the target of a bailout. We don't expect it to be, but
296 // we want it to work if it is.
297 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000298}
299
300
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000301void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000302 Comment cmnt(masm_, "[ Return sequence");
303 if (return_label_.is_bound()) {
304 __ jmp(&return_label_);
305 } else {
306 // Common return label
307 __ bind(&return_label_);
308 if (FLAG_trace) {
309 __ push(eax);
310 __ CallRuntime(Runtime::kTraceExit, 1);
311 }
312#ifdef DEBUG
313 // Add a label for checking the size of the code used for returning.
314 Label check_exit_codesize;
315 masm_->bind(&check_exit_codesize);
316#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000317 SetSourcePosition(function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000318 __ RecordJSReturn();
319 // Do not use the leave instruction here because it is too short to
320 // patch with the code required by the debugger.
321 __ mov(esp, ebp);
322 __ pop(ebp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000323
324 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize;
325 __ Ret(arguments_bytes, ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000326#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000327 // Check that the size of the code used for returning is large enough
328 // for the debugger's requirements.
329 ASSERT(Assembler::kJSReturnSequenceLength <=
330 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000331#endif
332 }
333}
334
335
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000336void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000337}
338
339
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000340void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
341 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
342 __ mov(result_register(), slot_operand);
343}
344
345
346void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
347 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
348 // Memory operands can be pushed directly.
349 __ push(slot_operand);
350}
351
352
353void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
354 // For simplicity we always test the accumulator register.
355 codegen()->Move(result_register(), slot);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000356 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000357 codegen()->DoTest(true_label_, false_label_, fall_through_);
358}
359
360
361void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
362 UNREACHABLE(); // Not used on IA32.
363}
364
365
366void FullCodeGenerator::AccumulatorValueContext::Plug(
367 Heap::RootListIndex index) const {
368 UNREACHABLE(); // Not used on IA32.
369}
370
371
372void FullCodeGenerator::StackValueContext::Plug(
373 Heap::RootListIndex index) const {
374 UNREACHABLE(); // Not used on IA32.
375}
376
377
378void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
379 UNREACHABLE(); // Not used on IA32.
380}
381
382
383void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
384}
385
386
387void FullCodeGenerator::AccumulatorValueContext::Plug(
388 Handle<Object> lit) const {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000389 __ Set(result_register(), Immediate(lit));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000390}
391
392
393void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
394 // Immediates can be pushed directly.
395 __ push(Immediate(lit));
396}
397
398
399void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000400 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
401 true,
402 true_label_,
403 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000404 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
405 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000406 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000407 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000408 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000409 } else if (lit->IsString()) {
410 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000411 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000412 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000413 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000414 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000415 } else if (lit->IsSmi()) {
416 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000417 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000418 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000419 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000420 }
421 } else {
422 // For simplicity we always test the accumulator register.
423 __ mov(result_register(), lit);
424 codegen()->DoTest(true_label_, false_label_, fall_through_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000425 }
426}
427
428
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000429void FullCodeGenerator::EffectContext::DropAndPlug(int count,
430 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000431 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000432 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000433}
434
435
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000436void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
437 int count,
438 Register reg) const {
439 ASSERT(count > 0);
440 __ Drop(count);
441 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000442}
443
444
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000445void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
446 Register reg) const {
447 ASSERT(count > 0);
448 if (count > 1) __ Drop(count - 1);
449 __ mov(Operand(esp, 0), reg);
450}
451
452
453void FullCodeGenerator::TestContext::DropAndPlug(int count,
454 Register reg) const {
455 ASSERT(count > 0);
456 // For simplicity we always test the accumulator register.
457 __ Drop(count);
458 __ Move(result_register(), reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000459 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000460 codegen()->DoTest(true_label_, false_label_, fall_through_);
461}
462
463
464void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
465 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000466 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000467 __ bind(materialize_true);
468}
469
470
471void FullCodeGenerator::AccumulatorValueContext::Plug(
472 Label* materialize_true,
473 Label* materialize_false) const {
474 NearLabel done;
475 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000476 __ mov(result_register(), isolate()->factory()->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000477 __ jmp(&done);
478 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000479 __ mov(result_register(), isolate()->factory()->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000480 __ bind(&done);
481}
482
483
484void FullCodeGenerator::StackValueContext::Plug(
485 Label* materialize_true,
486 Label* materialize_false) const {
487 NearLabel done;
488 __ bind(materialize_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000489 __ push(Immediate(isolate()->factory()->true_value()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000490 __ jmp(&done);
491 __ bind(materialize_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000492 __ push(Immediate(isolate()->factory()->false_value()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000493 __ bind(&done);
494}
495
496
497void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
498 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000499 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000500 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000501}
502
503
504void FullCodeGenerator::EffectContext::Plug(bool flag) const {
505}
506
507
508void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 Handle<Object> value = flag
510 ? isolate()->factory()->true_value()
511 : isolate()->factory()->false_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000512 __ mov(result_register(), value);
513}
514
515
516void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 Handle<Object> value = flag
518 ? isolate()->factory()->true_value()
519 : isolate()->factory()->false_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000520 __ push(Immediate(value));
521}
522
523
524void FullCodeGenerator::TestContext::Plug(bool flag) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000525 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
526 true,
527 true_label_,
528 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000529 if (flag) {
530 if (true_label_ != fall_through_) __ jmp(true_label_);
531 } else {
532 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000533 }
534}
535
536
ricow@chromium.org65fae842010-08-25 15:26:24 +0000537void FullCodeGenerator::DoTest(Label* if_true,
538 Label* if_false,
539 Label* fall_through) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000540 // Emit the inlined tests assumed by the stub.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000541 __ cmp(result_register(), isolate()->factory()->undefined_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000542 __ j(equal, if_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 __ cmp(result_register(), isolate()->factory()->true_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000544 __ j(equal, if_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 __ cmp(result_register(), isolate()->factory()->false_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000546 __ j(equal, if_false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000547 STATIC_ASSERT(kSmiTag == 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000548 __ test(result_register(), Operand(result_register()));
549 __ j(zero, if_false);
550 __ test(result_register(), Immediate(kSmiTagMask));
551 __ j(zero, if_true);
552
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000553 // Call the ToBoolean stub for all other cases.
554 ToBooleanStub stub;
555 __ push(result_register());
556 __ CallStub(&stub);
557 __ test(eax, Operand(eax));
558
ricow@chromium.org65fae842010-08-25 15:26:24 +0000559 // The stub returns nonzero for true.
560 Split(not_zero, if_true, if_false, fall_through);
561}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000562
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000563
ricow@chromium.org65fae842010-08-25 15:26:24 +0000564void FullCodeGenerator::Split(Condition cc,
565 Label* if_true,
566 Label* if_false,
567 Label* fall_through) {
568 if (if_false == fall_through) {
569 __ j(cc, if_true);
570 } else if (if_true == fall_through) {
571 __ j(NegateCondition(cc), if_false);
572 } else {
573 __ j(cc, if_true);
574 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000575 }
576}
577
578
579MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
580 switch (slot->type()) {
581 case Slot::PARAMETER:
582 case Slot::LOCAL:
583 return Operand(ebp, SlotOffset(slot));
584 case Slot::CONTEXT: {
585 int context_chain_length =
ager@chromium.org5c838252010-02-19 08:53:10 +0000586 scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000587 __ LoadContext(scratch, context_chain_length);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000588 return ContextOperand(scratch, slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000589 }
590 case Slot::LOOKUP:
591 UNREACHABLE();
592 }
593 UNREACHABLE();
594 return Operand(eax, 0);
595}
596
597
598void FullCodeGenerator::Move(Register destination, Slot* source) {
599 MemOperand location = EmitSlotSearch(source, destination);
600 __ mov(destination, location);
601}
602
603
604void FullCodeGenerator::Move(Slot* dst,
605 Register src,
606 Register scratch1,
607 Register scratch2) {
608 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
609 ASSERT(!scratch1.is(src) && !scratch2.is(src));
610 MemOperand location = EmitSlotSearch(dst, scratch1);
611 __ mov(location, src);
612 // Emit the write barrier code if the location is in the heap.
613 if (dst->type() == Slot::CONTEXT) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000614 int offset = Context::SlotOffset(dst->index());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000615 ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000616 __ RecordWrite(scratch1, offset, src, scratch2);
617 }
618}
619
620
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000621void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
622 bool should_normalize,
623 Label* if_true,
624 Label* if_false) {
625 // Only prepare for bailouts before splits if we're in a test
626 // context. Otherwise, we let the Visit function deal with the
627 // preparation to avoid preparing with the same AST id twice.
628 if (!context()->IsTest() || !info_->IsOptimizable()) return;
629
630 NearLabel skip;
631 if (should_normalize) __ jmp(&skip);
632
633 ForwardBailoutStack* current = forward_bailout_stack_;
634 while (current != NULL) {
635 PrepareForBailout(current->expr(), state);
636 current = current->parent();
637 }
638
639 if (should_normalize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 __ cmp(eax, isolate()->factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000641 Split(equal, if_true, if_false, NULL);
642 __ bind(&skip);
643 }
644}
645
646
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000647void FullCodeGenerator::EmitDeclaration(Variable* variable,
648 Variable::Mode mode,
649 FunctionLiteral* function) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000650 Comment cmnt(masm_, "[ Declaration");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000651 ASSERT(variable != NULL); // Must have been resolved.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000652 Slot* slot = variable->AsSlot();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000653 Property* prop = variable->AsProperty();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000654
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000655 if (slot != NULL) {
656 switch (slot->type()) {
657 case Slot::PARAMETER:
658 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000659 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000660 __ mov(Operand(ebp, SlotOffset(slot)),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000661 Immediate(isolate()->factory()->the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000662 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000663 VisitForAccumulatorValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000664 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
665 }
666 break;
667
668 case Slot::CONTEXT:
669 // We bypass the general EmitSlotSearch because we know more about
670 // this specific context.
671
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000672 // The variable in the decl always resides in the current function
673 // context.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000674 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000675 if (FLAG_debug_code) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000676 // Check that we're not inside a 'with'.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000677 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000678 __ cmp(ebx, Operand(esi));
679 __ Check(equal, "Unexpected declaration in current context.");
680 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000681 if (mode == Variable::CONST) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000682 __ mov(ContextOperand(esi, slot->index()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000683 Immediate(isolate()->factory()->the_hole_value()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000684 // No write barrier since the hole value is in old space.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000685 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000686 VisitForAccumulatorValue(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000687 __ mov(ContextOperand(esi, slot->index()), result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000688 int offset = Context::SlotOffset(slot->index());
689 __ mov(ebx, esi);
690 __ RecordWrite(ebx, offset, result_register(), ecx);
691 }
692 break;
693
694 case Slot::LOOKUP: {
695 __ push(esi);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000696 __ push(Immediate(variable->name()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000697 // Declaration nodes are always introduced in one of two modes.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000698 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
699 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000700 __ push(Immediate(Smi::FromInt(attr)));
701 // Push initial value, if any.
702 // Note: For variables we must not push an initial value (such as
703 // 'undefined') because we may have a (legal) redeclaration and we
704 // must not destroy the current value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000705 if (mode == Variable::CONST) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000706 __ push(Immediate(isolate()->factory()->the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000707 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000708 VisitForStackValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000709 } else {
710 __ push(Immediate(Smi::FromInt(0))); // No initial value!
711 }
712 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
713 break;
714 }
715 }
716
717 } else if (prop != NULL) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000718 if (function != NULL || mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000719 // We are declaring a function or constant that rewrites to a
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000720 // property. Use (keyed) IC to set the initial value. We cannot
721 // visit the rewrite because it's shared and we risk recording
722 // duplicate AST IDs for bailouts from optimized code.
723 ASSERT(prop->obj()->AsVariableProxy() != NULL);
724 { AccumulatorValueContext for_object(this);
725 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000726 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000727
728 if (function != NULL) {
729 __ push(eax);
730 VisitForAccumulatorValue(function);
731 __ pop(edx);
732 } else {
733 __ mov(edx, eax);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000734 __ mov(eax, isolate()->factory()->the_hole_value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000735 }
736 ASSERT(prop->key()->AsLiteral() != NULL &&
737 prop->key()->AsLiteral()->handle()->IsSmi());
738 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000739
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000740 Handle<Code> ic = is_strict_mode()
741 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
742 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000743 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000744 }
745 }
746}
747
748
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000749void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
750 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
751}
752
753
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000754void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
755 // Call the runtime to declare the globals.
756 __ push(esi); // The context is the first argument.
757 __ push(Immediate(pairs));
ager@chromium.org5c838252010-02-19 08:53:10 +0000758 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000759 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
760 __ CallRuntime(Runtime::kDeclareGlobals, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000761 // Return value is ignored.
762}
763
764
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000765void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
766 Comment cmnt(masm_, "[ SwitchStatement");
767 Breakable nested_statement(this, stmt);
768 SetStatementPosition(stmt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000769
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000770 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000771 VisitForStackValue(stmt->tag());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000772 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000773
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000774 ZoneList<CaseClause*>* clauses = stmt->cases();
775 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000776
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000777 Label next_test; // Recycled for each test.
778 // Compile all the tests with branches to their bodies.
779 for (int i = 0; i < clauses->length(); i++) {
780 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000781 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000782
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000783 // The default is not a test, but remember it as final fall through.
784 if (clause->is_default()) {
785 default_clause = clause;
786 continue;
787 }
788
789 Comment cmnt(masm_, "[ Case comparison");
790 __ bind(&next_test);
791 next_test.Unuse();
792
793 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000794 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000795
ricow@chromium.org65fae842010-08-25 15:26:24 +0000796 // Perform the comparison as if via '==='.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000797 __ mov(edx, Operand(esp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000798 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000799 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000800 if (inline_smi_code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000801 NearLabel slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000802 __ mov(ecx, edx);
803 __ or_(ecx, Operand(eax));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000804 patch_site.EmitJumpIfNotSmi(ecx, &slow_case);
805
ricow@chromium.org65fae842010-08-25 15:26:24 +0000806 __ cmp(edx, Operand(eax));
807 __ j(not_equal, &next_test);
808 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000809 __ jmp(clause->body_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000810 __ bind(&slow_case);
811 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000812
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000813 // Record position before stub call for type feedback.
814 SetSourcePosition(clause->position());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000815 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000816 EmitCallIC(ic, &patch_site, clause->CompareId());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000817 __ test(eax, Operand(eax));
818 __ j(not_equal, &next_test);
819 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000820 __ jmp(clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000821 }
822
823 // Discard the test value and jump to the default if present, otherwise to
824 // the end of the statement.
825 __ bind(&next_test);
826 __ Drop(1); // Switch value is no longer needed.
827 if (default_clause == NULL) {
828 __ jmp(nested_statement.break_target());
829 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000830 __ jmp(default_clause->body_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000831 }
832
833 // Compile all the case bodies.
834 for (int i = 0; i < clauses->length(); i++) {
835 Comment cmnt(masm_, "[ Case body");
836 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000837 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000838 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000839 VisitStatements(clause->statements());
840 }
841
842 __ bind(nested_statement.break_target());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000843 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000844}
845
846
847void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
848 Comment cmnt(masm_, "[ ForInStatement");
849 SetStatementPosition(stmt);
850
851 Label loop, exit;
852 ForIn loop_statement(this, stmt);
853 increment_loop_depth();
854
855 // Get the object to enumerate over. Both SpiderMonkey and JSC
856 // ignore null and undefined in contrast to the specification; see
857 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000858 VisitForAccumulatorValue(stmt->enumerable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 __ cmp(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000860 __ j(equal, &exit);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000862 __ j(equal, &exit);
863
864 // Convert the object to a JS object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000865 NearLabel convert, done_convert;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000866 __ test(eax, Immediate(kSmiTagMask));
867 __ j(zero, &convert);
868 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
869 __ j(above_equal, &done_convert);
870 __ bind(&convert);
871 __ push(eax);
872 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
873 __ bind(&done_convert);
874 __ push(eax);
875
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000876 // Check cache validity in generated code. This is a fast case for
877 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
878 // guarantee cache validity, call the runtime system to check cache
879 // validity or get the property names in a fixed array.
880 Label next, call_runtime;
881 __ mov(ecx, eax);
882 __ bind(&next);
883
884 // Check that there are no elements. Register ecx contains the
885 // current JS object we've reached through the prototype chain.
886 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000887 isolate()->factory()->empty_fixed_array());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000888 __ j(not_equal, &call_runtime);
889
890 // Check that instance descriptors are not empty so that we can
891 // check for an enum cache. Leave the map in ebx for the subsequent
892 // prototype load.
893 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
894 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 __ cmp(edx, isolate()->factory()->empty_descriptor_array());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000896 __ j(equal, &call_runtime);
897
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000898 // Check that there is an enum cache in the non-empty instance
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000899 // descriptors (edx). This is the case if the next enumeration
900 // index field does not contain a smi.
901 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
902 __ test(edx, Immediate(kSmiTagMask));
903 __ j(zero, &call_runtime);
904
905 // For all objects but the receiver, check that the cache is empty.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000906 NearLabel check_prototype;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000907 __ cmp(ecx, Operand(eax));
908 __ j(equal, &check_prototype);
909 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000910 __ cmp(edx, isolate()->factory()->empty_fixed_array());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000911 __ j(not_equal, &call_runtime);
912
913 // Load the prototype from the map and loop if non-null.
914 __ bind(&check_prototype);
915 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000916 __ cmp(ecx, isolate()->factory()->null_value());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000917 __ j(not_equal, &next);
918
919 // The enum cache is valid. Load the map of the object being
920 // iterated over and use the cache for the iteration.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000921 NearLabel use_cache;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000922 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
923 __ jmp(&use_cache);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000924
925 // Get the set of properties to enumerate.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000926 __ bind(&call_runtime);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000927 __ push(eax); // Duplicate the enumerable object on the stack.
928 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
929
930 // If we got a map from the runtime call, we can do a fast
931 // modification check. Otherwise, we got a fixed array, and we have
932 // to do a slow check.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000933 NearLabel fixed_array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
935 isolate()->factory()->meta_map());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000936 __ j(not_equal, &fixed_array);
937
938 // We got a map in register eax. Get the enumeration cache from it.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000939 __ bind(&use_cache);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000940 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset));
941 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
942 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
943
944 // Setup the four remaining stack slots.
945 __ push(eax); // Map.
946 __ push(edx); // Enumeration cache.
947 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000948 __ push(eax); // Enumeration cache length (as smi).
949 __ push(Immediate(Smi::FromInt(0))); // Initial index.
950 __ jmp(&loop);
951
952 // We got a fixed array in register eax. Iterate through that.
953 __ bind(&fixed_array);
954 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
955 __ push(eax);
956 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000957 __ push(eax); // Fixed array length (as smi).
958 __ push(Immediate(Smi::FromInt(0))); // Initial index.
959
960 // Generate code for doing the condition check.
961 __ bind(&loop);
962 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
963 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
964 __ j(above_equal, loop_statement.break_target());
965
966 // Get the current entry of the array into register ebx.
967 __ mov(ebx, Operand(esp, 2 * kPointerSize));
968 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
969
970 // Get the expected map from the stack or a zero map in the
971 // permanent slow case into register edx.
972 __ mov(edx, Operand(esp, 3 * kPointerSize));
973
974 // Check if the expected map still matches that of the enumerable.
975 // If not, we have to filter the key.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000976 NearLabel update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000977 __ mov(ecx, Operand(esp, 4 * kPointerSize));
978 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
979 __ j(equal, &update_each);
980
981 // Convert the entry to a string or null if it isn't a property
982 // anymore. If the property has been removed while iterating, we
983 // just skip it.
984 __ push(ecx); // Enumerable.
985 __ push(ebx); // Current entry.
986 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000987 __ test(eax, Operand(eax));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000988 __ j(equal, loop_statement.continue_target());
989 __ mov(ebx, Operand(eax));
990
991 // Update the 'each' property or variable from the possibly filtered
992 // entry in register ebx.
993 __ bind(&update_each);
994 __ mov(result_register(), ebx);
995 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000996 { EffectContext context(this);
997 EmitAssignment(stmt->each(), stmt->AssignmentId());
998 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000999
1000 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001001 Visit(stmt->body());
1002
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001003 // Generate code for going to the next element by incrementing the
1004 // index (smi) stored on top of the stack.
1005 __ bind(loop_statement.continue_target());
1006 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001007
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001008 EmitStackCheck(stmt);
1009 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001010
1011 // Remove the pointers stored on the stack.
1012 __ bind(loop_statement.break_target());
1013 __ add(Operand(esp), Immediate(5 * kPointerSize));
1014
1015 // Exit and decrement the loop depth.
1016 __ bind(&exit);
1017 decrement_loop_depth();
1018}
1019
1020
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001021void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1022 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001023 // Use the fast case closure allocation code that allocates in new
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001024 // space for nested functions that don't need literals cloning. If
1025 // we're running with the --always-opt or the --prepare-always-opt
1026 // flag, we need to use the runtime function so that the new function
1027 // we are creating here gets a chance to have its code optimized and
1028 // doesn't just get a copy of the existing unoptimized code.
1029 if (!FLAG_always_opt &&
1030 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001031 !pretenure &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001032 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 info->num_literals() == 0) {
1034 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001035 __ push(Immediate(info));
1036 __ CallStub(&stub);
1037 } else {
1038 __ push(esi);
1039 __ push(Immediate(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001040 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041 ? isolate()->factory()->true_value()
1042 : isolate()->factory()->false_value()));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001043 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001044 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001045 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001046}
1047
1048
1049void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1050 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001051 EmitVariableLoad(expr->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001052}
1053
1054
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001055void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
1056 Slot* slot,
1057 TypeofState typeof_state,
1058 Label* slow) {
1059 Register context = esi;
1060 Register temp = edx;
1061
1062 Scope* s = scope();
1063 while (s != NULL) {
1064 if (s->num_heap_slots() > 0) {
1065 if (s->calls_eval()) {
1066 // Check that extension is NULL.
1067 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1068 Immediate(0));
1069 __ j(not_equal, slow);
1070 }
1071 // Load next context in chain.
1072 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1073 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1074 // Walk the rest of the chain without clobbering esi.
1075 context = temp;
1076 }
1077 // If no outer scope calls eval, we do not need to check more
1078 // context extensions. If we have reached an eval scope, we check
1079 // all extensions from this point.
1080 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1081 s = s->outer_scope();
1082 }
1083
1084 if (s != NULL && s->is_eval_scope()) {
1085 // Loop up the context chain. There is no frame effect so it is
1086 // safe to use raw labels here.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001087 NearLabel next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001088 if (!context.is(temp)) {
1089 __ mov(temp, context);
1090 }
1091 __ bind(&next);
1092 // Terminate at global context.
1093 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094 Immediate(isolate()->factory()->global_context_map()));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001095 __ j(equal, &fast);
1096 // Check that extension is NULL.
1097 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1098 __ j(not_equal, slow);
1099 // Load next context in chain.
1100 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX));
1101 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1102 __ jmp(&next);
1103 __ bind(&fast);
1104 }
1105
1106 // All extension objects were empty and it is safe to use a global
1107 // load IC call.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001108 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001109 __ mov(ecx, slot->var()->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001110 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001111 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1112 ? RelocInfo::CODE_TARGET
1113 : RelocInfo::CODE_TARGET_CONTEXT;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001114 EmitCallIC(ic, mode, AstNode::kNoNumber);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001115}
1116
1117
1118MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1119 Slot* slot,
1120 Label* slow) {
1121 ASSERT(slot->type() == Slot::CONTEXT);
1122 Register context = esi;
1123 Register temp = ebx;
1124
1125 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1126 if (s->num_heap_slots() > 0) {
1127 if (s->calls_eval()) {
1128 // Check that extension is NULL.
1129 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1130 Immediate(0));
1131 __ j(not_equal, slow);
1132 }
1133 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1134 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1135 // Walk the rest of the chain without clobbering esi.
1136 context = temp;
1137 }
1138 }
1139 // Check that last extension is NULL.
1140 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1141 __ j(not_equal, slow);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001142
1143 // This function is used only for loads, not stores, so it's safe to
1144 // return an esi-based operand (the write barrier cannot be allowed to
1145 // destroy the esi register).
1146 return ContextOperand(context, slot->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001147}
1148
1149
1150void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1151 Slot* slot,
1152 TypeofState typeof_state,
1153 Label* slow,
1154 Label* done) {
1155 // Generate fast-case code for variables that might be shadowed by
1156 // eval-introduced variables. Eval is used a lot without
1157 // introducing variables. In those cases, we do not want to
1158 // perform a runtime call for all variables in the scope
1159 // containing the eval.
1160 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1161 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1162 __ jmp(done);
1163 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001164 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001165 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1166 if (potential_slot != NULL) {
1167 // Generate fast case for locals that rewrite to slots.
1168 __ mov(eax,
1169 ContextSlotOperandCheckExtensions(potential_slot, slow));
1170 if (potential_slot->var()->mode() == Variable::CONST) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 __ cmp(eax, isolate()->factory()->the_hole_value());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001172 __ j(not_equal, done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001173 __ mov(eax, isolate()->factory()->undefined_value());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001174 }
1175 __ jmp(done);
1176 } else if (rewrite != NULL) {
1177 // Generate fast case for calls of an argument function.
1178 Property* property = rewrite->AsProperty();
1179 if (property != NULL) {
1180 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1181 Literal* key_literal = property->key()->AsLiteral();
1182 if (obj_proxy != NULL &&
1183 key_literal != NULL &&
1184 obj_proxy->IsArguments() &&
1185 key_literal->handle()->IsSmi()) {
1186 // Load arguments object if there are no eval-introduced
1187 // variables. Then load the argument from the arguments
1188 // object using keyed load.
1189 __ mov(edx,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001190 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001191 slow));
1192 __ mov(eax, Immediate(key_literal->handle()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001193 Handle<Code> ic =
1194 isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001195 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001196 __ jmp(done);
1197 }
1198 }
1199 }
1200 }
1201}
1202
1203
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001204void FullCodeGenerator::EmitVariableLoad(Variable* var) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001205 // Four cases: non-this global variables, lookup slots, all other
1206 // types of slots, and parameters that rewrite to explicit property
1207 // accesses on the arguments object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001208 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001209 Property* property = var->AsProperty();
1210
1211 if (var->is_global() && !var->is_this()) {
1212 Comment cmnt(masm_, "Global variable");
1213 // Use inline caching. Variable name is passed in ecx and the global
1214 // object on the stack.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001215 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001216 __ mov(ecx, var->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001217 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001218 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001219 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001220
1221 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001222 Label done, slow;
1223
1224 // Generate code for loading from variables potentially shadowed
1225 // by eval-introduced variables.
1226 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1227
1228 __ bind(&slow);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001229 Comment cmnt(masm_, "Lookup slot");
1230 __ push(esi); // Context.
1231 __ push(Immediate(var->name()));
1232 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001233 __ bind(&done);
1234
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001235 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001236
1237 } else if (slot != NULL) {
1238 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1239 ? "Context slot"
1240 : "Stack slot");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001241 if (var->mode() == Variable::CONST) {
1242 // Constants may be the hole value if they have not been initialized.
1243 // Unhole them.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001244 NearLabel done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001245 MemOperand slot_operand = EmitSlotSearch(slot, eax);
1246 __ mov(eax, slot_operand);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 __ cmp(eax, isolate()->factory()->the_hole_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001248 __ j(not_equal, &done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001249 __ mov(eax, isolate()->factory()->undefined_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001250 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001251 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001252 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001253 context()->Plug(slot);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001254 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001255
1256 } else {
1257 Comment cmnt(masm_, "Rewritten parameter");
1258 ASSERT_NOT_NULL(property);
1259 // Rewritten parameter accesses are of the form "slot[literal]".
1260
1261 // Assert that the object is in a slot.
1262 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1263 ASSERT_NOT_NULL(object_var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001264 Slot* object_slot = object_var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001265 ASSERT_NOT_NULL(object_slot);
1266
1267 // Load the object.
1268 MemOperand object_loc = EmitSlotSearch(object_slot, eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001269 __ mov(edx, object_loc);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001270
1271 // Assert that the key is a smi.
1272 Literal* key_literal = property->key()->AsLiteral();
1273 ASSERT_NOT_NULL(key_literal);
1274 ASSERT(key_literal->handle()->IsSmi());
1275
1276 // Load the key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001277 __ mov(eax, Immediate(key_literal->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001278
1279 // Do a keyed property load.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001280 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001281 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001282
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001283 // Drop key and object left on the stack by IC.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001284 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001285 }
1286}
1287
1288
1289void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1290 Comment cmnt(masm_, "[ RegExpLiteral");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001291 NearLabel materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001292 // Registers will be used as follows:
1293 // edi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001294 // ecx = literals array.
1295 // ebx = regexp literal.
1296 // eax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001297 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001298 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001299 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001300 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001301 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 __ cmp(ebx, isolate()->factory()->undefined_value());
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001303 __ j(not_equal, &materialized);
1304
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001305 // Create regexp literal using runtime function
1306 // Result will be in eax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001307 __ push(ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001308 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1309 __ push(Immediate(expr->pattern()));
1310 __ push(Immediate(expr->flags()));
1311 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001312 __ mov(ebx, eax);
1313
1314 __ bind(&materialized);
1315 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1316 Label allocated, runtime_allocate;
1317 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1318 __ jmp(&allocated);
1319
1320 __ bind(&runtime_allocate);
1321 __ push(ebx);
1322 __ push(Immediate(Smi::FromInt(size)));
1323 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1324 __ pop(ebx);
1325
1326 __ bind(&allocated);
1327 // Copy the content into the newly allocated memory.
1328 // (Unroll copy loop once for better throughput).
1329 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1330 __ mov(edx, FieldOperand(ebx, i));
1331 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1332 __ mov(FieldOperand(eax, i), edx);
1333 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1334 }
1335 if ((size % (2 * kPointerSize)) != 0) {
1336 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1337 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1338 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001339 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001340}
1341
1342
1343void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1344 Comment cmnt(masm_, "[ ObjectLiteral");
1345 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1346 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1347 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1348 __ push(Immediate(expr->constant_properties()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001349 int flags = expr->fast_elements()
1350 ? ObjectLiteral::kFastElements
1351 : ObjectLiteral::kNoFlags;
1352 flags |= expr->has_function()
1353 ? ObjectLiteral::kHasFunction
1354 : ObjectLiteral::kNoFlags;
1355 __ push(Immediate(Smi::FromInt(flags)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001356 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001357 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001358 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001359 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001360 }
1361
1362 // If result_saved is true the result is on top of the stack. If
1363 // result_saved is false the result is in eax.
1364 bool result_saved = false;
1365
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001366 // Mark all computed expressions that are bound to a key that
1367 // is shadowed by a later occurrence of the same key. For the
1368 // marked expressions, no store code is emitted.
1369 expr->CalculateEmitStore();
1370
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001371 for (int i = 0; i < expr->properties()->length(); i++) {
1372 ObjectLiteral::Property* property = expr->properties()->at(i);
1373 if (property->IsCompileTimeValue()) continue;
1374
1375 Literal* key = property->key();
1376 Expression* value = property->value();
1377 if (!result_saved) {
1378 __ push(eax); // Save result on the stack
1379 result_saved = true;
1380 }
1381 switch (property->kind()) {
1382 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1383 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1384 // Fall through.
1385 case ObjectLiteral::Property::COMPUTED:
1386 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001387 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001388 VisitForAccumulatorValue(value);
1389 __ mov(ecx, Immediate(key->handle()));
1390 __ mov(edx, Operand(esp, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001391 Handle<Code> ic = is_strict_mode()
1392 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1393 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001394 EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001395 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1396 } else {
1397 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001398 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001399 break;
1400 }
1401 // Fall through.
1402 case ObjectLiteral::Property::PROTOTYPE:
1403 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001404 VisitForStackValue(key);
1405 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001406 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001407 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1408 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001409 } else {
1410 __ Drop(3);
1411 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001412 break;
1413 case ObjectLiteral::Property::SETTER:
1414 case ObjectLiteral::Property::GETTER:
1415 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001416 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001417 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
1418 Smi::FromInt(1) :
1419 Smi::FromInt(0)));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001420 VisitForStackValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001421 __ CallRuntime(Runtime::kDefineAccessor, 4);
1422 break;
1423 default: UNREACHABLE();
1424 }
1425 }
1426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001427 if (expr->has_function()) {
1428 ASSERT(result_saved);
1429 __ push(Operand(esp, 0));
1430 __ CallRuntime(Runtime::kToFastProperties, 1);
1431 }
1432
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001433 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001434 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001435 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001436 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001437 }
1438}
1439
1440
1441void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1442 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001443
1444 ZoneList<Expression*>* subexprs = expr->values();
1445 int length = subexprs->length();
1446
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001447 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1448 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1449 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1450 __ push(Immediate(expr->constant_elements()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 if (expr->constant_elements()->map() ==
1452 isolate()->heap()->fixed_cow_array_map()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001453 ASSERT(expr->depth() == 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001454 FastCloneShallowArrayStub stub(
1455 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1456 __ CallStub(&stub);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001458 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001459 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001460 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001461 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001462 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001463 FastCloneShallowArrayStub stub(
1464 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001465 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001466 }
1467
1468 bool result_saved = false; // Is the result saved to the stack?
1469
1470 // Emit code to evaluate all the non-constant subexpressions and to store
1471 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001472 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001473 Expression* subexpr = subexprs->at(i);
1474 // If the subexpression is a literal or a simple materialized literal it
1475 // is already set in the cloned array.
1476 if (subexpr->AsLiteral() != NULL ||
1477 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1478 continue;
1479 }
1480
1481 if (!result_saved) {
1482 __ push(eax);
1483 result_saved = true;
1484 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001485 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001486
1487 // Store the subexpression value in the array's elements.
1488 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1489 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1490 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1491 __ mov(FieldOperand(ebx, offset), result_register());
1492
1493 // Update the write barrier for the array store.
1494 __ RecordWrite(ebx, offset, result_register(), ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001495
1496 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001497 }
1498
1499 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001500 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001501 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001502 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001503 }
1504}
1505
1506
ager@chromium.org5c838252010-02-19 08:53:10 +00001507void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1508 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001509 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1510 // on the left-hand side.
1511 if (!expr->target()->IsValidLeftHandSide()) {
1512 VisitForEffect(expr->target());
1513 return;
1514 }
1515
ager@chromium.org5c838252010-02-19 08:53:10 +00001516 // Left-hand side can only be a property, a global or a (parameter or local)
1517 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1518 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1519 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001520 Property* property = expr->target()->AsProperty();
1521 if (property != NULL) {
1522 assign_type = (property->key()->IsPropertyName())
1523 ? NAMED_PROPERTY
1524 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001525 }
1526
1527 // Evaluate LHS expression.
1528 switch (assign_type) {
1529 case VARIABLE:
1530 // Nothing to do here.
1531 break;
1532 case NAMED_PROPERTY:
1533 if (expr->is_compound()) {
1534 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001535 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001536 __ push(result_register());
1537 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001538 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001539 }
1540 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001541 case KEYED_PROPERTY: {
ager@chromium.org5c838252010-02-19 08:53:10 +00001542 if (expr->is_compound()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001543 if (property->is_arguments_access()) {
1544 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001545 MemOperand slot_operand =
1546 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
1547 __ push(slot_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001548 __ mov(eax, Immediate(property->key()->AsLiteral()->handle()));
1549 } else {
1550 VisitForStackValue(property->obj());
1551 VisitForAccumulatorValue(property->key());
1552 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001553 __ mov(edx, Operand(esp, 0));
1554 __ push(eax);
1555 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001556 if (property->is_arguments_access()) {
1557 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001558 MemOperand slot_operand =
1559 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
1560 __ push(slot_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001561 __ push(Immediate(property->key()->AsLiteral()->handle()));
1562 } else {
1563 VisitForStackValue(property->obj());
1564 VisitForStackValue(property->key());
1565 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001566 }
1567 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001568 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001569 }
1570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001571 // For compound assignments we need another deoptimization point after the
1572 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001573 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001574 { AccumulatorValueContext context(this);
1575 switch (assign_type) {
1576 case VARIABLE:
1577 EmitVariableLoad(expr->target()->AsVariableProxy()->var());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001578 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001579 break;
1580 case NAMED_PROPERTY:
1581 EmitNamedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001582 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001583 break;
1584 case KEYED_PROPERTY:
1585 EmitKeyedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001586 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001587 break;
1588 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001589 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001590
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001591 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001592 __ push(eax); // Left operand goes on the stack.
1593 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001594
ricow@chromium.org65fae842010-08-25 15:26:24 +00001595 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1596 ? OVERWRITE_RIGHT
1597 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001598 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001599 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001600 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001601 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001602 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001603 mode,
1604 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001605 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001606 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001607 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001608 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001609
1610 // Deoptimization point in case the binary operation may have side effects.
1611 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001612 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001613 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001614 }
1615
1616 // Record source position before possible IC call.
1617 SetSourcePosition(expr->position());
1618
1619 // Store the value.
1620 switch (assign_type) {
1621 case VARIABLE:
1622 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001623 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001624 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1625 context()->Plug(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001626 break;
1627 case NAMED_PROPERTY:
1628 EmitNamedPropertyAssignment(expr);
1629 break;
1630 case KEYED_PROPERTY:
1631 EmitKeyedPropertyAssignment(expr);
1632 break;
1633 }
1634}
1635
1636
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001637void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1638 SetSourcePosition(prop->position());
1639 Literal* key = prop->key()->AsLiteral();
1640 __ mov(ecx, Immediate(key->handle()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001641 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001642 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001643}
1644
1645
1646void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1647 SetSourcePosition(prop->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001648 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001649 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001650}
1651
1652
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001653void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001654 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001655 OverwriteMode mode,
1656 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001657 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001658 // Do combined smi check of the operands. Left operand is on the
1659 // stack. Right operand is in eax.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001660 NearLabel done, smi_case, stub_call;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001661 __ pop(edx);
1662 __ mov(ecx, eax);
1663 __ or_(eax, Operand(edx));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001664 JumpPatchSite patch_site(masm_);
1665 patch_site.EmitJumpIfSmi(eax, &smi_case);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001666
1667 __ bind(&stub_call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001668 __ mov(eax, ecx);
1669 TypeRecordingBinaryOpStub stub(op, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001670 EmitCallIC(stub.GetCode(), &patch_site, expr->id());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001671 __ jmp(&done);
1672
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001673 // Smi case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001674 __ bind(&smi_case);
1675 __ mov(eax, edx); // Copy left operand in case of a stub call.
1676
1677 switch (op) {
1678 case Token::SAR:
1679 __ SmiUntag(eax);
1680 __ SmiUntag(ecx);
1681 __ sar_cl(eax); // No checks of result necessary
1682 __ SmiTag(eax);
1683 break;
1684 case Token::SHL: {
1685 Label result_ok;
1686 __ SmiUntag(eax);
1687 __ SmiUntag(ecx);
1688 __ shl_cl(eax);
1689 // Check that the *signed* result fits in a smi.
1690 __ cmp(eax, 0xc0000000);
1691 __ j(positive, &result_ok);
1692 __ SmiTag(ecx);
1693 __ jmp(&stub_call);
1694 __ bind(&result_ok);
1695 __ SmiTag(eax);
1696 break;
1697 }
1698 case Token::SHR: {
1699 Label result_ok;
1700 __ SmiUntag(eax);
1701 __ SmiUntag(ecx);
1702 __ shr_cl(eax);
1703 __ test(eax, Immediate(0xc0000000));
1704 __ j(zero, &result_ok);
1705 __ SmiTag(ecx);
1706 __ jmp(&stub_call);
1707 __ bind(&result_ok);
1708 __ SmiTag(eax);
1709 break;
1710 }
1711 case Token::ADD:
1712 __ add(eax, Operand(ecx));
1713 __ j(overflow, &stub_call);
1714 break;
1715 case Token::SUB:
1716 __ sub(eax, Operand(ecx));
1717 __ j(overflow, &stub_call);
1718 break;
1719 case Token::MUL: {
1720 __ SmiUntag(eax);
1721 __ imul(eax, Operand(ecx));
1722 __ j(overflow, &stub_call);
1723 __ test(eax, Operand(eax));
1724 __ j(not_zero, &done, taken);
1725 __ mov(ebx, edx);
1726 __ or_(ebx, Operand(ecx));
1727 __ j(negative, &stub_call);
1728 break;
1729 }
1730 case Token::BIT_OR:
1731 __ or_(eax, Operand(ecx));
1732 break;
1733 case Token::BIT_AND:
1734 __ and_(eax, Operand(ecx));
1735 break;
1736 case Token::BIT_XOR:
1737 __ xor_(eax, Operand(ecx));
1738 break;
1739 default:
1740 UNREACHABLE();
1741 }
1742
1743 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001744 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001745}
1746
1747
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001748void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1749 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001750 OverwriteMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001751 __ pop(edx);
1752 TypeRecordingBinaryOpStub stub(op, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001753 // NULL signals no inlined smi code.
1754 EmitCallIC(stub.GetCode(), NULL, expr->id());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001755 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001756}
1757
1758
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001759void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001760 // Invalid left-hand sides are rewritten to have a 'throw
1761 // ReferenceError' on the left-hand side.
1762 if (!expr->IsValidLeftHandSide()) {
1763 VisitForEffect(expr);
1764 return;
1765 }
1766
1767 // Left-hand side can only be a property, a global or a (parameter or local)
1768 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1769 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1770 LhsKind assign_type = VARIABLE;
1771 Property* prop = expr->AsProperty();
1772 if (prop != NULL) {
1773 assign_type = (prop->key()->IsPropertyName())
1774 ? NAMED_PROPERTY
1775 : KEYED_PROPERTY;
1776 }
1777
1778 switch (assign_type) {
1779 case VARIABLE: {
1780 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001781 EffectContext context(this);
1782 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001783 break;
1784 }
1785 case NAMED_PROPERTY: {
1786 __ push(eax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001787 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001788 __ mov(edx, eax);
1789 __ pop(eax); // Restore value.
1790 __ mov(ecx, prop->key()->AsLiteral()->handle());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001791 Handle<Code> ic = is_strict_mode()
1792 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1793 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001794 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001795 break;
1796 }
1797 case KEYED_PROPERTY: {
1798 __ push(eax); // Preserve value.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001799 if (prop->is_synthetic()) {
1800 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1801 ASSERT(prop->key()->AsLiteral() != NULL);
1802 { AccumulatorValueContext for_object(this);
1803 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1804 }
1805 __ mov(edx, eax);
1806 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
1807 } else {
1808 VisitForStackValue(prop->obj());
1809 VisitForAccumulatorValue(prop->key());
1810 __ mov(ecx, eax);
1811 __ pop(edx);
1812 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001813 __ pop(eax); // Restore value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001814 Handle<Code> ic = is_strict_mode()
1815 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1816 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001817 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001818 break;
1819 }
1820 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001821 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1822 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001823}
1824
1825
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001826void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001827 Token::Value op) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001828 // Left-hand sides that rewrite to explicit property accesses do not reach
1829 // here.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001830 ASSERT(var != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001831 ASSERT(var->is_global() || var->AsSlot() != NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001832
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001833 if (var->is_global()) {
1834 ASSERT(!var->is_this());
1835 // Assignment to a global variable. Use inline caching for the
1836 // assignment. Right-hand-side value is passed in eax, variable name in
1837 // ecx, and the global object on the stack.
1838 __ mov(ecx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001839 __ mov(edx, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001840 Handle<Code> ic = is_strict_mode()
1841 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1842 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001843 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001844
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001845 } else if (op == Token::INIT_CONST) {
1846 // Like var declarations, const declarations are hoisted to function
1847 // scope. However, unlike var initializers, const initializers are able
1848 // to drill a hole to that function context, even from inside a 'with'
1849 // context. We thus bypass the normal static scope lookup.
1850 Slot* slot = var->AsSlot();
1851 Label skip;
1852 switch (slot->type()) {
1853 case Slot::PARAMETER:
1854 // No const parameters.
1855 UNREACHABLE();
1856 break;
1857 case Slot::LOCAL:
1858 __ mov(edx, Operand(ebp, SlotOffset(slot)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001859 __ cmp(edx, isolate()->factory()->the_hole_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001860 __ j(not_equal, &skip);
1861 __ mov(Operand(ebp, SlotOffset(slot)), eax);
1862 break;
1863 case Slot::CONTEXT: {
1864 __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX));
1865 __ mov(edx, ContextOperand(ecx, slot->index()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001866 __ cmp(edx, isolate()->factory()->the_hole_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001867 __ j(not_equal, &skip);
1868 __ mov(ContextOperand(ecx, slot->index()), eax);
1869 int offset = Context::SlotOffset(slot->index());
1870 __ mov(edx, eax); // Preserve the stored value in eax.
1871 __ RecordWrite(ecx, offset, edx, ebx);
1872 break;
1873 }
1874 case Slot::LOOKUP:
1875 __ push(eax);
1876 __ push(esi);
1877 __ push(Immediate(var->name()));
1878 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1879 break;
1880 }
1881 __ bind(&skip);
1882
1883 } else if (var->mode() != Variable::CONST) {
1884 // Perform the assignment for non-const variables. Const assignments
1885 // are simply skipped.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001886 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001887 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001888 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001889 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001890 // Perform the assignment.
1891 __ mov(Operand(ebp, SlotOffset(slot)), eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001892 break;
1893
1894 case Slot::CONTEXT: {
1895 MemOperand target = EmitSlotSearch(slot, ecx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001896 // Perform the assignment and issue the write barrier.
1897 __ mov(target, eax);
1898 // The value of the assignment is in eax. RecordWrite clobbers its
1899 // register arguments.
1900 __ mov(edx, eax);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001901 int offset = Context::SlotOffset(slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001902 __ RecordWrite(ecx, offset, edx, ebx);
1903 break;
1904 }
1905
1906 case Slot::LOOKUP:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001907 // Call the runtime for the assignment.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001908 __ push(eax); // Value.
1909 __ push(esi); // Context.
1910 __ push(Immediate(var->name()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001911 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
1912 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001913 break;
1914 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001915 }
1916}
1917
1918
1919void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1920 // Assignment to a property, using a named store IC.
1921 Property* prop = expr->target()->AsProperty();
1922 ASSERT(prop != NULL);
1923 ASSERT(prop->key()->AsLiteral() != NULL);
1924
1925 // If the assignment starts a block of assignments to the same object,
1926 // change to slow case to avoid the quadratic behavior of repeatedly
1927 // adding fast properties.
1928 if (expr->starts_initialization_block()) {
1929 __ push(result_register());
1930 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
1931 __ CallRuntime(Runtime::kToSlowProperties, 1);
1932 __ pop(result_register());
1933 }
1934
1935 // Record source code position before IC call.
1936 SetSourcePosition(expr->position());
1937 __ mov(ecx, prop->key()->AsLiteral()->handle());
1938 if (expr->ends_initialization_block()) {
1939 __ mov(edx, Operand(esp, 0));
1940 } else {
1941 __ pop(edx);
1942 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001943 Handle<Code> ic = is_strict_mode()
1944 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1945 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001946 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001947
1948 // If the assignment ends an initialization block, revert to fast case.
1949 if (expr->ends_initialization_block()) {
1950 __ push(eax); // Result of assignment, saved even if not needed.
1951 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
1952 __ CallRuntime(Runtime::kToFastProperties, 1);
1953 __ pop(eax);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001954 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001955 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001956 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1957 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001958}
1959
1960
1961void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1962 // Assignment to a property, using a keyed store IC.
1963
1964 // If the assignment starts a block of assignments to the same object,
1965 // change to slow case to avoid the quadratic behavior of repeatedly
1966 // adding fast properties.
1967 if (expr->starts_initialization_block()) {
1968 __ push(result_register());
1969 // Receiver is now under the key and value.
1970 __ push(Operand(esp, 2 * kPointerSize));
1971 __ CallRuntime(Runtime::kToSlowProperties, 1);
1972 __ pop(result_register());
1973 }
1974
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001975 __ pop(ecx);
1976 if (expr->ends_initialization_block()) {
1977 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
1978 } else {
1979 __ pop(edx);
1980 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001981 // Record source code position before IC call.
1982 SetSourcePosition(expr->position());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001983 Handle<Code> ic = is_strict_mode()
1984 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1985 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001986 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001987
1988 // If the assignment ends an initialization block, revert to fast case.
1989 if (expr->ends_initialization_block()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001990 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001991 __ push(eax); // Result of assignment, saved even if not needed.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001992 __ push(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001993 __ CallRuntime(Runtime::kToFastProperties, 1);
1994 __ pop(eax);
1995 }
1996
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001997 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001998 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001999}
2000
2001
2002void FullCodeGenerator::VisitProperty(Property* expr) {
2003 Comment cmnt(masm_, "[ Property");
2004 Expression* key = expr->key();
2005
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002006 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002007 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002008 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002009 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002010 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002011 VisitForStackValue(expr->obj());
2012 VisitForAccumulatorValue(expr->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00002013 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002014 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002015 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002016 }
2017}
2018
2019
2020void FullCodeGenerator::EmitCallWithIC(Call* expr,
2021 Handle<Object> name,
2022 RelocInfo::Mode mode) {
2023 // Code common for calls using the IC.
2024 ZoneList<Expression*>* args = expr->arguments();
2025 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002026 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002027 for (int i = 0; i < arg_count; i++) {
2028 VisitForStackValue(args->at(i));
2029 }
2030 __ Set(ecx, Immediate(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002031 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002032 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002033 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002034 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
2036 arg_count, in_loop);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002037 EmitCallIC(ic, mode, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002038 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002039 // Restore context register.
2040 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002041 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002042}
2043
2044
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002045void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
2046 Expression* key,
2047 RelocInfo::Mode mode) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002048 // Load the key.
2049 VisitForAccumulatorValue(key);
2050
2051 // Swap the name of the function and the receiver on the stack to follow
2052 // the calling convention for call ICs.
2053 __ pop(ecx);
2054 __ push(eax);
2055 __ push(ecx);
2056
2057 // Load the arguments.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002058 ZoneList<Expression*>* args = expr->arguments();
2059 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002060 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002061 for (int i = 0; i < arg_count; i++) {
2062 VisitForStackValue(args->at(i));
2063 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002064 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002065 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002066 SetSourcePosition(expr->position());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002067 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
2069 arg_count, in_loop);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002070 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002071 EmitCallIC(ic, mode, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002072 RecordJSReturnSite(expr);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002073 // Restore context register.
2074 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002075 context()->DropAndPlug(1, eax); // Drop the key still on the stack.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002076}
2077
2078
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002079void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002080 // Code common for calls using the call stub.
2081 ZoneList<Expression*>* args = expr->arguments();
2082 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002083 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002084 for (int i = 0; i < arg_count; i++) {
2085 VisitForStackValue(args->at(i));
2086 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002087 }
2088 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002089 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002090 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002091 CallFunctionStub stub(arg_count, in_loop, flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002092 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002093 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002094 // Restore context register.
2095 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002096 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002097}
2098
2099
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002100void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2101 int arg_count) {
2102 // Push copy of the first argument or undefined if it doesn't exist.
2103 if (arg_count > 0) {
2104 __ push(Operand(esp, arg_count * kPointerSize));
2105 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002106 __ push(Immediate(isolate()->factory()->undefined_value()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002107 }
2108
2109 // Push the receiver of the enclosing function.
2110 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
2111
2112 // Push the strict mode flag.
2113 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
2114
2115 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2116 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2117 : Runtime::kResolvePossiblyDirectEval, 4);
2118}
2119
2120
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002121void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002122#ifdef DEBUG
2123 // We want to verify that RecordJSReturnSite gets called on all paths
2124 // through this function. Avoid early returns.
2125 expr->return_is_recorded_ = false;
2126#endif
2127
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002128 Comment cmnt(masm_, "[ Call");
2129 Expression* fun = expr->expression();
2130 Variable* var = fun->AsVariableProxy()->AsVariable();
2131
2132 if (var != NULL && var->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002133 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2134 // resolve the function we need to call and the receiver of the
2135 // call. Then we call the resolved function using the given
2136 // arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002137 ZoneList<Expression*>* args = expr->arguments();
2138 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002139 { PreservePositionScope pos_scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002140 VisitForStackValue(fun);
2141 // Reserved receiver slot.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002142 __ push(Immediate(isolate()->factory()->undefined_value()));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002143
2144 // Push the arguments.
2145 for (int i = 0; i < arg_count; i++) {
2146 VisitForStackValue(args->at(i));
2147 }
2148
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002149 // If we know that eval can only be shadowed by eval-introduced
2150 // variables we attempt to load the global eval function directly
2151 // in generated code. If we succeed, there is no need to perform a
2152 // context lookup in the runtime system.
2153 Label done;
2154 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2155 Label slow;
2156 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2157 NOT_INSIDE_TYPEOF,
2158 &slow);
2159 // Push the function and resolve eval.
2160 __ push(eax);
2161 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2162 __ jmp(&done);
2163 __ bind(&slow);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002164 }
2165
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002166 // Push copy of the function (found below the arguments) and
2167 // resolve eval.
2168 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2169 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2170 if (done.is_linked()) {
2171 __ bind(&done);
2172 }
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002173
2174 // The runtime call returns a pair of values in eax (function) and
2175 // edx (receiver). Touch up the stack with the right values.
2176 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2177 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002178 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002179 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002180 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002181 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2182 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
2183 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002184 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002185 // Restore context register.
2186 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002187 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002188 } else if (var != NULL && !var->is_this() && var->is_global()) {
2189 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002190 __ push(GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002191 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002192 } else if (var != NULL && var->AsSlot() != NULL &&
2193 var->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002194 // Call to a lookup slot (dynamically introduced variable).
2195 Label slow, done;
2196
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002197 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002198 // Generate code for loading from variables potentially shadowed
2199 // by eval-introduced variables.
2200 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
2201 NOT_INSIDE_TYPEOF,
2202 &slow,
2203 &done);
2204 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002205
2206 __ bind(&slow);
2207 // Call the runtime to find the function to call (returned in eax)
2208 // and the object holding it (returned in edx).
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002209 __ push(context_register());
2210 __ push(Immediate(var->name()));
2211 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2212 __ push(eax); // Function.
2213 __ push(edx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002214
2215 // If fast case code has been generated, emit code to push the
2216 // function and receiver and have the slow path jump around this
2217 // code.
2218 if (done.is_linked()) {
2219 Label call;
2220 __ jmp(&call);
2221 __ bind(&done);
2222 // Push function.
2223 __ push(eax);
2224 // Push global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002225 __ mov(ebx, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002226 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2227 __ bind(&call);
2228 }
2229
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002230 // The receiver is either the global receiver or a JSObject found by
2231 // LoadContextSlot.
2232 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002233 } else if (fun->AsProperty() != NULL) {
2234 // Call to an object property.
2235 Property* prop = fun->AsProperty();
2236 Literal* key = prop->key()->AsLiteral();
2237 if (key != NULL && key->handle()->IsSymbol()) {
2238 // Call to a named property, use call IC.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002239 { PreservePositionScope scope(masm()->positions_recorder());
2240 VisitForStackValue(prop->obj());
2241 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002242 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
2243 } else {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002244 // Call to a keyed property.
2245 // For a synthetic property use keyed load IC followed by function call,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002246 // for a regular property use keyed EmitCallIC.
ager@chromium.org5c838252010-02-19 08:53:10 +00002247 if (prop->is_synthetic()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002248 // Do not visit the object and key subexpressions (they are shared
2249 // by all occurrences of the same rewritten parameter).
2250 ASSERT(prop->obj()->AsVariableProxy() != NULL);
2251 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
2252 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
2253 MemOperand operand = EmitSlotSearch(slot, edx);
2254 __ mov(edx, operand);
2255
2256 ASSERT(prop->key()->AsLiteral() != NULL);
2257 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
2258 __ mov(eax, prop->key()->AsLiteral()->handle());
2259
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002260 // Record source code position for IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002261 SetSourcePosition(prop->position());
ager@chromium.org5c838252010-02-19 08:53:10 +00002262
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002263 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002264 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
ager@chromium.org5c838252010-02-19 08:53:10 +00002265 // Push result (function).
2266 __ push(eax);
2267 // Push Global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002268 __ mov(ecx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002269 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002270 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002271 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002272 { PreservePositionScope scope(masm()->positions_recorder());
2273 VisitForStackValue(prop->obj());
2274 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002275 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002276 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002277 }
2278 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002279 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002280 VisitForStackValue(fun);
2281 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002282 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002283 __ mov(ebx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002284 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2285 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002286 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002287 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002288
2289#ifdef DEBUG
2290 // RecordJSReturnSite should have been called.
2291 ASSERT(expr->return_is_recorded_);
2292#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002293}
2294
2295
2296void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2297 Comment cmnt(masm_, "[ CallNew");
2298 // According to ECMA-262, section 11.2.2, page 44, the function
2299 // expression in new calls must be evaluated before the
2300 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002301
ricow@chromium.org65fae842010-08-25 15:26:24 +00002302 // Push constructor on the stack. If it's not a function it's used as
2303 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2304 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002305 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002306
2307 // Push the arguments ("left-to-right") on the stack.
2308 ZoneList<Expression*>* args = expr->arguments();
2309 int arg_count = args->length();
2310 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002311 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002312 }
2313
2314 // Call the construct call builtin that handles allocation and
2315 // constructor invocation.
2316 SetSourcePosition(expr->position());
2317
ricow@chromium.org65fae842010-08-25 15:26:24 +00002318 // Load function and argument count into edi and eax.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002319 __ Set(eax, Immediate(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002320 __ mov(edi, Operand(esp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002321
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002322 Handle<Code> construct_builtin =
2323 isolate()->builtins()->JSConstructCall();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002324 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002325 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002326}
2327
2328
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002329void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2330 ASSERT(args->length() == 1);
2331
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002332 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002333
2334 Label materialize_true, materialize_false;
2335 Label* if_true = NULL;
2336 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002337 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002338 context()->PrepareTest(&materialize_true, &materialize_false,
2339 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002340
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002341 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002342 __ test(eax, Immediate(kSmiTagMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002343 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002344
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002345 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002346}
2347
2348
2349void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2350 ASSERT(args->length() == 1);
2351
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002352 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002353
2354 Label materialize_true, materialize_false;
2355 Label* if_true = NULL;
2356 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002357 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002358 context()->PrepareTest(&materialize_true, &materialize_false,
2359 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002360
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002361 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002362 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002363 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002364
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002365 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002366}
2367
2368
2369void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2370 ASSERT(args->length() == 1);
2371
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002372 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002373
2374 Label materialize_true, materialize_false;
2375 Label* if_true = NULL;
2376 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002377 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002378 context()->PrepareTest(&materialize_true, &materialize_false,
2379 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002380
2381 __ test(eax, Immediate(kSmiTagMask));
2382 __ j(zero, if_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002383 __ cmp(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002384 __ j(equal, if_true);
2385 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2386 // Undetectable objects behave like undefined when tested with typeof.
2387 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2388 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2389 __ j(not_zero, if_false);
2390 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2391 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
2392 __ j(below, if_false);
2393 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002394 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002395 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002396
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002397 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002398}
2399
2400
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002401void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2402 ASSERT(args->length() == 1);
2403
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002404 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002405
2406 Label materialize_true, materialize_false;
2407 Label* if_true = NULL;
2408 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002409 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002410 context()->PrepareTest(&materialize_true, &materialize_false,
2411 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002412
2413 __ test(eax, Immediate(kSmiTagMask));
2414 __ j(equal, if_false);
2415 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002416 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002417 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002418
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002419 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002420}
2421
2422
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002423void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2424 ASSERT(args->length() == 1);
2425
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002426 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002427
2428 Label materialize_true, materialize_false;
2429 Label* if_true = NULL;
2430 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002431 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002432 context()->PrepareTest(&materialize_true, &materialize_false,
2433 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002434
2435 __ test(eax, Immediate(kSmiTagMask));
2436 __ j(zero, if_false);
2437 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2438 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2439 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002440 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002441 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002442
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002443 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002444}
2445
2446
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002447void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2448 ZoneList<Expression*>* args) {
2449 ASSERT(args->length() == 1);
2450
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002451 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002452
2453 Label materialize_true, materialize_false;
2454 Label* if_true = NULL;
2455 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002456 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002457 context()->PrepareTest(&materialize_true, &materialize_false,
2458 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002460 if (FLAG_debug_code) __ AbortIfSmi(eax);
2461
2462 // Check whether this map has already been checked to be safe for default
2463 // valueOf.
2464 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2465 __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
2466 1 << Map::kStringWrapperSafeForDefaultValueOf);
2467 __ j(not_zero, if_true);
2468
2469 // Check for fast case object. Return false for slow case objects.
2470 __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
2471 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2472 __ cmp(ecx, FACTORY->hash_table_map());
2473 __ j(equal, if_false);
2474
2475 // Look for valueOf symbol in the descriptor array, and indicate false if
2476 // found. The type is not checked, so if it is a transition it is a false
2477 // negative.
2478 __ mov(ebx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
2479 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
2480 // ebx: descriptor array
2481 // ecx: length of descriptor array
2482 // Calculate the end of the descriptor array.
2483 STATIC_ASSERT(kSmiTag == 0);
2484 STATIC_ASSERT(kSmiTagSize == 1);
2485 STATIC_ASSERT(kPointerSize == 4);
2486 __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
2487 // Calculate location of the first key name.
2488 __ add(Operand(ebx),
2489 Immediate(FixedArray::kHeaderSize +
2490 DescriptorArray::kFirstIndex * kPointerSize));
2491 // Loop through all the keys in the descriptor array. If one of these is the
2492 // symbol valueOf the result is false.
2493 Label entry, loop;
2494 __ jmp(&entry);
2495 __ bind(&loop);
2496 __ mov(edx, FieldOperand(ebx, 0));
2497 __ cmp(edx, FACTORY->value_of_symbol());
2498 __ j(equal, if_false);
2499 __ add(Operand(ebx), Immediate(kPointerSize));
2500 __ bind(&entry);
2501 __ cmp(ebx, Operand(ecx));
2502 __ j(not_equal, &loop);
2503
2504 // Reload map as register ebx was used as temporary above.
2505 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2506
2507 // If a valueOf property is not found on the object check that it's
2508 // prototype is the un-modified String prototype. If not result is false.
2509 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
2510 __ test(ecx, Immediate(kSmiTagMask));
2511 __ j(zero, if_false);
2512 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2513 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2514 __ mov(edx,
2515 FieldOperand(edx, GlobalObject::kGlobalContextOffset));
2516 __ cmp(ecx,
2517 ContextOperand(edx,
2518 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2519 __ j(not_equal, if_false);
2520 // Set the bit in the map to indicate that it has been checked safe for
2521 // default valueOf and set true result.
2522 __ or_(FieldOperand(ebx, Map::kBitField2Offset),
2523 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2524 __ jmp(if_true);
2525
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002526 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002527 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002528}
2529
2530
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002531void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2532 ASSERT(args->length() == 1);
2533
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002534 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002535
2536 Label materialize_true, materialize_false;
2537 Label* if_true = NULL;
2538 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002539 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002540 context()->PrepareTest(&materialize_true, &materialize_false,
2541 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002542
2543 __ test(eax, Immediate(kSmiTagMask));
2544 __ j(zero, if_false);
2545 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002546 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002547 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002548
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002549 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002550}
2551
2552
2553void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2554 ASSERT(args->length() == 1);
2555
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002556 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002557
2558 Label materialize_true, materialize_false;
2559 Label* if_true = NULL;
2560 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002561 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002562 context()->PrepareTest(&materialize_true, &materialize_false,
2563 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002564
2565 __ test(eax, Immediate(kSmiTagMask));
2566 __ j(equal, if_false);
2567 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002568 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002569 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002570
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002571 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002572}
2573
2574
2575void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2576 ASSERT(args->length() == 1);
2577
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002578 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002579
2580 Label materialize_true, materialize_false;
2581 Label* if_true = NULL;
2582 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002583 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002584 context()->PrepareTest(&materialize_true, &materialize_false,
2585 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002586
2587 __ test(eax, Immediate(kSmiTagMask));
2588 __ j(equal, if_false);
2589 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002590 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002591 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002592
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002593 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002594}
2595
2596
2597
2598void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2599 ASSERT(args->length() == 0);
2600
2601 Label materialize_true, materialize_false;
2602 Label* if_true = NULL;
2603 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002604 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002605 context()->PrepareTest(&materialize_true, &materialize_false,
2606 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002607
2608 // Get the frame pointer for the calling frame.
2609 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2610
2611 // Skip the arguments adaptor frame if it exists.
2612 Label check_frame_marker;
2613 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2614 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2615 __ j(not_equal, &check_frame_marker);
2616 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2617
2618 // Check the marker in the calling frame.
2619 __ bind(&check_frame_marker);
2620 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2621 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002622 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002623 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002624
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002625 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002626}
2627
2628
2629void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2630 ASSERT(args->length() == 2);
2631
2632 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002633 VisitForStackValue(args->at(0));
2634 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002635
2636 Label materialize_true, materialize_false;
2637 Label* if_true = NULL;
2638 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002639 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002640 context()->PrepareTest(&materialize_true, &materialize_false,
2641 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002642
2643 __ pop(ebx);
2644 __ cmp(eax, Operand(ebx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002645 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002646 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002647
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002648 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002649}
2650
2651
2652void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2653 ASSERT(args->length() == 1);
2654
2655 // ArgumentsAccessStub expects the key in edx and the formal
2656 // parameter count in eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002657 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002658 __ mov(edx, eax);
2659 __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2660 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2661 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002662 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002663}
2664
2665
2666void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2667 ASSERT(args->length() == 0);
2668
2669 Label exit;
2670 // Get the number of formal parameters.
2671 __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2672
2673 // Check if the calling frame is an arguments adaptor frame.
2674 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2675 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2676 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2677 __ j(not_equal, &exit);
2678
2679 // Arguments adaptor case: Read the arguments length from the
2680 // adaptor frame.
2681 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2682
2683 __ bind(&exit);
2684 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002685 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002686}
2687
2688
2689void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2690 ASSERT(args->length() == 1);
2691 Label done, null, function, non_function_constructor;
2692
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002693 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002694
2695 // If the object is a smi, we return null.
2696 __ test(eax, Immediate(kSmiTagMask));
2697 __ j(zero, &null);
2698
2699 // Check that the object is a JS object but take special care of JS
2700 // functions to make sure they have 'Function' as their class.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002701 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, eax); // Map is now in eax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002702 __ j(below, &null);
2703
2704 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2705 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2706 // LAST_JS_OBJECT_TYPE.
2707 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2708 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002709 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002710 __ j(equal, &function);
2711
2712 // Check if the constructor in the map is a function.
2713 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2714 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2715 __ j(not_equal, &non_function_constructor);
2716
2717 // eax now contains the constructor function. Grab the
2718 // instance class name from there.
2719 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2720 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2721 __ jmp(&done);
2722
2723 // Functions have class 'Function'.
2724 __ bind(&function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002725 __ mov(eax, isolate()->factory()->function_class_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002726 __ jmp(&done);
2727
2728 // Objects with a non-function constructor have class 'Object'.
2729 __ bind(&non_function_constructor);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002730 __ mov(eax, isolate()->factory()->Object_symbol());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002731 __ jmp(&done);
2732
2733 // Non-JS objects have class null.
2734 __ bind(&null);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002735 __ mov(eax, isolate()->factory()->null_value());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002736
2737 // All done.
2738 __ bind(&done);
2739
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002740 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002741}
2742
2743
2744void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2745 // Conditionally generate a log call.
2746 // Args:
2747 // 0 (literal string): The type of logging (corresponds to the flags).
2748 // This is used to determine whether or not to generate the log call.
2749 // 1 (string): Format string. Access the string at argument index 2
2750 // with '%2s' (see Logger::LogRuntime for all the formats).
2751 // 2 (array): Arguments to the format string.
2752 ASSERT_EQ(args->length(), 3);
2753#ifdef ENABLE_LOGGING_AND_PROFILING
2754 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002755 VisitForStackValue(args->at(1));
2756 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002757 __ CallRuntime(Runtime::kLog, 2);
2758 }
2759#endif
2760 // Finally, we're expected to leave a value on the top of the stack.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002761 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002762 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002763}
2764
2765
2766void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2767 ASSERT(args->length() == 0);
2768
2769 Label slow_allocate_heapnumber;
2770 Label heapnumber_allocated;
2771
2772 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2773 __ jmp(&heapnumber_allocated);
2774
2775 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002776 // Allocate a heap number.
2777 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002778 __ mov(edi, eax);
2779
2780 __ bind(&heapnumber_allocated);
2781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002782 __ PrepareCallCFunction(1, ebx);
2783 __ mov(Operand(esp, 0), Immediate(ExternalReference::isolate_address()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002784 __ CallCFunction(ExternalReference::random_uint32_function(isolate()),
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002785 1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002786
2787 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2788 // by computing:
2789 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2790 // This is implemented on both SSE2 and FPU.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002791 if (CpuFeatures::IsSupported(SSE2)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002792 CpuFeatures::Scope fscope(SSE2);
2793 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2794 __ movd(xmm1, Operand(ebx));
2795 __ movd(xmm0, Operand(eax));
2796 __ cvtss2sd(xmm1, xmm1);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002797 __ xorps(xmm0, xmm1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002798 __ subsd(xmm0, xmm1);
2799 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2800 } else {
2801 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2802 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2803 Immediate(0x41300000));
2804 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2805 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2806 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2807 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2808 __ fsubp(1);
2809 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2810 }
2811 __ mov(eax, edi);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002812 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002813}
2814
2815
2816void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2817 // Load the arguments on the stack and call the stub.
2818 SubStringStub stub;
2819 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002820 VisitForStackValue(args->at(0));
2821 VisitForStackValue(args->at(1));
2822 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002823 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002824 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002825}
2826
2827
2828void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2829 // Load the arguments on the stack and call the stub.
2830 RegExpExecStub stub;
2831 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002832 VisitForStackValue(args->at(0));
2833 VisitForStackValue(args->at(1));
2834 VisitForStackValue(args->at(2));
2835 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002836 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002837 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002838}
2839
2840
2841void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2842 ASSERT(args->length() == 1);
2843
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002844 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002845
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002846 NearLabel done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002847 // If the object is a smi return the object.
2848 __ test(eax, Immediate(kSmiTagMask));
2849 __ j(zero, &done);
2850 // If the object is not a value type, return the object.
2851 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
2852 __ j(not_equal, &done);
2853 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2854
2855 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002856 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002857}
2858
2859
2860void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2861 // Load the arguments on the stack and call the runtime function.
2862 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002863 VisitForStackValue(args->at(0));
2864 VisitForStackValue(args->at(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002866 if (CpuFeatures::IsSupported(SSE2)) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002867 MathPowStub stub;
2868 __ CallStub(&stub);
2869 } else {
2870 __ CallRuntime(Runtime::kMath_pow, 2);
2871 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002872 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002873}
2874
2875
2876void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2877 ASSERT(args->length() == 2);
2878
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002879 VisitForStackValue(args->at(0)); // Load the object.
2880 VisitForAccumulatorValue(args->at(1)); // Load the value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002881 __ pop(ebx); // eax = value. ebx = object.
2882
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002883 NearLabel done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002884 // If the object is a smi, return the value.
2885 __ test(ebx, Immediate(kSmiTagMask));
2886 __ j(zero, &done);
2887
2888 // If the object is not a value type, return the value.
2889 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
2890 __ j(not_equal, &done);
2891
2892 // Store the value.
2893 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
2894 // Update the write barrier. Save the value as it will be
2895 // overwritten by the write barrier code and is needed afterward.
2896 __ mov(edx, eax);
2897 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
2898
2899 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002900 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002901}
2902
2903
2904void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2905 ASSERT_EQ(args->length(), 1);
2906
2907 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002908 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002909
2910 NumberToStringStub stub;
2911 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002912 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002913}
2914
2915
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002916void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002917 ASSERT(args->length() == 1);
2918
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002919 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002920
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002921 Label done;
2922 StringCharFromCodeGenerator generator(eax, ebx);
2923 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002924 __ jmp(&done);
2925
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002926 NopRuntimeCallHelper call_helper;
2927 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002928
2929 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002930 context()->Plug(ebx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002931}
2932
2933
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002934void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2935 ASSERT(args->length() == 2);
2936
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002937 VisitForStackValue(args->at(0));
2938 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002939
2940 Register object = ebx;
2941 Register index = eax;
2942 Register scratch = ecx;
2943 Register result = edx;
2944
2945 __ pop(object);
2946
2947 Label need_conversion;
2948 Label index_out_of_range;
2949 Label done;
2950 StringCharCodeAtGenerator generator(object,
2951 index,
2952 scratch,
2953 result,
2954 &need_conversion,
2955 &need_conversion,
2956 &index_out_of_range,
2957 STRING_INDEX_IS_NUMBER);
2958 generator.GenerateFast(masm_);
2959 __ jmp(&done);
2960
2961 __ bind(&index_out_of_range);
2962 // When the index is out of range, the spec requires us to return
2963 // NaN.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002964 __ Set(result, Immediate(isolate()->factory()->nan_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002965 __ jmp(&done);
2966
2967 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002968 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002969 // trigger conversion.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002970 __ Set(result, Immediate(isolate()->factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002971 __ jmp(&done);
2972
2973 NopRuntimeCallHelper call_helper;
2974 generator.GenerateSlow(masm_, call_helper);
2975
2976 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002977 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002978}
2979
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002980
2981void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2982 ASSERT(args->length() == 2);
2983
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002984 VisitForStackValue(args->at(0));
2985 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002986
2987 Register object = ebx;
2988 Register index = eax;
2989 Register scratch1 = ecx;
2990 Register scratch2 = edx;
2991 Register result = eax;
2992
2993 __ pop(object);
2994
2995 Label need_conversion;
2996 Label index_out_of_range;
2997 Label done;
2998 StringCharAtGenerator generator(object,
2999 index,
3000 scratch1,
3001 scratch2,
3002 result,
3003 &need_conversion,
3004 &need_conversion,
3005 &index_out_of_range,
3006 STRING_INDEX_IS_NUMBER);
3007 generator.GenerateFast(masm_);
3008 __ jmp(&done);
3009
3010 __ bind(&index_out_of_range);
3011 // When the index is out of range, the spec requires us to return
3012 // the empty string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003013 __ Set(result, Immediate(isolate()->factory()->empty_string()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003014 __ jmp(&done);
3015
3016 __ bind(&need_conversion);
3017 // Move smi zero into the result register, which will trigger
3018 // conversion.
3019 __ Set(result, Immediate(Smi::FromInt(0)));
3020 __ jmp(&done);
3021
3022 NopRuntimeCallHelper call_helper;
3023 generator.GenerateSlow(masm_, call_helper);
3024
3025 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003026 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003027}
3028
3029
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003030void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
3031 ASSERT_EQ(2, args->length());
3032
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003033 VisitForStackValue(args->at(0));
3034 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003035
3036 StringAddStub stub(NO_STRING_ADD_FLAGS);
3037 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003038 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003039}
3040
3041
3042void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
3043 ASSERT_EQ(2, args->length());
3044
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003045 VisitForStackValue(args->at(0));
3046 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003047
3048 StringCompareStub stub;
3049 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003050 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003051}
3052
3053
3054void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
3055 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003056 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3057 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003058 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003059 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003060 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003061 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003062}
3063
3064
3065void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
3066 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003067 TranscendentalCacheStub stub(TranscendentalCache::COS,
3068 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003069 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003070 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003071 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003072 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003073}
3074
3075
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003076void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3077 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003078 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3079 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003080 ASSERT(args->length() == 1);
3081 VisitForStackValue(args->at(0));
3082 __ CallStub(&stub);
3083 context()->Plug(eax);
3084}
3085
3086
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003087void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
3088 // Load the argument on the stack and call the runtime function.
3089 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003090 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003091 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003092 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003093}
3094
3095
3096void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
3097 ASSERT(args->length() >= 2);
3098
danno@chromium.org160a7b02011-04-18 15:51:38 +00003099 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3100 for (int i = 0; i < arg_count + 1; ++i) {
3101 VisitForStackValue(args->at(i));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003102 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003103 VisitForAccumulatorValue(args->last()); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003104
danno@chromium.org160a7b02011-04-18 15:51:38 +00003105 // InvokeFunction requires the function in edi. Move it in there.
3106 __ mov(edi, result_register());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003107 ParameterCount count(arg_count);
3108 __ InvokeFunction(edi, count, CALL_FUNCTION);
3109 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003110 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003111}
3112
3113
3114void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003115 // Load the arguments on the stack and call the stub.
3116 RegExpConstructResultStub stub;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003117 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003118 VisitForStackValue(args->at(0));
3119 VisitForStackValue(args->at(1));
3120 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003121 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003122 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003123}
3124
3125
3126void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
3127 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003128 VisitForStackValue(args->at(0));
3129 VisitForStackValue(args->at(1));
3130 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003131 Label done;
3132 Label slow_case;
3133 Register object = eax;
3134 Register index_1 = ebx;
3135 Register index_2 = ecx;
3136 Register elements = edi;
3137 Register temp = edx;
3138 __ mov(object, Operand(esp, 2 * kPointerSize));
3139 // Fetch the map and check if array is in fast case.
3140 // Check that object doesn't require security checks and
3141 // has no indexed interceptor.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003142 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3143 __ j(not_equal, &slow_case);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003144 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
3145 KeyedLoadIC::kSlowCaseBitFieldMask);
3146 __ j(not_zero, &slow_case);
3147
3148 // Check the object's elements are in fast case and writable.
3149 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
3150 __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003151 Immediate(isolate()->factory()->fixed_array_map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003152 __ j(not_equal, &slow_case);
3153
3154 // Check that both indices are smis.
3155 __ mov(index_1, Operand(esp, 1 * kPointerSize));
3156 __ mov(index_2, Operand(esp, 0));
3157 __ mov(temp, index_1);
3158 __ or_(temp, Operand(index_2));
3159 __ test(temp, Immediate(kSmiTagMask));
3160 __ j(not_zero, &slow_case);
3161
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003162 // Check that both indices are valid.
3163 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
3164 __ cmp(temp, Operand(index_1));
3165 __ j(below_equal, &slow_case);
3166 __ cmp(temp, Operand(index_2));
3167 __ j(below_equal, &slow_case);
3168
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003169 // Bring addresses into index1 and index2.
3170 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1));
3171 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2));
3172
3173 // Swap elements. Use object and temp as scratch registers.
3174 __ mov(object, Operand(index_1, 0));
3175 __ mov(temp, Operand(index_2, 0));
3176 __ mov(Operand(index_2, 0), object);
3177 __ mov(Operand(index_1, 0), temp);
3178
3179 Label new_space;
3180 __ InNewSpace(elements, temp, equal, &new_space);
3181
3182 __ mov(object, elements);
3183 __ RecordWriteHelper(object, index_1, temp);
3184 __ RecordWriteHelper(elements, index_2, temp);
3185
3186 __ bind(&new_space);
3187 // We are done. Drop elements from the stack, and return undefined.
3188 __ add(Operand(esp), Immediate(3 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003189 __ mov(eax, isolate()->factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003190 __ jmp(&done);
3191
3192 __ bind(&slow_case);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003193 __ CallRuntime(Runtime::kSwapElements, 3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003194
3195 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003196 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003197}
3198
3199
3200void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3201 ASSERT_EQ(2, args->length());
3202
3203 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3204 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3205
3206 Handle<FixedArray> jsfunction_result_caches(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003207 isolate()->global_context()->jsfunction_result_caches());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003208 if (jsfunction_result_caches->length() <= cache_id) {
3209 __ Abort("Attempt to use undefined cache.");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003210 __ mov(eax, isolate()->factory()->undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003211 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003212 return;
3213 }
3214
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003215 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003216
3217 Register key = eax;
3218 Register cache = ebx;
3219 Register tmp = ecx;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003220 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003221 __ mov(cache,
3222 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003223 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003224 __ mov(cache,
3225 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3226
3227 Label done, not_found;
3228 // tmp now holds finger offset as a smi.
3229 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3230 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3231 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3232 __ j(not_equal, &not_found);
3233
3234 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3235 __ jmp(&done);
3236
3237 __ bind(&not_found);
3238 // Call runtime to perform the lookup.
3239 __ push(cache);
3240 __ push(key);
3241 __ CallRuntime(Runtime::kGetFromCache, 2);
3242
3243 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003244 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003245}
3246
3247
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003248void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3249 ASSERT_EQ(2, args->length());
3250
3251 Register right = eax;
3252 Register left = ebx;
3253 Register tmp = ecx;
3254
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003255 VisitForStackValue(args->at(0));
3256 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003257 __ pop(left);
3258
3259 Label done, fail, ok;
3260 __ cmp(left, Operand(right));
3261 __ j(equal, &ok);
3262 // Fail if either is a non-HeapObject.
3263 __ mov(tmp, left);
3264 __ and_(Operand(tmp), right);
3265 __ test(Operand(tmp), Immediate(kSmiTagMask));
3266 __ j(zero, &fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003267 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
3268 __ CmpInstanceType(tmp, JS_REGEXP_TYPE);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003269 __ j(not_equal, &fail);
3270 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3271 __ j(not_equal, &fail);
3272 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3273 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3274 __ j(equal, &ok);
3275 __ bind(&fail);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003276 __ mov(eax, Immediate(isolate()->factory()->false_value()));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003277 __ jmp(&done);
3278 __ bind(&ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003279 __ mov(eax, Immediate(isolate()->factory()->true_value()));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003280 __ bind(&done);
3281
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003282 context()->Plug(eax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003283}
3284
3285
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003286void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
3287 ASSERT(args->length() == 1);
3288
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003289 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003290
3291 if (FLAG_debug_code) {
3292 __ AbortIfNotString(eax);
3293 }
3294
3295 Label materialize_true, materialize_false;
3296 Label* if_true = NULL;
3297 Label* if_false = NULL;
3298 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003299 context()->PrepareTest(&materialize_true, &materialize_false,
3300 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003301
3302 __ test(FieldOperand(eax, String::kHashFieldOffset),
3303 Immediate(String::kContainsCachedArrayIndexMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003304 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003305 Split(zero, if_true, if_false, fall_through);
3306
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003307 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003308}
3309
3310
3311void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3312 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003313 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003314
3315 if (FLAG_debug_code) {
3316 __ AbortIfNotString(eax);
3317 }
3318
3319 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3320 __ IndexFromHash(eax, eax);
3321
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003322 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003323}
3324
3325
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003326void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003327 Label bailout, done, one_char_separator, long_separator,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003328 non_trivial_array, not_size_one_array, loop,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003329 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003330
3331 ASSERT(args->length() == 2);
3332 // We will leave the separator on the stack until the end of the function.
3333 VisitForStackValue(args->at(1));
3334 // Load this to eax (= array)
3335 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003336 // All aliases of the same register have disjoint lifetimes.
3337 Register array = eax;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003338 Register elements = no_reg; // Will be eax.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003339
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003340 Register index = edx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003341
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003342 Register string_length = ecx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003343
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003344 Register string = esi;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003345
3346 Register scratch = ebx;
3347
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003348 Register array_length = edi;
3349 Register result_pos = no_reg; // Will be edi.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003350
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003351 // Separator operand is already pushed.
3352 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3353 Operand result_operand = Operand(esp, 1 * kPointerSize);
3354 Operand array_length_operand = Operand(esp, 0);
3355 __ sub(Operand(esp), Immediate(2 * kPointerSize));
3356 __ cld();
3357 // Check that the array is a JSArray
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003358 __ test(array, Immediate(kSmiTagMask));
3359 __ j(zero, &bailout);
3360 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3361 __ j(not_equal, &bailout);
3362
3363 // Check that the array has fast elements.
3364 __ test_b(FieldOperand(scratch, Map::kBitField2Offset),
3365 1 << Map::kHasFastElements);
3366 __ j(zero, &bailout);
3367
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003368 // If the array has length zero, return the empty string.
3369 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003370 __ SmiUntag(array_length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003371 __ j(not_zero, &non_trivial_array);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003372 __ mov(result_operand, isolate()->factory()->empty_string());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003373 __ jmp(&done);
3374
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003375 // Save the array length.
3376 __ bind(&non_trivial_array);
3377 __ mov(array_length_operand, array_length);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003378
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003379 // Save the FixedArray containing array's elements.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003380 // End of array's live range.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003381 elements = array;
3382 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003383 array = no_reg;
3384
3385
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003386 // Check that all array elements are sequential ASCII strings, and
3387 // accumulate the sum of their lengths, as a smi-encoded value.
3388 __ Set(index, Immediate(0));
3389 __ Set(string_length, Immediate(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003390 // Loop condition: while (index < length).
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003391 // Live loop registers: index, array_length, string,
3392 // scratch, string_length, elements.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003393 if (FLAG_debug_code) {
3394 __ cmp(index, Operand(array_length));
3395 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
3396 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003397 __ bind(&loop);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003398 __ mov(string, FieldOperand(elements,
3399 index,
3400 times_pointer_size,
3401 FixedArray::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003402 __ test(string, Immediate(kSmiTagMask));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003403 __ j(zero, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003404 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3405 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3406 __ and_(scratch, Immediate(
3407 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3408 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3409 __ j(not_equal, &bailout);
3410 __ add(string_length,
3411 FieldOperand(string, SeqAsciiString::kLengthOffset));
3412 __ j(overflow, &bailout);
3413 __ add(Operand(index), Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003414 __ cmp(index, Operand(array_length));
3415 __ j(less, &loop);
3416
3417 // If array_length is 1, return elements[0], a string.
3418 __ cmp(array_length, 1);
3419 __ j(not_equal, &not_size_one_array);
3420 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3421 __ mov(result_operand, scratch);
3422 __ jmp(&done);
3423
3424 __ bind(&not_size_one_array);
3425
3426 // End of array_length live range.
3427 result_pos = array_length;
3428 array_length = no_reg;
3429
3430 // Live registers:
3431 // string_length: Sum of string lengths, as a smi.
3432 // elements: FixedArray of strings.
3433
3434 // Check that the separator is a flat ASCII string.
3435 __ mov(string, separator_operand);
3436 __ test(string, Immediate(kSmiTagMask));
3437 __ j(zero, &bailout);
3438 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3439 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003440 __ and_(scratch, Immediate(
3441 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003442 __ cmp(scratch, ASCII_STRING_TYPE);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003443 __ j(not_equal, &bailout);
3444
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003445 // Add (separator length times array_length) - separator length
3446 // to string_length.
3447 __ mov(scratch, separator_operand);
3448 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset));
3449 __ sub(string_length, Operand(scratch)); // May be negative, temporarily.
3450 __ imul(scratch, array_length_operand);
3451 __ j(overflow, &bailout);
3452 __ add(string_length, Operand(scratch));
3453 __ j(overflow, &bailout);
3454
3455 __ shr(string_length, 1);
3456 // Live registers and stack values:
3457 // string_length
3458 // elements
3459 __ AllocateAsciiString(result_pos, string_length, scratch,
3460 index, string, &bailout);
3461 __ mov(result_operand, result_pos);
3462 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3463
3464
3465 __ mov(string, separator_operand);
3466 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset),
3467 Immediate(Smi::FromInt(1)));
3468 __ j(equal, &one_char_separator);
3469 __ j(greater, &long_separator);
3470
3471
3472 // Empty separator case
3473 __ mov(index, Immediate(0));
3474 __ jmp(&loop_1_condition);
3475 // Loop condition: while (index < length).
3476 __ bind(&loop_1);
3477 // Each iteration of the loop concatenates one string to the result.
3478 // Live values in registers:
3479 // index: which element of the elements array we are adding to the result.
3480 // result_pos: the position to which we are currently copying characters.
3481 // elements: the FixedArray of strings we are joining.
3482
3483 // Get string = array[index].
3484 __ mov(string, FieldOperand(elements, index,
3485 times_pointer_size,
3486 FixedArray::kHeaderSize));
3487 __ mov(string_length,
3488 FieldOperand(string, String::kLengthOffset));
3489 __ shr(string_length, 1);
3490 __ lea(string,
3491 FieldOperand(string, SeqAsciiString::kHeaderSize));
3492 __ CopyBytes(string, result_pos, string_length, scratch);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003493 __ add(Operand(index), Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003494 __ bind(&loop_1_condition);
3495 __ cmp(index, array_length_operand);
3496 __ j(less, &loop_1); // End while (index < length).
3497 __ jmp(&done);
3498
3499
3500
3501 // One-character separator case
3502 __ bind(&one_char_separator);
3503 // Replace separator with its ascii character value.
3504 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3505 __ mov_b(separator_operand, scratch);
3506
3507 __ Set(index, Immediate(0));
3508 // Jump into the loop after the code that copies the separator, so the first
3509 // element is not preceded by a separator
3510 __ jmp(&loop_2_entry);
3511 // Loop condition: while (index < length).
3512 __ bind(&loop_2);
3513 // Each iteration of the loop concatenates one string to the result.
3514 // Live values in registers:
3515 // index: which element of the elements array we are adding to the result.
3516 // result_pos: the position to which we are currently copying characters.
3517
3518 // Copy the separator character to the result.
3519 __ mov_b(scratch, separator_operand);
3520 __ mov_b(Operand(result_pos, 0), scratch);
3521 __ inc(result_pos);
3522
3523 __ bind(&loop_2_entry);
3524 // Get string = array[index].
3525 __ mov(string, FieldOperand(elements, index,
3526 times_pointer_size,
3527 FixedArray::kHeaderSize));
3528 __ mov(string_length,
3529 FieldOperand(string, String::kLengthOffset));
3530 __ shr(string_length, 1);
3531 __ lea(string,
3532 FieldOperand(string, SeqAsciiString::kHeaderSize));
3533 __ CopyBytes(string, result_pos, string_length, scratch);
3534 __ add(Operand(index), Immediate(1));
3535
3536 __ cmp(index, array_length_operand);
3537 __ j(less, &loop_2); // End while (index < length).
3538 __ jmp(&done);
3539
3540
3541 // Long separator case (separator is more than one character).
3542 __ bind(&long_separator);
3543
3544 __ Set(index, Immediate(0));
3545 // Jump into the loop after the code that copies the separator, so the first
3546 // element is not preceded by a separator
3547 __ jmp(&loop_3_entry);
3548 // Loop condition: while (index < length).
3549 __ bind(&loop_3);
3550 // Each iteration of the loop concatenates one string to the result.
3551 // Live values in registers:
3552 // index: which element of the elements array we are adding to the result.
3553 // result_pos: the position to which we are currently copying characters.
3554
3555 // Copy the separator to the result.
3556 __ mov(string, separator_operand);
3557 __ mov(string_length,
3558 FieldOperand(string, String::kLengthOffset));
3559 __ shr(string_length, 1);
3560 __ lea(string,
3561 FieldOperand(string, SeqAsciiString::kHeaderSize));
3562 __ CopyBytes(string, result_pos, string_length, scratch);
3563
3564 __ bind(&loop_3_entry);
3565 // Get string = array[index].
3566 __ mov(string, FieldOperand(elements, index,
3567 times_pointer_size,
3568 FixedArray::kHeaderSize));
3569 __ mov(string_length,
3570 FieldOperand(string, String::kLengthOffset));
3571 __ shr(string_length, 1);
3572 __ lea(string,
3573 FieldOperand(string, SeqAsciiString::kHeaderSize));
3574 __ CopyBytes(string, result_pos, string_length, scratch);
3575 __ add(Operand(index), Immediate(1));
3576
3577 __ cmp(index, array_length_operand);
3578 __ j(less, &loop_3); // End while (index < length).
3579 __ jmp(&done);
3580
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003581
3582 __ bind(&bailout);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003583 __ mov(result_operand, isolate()->factory()->undefined_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003584 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003585 __ mov(eax, result_operand);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003586 // Drop temp values from the stack, and restore context register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003587 __ add(Operand(esp), Immediate(3 * kPointerSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003588
3589 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3590 context()->Plug(eax);
3591}
3592
3593
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003594void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003595 Handle<String> name = expr->name();
3596 if (name->length() > 0 && name->Get(0) == '_') {
3597 Comment cmnt(masm_, "[ InlineRuntimeCall");
3598 EmitInlineRuntimeCall(expr);
3599 return;
3600 }
3601
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003602 Comment cmnt(masm_, "[ CallRuntime");
3603 ZoneList<Expression*>* args = expr->arguments();
3604
3605 if (expr->is_jsruntime()) {
3606 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003607 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003608 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3609 }
3610
3611 // Push the arguments ("left-to-right").
3612 int arg_count = args->length();
3613 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003614 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003615 }
3616
3617 if (expr->is_jsruntime()) {
3618 // Call the JS runtime function via a call IC.
3619 __ Set(ecx, Immediate(expr->name()));
3620 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
3622 arg_count, in_loop);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003623 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003624 // Restore context register.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003625 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3626 } else {
3627 // Call the C runtime function.
3628 __ CallRuntime(expr->function(), arg_count);
3629 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003630 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003631}
3632
3633
3634void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3635 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003636 case Token::DELETE: {
3637 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3638 Property* prop = expr->expression()->AsProperty();
3639 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003640
3641 if (prop != NULL) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003642 if (prop->is_synthetic()) {
3643 // Result of deleting parameters is false, even when they rewrite
3644 // to accesses on the arguments object.
3645 context()->Plug(false);
3646 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003647 VisitForStackValue(prop->obj());
3648 VisitForStackValue(prop->key());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003649 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003650 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003651 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003652 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003653 } else if (var != NULL) {
3654 // Delete of an unqualified identifier is disallowed in strict mode
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003655 // but "delete this" is.
3656 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003657 if (var->is_global()) {
3658 __ push(GlobalObjectOperand());
3659 __ push(Immediate(var->name()));
3660 __ push(Immediate(Smi::FromInt(kNonStrictMode)));
3661 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3662 context()->Plug(eax);
3663 } else if (var->AsSlot() != NULL &&
3664 var->AsSlot()->type() != Slot::LOOKUP) {
3665 // Result of deleting non-global, non-dynamic variables is false.
3666 // The subexpression does not have side effects.
3667 context()->Plug(false);
3668 } else {
3669 // Non-global variable. Call the runtime to try to delete from the
3670 // context where the variable was introduced.
3671 __ push(context_register());
3672 __ push(Immediate(var->name()));
3673 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3674 context()->Plug(eax);
3675 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003676 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003677 // Result of deleting non-property, non-variable reference is true.
3678 // The subexpression may have side effects.
3679 VisitForEffect(expr->expression());
3680 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003681 }
3682 break;
3683 }
3684
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003685 case Token::VOID: {
3686 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3687 VisitForEffect(expr->expression());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003688 context()->Plug(isolate()->factory()->undefined_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003689 break;
3690 }
3691
3692 case Token::NOT: {
3693 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003694 if (context()->IsEffect()) {
3695 // Unary NOT has no side effects so it's only necessary to visit the
3696 // subexpression. Match the optimizing compiler by not branching.
3697 VisitForEffect(expr->expression());
3698 } else {
3699 Label materialize_true, materialize_false;
3700 Label* if_true = NULL;
3701 Label* if_false = NULL;
3702 Label* fall_through = NULL;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003703
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003704 // Notice that the labels are swapped.
3705 context()->PrepareTest(&materialize_true, &materialize_false,
3706 &if_false, &if_true, &fall_through);
3707 if (context()->IsTest()) ForwardBailoutToChild(expr);
3708 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3709 context()->Plug(if_false, if_true); // Labels swapped.
3710 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003711 break;
3712 }
3713
3714 case Token::TYPEOF: {
3715 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003716 { StackValueContext context(this);
3717 VisitForTypeofValue(expr->expression());
3718 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003719 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003720 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003721 break;
3722 }
3723
3724 case Token::ADD: {
3725 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003726 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003727 Label no_conversion;
3728 __ test(result_register(), Immediate(kSmiTagMask));
3729 __ j(zero, &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003730 ToNumberStub convert_stub;
3731 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003732 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003733 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003734 break;
3735 }
3736
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003737 case Token::SUB:
3738 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003739 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003740
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003741 case Token::BIT_NOT:
3742 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003743 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003744
3745 default:
3746 UNREACHABLE();
3747 }
3748}
3749
3750
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003751void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3752 const char* comment) {
3753 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
3754 Comment cmt(masm_, comment);
3755 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3756 UnaryOverwriteMode overwrite =
3757 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
3758 TypeRecordingUnaryOpStub stub(expr->op(), overwrite);
3759 // TypeRecordingUnaryOpStub expects the argument to be in the
3760 // accumulator register eax.
3761 VisitForAccumulatorValue(expr->expression());
3762 SetSourcePosition(expr->position());
3763 EmitCallIC(stub.GetCode(), NULL, expr->id());
3764 context()->Plug(eax);
3765}
3766
3767
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003768void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3769 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003770 SetSourcePosition(expr->position());
3771
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003772 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3773 // as the left-hand side.
3774 if (!expr->expression()->IsValidLeftHandSide()) {
3775 VisitForEffect(expr->expression());
3776 return;
3777 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003778
3779 // Expression can only be a property, a global or a (parameter or local)
3780 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
3781 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3782 LhsKind assign_type = VARIABLE;
3783 Property* prop = expr->expression()->AsProperty();
3784 // In case of a property we use the uninitialized expression context
3785 // of the key to detect a named property.
3786 if (prop != NULL) {
3787 assign_type =
3788 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3789 }
3790
3791 // Evaluate expression and get value.
3792 if (assign_type == VARIABLE) {
3793 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003794 AccumulatorValueContext context(this);
3795 EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003796 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003797 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003798 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003799 __ push(Immediate(Smi::FromInt(0)));
3800 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003801 if (assign_type == NAMED_PROPERTY) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003802 // Put the object both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003803 VisitForAccumulatorValue(prop->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00003804 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003805 EmitNamedPropertyLoad(prop);
3806 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003807 if (prop->is_arguments_access()) {
3808 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003809 MemOperand slot_operand =
3810 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
3811 __ push(slot_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003812 __ mov(eax, Immediate(prop->key()->AsLiteral()->handle()));
3813 } else {
3814 VisitForStackValue(prop->obj());
3815 VisitForAccumulatorValue(prop->key());
3816 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003817 __ mov(edx, Operand(esp, 0));
3818 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003819 EmitKeyedPropertyLoad(prop);
3820 }
3821 }
3822
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003823 // We need a second deoptimization point after loading the value
3824 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003825 if (assign_type == VARIABLE) {
3826 PrepareForBailout(expr->expression(), TOS_REG);
3827 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003828 PrepareForBailoutForId(expr->CountId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003829 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003830
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003831 // Call ToNumber only if operand is not a smi.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003832 NearLabel no_conversion;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003833 if (ShouldInlineSmiCase(expr->op())) {
3834 __ test(eax, Immediate(kSmiTagMask));
3835 __ j(zero, &no_conversion);
3836 }
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003837 ToNumberStub convert_stub;
3838 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003839 __ bind(&no_conversion);
3840
3841 // Save result for postfix expressions.
3842 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003843 if (!context()->IsEffect()) {
3844 // Save the result on the stack. If we have a named or keyed property
3845 // we store the result under the receiver that is currently on top
3846 // of the stack.
3847 switch (assign_type) {
3848 case VARIABLE:
3849 __ push(eax);
3850 break;
3851 case NAMED_PROPERTY:
3852 __ mov(Operand(esp, kPointerSize), eax);
3853 break;
3854 case KEYED_PROPERTY:
3855 __ mov(Operand(esp, 2 * kPointerSize), eax);
3856 break;
3857 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003858 }
3859 }
3860
3861 // Inline smi case if we are in a loop.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003862 NearLabel stub_call, done;
3863 JumpPatchSite patch_site(masm_);
3864
ricow@chromium.org65fae842010-08-25 15:26:24 +00003865 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003866 if (expr->op() == Token::INC) {
3867 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3868 } else {
3869 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3870 }
3871 __ j(overflow, &stub_call);
3872 // We could eliminate this smi check if we split the code at
3873 // the first smi check before calling ToNumber.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003874 patch_site.EmitJumpIfSmi(eax, &done);
3875
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003876 __ bind(&stub_call);
3877 // Call stub. Undo operation first.
3878 if (expr->op() == Token::INC) {
3879 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3880 } else {
3881 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3882 }
3883 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003884
3885 // Record position before stub call.
3886 SetSourcePosition(expr->position());
3887
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003888 // Call stub for +1/-1.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003889 __ mov(edx, eax);
3890 __ mov(eax, Immediate(Smi::FromInt(1)));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003891 TypeRecordingBinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003892 EmitCallIC(stub.GetCode(), &patch_site, expr->CountId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003893 __ bind(&done);
3894
3895 // Store the value returned in eax.
3896 switch (assign_type) {
3897 case VARIABLE:
3898 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003899 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003900 { EffectContext context(this);
3901 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3902 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003903 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3904 context.Plug(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003905 }
3906 // For all contexts except EffectContext We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003907 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003908 if (!context()->IsEffect()) {
3909 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003910 }
3911 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003912 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003913 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003914 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003915 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3916 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003917 }
3918 break;
3919 case NAMED_PROPERTY: {
3920 __ mov(ecx, prop->key()->AsLiteral()->handle());
3921 __ pop(edx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003922 Handle<Code> ic = is_strict_mode()
3923 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3924 : isolate()->builtins()->StoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003925 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003926 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003927 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003928 if (!context()->IsEffect()) {
3929 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003930 }
3931 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003932 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003933 }
3934 break;
3935 }
3936 case KEYED_PROPERTY: {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003937 __ pop(ecx);
3938 __ pop(edx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003939 Handle<Code> ic = is_strict_mode()
3940 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3941 : isolate()->builtins()->KeyedStoreIC_Initialize();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003942 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003943 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003944 if (expr->is_postfix()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003945 // Result is on the stack
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003946 if (!context()->IsEffect()) {
3947 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003948 }
3949 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003950 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003951 }
3952 break;
3953 }
3954 }
3955}
3956
3957
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003958void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003959 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003960 ASSERT(!context()->IsEffect());
3961 ASSERT(!context()->IsTest());
3962
ricow@chromium.org65fae842010-08-25 15:26:24 +00003963 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3964 Comment cmnt(masm_, "Global variable");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003965 __ mov(eax, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003966 __ mov(ecx, Immediate(proxy->name()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003967 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003968 // Use a regular load, not a contextual load, to avoid a reference
3969 // error.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003970 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003971 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003972 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003973 } else if (proxy != NULL &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003974 proxy->var()->AsSlot() != NULL &&
3975 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003976 Label done, slow;
3977
3978 // Generate code for loading from variables potentially shadowed
3979 // by eval-introduced variables.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003980 Slot* slot = proxy->var()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003981 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3982
3983 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003984 __ push(esi);
3985 __ push(Immediate(proxy->name()));
3986 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003987 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003988 __ bind(&done);
3989
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003990 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003991 } else {
3992 // This expression cannot throw a reference error at the top level.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003993 context()->HandleExpression(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003994 }
3995}
3996
3997
ricow@chromium.org65fae842010-08-25 15:26:24 +00003998bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
3999 Expression* left,
4000 Expression* right,
4001 Label* if_true,
4002 Label* if_false,
4003 Label* fall_through) {
4004 if (op != Token::EQ && op != Token::EQ_STRICT) return false;
4005
4006 // Check for the pattern: typeof <expression> == <string literal>.
4007 Literal* right_literal = right->AsLiteral();
4008 if (right_literal == NULL) return false;
4009 Handle<Object> right_literal_value = right_literal->handle();
4010 if (!right_literal_value->IsString()) return false;
4011 UnaryOperation* left_unary = left->AsUnaryOperation();
4012 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
4013 Handle<String> check = Handle<String>::cast(right_literal_value);
4014
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004015 { AccumulatorValueContext context(this);
4016 VisitForTypeofValue(left_unary->expression());
4017 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004018 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004019
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004020 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004021 __ JumpIfSmi(eax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004022 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004023 isolate()->factory()->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004024 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004025 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004026 __ JumpIfSmi(eax, if_false);
4027 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
4028 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004029 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004030 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4031 1 << Map::kIsUndetectable);
4032 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004033 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
4034 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004035 __ j(equal, if_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004036 __ cmp(eax, isolate()->factory()->false_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004037 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
4039 __ cmp(eax, isolate()->factory()->undefined_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004040 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004041 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004042 // Check for undetectable objects => true.
4043 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4044 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4045 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4046 Split(not_zero, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004048 __ JumpIfSmi(eax, if_false);
4049 __ CmpObjectType(eax, FIRST_FUNCTION_CLASS_TYPE, edx);
4050 Split(above_equal, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004051 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004052 __ JumpIfSmi(eax, if_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004053 __ cmp(eax, isolate()->factory()->null_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004054 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004055 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, edx);
4056 __ j(below, if_false);
4057 __ CmpInstanceType(edx, FIRST_FUNCTION_CLASS_TYPE);
4058 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004059 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004060 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4061 1 << Map::kIsUndetectable);
4062 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004063 } else {
4064 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004065 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004066
4067 return true;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004068}
4069
4070
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004071void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4072 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004073 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004074
4075 // Always perform the comparison for its control flow. Pack the result
4076 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004077
4078 Label materialize_true, materialize_false;
4079 Label* if_true = NULL;
4080 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004081 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004082 context()->PrepareTest(&materialize_true, &materialize_false,
4083 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004084
4085 // First we try a fast inlined version of the compare when one of
4086 // the operands is a literal.
4087 Token::Value op = expr->op();
4088 Expression* left = expr->left();
4089 Expression* right = expr->right();
4090 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004091 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004092 return;
4093 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004094
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004095 VisitForStackValue(expr->left());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004096 switch (expr->op()) {
4097 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004098 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004099 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004100 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004101 __ cmp(eax, isolate()->factory()->true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004102 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004103 break;
4104
4105 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004106 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004107 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004108 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004109 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004110 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004111 // The stub returns 0 for true.
4112 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004113 break;
4114 }
4115
4116 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004117 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004118 Condition cc = no_condition;
4119 bool strict = false;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004120 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004121 case Token::EQ_STRICT:
4122 strict = true;
4123 // Fall through
ricow@chromium.org65fae842010-08-25 15:26:24 +00004124 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004125 cc = equal;
4126 __ pop(edx);
4127 break;
4128 case Token::LT:
4129 cc = less;
4130 __ pop(edx);
4131 break;
4132 case Token::GT:
4133 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4134 cc = less;
4135 __ mov(edx, result_register());
4136 __ pop(eax);
4137 break;
4138 case Token::LTE:
4139 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4140 cc = greater_equal;
4141 __ mov(edx, result_register());
4142 __ pop(eax);
4143 break;
4144 case Token::GTE:
4145 cc = greater_equal;
4146 __ pop(edx);
4147 break;
4148 case Token::IN:
4149 case Token::INSTANCEOF:
4150 default:
4151 UNREACHABLE();
4152 }
4153
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004154 bool inline_smi_code = ShouldInlineSmiCase(op);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004155 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004156 if (inline_smi_code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004157 NearLabel slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004158 __ mov(ecx, Operand(edx));
4159 __ or_(ecx, Operand(eax));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004160 patch_site.EmitJumpIfNotSmi(ecx, &slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004161 __ cmp(edx, Operand(eax));
4162 Split(cc, if_true, if_false, NULL);
4163 __ bind(&slow_case);
4164 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004165
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004166 // Record position and call the compare IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004167 SetSourcePosition(expr->position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004168 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004169 EmitCallIC(ic, &patch_site, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004170
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004171 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004172 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004173 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004174 }
4175 }
4176
4177 // Convert the result of the comparison into one expected for this
4178 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004179 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004180}
4181
4182
ricow@chromium.org65fae842010-08-25 15:26:24 +00004183void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4184 Label materialize_true, materialize_false;
4185 Label* if_true = NULL;
4186 Label* if_false = NULL;
4187 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004188 context()->PrepareTest(&materialize_true, &materialize_false,
4189 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004190
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004191 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004192 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4193
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004194 __ cmp(eax, isolate()->factory()->null_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004195 if (expr->is_strict()) {
4196 Split(equal, if_true, if_false, fall_through);
4197 } else {
4198 __ j(equal, if_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004199 __ cmp(eax, isolate()->factory()->undefined_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004200 __ j(equal, if_true);
4201 __ test(eax, Immediate(kSmiTagMask));
4202 __ j(zero, if_false);
4203 // It can be an undetectable object.
4204 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4205 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
4206 __ test(edx, Immediate(1 << Map::kIsUndetectable));
4207 Split(not_zero, if_true, if_false, fall_through);
4208 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004209 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004210}
4211
4212
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004213void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4214 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004215 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004216}
4217
4218
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004219Register FullCodeGenerator::result_register() {
4220 return eax;
4221}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004222
4223
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004224Register FullCodeGenerator::context_register() {
4225 return esi;
4226}
4227
4228
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004229void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
4230 RelocInfo::Mode mode,
4231 unsigned ast_id) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004232 ASSERT(mode == RelocInfo::CODE_TARGET ||
4233 mode == RelocInfo::CODE_TARGET_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004234 switch (ic->kind()) {
4235 case Code::LOAD_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004236 __ IncrementCounter(isolate()->counters()->named_load_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004237 break;
4238 case Code::KEYED_LOAD_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004239 __ IncrementCounter(isolate()->counters()->keyed_load_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004240 break;
4241 case Code::STORE_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004242 __ IncrementCounter(isolate()->counters()->named_store_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004243 break;
4244 case Code::KEYED_STORE_IC:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004245 __ IncrementCounter(isolate()->counters()->keyed_store_full(), 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004246 default:
4247 break;
4248 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004249 __ call(ic, mode, ast_id);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004250}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004251
4252
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004253void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
4254 JumpPatchSite* patch_site,
4255 unsigned ast_id) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004256 Counters* counters = isolate()->counters();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004257 switch (ic->kind()) {
4258 case Code::LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004259 __ IncrementCounter(counters->named_load_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004260 break;
4261 case Code::KEYED_LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004262 __ IncrementCounter(counters->keyed_load_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004263 break;
4264 case Code::STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004265 __ IncrementCounter(counters->named_store_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004266 break;
4267 case Code::KEYED_STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004268 __ IncrementCounter(counters->keyed_store_full(), 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004269 default:
4270 break;
4271 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004272 __ call(ic, RelocInfo::CODE_TARGET, ast_id);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004273 if (patch_site != NULL && patch_site->is_bound()) {
4274 patch_site->EmitPatchInfo();
4275 } else {
4276 __ nop(); // Signals no inlined code.
4277 }
4278}
4279
4280
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004281void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4282 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4283 __ mov(Operand(ebp, frame_offset), value);
4284}
4285
4286
4287void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004288 __ mov(dst, ContextOperand(esi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004289}
4290
4291
4292// ----------------------------------------------------------------------------
4293// Non-local control flow support.
4294
4295void FullCodeGenerator::EnterFinallyBlock() {
4296 // Cook return address on top of stack (smi encoded Code* delta)
4297 ASSERT(!result_register().is(edx));
4298 __ mov(edx, Operand(esp, 0));
4299 __ sub(Operand(edx), Immediate(masm_->CodeObject()));
4300 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4301 ASSERT_EQ(0, kSmiTag);
4302 __ add(edx, Operand(edx)); // Convert to smi.
4303 __ mov(Operand(esp, 0), edx);
4304 // Store result register while executing finally block.
4305 __ push(result_register());
4306}
4307
4308
4309void FullCodeGenerator::ExitFinallyBlock() {
4310 ASSERT(!result_register().is(edx));
4311 // Restore result register from stack.
4312 __ pop(result_register());
4313 // Uncook return address.
4314 __ mov(edx, Operand(esp, 0));
4315 __ sar(edx, 1); // Convert smi to int.
4316 __ add(Operand(edx), Immediate(masm_->CodeObject()));
4317 __ mov(Operand(esp, 0), edx);
4318 // And return.
4319 __ ret(0);
4320}
4321
4322
4323#undef __
4324
4325} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004326
4327#endif // V8_TARGET_ARCH_IA32