blob: 174a946e96d1fae33dc5fe2f3fc0a19a7d37253f [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"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000033#include "codegen-inl.h"
34#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
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000047
48class JumpPatchSite BASE_EMBEDDED {
49 public:
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000050 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000051#ifdef DEBUG
52 info_emitted_ = false;
53#endif
54 }
55
56 ~JumpPatchSite() {
57 ASSERT(patch_site_.is_bound() == info_emitted_);
58 }
59
60 void EmitJumpIfNotSmi(Register reg, NearLabel* target) {
61 __ test(reg, Immediate(kSmiTagMask));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000062 EmitJump(not_carry, target); // Always taken before patched.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000063 }
64
65 void EmitJumpIfSmi(Register reg, NearLabel* target) {
66 __ test(reg, Immediate(kSmiTagMask));
67 EmitJump(carry, target); // Never taken before patched.
68 }
69
70 void EmitPatchInfo() {
71 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
72 ASSERT(is_int8(delta_to_patch_site));
73 __ test(eax, Immediate(delta_to_patch_site));
74#ifdef DEBUG
75 info_emitted_ = true;
76#endif
77 }
78
79 bool is_bound() const { return patch_site_.is_bound(); }
80
81 private:
82 // jc will be patched with jz, jnc will become jnz.
83 void EmitJump(Condition cc, NearLabel* target) {
84 ASSERT(!patch_site_.is_bound() && !info_emitted_);
85 ASSERT(cc == carry || cc == not_carry);
86 __ bind(&patch_site_);
87 __ j(cc, target);
88 }
89
90 MacroAssembler* masm_;
91 Label patch_site_;
92#ifdef DEBUG
93 bool info_emitted_;
94#endif
95};
96
97
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000098// Generate code for a JS function. On entry to the function the receiver
99// and arguments have been pushed on the stack left to right, with the
100// return address on top of them. The actual argument count matches the
101// formal parameter count expected by the function.
102//
103// The live registers are:
104// o edi: the JS function object being called (ie, ourselves)
105// o esi: our context
106// o ebp: our caller's frame pointer
107// o esp: stack pointer (pointing to return address)
108//
109// The function builds a JS frame. Please see JavaScriptFrameConstants in
110// frames-ia32.h for its layout.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000111void FullCodeGenerator::Generate(CompilationInfo* info) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000112 ASSERT(info_ == NULL);
113 info_ = info;
114 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000115 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000116
vegorov@chromium.org42841962010-10-18 11:18:59 +0000117#ifdef DEBUG
118 if (strlen(FLAG_stop_at) > 0 &&
119 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
120 __ int3();
121 }
122#endif
123
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000124 __ push(ebp); // Caller's frame pointer.
125 __ mov(ebp, esp);
126 __ push(esi); // Callee's context.
127 __ push(edi); // Callee's JS Function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000129 { Comment cmnt(masm_, "[ Allocate locals");
130 int locals_count = scope()->num_stack_slots();
131 if (locals_count == 1) {
132 __ push(Immediate(Factory::undefined_value()));
133 } else if (locals_count > 1) {
134 __ mov(eax, Immediate(Factory::undefined_value()));
135 for (int i = 0; i < locals_count; i++) {
136 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 }
138 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000139 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000140
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000141 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000142
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000143 // Possibly allocate a local context.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000144 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000145 if (heap_slots > 0) {
146 Comment cmnt(masm_, "[ Allocate local context");
147 // Argument to NewContext is the function, which is still in edi.
148 __ push(edi);
149 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
150 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000152 } else {
153 __ CallRuntime(Runtime::kNewContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000155 function_in_register = false;
156 // Context is returned in both eax and esi. It replaces the context
157 // passed to us. It's saved in the stack and kept live in esi.
158 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
159
160 // Copy parameters into context if necessary.
161 int num_parameters = scope()->num_parameters();
162 for (int i = 0; i < num_parameters; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000163 Slot* slot = scope()->parameter(i)->AsSlot();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000164 if (slot != NULL && slot->type() == Slot::CONTEXT) {
165 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
166 (num_parameters - 1 - i) * kPointerSize;
167 // Load parameter from stack.
168 __ mov(eax, Operand(ebp, parameter_offset));
169 // Store it in the context.
170 int context_offset = Context::SlotOffset(slot->index());
171 __ mov(Operand(esi, context_offset), eax);
172 // Update the write barrier. This clobbers all involved
173 // registers, so we have use a third register to avoid
174 // clobbering esi.
175 __ mov(ecx, esi);
176 __ RecordWrite(ecx, context_offset, eax, ebx);
177 }
178 }
179 }
180
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000181 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000182 if (arguments != NULL) {
183 // Function uses arguments object.
184 Comment cmnt(masm_, "[ Allocate arguments object");
185 if (function_in_register) {
186 __ push(edi);
187 } else {
188 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
189 }
190 // Receiver is just before the parameters on the caller's stack.
191 int offset = scope()->num_parameters() * kPointerSize;
192 __ lea(edx,
193 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
194 __ push(edx);
195 __ push(Immediate(Smi::FromInt(scope()->num_parameters())));
196 // Arguments to ArgumentsAccessStub:
197 // function, receiver address, parameter count.
198 // The stub will rewrite receiver and parameter count if the previous
199 // stack frame was an arguments adapter frame.
200 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
201 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000202
203 Variable* arguments_shadow = scope()->arguments_shadow();
204 if (arguments_shadow != NULL) {
205 __ mov(ecx, eax); // Duplicate result.
206 Move(arguments_shadow->AsSlot(), ecx, ebx, edx);
207 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000208 Move(arguments->AsSlot(), eax, ebx, edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000209 }
210
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000211 if (FLAG_trace) {
212 __ CallRuntime(Runtime::kTraceEnter, 0);
213 }
214
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000215 // Visit the declarations and body unless there is an illegal
216 // redeclaration.
217 if (scope()->HasIllegalRedeclaration()) {
218 Comment cmnt(masm_, "[ Declarations");
219 scope()->VisitIllegalRedeclaration(this);
220
221 } else {
222 { Comment cmnt(masm_, "[ Declarations");
223 // For named function expressions, declare the function name as a
224 // constant.
225 if (scope()->is_function_scope() && scope()->function() != NULL) {
226 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
227 }
228 VisitDeclarations(scope()->declarations());
229 }
230
231 { Comment cmnt(masm_, "[ Stack check");
232 PrepareForBailout(info->function(), NO_REGISTERS);
233 NearLabel ok;
234 ExternalReference stack_limit =
235 ExternalReference::address_of_stack_limit();
236 __ cmp(esp, Operand::StaticVariable(stack_limit));
237 __ j(above_equal, &ok, taken);
238 StackCheckStub stub;
239 __ CallStub(&stub);
240 __ bind(&ok);
241 }
242
243 { Comment cmnt(masm_, "[ Body");
244 ASSERT(loop_depth() == 0);
245 VisitStatements(function()->body());
246 ASSERT(loop_depth() == 0);
247 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000248 }
249
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000250 // Always emit a 'return undefined' in case control fell off the end of
251 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000252 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000253 __ mov(eax, Factory::undefined_value());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000254 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000255 }
256}
257
258
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000259void FullCodeGenerator::ClearAccumulator() {
260 __ Set(eax, Immediate(Smi::FromInt(0)));
261}
262
263
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000264void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
265 Comment cmnt(masm_, "[ Stack check");
266 NearLabel ok;
267 ExternalReference stack_limit = ExternalReference::address_of_stack_limit();
268 __ cmp(esp, Operand::StaticVariable(stack_limit));
269 __ j(above_equal, &ok, taken);
270 StackCheckStub stub;
271 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000272 // Record a mapping of this PC offset to the OSR id. This is used to find
273 // the AST id from the unoptimized code in order to use it as a key into
274 // the deoptimization input data found in the optimized code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000275 RecordStackCheck(stmt->OsrEntryId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000276
277 // Loop stack checks can be patched to perform on-stack replacement. In
278 // order to decide whether or not to perform OSR we embed the loop depth
279 // in a test instruction after the call so we can extract it from the OSR
280 // builtin.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000281 ASSERT(loop_depth() > 0);
282 __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000283
284 __ bind(&ok);
285 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
286 // Record a mapping of the OSR id to this PC. This is used if the OSR
287 // entry becomes the target of a bailout. We don't expect it to be, but
288 // we want it to work if it is.
289 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000290}
291
292
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000293void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000294 Comment cmnt(masm_, "[ Return sequence");
295 if (return_label_.is_bound()) {
296 __ jmp(&return_label_);
297 } else {
298 // Common return label
299 __ bind(&return_label_);
300 if (FLAG_trace) {
301 __ push(eax);
302 __ CallRuntime(Runtime::kTraceExit, 1);
303 }
304#ifdef DEBUG
305 // Add a label for checking the size of the code used for returning.
306 Label check_exit_codesize;
307 masm_->bind(&check_exit_codesize);
308#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000309 SetSourcePosition(function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000310 __ RecordJSReturn();
311 // Do not use the leave instruction here because it is too short to
312 // patch with the code required by the debugger.
313 __ mov(esp, ebp);
314 __ pop(ebp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000315
316 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize;
317 __ Ret(arguments_bytes, ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000318#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000319 // Check that the size of the code used for returning is large enough
320 // for the debugger's requirements.
321 ASSERT(Assembler::kJSReturnSequenceLength <=
322 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000323#endif
324 }
325}
326
327
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000328void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000329}
330
331
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000332void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
333 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
334 __ mov(result_register(), slot_operand);
335}
336
337
338void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
339 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
340 // Memory operands can be pushed directly.
341 __ push(slot_operand);
342}
343
344
345void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
346 // For simplicity we always test the accumulator register.
347 codegen()->Move(result_register(), slot);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000348 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000349 codegen()->DoTest(true_label_, false_label_, fall_through_);
350}
351
352
353void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
354 UNREACHABLE(); // Not used on IA32.
355}
356
357
358void FullCodeGenerator::AccumulatorValueContext::Plug(
359 Heap::RootListIndex index) const {
360 UNREACHABLE(); // Not used on IA32.
361}
362
363
364void FullCodeGenerator::StackValueContext::Plug(
365 Heap::RootListIndex index) const {
366 UNREACHABLE(); // Not used on IA32.
367}
368
369
370void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
371 UNREACHABLE(); // Not used on IA32.
372}
373
374
375void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
376}
377
378
379void FullCodeGenerator::AccumulatorValueContext::Plug(
380 Handle<Object> lit) const {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000381 __ Set(result_register(), Immediate(lit));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000382}
383
384
385void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
386 // Immediates can be pushed directly.
387 __ push(Immediate(lit));
388}
389
390
391void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000392 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
393 true,
394 true_label_,
395 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000396 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
397 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000398 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000399 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000400 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000401 } else if (lit->IsString()) {
402 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000403 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000404 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000405 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000406 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000407 } else if (lit->IsSmi()) {
408 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000409 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000410 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000411 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000412 }
413 } else {
414 // For simplicity we always test the accumulator register.
415 __ mov(result_register(), lit);
416 codegen()->DoTest(true_label_, false_label_, fall_through_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000417 }
418}
419
420
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000421void FullCodeGenerator::EffectContext::DropAndPlug(int count,
422 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000423 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000424 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000425}
426
427
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000428void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
429 int count,
430 Register reg) const {
431 ASSERT(count > 0);
432 __ Drop(count);
433 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000434}
435
436
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000437void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
438 Register reg) const {
439 ASSERT(count > 0);
440 if (count > 1) __ Drop(count - 1);
441 __ mov(Operand(esp, 0), reg);
442}
443
444
445void FullCodeGenerator::TestContext::DropAndPlug(int count,
446 Register reg) const {
447 ASSERT(count > 0);
448 // For simplicity we always test the accumulator register.
449 __ Drop(count);
450 __ Move(result_register(), reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000451 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000452 codegen()->DoTest(true_label_, false_label_, fall_through_);
453}
454
455
456void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
457 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000458 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000459 __ bind(materialize_true);
460}
461
462
463void FullCodeGenerator::AccumulatorValueContext::Plug(
464 Label* materialize_true,
465 Label* materialize_false) const {
466 NearLabel done;
467 __ bind(materialize_true);
468 __ mov(result_register(), Factory::true_value());
469 __ jmp(&done);
470 __ bind(materialize_false);
471 __ mov(result_register(), Factory::false_value());
472 __ bind(&done);
473}
474
475
476void FullCodeGenerator::StackValueContext::Plug(
477 Label* materialize_true,
478 Label* materialize_false) const {
479 NearLabel done;
480 __ bind(materialize_true);
481 __ push(Immediate(Factory::true_value()));
482 __ jmp(&done);
483 __ bind(materialize_false);
484 __ push(Immediate(Factory::false_value()));
485 __ bind(&done);
486}
487
488
489void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
490 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000491 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000492 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000493}
494
495
496void FullCodeGenerator::EffectContext::Plug(bool flag) const {
497}
498
499
500void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
501 Handle<Object> value =
502 flag ? Factory::true_value() : Factory::false_value();
503 __ mov(result_register(), value);
504}
505
506
507void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
508 Handle<Object> value =
509 flag ? Factory::true_value() : Factory::false_value();
510 __ push(Immediate(value));
511}
512
513
514void FullCodeGenerator::TestContext::Plug(bool flag) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000515 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
516 true,
517 true_label_,
518 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000519 if (flag) {
520 if (true_label_ != fall_through_) __ jmp(true_label_);
521 } else {
522 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000523 }
524}
525
526
ricow@chromium.org65fae842010-08-25 15:26:24 +0000527void FullCodeGenerator::DoTest(Label* if_true,
528 Label* if_false,
529 Label* fall_through) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000530 // Emit the inlined tests assumed by the stub.
531 __ cmp(result_register(), Factory::undefined_value());
532 __ j(equal, if_false);
533 __ cmp(result_register(), Factory::true_value());
534 __ j(equal, if_true);
535 __ cmp(result_register(), Factory::false_value());
536 __ j(equal, if_false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000537 STATIC_ASSERT(kSmiTag == 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000538 __ test(result_register(), Operand(result_register()));
539 __ j(zero, if_false);
540 __ test(result_register(), Immediate(kSmiTagMask));
541 __ j(zero, if_true);
542
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000543 // Call the ToBoolean stub for all other cases.
544 ToBooleanStub stub;
545 __ push(result_register());
546 __ CallStub(&stub);
547 __ test(eax, Operand(eax));
548
ricow@chromium.org65fae842010-08-25 15:26:24 +0000549 // The stub returns nonzero for true.
550 Split(not_zero, if_true, if_false, fall_through);
551}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000552
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000553
ricow@chromium.org65fae842010-08-25 15:26:24 +0000554void FullCodeGenerator::Split(Condition cc,
555 Label* if_true,
556 Label* if_false,
557 Label* fall_through) {
558 if (if_false == fall_through) {
559 __ j(cc, if_true);
560 } else if (if_true == fall_through) {
561 __ j(NegateCondition(cc), if_false);
562 } else {
563 __ j(cc, if_true);
564 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000565 }
566}
567
568
569MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
570 switch (slot->type()) {
571 case Slot::PARAMETER:
572 case Slot::LOCAL:
573 return Operand(ebp, SlotOffset(slot));
574 case Slot::CONTEXT: {
575 int context_chain_length =
ager@chromium.org5c838252010-02-19 08:53:10 +0000576 scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000577 __ LoadContext(scratch, context_chain_length);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000578 return ContextOperand(scratch, slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000579 }
580 case Slot::LOOKUP:
581 UNREACHABLE();
582 }
583 UNREACHABLE();
584 return Operand(eax, 0);
585}
586
587
588void FullCodeGenerator::Move(Register destination, Slot* source) {
589 MemOperand location = EmitSlotSearch(source, destination);
590 __ mov(destination, location);
591}
592
593
594void FullCodeGenerator::Move(Slot* dst,
595 Register src,
596 Register scratch1,
597 Register scratch2) {
598 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
599 ASSERT(!scratch1.is(src) && !scratch2.is(src));
600 MemOperand location = EmitSlotSearch(dst, scratch1);
601 __ mov(location, src);
602 // Emit the write barrier code if the location is in the heap.
603 if (dst->type() == Slot::CONTEXT) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000604 int offset = Context::SlotOffset(dst->index());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000605 ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000606 __ RecordWrite(scratch1, offset, src, scratch2);
607 }
608}
609
610
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000611void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
612 bool should_normalize,
613 Label* if_true,
614 Label* if_false) {
615 // Only prepare for bailouts before splits if we're in a test
616 // context. Otherwise, we let the Visit function deal with the
617 // preparation to avoid preparing with the same AST id twice.
618 if (!context()->IsTest() || !info_->IsOptimizable()) return;
619
620 NearLabel skip;
621 if (should_normalize) __ jmp(&skip);
622
623 ForwardBailoutStack* current = forward_bailout_stack_;
624 while (current != NULL) {
625 PrepareForBailout(current->expr(), state);
626 current = current->parent();
627 }
628
629 if (should_normalize) {
630 __ cmp(eax, Factory::true_value());
631 Split(equal, if_true, if_false, NULL);
632 __ bind(&skip);
633 }
634}
635
636
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000637void FullCodeGenerator::EmitDeclaration(Variable* variable,
638 Variable::Mode mode,
639 FunctionLiteral* function) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000640 Comment cmnt(masm_, "[ Declaration");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000641 ASSERT(variable != NULL); // Must have been resolved.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000642 Slot* slot = variable->AsSlot();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000643 Property* prop = variable->AsProperty();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000644
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000645 if (slot != NULL) {
646 switch (slot->type()) {
647 case Slot::PARAMETER:
648 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000649 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000650 __ mov(Operand(ebp, SlotOffset(slot)),
651 Immediate(Factory::the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000652 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000653 VisitForAccumulatorValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000654 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
655 }
656 break;
657
658 case Slot::CONTEXT:
659 // We bypass the general EmitSlotSearch because we know more about
660 // this specific context.
661
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000662 // The variable in the decl always resides in the current function
663 // context.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000664 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000665 if (FLAG_debug_code) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000666 // Check that we're not inside a 'with'.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000667 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000668 __ cmp(ebx, Operand(esi));
669 __ Check(equal, "Unexpected declaration in current context.");
670 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000671 if (mode == Variable::CONST) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000672 __ mov(ContextOperand(esi, slot->index()),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000673 Immediate(Factory::the_hole_value()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000674 // No write barrier since the hole value is in old space.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000675 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000676 VisitForAccumulatorValue(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000677 __ mov(ContextOperand(esi, slot->index()), result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000678 int offset = Context::SlotOffset(slot->index());
679 __ mov(ebx, esi);
680 __ RecordWrite(ebx, offset, result_register(), ecx);
681 }
682 break;
683
684 case Slot::LOOKUP: {
685 __ push(esi);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000686 __ push(Immediate(variable->name()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000687 // Declaration nodes are always introduced in one of two modes.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000688 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
689 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000690 __ push(Immediate(Smi::FromInt(attr)));
691 // Push initial value, if any.
692 // Note: For variables we must not push an initial value (such as
693 // 'undefined') because we may have a (legal) redeclaration and we
694 // must not destroy the current value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000695 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000696 __ push(Immediate(Factory::the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000697 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000698 VisitForStackValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000699 } else {
700 __ push(Immediate(Smi::FromInt(0))); // No initial value!
701 }
702 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
703 break;
704 }
705 }
706
707 } else if (prop != NULL) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000708 if (function != NULL || mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000709 // We are declaring a function or constant that rewrites to a
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000710 // property. Use (keyed) IC to set the initial value. We cannot
711 // visit the rewrite because it's shared and we risk recording
712 // duplicate AST IDs for bailouts from optimized code.
713 ASSERT(prop->obj()->AsVariableProxy() != NULL);
714 { AccumulatorValueContext for_object(this);
715 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000716 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000717
718 if (function != NULL) {
719 __ push(eax);
720 VisitForAccumulatorValue(function);
721 __ pop(edx);
722 } else {
723 __ mov(edx, eax);
724 __ mov(eax, Factory::the_hole_value());
725 }
726 ASSERT(prop->key()->AsLiteral() != NULL &&
727 prop->key()->AsLiteral()->handle()->IsSmi());
728 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000729
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000730 Handle<Code> ic(Builtins::builtin(is_strict()
731 ? Builtins::KeyedStoreIC_Initialize_Strict
732 : Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000733 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000734 }
735 }
736}
737
738
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000739void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
740 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
741}
742
743
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000744void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
745 // Call the runtime to declare the globals.
746 __ push(esi); // The context is the first argument.
747 __ push(Immediate(pairs));
ager@chromium.org5c838252010-02-19 08:53:10 +0000748 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000749 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
750 __ CallRuntime(Runtime::kDeclareGlobals, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000751 // Return value is ignored.
752}
753
754
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000755void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
756 Comment cmnt(masm_, "[ SwitchStatement");
757 Breakable nested_statement(this, stmt);
758 SetStatementPosition(stmt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000759
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000760 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000761 VisitForStackValue(stmt->tag());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000762 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000763
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000764 ZoneList<CaseClause*>* clauses = stmt->cases();
765 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000766
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000767 Label next_test; // Recycled for each test.
768 // Compile all the tests with branches to their bodies.
769 for (int i = 0; i < clauses->length(); i++) {
770 CaseClause* clause = clauses->at(i);
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000771 clause->body_target()->entry_label()->Unuse();
772
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000773 // The default is not a test, but remember it as final fall through.
774 if (clause->is_default()) {
775 default_clause = clause;
776 continue;
777 }
778
779 Comment cmnt(masm_, "[ Case comparison");
780 __ bind(&next_test);
781 next_test.Unuse();
782
783 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000784 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000785
ricow@chromium.org65fae842010-08-25 15:26:24 +0000786 // Perform the comparison as if via '==='.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000787 __ mov(edx, Operand(esp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000788 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000789 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000790 if (inline_smi_code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000791 NearLabel slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000792 __ mov(ecx, edx);
793 __ or_(ecx, Operand(eax));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000794 patch_site.EmitJumpIfNotSmi(ecx, &slow_case);
795
ricow@chromium.org65fae842010-08-25 15:26:24 +0000796 __ cmp(edx, Operand(eax));
797 __ j(not_equal, &next_test);
798 __ Drop(1); // Switch value is no longer needed.
799 __ jmp(clause->body_target()->entry_label());
800 __ bind(&slow_case);
801 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000802
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000803 // Record position before stub call for type feedback.
804 SetSourcePosition(clause->position());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000805 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000806 EmitCallIC(ic, &patch_site);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000807 __ test(eax, Operand(eax));
808 __ j(not_equal, &next_test);
809 __ Drop(1); // Switch value is no longer needed.
810 __ jmp(clause->body_target()->entry_label());
811 }
812
813 // Discard the test value and jump to the default if present, otherwise to
814 // the end of the statement.
815 __ bind(&next_test);
816 __ Drop(1); // Switch value is no longer needed.
817 if (default_clause == NULL) {
818 __ jmp(nested_statement.break_target());
819 } else {
820 __ jmp(default_clause->body_target()->entry_label());
821 }
822
823 // Compile all the case bodies.
824 for (int i = 0; i < clauses->length(); i++) {
825 Comment cmnt(masm_, "[ Case body");
826 CaseClause* clause = clauses->at(i);
827 __ bind(clause->body_target()->entry_label());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000828 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000829 VisitStatements(clause->statements());
830 }
831
832 __ bind(nested_statement.break_target());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000833 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000834}
835
836
837void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
838 Comment cmnt(masm_, "[ ForInStatement");
839 SetStatementPosition(stmt);
840
841 Label loop, exit;
842 ForIn loop_statement(this, stmt);
843 increment_loop_depth();
844
845 // Get the object to enumerate over. Both SpiderMonkey and JSC
846 // ignore null and undefined in contrast to the specification; see
847 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000848 VisitForAccumulatorValue(stmt->enumerable());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000849 __ cmp(eax, Factory::undefined_value());
850 __ j(equal, &exit);
851 __ cmp(eax, Factory::null_value());
852 __ j(equal, &exit);
853
854 // Convert the object to a JS object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000855 NearLabel convert, done_convert;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000856 __ test(eax, Immediate(kSmiTagMask));
857 __ j(zero, &convert);
858 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
859 __ j(above_equal, &done_convert);
860 __ bind(&convert);
861 __ push(eax);
862 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
863 __ bind(&done_convert);
864 __ push(eax);
865
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000866 // Check cache validity in generated code. This is a fast case for
867 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
868 // guarantee cache validity, call the runtime system to check cache
869 // validity or get the property names in a fixed array.
870 Label next, call_runtime;
871 __ mov(ecx, eax);
872 __ bind(&next);
873
874 // Check that there are no elements. Register ecx contains the
875 // current JS object we've reached through the prototype chain.
876 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset),
877 Factory::empty_fixed_array());
878 __ j(not_equal, &call_runtime);
879
880 // Check that instance descriptors are not empty so that we can
881 // check for an enum cache. Leave the map in ebx for the subsequent
882 // prototype load.
883 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
884 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
885 __ cmp(edx, Factory::empty_descriptor_array());
886 __ j(equal, &call_runtime);
887
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000888 // Check that there is an enum cache in the non-empty instance
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000889 // descriptors (edx). This is the case if the next enumeration
890 // index field does not contain a smi.
891 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
892 __ test(edx, Immediate(kSmiTagMask));
893 __ j(zero, &call_runtime);
894
895 // For all objects but the receiver, check that the cache is empty.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 NearLabel check_prototype;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000897 __ cmp(ecx, Operand(eax));
898 __ j(equal, &check_prototype);
899 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
900 __ cmp(edx, Factory::empty_fixed_array());
901 __ j(not_equal, &call_runtime);
902
903 // Load the prototype from the map and loop if non-null.
904 __ bind(&check_prototype);
905 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
906 __ cmp(ecx, Factory::null_value());
907 __ j(not_equal, &next);
908
909 // The enum cache is valid. Load the map of the object being
910 // iterated over and use the cache for the iteration.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000911 NearLabel use_cache;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000912 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
913 __ jmp(&use_cache);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000914
915 // Get the set of properties to enumerate.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000916 __ bind(&call_runtime);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000917 __ push(eax); // Duplicate the enumerable object on the stack.
918 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
919
920 // If we got a map from the runtime call, we can do a fast
921 // modification check. Otherwise, we got a fixed array, and we have
922 // to do a slow check.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000923 NearLabel fixed_array;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000924 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map());
925 __ j(not_equal, &fixed_array);
926
927 // We got a map in register eax. Get the enumeration cache from it.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000928 __ bind(&use_cache);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000929 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset));
930 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
931 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
932
933 // Setup the four remaining stack slots.
934 __ push(eax); // Map.
935 __ push(edx); // Enumeration cache.
936 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000937 __ push(eax); // Enumeration cache length (as smi).
938 __ push(Immediate(Smi::FromInt(0))); // Initial index.
939 __ jmp(&loop);
940
941 // We got a fixed array in register eax. Iterate through that.
942 __ bind(&fixed_array);
943 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
944 __ push(eax);
945 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000946 __ push(eax); // Fixed array length (as smi).
947 __ push(Immediate(Smi::FromInt(0))); // Initial index.
948
949 // Generate code for doing the condition check.
950 __ bind(&loop);
951 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
952 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
953 __ j(above_equal, loop_statement.break_target());
954
955 // Get the current entry of the array into register ebx.
956 __ mov(ebx, Operand(esp, 2 * kPointerSize));
957 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
958
959 // Get the expected map from the stack or a zero map in the
960 // permanent slow case into register edx.
961 __ mov(edx, Operand(esp, 3 * kPointerSize));
962
963 // Check if the expected map still matches that of the enumerable.
964 // If not, we have to filter the key.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000965 NearLabel update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000966 __ mov(ecx, Operand(esp, 4 * kPointerSize));
967 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
968 __ j(equal, &update_each);
969
970 // Convert the entry to a string or null if it isn't a property
971 // anymore. If the property has been removed while iterating, we
972 // just skip it.
973 __ push(ecx); // Enumerable.
974 __ push(ebx); // Current entry.
975 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000976 __ test(eax, Operand(eax));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000977 __ j(equal, loop_statement.continue_target());
978 __ mov(ebx, Operand(eax));
979
980 // Update the 'each' property or variable from the possibly filtered
981 // entry in register ebx.
982 __ bind(&update_each);
983 __ mov(result_register(), ebx);
984 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000985 { EffectContext context(this);
986 EmitAssignment(stmt->each(), stmt->AssignmentId());
987 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000988
989 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000990 Visit(stmt->body());
991
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000992 // Generate code for going to the next element by incrementing the
993 // index (smi) stored on top of the stack.
994 __ bind(loop_statement.continue_target());
995 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000996
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000997 EmitStackCheck(stmt);
998 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000999
1000 // Remove the pointers stored on the stack.
1001 __ bind(loop_statement.break_target());
1002 __ add(Operand(esp), Immediate(5 * kPointerSize));
1003
1004 // Exit and decrement the loop depth.
1005 __ bind(&exit);
1006 decrement_loop_depth();
1007}
1008
1009
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001010void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1011 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001012 // Use the fast case closure allocation code that allocates in new
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001013 // space for nested functions that don't need literals cloning. If
1014 // we're running with the --always-opt or the --prepare-always-opt
1015 // flag, we need to use the runtime function so that the new function
1016 // we are creating here gets a chance to have its code optimized and
1017 // doesn't just get a copy of the existing unoptimized code.
1018 if (!FLAG_always_opt &&
1019 !FLAG_prepare_always_opt &&
1020 scope()->is_function_scope() &&
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001021 info->num_literals() == 0 &&
1022 !pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001023 FastNewClosureStub stub;
1024 __ push(Immediate(info));
1025 __ CallStub(&stub);
1026 } else {
1027 __ push(esi);
1028 __ push(Immediate(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001029 __ push(Immediate(pretenure
1030 ? Factory::true_value()
1031 : Factory::false_value()));
1032 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001033 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001034 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001035}
1036
1037
1038void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1039 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 EmitVariableLoad(expr->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001041}
1042
1043
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001044void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
1045 Slot* slot,
1046 TypeofState typeof_state,
1047 Label* slow) {
1048 Register context = esi;
1049 Register temp = edx;
1050
1051 Scope* s = scope();
1052 while (s != NULL) {
1053 if (s->num_heap_slots() > 0) {
1054 if (s->calls_eval()) {
1055 // Check that extension is NULL.
1056 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1057 Immediate(0));
1058 __ j(not_equal, slow);
1059 }
1060 // Load next context in chain.
1061 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1062 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1063 // Walk the rest of the chain without clobbering esi.
1064 context = temp;
1065 }
1066 // If no outer scope calls eval, we do not need to check more
1067 // context extensions. If we have reached an eval scope, we check
1068 // all extensions from this point.
1069 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1070 s = s->outer_scope();
1071 }
1072
1073 if (s != NULL && s->is_eval_scope()) {
1074 // Loop up the context chain. There is no frame effect so it is
1075 // safe to use raw labels here.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 NearLabel next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001077 if (!context.is(temp)) {
1078 __ mov(temp, context);
1079 }
1080 __ bind(&next);
1081 // Terminate at global context.
1082 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
1083 Immediate(Factory::global_context_map()));
1084 __ j(equal, &fast);
1085 // Check that extension is NULL.
1086 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1087 __ j(not_equal, slow);
1088 // Load next context in chain.
1089 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX));
1090 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1091 __ jmp(&next);
1092 __ bind(&fast);
1093 }
1094
1095 // All extension objects were empty and it is safe to use a global
1096 // load IC call.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001097 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001098 __ mov(ecx, slot->var()->name());
1099 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1100 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1101 ? RelocInfo::CODE_TARGET
1102 : RelocInfo::CODE_TARGET_CONTEXT;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001103 EmitCallIC(ic, mode);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001104}
1105
1106
1107MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1108 Slot* slot,
1109 Label* slow) {
1110 ASSERT(slot->type() == Slot::CONTEXT);
1111 Register context = esi;
1112 Register temp = ebx;
1113
1114 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1115 if (s->num_heap_slots() > 0) {
1116 if (s->calls_eval()) {
1117 // Check that extension is NULL.
1118 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1119 Immediate(0));
1120 __ j(not_equal, slow);
1121 }
1122 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1123 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1124 // Walk the rest of the chain without clobbering esi.
1125 context = temp;
1126 }
1127 }
1128 // Check that last extension is NULL.
1129 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1130 __ j(not_equal, slow);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001131
1132 // This function is used only for loads, not stores, so it's safe to
1133 // return an esi-based operand (the write barrier cannot be allowed to
1134 // destroy the esi register).
1135 return ContextOperand(context, slot->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001136}
1137
1138
1139void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1140 Slot* slot,
1141 TypeofState typeof_state,
1142 Label* slow,
1143 Label* done) {
1144 // Generate fast-case code for variables that might be shadowed by
1145 // eval-introduced variables. Eval is used a lot without
1146 // introducing variables. In those cases, we do not want to
1147 // perform a runtime call for all variables in the scope
1148 // containing the eval.
1149 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1150 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1151 __ jmp(done);
1152 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001153 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001154 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1155 if (potential_slot != NULL) {
1156 // Generate fast case for locals that rewrite to slots.
1157 __ mov(eax,
1158 ContextSlotOperandCheckExtensions(potential_slot, slow));
1159 if (potential_slot->var()->mode() == Variable::CONST) {
1160 __ cmp(eax, Factory::the_hole_value());
1161 __ j(not_equal, done);
1162 __ mov(eax, Factory::undefined_value());
1163 }
1164 __ jmp(done);
1165 } else if (rewrite != NULL) {
1166 // Generate fast case for calls of an argument function.
1167 Property* property = rewrite->AsProperty();
1168 if (property != NULL) {
1169 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1170 Literal* key_literal = property->key()->AsLiteral();
1171 if (obj_proxy != NULL &&
1172 key_literal != NULL &&
1173 obj_proxy->IsArguments() &&
1174 key_literal->handle()->IsSmi()) {
1175 // Load arguments object if there are no eval-introduced
1176 // variables. Then load the argument from the arguments
1177 // object using keyed load.
1178 __ mov(edx,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001179 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001180 slow));
1181 __ mov(eax, Immediate(key_literal->handle()));
1182 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001183 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001184 __ jmp(done);
1185 }
1186 }
1187 }
1188 }
1189}
1190
1191
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001192void FullCodeGenerator::EmitVariableLoad(Variable* var) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001193 // Four cases: non-this global variables, lookup slots, all other
1194 // types of slots, and parameters that rewrite to explicit property
1195 // accesses on the arguments object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001196 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001197 Property* property = var->AsProperty();
1198
1199 if (var->is_global() && !var->is_this()) {
1200 Comment cmnt(masm_, "Global variable");
1201 // Use inline caching. Variable name is passed in ecx and the global
1202 // object on the stack.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001203 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001204 __ mov(ecx, var->name());
1205 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001206 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001207 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001208
1209 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001210 Label done, slow;
1211
1212 // Generate code for loading from variables potentially shadowed
1213 // by eval-introduced variables.
1214 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1215
1216 __ bind(&slow);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001217 Comment cmnt(masm_, "Lookup slot");
1218 __ push(esi); // Context.
1219 __ push(Immediate(var->name()));
1220 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001221 __ bind(&done);
1222
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001223 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001224
1225 } else if (slot != NULL) {
1226 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1227 ? "Context slot"
1228 : "Stack slot");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001229 if (var->mode() == Variable::CONST) {
1230 // Constants may be the hole value if they have not been initialized.
1231 // Unhole them.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001232 NearLabel done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001233 MemOperand slot_operand = EmitSlotSearch(slot, eax);
1234 __ mov(eax, slot_operand);
1235 __ cmp(eax, Factory::the_hole_value());
1236 __ j(not_equal, &done);
1237 __ mov(eax, Factory::undefined_value());
1238 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001239 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001240 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001241 context()->Plug(slot);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001242 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001243
1244 } else {
1245 Comment cmnt(masm_, "Rewritten parameter");
1246 ASSERT_NOT_NULL(property);
1247 // Rewritten parameter accesses are of the form "slot[literal]".
1248
1249 // Assert that the object is in a slot.
1250 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1251 ASSERT_NOT_NULL(object_var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001252 Slot* object_slot = object_var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001253 ASSERT_NOT_NULL(object_slot);
1254
1255 // Load the object.
1256 MemOperand object_loc = EmitSlotSearch(object_slot, eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001257 __ mov(edx, object_loc);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001258
1259 // Assert that the key is a smi.
1260 Literal* key_literal = property->key()->AsLiteral();
1261 ASSERT_NOT_NULL(key_literal);
1262 ASSERT(key_literal->handle()->IsSmi());
1263
1264 // Load the key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001265 __ mov(eax, Immediate(key_literal->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001266
1267 // Do a keyed property load.
1268 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001269 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1270
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001271 // Drop key and object left on the stack by IC.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001272 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001273 }
1274}
1275
1276
1277void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1278 Comment cmnt(masm_, "[ RegExpLiteral");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001279 NearLabel materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001280 // Registers will be used as follows:
1281 // edi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001282 // ecx = literals array.
1283 // ebx = regexp literal.
1284 // eax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001285 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001286 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001287 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001288 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001289 __ mov(ebx, FieldOperand(ecx, literal_offset));
1290 __ cmp(ebx, Factory::undefined_value());
1291 __ j(not_equal, &materialized);
1292
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001293 // Create regexp literal using runtime function
1294 // Result will be in eax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001295 __ push(ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001296 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1297 __ push(Immediate(expr->pattern()));
1298 __ push(Immediate(expr->flags()));
1299 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001300 __ mov(ebx, eax);
1301
1302 __ bind(&materialized);
1303 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1304 Label allocated, runtime_allocate;
1305 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1306 __ jmp(&allocated);
1307
1308 __ bind(&runtime_allocate);
1309 __ push(ebx);
1310 __ push(Immediate(Smi::FromInt(size)));
1311 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1312 __ pop(ebx);
1313
1314 __ bind(&allocated);
1315 // Copy the content into the newly allocated memory.
1316 // (Unroll copy loop once for better throughput).
1317 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1318 __ mov(edx, FieldOperand(ebx, i));
1319 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1320 __ mov(FieldOperand(eax, i), edx);
1321 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1322 }
1323 if ((size % (2 * kPointerSize)) != 0) {
1324 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1325 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1326 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001327 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001328}
1329
1330
1331void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1332 Comment cmnt(masm_, "[ ObjectLiteral");
1333 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1334 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1335 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1336 __ push(Immediate(expr->constant_properties()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001337 __ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001338 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001339 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001340 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001341 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001342 }
1343
1344 // If result_saved is true the result is on top of the stack. If
1345 // result_saved is false the result is in eax.
1346 bool result_saved = false;
1347
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001348 // Mark all computed expressions that are bound to a key that
1349 // is shadowed by a later occurrence of the same key. For the
1350 // marked expressions, no store code is emitted.
1351 expr->CalculateEmitStore();
1352
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001353 for (int i = 0; i < expr->properties()->length(); i++) {
1354 ObjectLiteral::Property* property = expr->properties()->at(i);
1355 if (property->IsCompileTimeValue()) continue;
1356
1357 Literal* key = property->key();
1358 Expression* value = property->value();
1359 if (!result_saved) {
1360 __ push(eax); // Save result on the stack
1361 result_saved = true;
1362 }
1363 switch (property->kind()) {
1364 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1365 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1366 // Fall through.
1367 case ObjectLiteral::Property::COMPUTED:
1368 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001369 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001370 VisitForAccumulatorValue(value);
1371 __ mov(ecx, Immediate(key->handle()));
1372 __ mov(edx, Operand(esp, 0));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001373 Handle<Code> ic(Builtins::builtin(
1374 is_strict() ? Builtins::StoreIC_Initialize_Strict
1375 : Builtins::StoreIC_Initialize));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001376 EmitCallIC(ic, RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001377 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1378 } else {
1379 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001380 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001381 break;
1382 }
1383 // Fall through.
1384 case ObjectLiteral::Property::PROTOTYPE:
1385 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001386 VisitForStackValue(key);
1387 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001388 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001389 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1390 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001391 } else {
1392 __ Drop(3);
1393 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001394 break;
1395 case ObjectLiteral::Property::SETTER:
1396 case ObjectLiteral::Property::GETTER:
1397 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001398 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001399 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
1400 Smi::FromInt(1) :
1401 Smi::FromInt(0)));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001402 VisitForStackValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001403 __ CallRuntime(Runtime::kDefineAccessor, 4);
1404 break;
1405 default: UNREACHABLE();
1406 }
1407 }
1408
1409 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001410 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001411 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001412 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001413 }
1414}
1415
1416
1417void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1418 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001419
1420 ZoneList<Expression*>* subexprs = expr->values();
1421 int length = subexprs->length();
1422
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001423 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1424 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1425 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1426 __ push(Immediate(expr->constant_elements()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001427 if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001428 ASSERT(expr->depth() == 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001429 FastCloneShallowArrayStub stub(
1430 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1431 __ CallStub(&stub);
1432 __ IncrementCounter(&Counters::cow_arrays_created_stub, 1);
1433 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001434 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001435 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001436 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001437 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001438 FastCloneShallowArrayStub stub(
1439 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001440 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001441 }
1442
1443 bool result_saved = false; // Is the result saved to the stack?
1444
1445 // Emit code to evaluate all the non-constant subexpressions and to store
1446 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001447 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001448 Expression* subexpr = subexprs->at(i);
1449 // If the subexpression is a literal or a simple materialized literal it
1450 // is already set in the cloned array.
1451 if (subexpr->AsLiteral() != NULL ||
1452 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1453 continue;
1454 }
1455
1456 if (!result_saved) {
1457 __ push(eax);
1458 result_saved = true;
1459 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001460 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001461
1462 // Store the subexpression value in the array's elements.
1463 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1464 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1465 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1466 __ mov(FieldOperand(ebx, offset), result_register());
1467
1468 // Update the write barrier for the array store.
1469 __ RecordWrite(ebx, offset, result_register(), ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001470
1471 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001472 }
1473
1474 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001475 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001476 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001477 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001478 }
1479}
1480
1481
ager@chromium.org5c838252010-02-19 08:53:10 +00001482void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1483 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001484 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1485 // on the left-hand side.
1486 if (!expr->target()->IsValidLeftHandSide()) {
1487 VisitForEffect(expr->target());
1488 return;
1489 }
1490
ager@chromium.org5c838252010-02-19 08:53:10 +00001491 // Left-hand side can only be a property, a global or a (parameter or local)
1492 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1493 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1494 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001495 Property* property = expr->target()->AsProperty();
1496 if (property != NULL) {
1497 assign_type = (property->key()->IsPropertyName())
1498 ? NAMED_PROPERTY
1499 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001500 }
1501
1502 // Evaluate LHS expression.
1503 switch (assign_type) {
1504 case VARIABLE:
1505 // Nothing to do here.
1506 break;
1507 case NAMED_PROPERTY:
1508 if (expr->is_compound()) {
1509 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001510 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001511 __ push(result_register());
1512 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001513 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001514 }
1515 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001516 case KEYED_PROPERTY: {
ager@chromium.org5c838252010-02-19 08:53:10 +00001517 if (expr->is_compound()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001518 if (property->is_arguments_access()) {
1519 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001520 MemOperand slot_operand =
1521 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
1522 __ push(slot_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001523 __ mov(eax, Immediate(property->key()->AsLiteral()->handle()));
1524 } else {
1525 VisitForStackValue(property->obj());
1526 VisitForAccumulatorValue(property->key());
1527 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001528 __ mov(edx, Operand(esp, 0));
1529 __ push(eax);
1530 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001531 if (property->is_arguments_access()) {
1532 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001533 MemOperand slot_operand =
1534 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
1535 __ push(slot_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001536 __ push(Immediate(property->key()->AsLiteral()->handle()));
1537 } else {
1538 VisitForStackValue(property->obj());
1539 VisitForStackValue(property->key());
1540 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001541 }
1542 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001543 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001544 }
1545
ager@chromium.org5c838252010-02-19 08:53:10 +00001546 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001547 { AccumulatorValueContext context(this);
1548 switch (assign_type) {
1549 case VARIABLE:
1550 EmitVariableLoad(expr->target()->AsVariableProxy()->var());
1551 break;
1552 case NAMED_PROPERTY:
1553 EmitNamedPropertyLoad(property);
1554 break;
1555 case KEYED_PROPERTY:
1556 EmitKeyedPropertyLoad(property);
1557 break;
1558 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001559 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001560
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001561 // For property compound assignments we need another deoptimization
1562 // point after the property load.
1563 if (property != NULL) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001564 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001565 }
1566
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001567 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001568 __ push(eax); // Left operand goes on the stack.
1569 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001570
ricow@chromium.org65fae842010-08-25 15:26:24 +00001571 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1572 ? OVERWRITE_RIGHT
1573 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001574 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001575 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001576 if (ShouldInlineSmiCase(op)) {
1577 EmitInlineSmiBinaryOp(expr,
1578 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001579 mode,
1580 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001581 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001582 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001583 EmitBinaryOp(op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001584 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001585
1586 // Deoptimization point in case the binary operation may have side effects.
1587 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001588 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001589 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001590 }
1591
1592 // Record source position before possible IC call.
1593 SetSourcePosition(expr->position());
1594
1595 // Store the value.
1596 switch (assign_type) {
1597 case VARIABLE:
1598 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001599 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001600 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1601 context()->Plug(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001602 break;
1603 case NAMED_PROPERTY:
1604 EmitNamedPropertyAssignment(expr);
1605 break;
1606 case KEYED_PROPERTY:
1607 EmitKeyedPropertyAssignment(expr);
1608 break;
1609 }
1610}
1611
1612
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001613void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1614 SetSourcePosition(prop->position());
1615 Literal* key = prop->key()->AsLiteral();
1616 __ mov(ecx, Immediate(key->handle()));
1617 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001618 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001619}
1620
1621
1622void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1623 SetSourcePosition(prop->position());
1624 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001625 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001626}
1627
1628
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001629void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1630 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001631 OverwriteMode mode,
1632 Expression* left,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001633 Expression* right) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001634 // Do combined smi check of the operands. Left operand is on the
1635 // stack. Right operand is in eax.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001636 NearLabel done, smi_case, stub_call;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001637 __ pop(edx);
1638 __ mov(ecx, eax);
1639 __ or_(eax, Operand(edx));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001640 JumpPatchSite patch_site(masm_);
1641 patch_site.EmitJumpIfSmi(eax, &smi_case);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001642
1643 __ bind(&stub_call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001644 __ mov(eax, ecx);
1645 TypeRecordingBinaryOpStub stub(op, mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001646 EmitCallIC(stub.GetCode(), &patch_site);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001647 __ jmp(&done);
1648
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001649 // Smi case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001650 __ bind(&smi_case);
1651 __ mov(eax, edx); // Copy left operand in case of a stub call.
1652
1653 switch (op) {
1654 case Token::SAR:
1655 __ SmiUntag(eax);
1656 __ SmiUntag(ecx);
1657 __ sar_cl(eax); // No checks of result necessary
1658 __ SmiTag(eax);
1659 break;
1660 case Token::SHL: {
1661 Label result_ok;
1662 __ SmiUntag(eax);
1663 __ SmiUntag(ecx);
1664 __ shl_cl(eax);
1665 // Check that the *signed* result fits in a smi.
1666 __ cmp(eax, 0xc0000000);
1667 __ j(positive, &result_ok);
1668 __ SmiTag(ecx);
1669 __ jmp(&stub_call);
1670 __ bind(&result_ok);
1671 __ SmiTag(eax);
1672 break;
1673 }
1674 case Token::SHR: {
1675 Label result_ok;
1676 __ SmiUntag(eax);
1677 __ SmiUntag(ecx);
1678 __ shr_cl(eax);
1679 __ test(eax, Immediate(0xc0000000));
1680 __ j(zero, &result_ok);
1681 __ SmiTag(ecx);
1682 __ jmp(&stub_call);
1683 __ bind(&result_ok);
1684 __ SmiTag(eax);
1685 break;
1686 }
1687 case Token::ADD:
1688 __ add(eax, Operand(ecx));
1689 __ j(overflow, &stub_call);
1690 break;
1691 case Token::SUB:
1692 __ sub(eax, Operand(ecx));
1693 __ j(overflow, &stub_call);
1694 break;
1695 case Token::MUL: {
1696 __ SmiUntag(eax);
1697 __ imul(eax, Operand(ecx));
1698 __ j(overflow, &stub_call);
1699 __ test(eax, Operand(eax));
1700 __ j(not_zero, &done, taken);
1701 __ mov(ebx, edx);
1702 __ or_(ebx, Operand(ecx));
1703 __ j(negative, &stub_call);
1704 break;
1705 }
1706 case Token::BIT_OR:
1707 __ or_(eax, Operand(ecx));
1708 break;
1709 case Token::BIT_AND:
1710 __ and_(eax, Operand(ecx));
1711 break;
1712 case Token::BIT_XOR:
1713 __ xor_(eax, Operand(ecx));
1714 break;
1715 default:
1716 UNREACHABLE();
1717 }
1718
1719 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001720 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001721}
1722
1723
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001724void FullCodeGenerator::EmitBinaryOp(Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001725 OverwriteMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001726 __ pop(edx);
1727 TypeRecordingBinaryOpStub stub(op, mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001728 EmitCallIC(stub.GetCode(), NULL); // NULL signals no inlined smi code.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001729 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001730}
1731
1732
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001733void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001734 // Invalid left-hand sides are rewritten to have a 'throw
1735 // ReferenceError' on the left-hand side.
1736 if (!expr->IsValidLeftHandSide()) {
1737 VisitForEffect(expr);
1738 return;
1739 }
1740
1741 // Left-hand side can only be a property, a global or a (parameter or local)
1742 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1743 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1744 LhsKind assign_type = VARIABLE;
1745 Property* prop = expr->AsProperty();
1746 if (prop != NULL) {
1747 assign_type = (prop->key()->IsPropertyName())
1748 ? NAMED_PROPERTY
1749 : KEYED_PROPERTY;
1750 }
1751
1752 switch (assign_type) {
1753 case VARIABLE: {
1754 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001755 EffectContext context(this);
1756 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001757 break;
1758 }
1759 case NAMED_PROPERTY: {
1760 __ push(eax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001761 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001762 __ mov(edx, eax);
1763 __ pop(eax); // Restore value.
1764 __ mov(ecx, prop->key()->AsLiteral()->handle());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001765 Handle<Code> ic(Builtins::builtin(
1766 is_strict() ? Builtins::StoreIC_Initialize_Strict
1767 : Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001768 EmitCallIC(ic, RelocInfo::CODE_TARGET);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001769 break;
1770 }
1771 case KEYED_PROPERTY: {
1772 __ push(eax); // Preserve value.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001773 if (prop->is_synthetic()) {
1774 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1775 ASSERT(prop->key()->AsLiteral() != NULL);
1776 { AccumulatorValueContext for_object(this);
1777 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1778 }
1779 __ mov(edx, eax);
1780 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
1781 } else {
1782 VisitForStackValue(prop->obj());
1783 VisitForAccumulatorValue(prop->key());
1784 __ mov(ecx, eax);
1785 __ pop(edx);
1786 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001787 __ pop(eax); // Restore value.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001788 Handle<Code> ic(Builtins::builtin(
1789 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
1790 : Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001791 EmitCallIC(ic, RelocInfo::CODE_TARGET);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001792 break;
1793 }
1794 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001795 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1796 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001797}
1798
1799
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001800void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001801 Token::Value op) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001802 // Left-hand sides that rewrite to explicit property accesses do not reach
1803 // here.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001804 ASSERT(var != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001805 ASSERT(var->is_global() || var->AsSlot() != NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001806
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001807 if (var->is_global()) {
1808 ASSERT(!var->is_this());
1809 // Assignment to a global variable. Use inline caching for the
1810 // assignment. Right-hand-side value is passed in eax, variable name in
1811 // ecx, and the global object on the stack.
1812 __ mov(ecx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001813 __ mov(edx, GlobalObjectOperand());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001814 Handle<Code> ic(Builtins::builtin(
1815 is_strict() ? Builtins::StoreIC_Initialize_Strict
1816 : Builtins::StoreIC_Initialize));
1817 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001818
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001819 } else if (op == Token::INIT_CONST) {
1820 // Like var declarations, const declarations are hoisted to function
1821 // scope. However, unlike var initializers, const initializers are able
1822 // to drill a hole to that function context, even from inside a 'with'
1823 // context. We thus bypass the normal static scope lookup.
1824 Slot* slot = var->AsSlot();
1825 Label skip;
1826 switch (slot->type()) {
1827 case Slot::PARAMETER:
1828 // No const parameters.
1829 UNREACHABLE();
1830 break;
1831 case Slot::LOCAL:
1832 __ mov(edx, Operand(ebp, SlotOffset(slot)));
1833 __ cmp(edx, Factory::the_hole_value());
1834 __ j(not_equal, &skip);
1835 __ mov(Operand(ebp, SlotOffset(slot)), eax);
1836 break;
1837 case Slot::CONTEXT: {
1838 __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX));
1839 __ mov(edx, ContextOperand(ecx, slot->index()));
1840 __ cmp(edx, Factory::the_hole_value());
1841 __ j(not_equal, &skip);
1842 __ mov(ContextOperand(ecx, slot->index()), eax);
1843 int offset = Context::SlotOffset(slot->index());
1844 __ mov(edx, eax); // Preserve the stored value in eax.
1845 __ RecordWrite(ecx, offset, edx, ebx);
1846 break;
1847 }
1848 case Slot::LOOKUP:
1849 __ push(eax);
1850 __ push(esi);
1851 __ push(Immediate(var->name()));
1852 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1853 break;
1854 }
1855 __ bind(&skip);
1856
1857 } else if (var->mode() != Variable::CONST) {
1858 // Perform the assignment for non-const variables. Const assignments
1859 // are simply skipped.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001860 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001861 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001862 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001863 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001864 // Perform the assignment.
1865 __ mov(Operand(ebp, SlotOffset(slot)), eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001866 break;
1867
1868 case Slot::CONTEXT: {
1869 MemOperand target = EmitSlotSearch(slot, ecx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001870 // Perform the assignment and issue the write barrier.
1871 __ mov(target, eax);
1872 // The value of the assignment is in eax. RecordWrite clobbers its
1873 // register arguments.
1874 __ mov(edx, eax);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001875 int offset = Context::SlotOffset(slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001876 __ RecordWrite(ecx, offset, edx, ebx);
1877 break;
1878 }
1879
1880 case Slot::LOOKUP:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001881 // Call the runtime for the assignment.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001882 __ push(eax); // Value.
1883 __ push(esi); // Context.
1884 __ push(Immediate(var->name()));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001885 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
1886 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001887 break;
1888 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001889 }
1890}
1891
1892
1893void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1894 // Assignment to a property, using a named store IC.
1895 Property* prop = expr->target()->AsProperty();
1896 ASSERT(prop != NULL);
1897 ASSERT(prop->key()->AsLiteral() != NULL);
1898
1899 // If the assignment starts a block of assignments to the same object,
1900 // change to slow case to avoid the quadratic behavior of repeatedly
1901 // adding fast properties.
1902 if (expr->starts_initialization_block()) {
1903 __ push(result_register());
1904 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
1905 __ CallRuntime(Runtime::kToSlowProperties, 1);
1906 __ pop(result_register());
1907 }
1908
1909 // Record source code position before IC call.
1910 SetSourcePosition(expr->position());
1911 __ mov(ecx, prop->key()->AsLiteral()->handle());
1912 if (expr->ends_initialization_block()) {
1913 __ mov(edx, Operand(esp, 0));
1914 } else {
1915 __ pop(edx);
1916 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001917 Handle<Code> ic(Builtins::builtin(
1918 is_strict() ? Builtins::StoreIC_Initialize_Strict
1919 : Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001920 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001921
1922 // If the assignment ends an initialization block, revert to fast case.
1923 if (expr->ends_initialization_block()) {
1924 __ push(eax); // Result of assignment, saved even if not needed.
1925 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
1926 __ CallRuntime(Runtime::kToFastProperties, 1);
1927 __ pop(eax);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001928 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001929 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001930 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1931 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001932}
1933
1934
1935void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1936 // Assignment to a property, using a keyed store IC.
1937
1938 // If the assignment starts a block of assignments to the same object,
1939 // change to slow case to avoid the quadratic behavior of repeatedly
1940 // adding fast properties.
1941 if (expr->starts_initialization_block()) {
1942 __ push(result_register());
1943 // Receiver is now under the key and value.
1944 __ push(Operand(esp, 2 * kPointerSize));
1945 __ CallRuntime(Runtime::kToSlowProperties, 1);
1946 __ pop(result_register());
1947 }
1948
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001949 __ pop(ecx);
1950 if (expr->ends_initialization_block()) {
1951 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
1952 } else {
1953 __ pop(edx);
1954 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001955 // Record source code position before IC call.
1956 SetSourcePosition(expr->position());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001957 Handle<Code> ic(Builtins::builtin(
1958 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
1959 : Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001960 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001961
1962 // If the assignment ends an initialization block, revert to fast case.
1963 if (expr->ends_initialization_block()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001964 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001965 __ push(eax); // Result of assignment, saved even if not needed.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001966 __ push(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001967 __ CallRuntime(Runtime::kToFastProperties, 1);
1968 __ pop(eax);
1969 }
1970
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001971 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001972 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001973}
1974
1975
1976void FullCodeGenerator::VisitProperty(Property* expr) {
1977 Comment cmnt(masm_, "[ Property");
1978 Expression* key = expr->key();
1979
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001980 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001981 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001982 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001983 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001984 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001985 VisitForStackValue(expr->obj());
1986 VisitForAccumulatorValue(expr->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00001987 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001988 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001989 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001990 }
1991}
1992
1993
1994void FullCodeGenerator::EmitCallWithIC(Call* expr,
1995 Handle<Object> name,
1996 RelocInfo::Mode mode) {
1997 // Code common for calls using the IC.
1998 ZoneList<Expression*>* args = expr->arguments();
1999 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002000 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002001 for (int i = 0; i < arg_count; i++) {
2002 VisitForStackValue(args->at(i));
2003 }
2004 __ Set(ecx, Immediate(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002005 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002006 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002007 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002008 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002009 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002010 EmitCallIC(ic, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002011 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002012 // Restore context register.
2013 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002014 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002015}
2016
2017
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002018void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
2019 Expression* key,
2020 RelocInfo::Mode mode) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002021 // Load the key.
2022 VisitForAccumulatorValue(key);
2023
2024 // Swap the name of the function and the receiver on the stack to follow
2025 // the calling convention for call ICs.
2026 __ pop(ecx);
2027 __ push(eax);
2028 __ push(ecx);
2029
2030 // Load the arguments.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002031 ZoneList<Expression*>* args = expr->arguments();
2032 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002033 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002034 for (int i = 0; i < arg_count; i++) {
2035 VisitForStackValue(args->at(i));
2036 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002037 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002038 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002039 SetSourcePosition(expr->position());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002040 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002041 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
2042 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002043 EmitCallIC(ic, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002044 RecordJSReturnSite(expr);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002045 // Restore context register.
2046 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002047 context()->DropAndPlug(1, eax); // Drop the key still on the stack.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002048}
2049
2050
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002051void FullCodeGenerator::EmitCallWithStub(Call* expr) {
2052 // Code common for calls using the call stub.
2053 ZoneList<Expression*>* args = expr->arguments();
2054 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002055 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002056 for (int i = 0; i < arg_count; i++) {
2057 VisitForStackValue(args->at(i));
2058 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002059 }
2060 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002061 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002062 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2063 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002064 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002065 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002066 // Restore context register.
2067 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002068 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002069}
2070
2071
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002072void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2073 int arg_count) {
2074 // Push copy of the first argument or undefined if it doesn't exist.
2075 if (arg_count > 0) {
2076 __ push(Operand(esp, arg_count * kPointerSize));
2077 } else {
2078 __ push(Immediate(Factory::undefined_value()));
2079 }
2080
2081 // Push the receiver of the enclosing function.
2082 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
2083
2084 // Push the strict mode flag.
2085 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
2086
2087 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2088 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2089 : Runtime::kResolvePossiblyDirectEval, 4);
2090}
2091
2092
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002093void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002094#ifdef DEBUG
2095 // We want to verify that RecordJSReturnSite gets called on all paths
2096 // through this function. Avoid early returns.
2097 expr->return_is_recorded_ = false;
2098#endif
2099
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002100 Comment cmnt(masm_, "[ Call");
2101 Expression* fun = expr->expression();
2102 Variable* var = fun->AsVariableProxy()->AsVariable();
2103
2104 if (var != NULL && var->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002105 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2106 // resolve the function we need to call and the receiver of the
2107 // call. Then we call the resolved function using the given
2108 // arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002109 ZoneList<Expression*>* args = expr->arguments();
2110 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002111 { PreservePositionScope pos_scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002112 VisitForStackValue(fun);
2113 // Reserved receiver slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002114 __ push(Immediate(Factory::undefined_value()));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002115
2116 // Push the arguments.
2117 for (int i = 0; i < arg_count; i++) {
2118 VisitForStackValue(args->at(i));
2119 }
2120
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002121 // If we know that eval can only be shadowed by eval-introduced
2122 // variables we attempt to load the global eval function directly
2123 // in generated code. If we succeed, there is no need to perform a
2124 // context lookup in the runtime system.
2125 Label done;
2126 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2127 Label slow;
2128 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2129 NOT_INSIDE_TYPEOF,
2130 &slow);
2131 // Push the function and resolve eval.
2132 __ push(eax);
2133 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2134 __ jmp(&done);
2135 __ bind(&slow);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002136 }
2137
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002138 // Push copy of the function (found below the arguments) and
2139 // resolve eval.
2140 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2141 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2142 if (done.is_linked()) {
2143 __ bind(&done);
2144 }
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002145
2146 // The runtime call returns a pair of values in eax (function) and
2147 // edx (receiver). Touch up the stack with the right values.
2148 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2149 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002150 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002151 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002152 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002153 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2154 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
2155 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002156 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002157 // Restore context register.
2158 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002159 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002160 } else if (var != NULL && !var->is_this() && var->is_global()) {
2161 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002162 __ push(GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002163 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002164 } else if (var != NULL && var->AsSlot() != NULL &&
2165 var->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002166 // Call to a lookup slot (dynamically introduced variable).
2167 Label slow, done;
2168
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002169 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002170 // Generate code for loading from variables potentially shadowed
2171 // by eval-introduced variables.
2172 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
2173 NOT_INSIDE_TYPEOF,
2174 &slow,
2175 &done);
2176 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002177
2178 __ bind(&slow);
2179 // Call the runtime to find the function to call (returned in eax)
2180 // and the object holding it (returned in edx).
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002181 __ push(context_register());
2182 __ push(Immediate(var->name()));
2183 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2184 __ push(eax); // Function.
2185 __ push(edx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002186
2187 // If fast case code has been generated, emit code to push the
2188 // function and receiver and have the slow path jump around this
2189 // code.
2190 if (done.is_linked()) {
2191 Label call;
2192 __ jmp(&call);
2193 __ bind(&done);
2194 // Push function.
2195 __ push(eax);
2196 // Push global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002197 __ mov(ebx, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002198 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2199 __ bind(&call);
2200 }
2201
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002202 EmitCallWithStub(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002203 } else if (fun->AsProperty() != NULL) {
2204 // Call to an object property.
2205 Property* prop = fun->AsProperty();
2206 Literal* key = prop->key()->AsLiteral();
2207 if (key != NULL && key->handle()->IsSymbol()) {
2208 // Call to a named property, use call IC.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002209 { PreservePositionScope scope(masm()->positions_recorder());
2210 VisitForStackValue(prop->obj());
2211 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002212 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
2213 } else {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002214 // Call to a keyed property.
2215 // For a synthetic property use keyed load IC followed by function call,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002216 // for a regular property use keyed EmitCallIC.
ager@chromium.org5c838252010-02-19 08:53:10 +00002217 if (prop->is_synthetic()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002218 // Do not visit the object and key subexpressions (they are shared
2219 // by all occurrences of the same rewritten parameter).
2220 ASSERT(prop->obj()->AsVariableProxy() != NULL);
2221 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
2222 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
2223 MemOperand operand = EmitSlotSearch(slot, edx);
2224 __ mov(edx, operand);
2225
2226 ASSERT(prop->key()->AsLiteral() != NULL);
2227 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
2228 __ mov(eax, prop->key()->AsLiteral()->handle());
2229
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002230 // Record source code position for IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002231 SetSourcePosition(prop->position());
ager@chromium.org5c838252010-02-19 08:53:10 +00002232
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002233 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002234 EmitCallIC(ic, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +00002235 // Push result (function).
2236 __ push(eax);
2237 // Push Global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002238 __ mov(ecx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002239 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002240 EmitCallWithStub(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002241 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002242 { PreservePositionScope scope(masm()->positions_recorder());
2243 VisitForStackValue(prop->obj());
2244 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002245 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002246 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002247 }
2248 } else {
2249 // Call to some other expression. If the expression is an anonymous
2250 // function literal not called in a loop, mark it as one that should
2251 // also use the full code generator.
2252 FunctionLiteral* lit = fun->AsFunctionLiteral();
2253 if (lit != NULL &&
2254 lit->name()->Equals(Heap::empty_string()) &&
2255 loop_depth() == 0) {
2256 lit->set_try_full_codegen(true);
2257 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002258 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002259 VisitForStackValue(fun);
2260 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002261 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002262 __ mov(ebx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002263 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2264 // Emit function call.
2265 EmitCallWithStub(expr);
2266 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002267
2268#ifdef DEBUG
2269 // RecordJSReturnSite should have been called.
2270 ASSERT(expr->return_is_recorded_);
2271#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002272}
2273
2274
2275void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2276 Comment cmnt(masm_, "[ CallNew");
2277 // According to ECMA-262, section 11.2.2, page 44, the function
2278 // expression in new calls must be evaluated before the
2279 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002280
ricow@chromium.org65fae842010-08-25 15:26:24 +00002281 // Push constructor on the stack. If it's not a function it's used as
2282 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2283 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002284 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002285
2286 // Push the arguments ("left-to-right") on the stack.
2287 ZoneList<Expression*>* args = expr->arguments();
2288 int arg_count = args->length();
2289 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002290 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002291 }
2292
2293 // Call the construct call builtin that handles allocation and
2294 // constructor invocation.
2295 SetSourcePosition(expr->position());
2296
ricow@chromium.org65fae842010-08-25 15:26:24 +00002297 // Load function and argument count into edi and eax.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002298 __ Set(eax, Immediate(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002299 __ mov(edi, Operand(esp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002300
2301 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
2302 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002303 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002304}
2305
2306
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002307void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2308 ASSERT(args->length() == 1);
2309
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002310 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002311
2312 Label materialize_true, materialize_false;
2313 Label* if_true = NULL;
2314 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002315 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002316 context()->PrepareTest(&materialize_true, &materialize_false,
2317 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002318
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002319 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002320 __ test(eax, Immediate(kSmiTagMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002321 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002322
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002323 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002324}
2325
2326
2327void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2328 ASSERT(args->length() == 1);
2329
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002330 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002331
2332 Label materialize_true, materialize_false;
2333 Label* if_true = NULL;
2334 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002335 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002336 context()->PrepareTest(&materialize_true, &materialize_false,
2337 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002338
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002339 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002340 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002341 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002342
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002343 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002344}
2345
2346
2347void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2348 ASSERT(args->length() == 1);
2349
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002350 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002351
2352 Label materialize_true, materialize_false;
2353 Label* if_true = NULL;
2354 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002355 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002356 context()->PrepareTest(&materialize_true, &materialize_false,
2357 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002358
2359 __ test(eax, Immediate(kSmiTagMask));
2360 __ j(zero, if_false);
2361 __ cmp(eax, Factory::null_value());
2362 __ j(equal, if_true);
2363 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2364 // Undetectable objects behave like undefined when tested with typeof.
2365 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2366 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2367 __ j(not_zero, if_false);
2368 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2369 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
2370 __ j(below, if_false);
2371 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002372 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002373 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002374
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002375 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002376}
2377
2378
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002379void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2380 ASSERT(args->length() == 1);
2381
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002382 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002383
2384 Label materialize_true, materialize_false;
2385 Label* if_true = NULL;
2386 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002387 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002388 context()->PrepareTest(&materialize_true, &materialize_false,
2389 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002390
2391 __ test(eax, Immediate(kSmiTagMask));
2392 __ j(equal, if_false);
2393 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
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(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002396
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002397 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002398}
2399
2400
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002401void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2402 ASSERT(args->length() == 1);
2403
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002404 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +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);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002412
2413 __ test(eax, Immediate(kSmiTagMask));
2414 __ j(zero, if_false);
2415 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2416 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2417 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002418 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002419 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002420
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002421 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002422}
2423
2424
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002425void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2426 ZoneList<Expression*>* args) {
2427 ASSERT(args->length() == 1);
2428
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002429 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002430
2431 Label materialize_true, materialize_false;
2432 Label* if_true = NULL;
2433 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002434 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002435 context()->PrepareTest(&materialize_true, &materialize_false,
2436 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002437
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002438 // TODO(3110205): Implement this.
2439 // Currently unimplemented. Emit false, a safe choice.
2440 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002441 __ jmp(if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002442 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002443}
2444
2445
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002446void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2447 ASSERT(args->length() == 1);
2448
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002449 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002450
2451 Label materialize_true, materialize_false;
2452 Label* if_true = NULL;
2453 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002454 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002455 context()->PrepareTest(&materialize_true, &materialize_false,
2456 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002457
2458 __ test(eax, Immediate(kSmiTagMask));
2459 __ j(zero, if_false);
2460 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002461 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002462 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002463
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002464 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002465}
2466
2467
2468void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2469 ASSERT(args->length() == 1);
2470
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002471 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002472
2473 Label materialize_true, materialize_false;
2474 Label* if_true = NULL;
2475 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002476 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002477 context()->PrepareTest(&materialize_true, &materialize_false,
2478 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002479
2480 __ test(eax, Immediate(kSmiTagMask));
2481 __ j(equal, if_false);
2482 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002483 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002484 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002485
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002486 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002487}
2488
2489
2490void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2491 ASSERT(args->length() == 1);
2492
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002493 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002494
2495 Label materialize_true, materialize_false;
2496 Label* if_true = NULL;
2497 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002498 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002499 context()->PrepareTest(&materialize_true, &materialize_false,
2500 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002501
2502 __ test(eax, Immediate(kSmiTagMask));
2503 __ j(equal, if_false);
2504 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002505 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002506 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002507
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002508 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002509}
2510
2511
2512
2513void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2514 ASSERT(args->length() == 0);
2515
2516 Label materialize_true, materialize_false;
2517 Label* if_true = NULL;
2518 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002519 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002520 context()->PrepareTest(&materialize_true, &materialize_false,
2521 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002522
2523 // Get the frame pointer for the calling frame.
2524 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2525
2526 // Skip the arguments adaptor frame if it exists.
2527 Label check_frame_marker;
2528 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2529 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2530 __ j(not_equal, &check_frame_marker);
2531 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2532
2533 // Check the marker in the calling frame.
2534 __ bind(&check_frame_marker);
2535 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2536 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002537 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002538 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002539
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002540 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002541}
2542
2543
2544void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2545 ASSERT(args->length() == 2);
2546
2547 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002548 VisitForStackValue(args->at(0));
2549 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002550
2551 Label materialize_true, materialize_false;
2552 Label* if_true = NULL;
2553 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002554 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002555 context()->PrepareTest(&materialize_true, &materialize_false,
2556 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002557
2558 __ pop(ebx);
2559 __ cmp(eax, Operand(ebx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002560 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002561 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002562
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002563 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002564}
2565
2566
2567void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2568 ASSERT(args->length() == 1);
2569
2570 // ArgumentsAccessStub expects the key in edx and the formal
2571 // parameter count in eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002572 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002573 __ mov(edx, eax);
2574 __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2575 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2576 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002577 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002578}
2579
2580
2581void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2582 ASSERT(args->length() == 0);
2583
2584 Label exit;
2585 // Get the number of formal parameters.
2586 __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2587
2588 // Check if the calling frame is an arguments adaptor frame.
2589 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2590 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2591 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2592 __ j(not_equal, &exit);
2593
2594 // Arguments adaptor case: Read the arguments length from the
2595 // adaptor frame.
2596 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2597
2598 __ bind(&exit);
2599 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002600 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002601}
2602
2603
2604void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2605 ASSERT(args->length() == 1);
2606 Label done, null, function, non_function_constructor;
2607
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002608 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002609
2610 // If the object is a smi, we return null.
2611 __ test(eax, Immediate(kSmiTagMask));
2612 __ j(zero, &null);
2613
2614 // Check that the object is a JS object but take special care of JS
2615 // functions to make sure they have 'Function' as their class.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002616 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, eax); // Map is now in eax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002617 __ j(below, &null);
2618
2619 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2620 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2621 // LAST_JS_OBJECT_TYPE.
2622 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2623 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002624 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002625 __ j(equal, &function);
2626
2627 // Check if the constructor in the map is a function.
2628 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2629 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2630 __ j(not_equal, &non_function_constructor);
2631
2632 // eax now contains the constructor function. Grab the
2633 // instance class name from there.
2634 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2635 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2636 __ jmp(&done);
2637
2638 // Functions have class 'Function'.
2639 __ bind(&function);
2640 __ mov(eax, Factory::function_class_symbol());
2641 __ jmp(&done);
2642
2643 // Objects with a non-function constructor have class 'Object'.
2644 __ bind(&non_function_constructor);
2645 __ mov(eax, Factory::Object_symbol());
2646 __ jmp(&done);
2647
2648 // Non-JS objects have class null.
2649 __ bind(&null);
2650 __ mov(eax, Factory::null_value());
2651
2652 // All done.
2653 __ bind(&done);
2654
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002655 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002656}
2657
2658
2659void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2660 // Conditionally generate a log call.
2661 // Args:
2662 // 0 (literal string): The type of logging (corresponds to the flags).
2663 // This is used to determine whether or not to generate the log call.
2664 // 1 (string): Format string. Access the string at argument index 2
2665 // with '%2s' (see Logger::LogRuntime for all the formats).
2666 // 2 (array): Arguments to the format string.
2667 ASSERT_EQ(args->length(), 3);
2668#ifdef ENABLE_LOGGING_AND_PROFILING
2669 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002670 VisitForStackValue(args->at(1));
2671 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002672 __ CallRuntime(Runtime::kLog, 2);
2673 }
2674#endif
2675 // Finally, we're expected to leave a value on the top of the stack.
2676 __ mov(eax, Factory::undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002677 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002678}
2679
2680
2681void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2682 ASSERT(args->length() == 0);
2683
2684 Label slow_allocate_heapnumber;
2685 Label heapnumber_allocated;
2686
2687 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2688 __ jmp(&heapnumber_allocated);
2689
2690 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002691 // Allocate a heap number.
2692 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002693 __ mov(edi, eax);
2694
2695 __ bind(&heapnumber_allocated);
2696
2697 __ PrepareCallCFunction(0, ebx);
2698 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2699
2700 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2701 // by computing:
2702 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2703 // This is implemented on both SSE2 and FPU.
2704 if (CpuFeatures::IsSupported(SSE2)) {
2705 CpuFeatures::Scope fscope(SSE2);
2706 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2707 __ movd(xmm1, Operand(ebx));
2708 __ movd(xmm0, Operand(eax));
2709 __ cvtss2sd(xmm1, xmm1);
2710 __ pxor(xmm0, xmm1);
2711 __ subsd(xmm0, xmm1);
2712 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2713 } else {
2714 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2715 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2716 Immediate(0x41300000));
2717 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2718 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2719 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2720 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2721 __ fsubp(1);
2722 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2723 }
2724 __ mov(eax, edi);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002725 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002726}
2727
2728
2729void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2730 // Load the arguments on the stack and call the stub.
2731 SubStringStub stub;
2732 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002733 VisitForStackValue(args->at(0));
2734 VisitForStackValue(args->at(1));
2735 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002736 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002737 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002738}
2739
2740
2741void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2742 // Load the arguments on the stack and call the stub.
2743 RegExpExecStub stub;
2744 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002745 VisitForStackValue(args->at(0));
2746 VisitForStackValue(args->at(1));
2747 VisitForStackValue(args->at(2));
2748 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002749 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002750 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002751}
2752
2753
2754void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2755 ASSERT(args->length() == 1);
2756
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002757 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002758
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002759 NearLabel done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002760 // If the object is a smi return the object.
2761 __ test(eax, Immediate(kSmiTagMask));
2762 __ j(zero, &done);
2763 // If the object is not a value type, return the object.
2764 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
2765 __ j(not_equal, &done);
2766 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2767
2768 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002769 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002770}
2771
2772
2773void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2774 // Load the arguments on the stack and call the runtime function.
2775 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002776 VisitForStackValue(args->at(0));
2777 VisitForStackValue(args->at(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002778
2779 MathPowStub stub;
2780 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002781 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002782}
2783
2784
2785void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2786 ASSERT(args->length() == 2);
2787
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002788 VisitForStackValue(args->at(0)); // Load the object.
2789 VisitForAccumulatorValue(args->at(1)); // Load the value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002790 __ pop(ebx); // eax = value. ebx = object.
2791
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002792 NearLabel done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002793 // If the object is a smi, return the value.
2794 __ test(ebx, Immediate(kSmiTagMask));
2795 __ j(zero, &done);
2796
2797 // If the object is not a value type, return the value.
2798 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
2799 __ j(not_equal, &done);
2800
2801 // Store the value.
2802 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
2803 // Update the write barrier. Save the value as it will be
2804 // overwritten by the write barrier code and is needed afterward.
2805 __ mov(edx, eax);
2806 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
2807
2808 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002809 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002810}
2811
2812
2813void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2814 ASSERT_EQ(args->length(), 1);
2815
2816 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002817 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002818
2819 NumberToStringStub stub;
2820 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002821 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002822}
2823
2824
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002825void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002826 ASSERT(args->length() == 1);
2827
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002828 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002829
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002830 Label done;
2831 StringCharFromCodeGenerator generator(eax, ebx);
2832 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002833 __ jmp(&done);
2834
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002835 NopRuntimeCallHelper call_helper;
2836 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002837
2838 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002839 context()->Plug(ebx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002840}
2841
2842
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002843void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2844 ASSERT(args->length() == 2);
2845
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002846 VisitForStackValue(args->at(0));
2847 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002848
2849 Register object = ebx;
2850 Register index = eax;
2851 Register scratch = ecx;
2852 Register result = edx;
2853
2854 __ pop(object);
2855
2856 Label need_conversion;
2857 Label index_out_of_range;
2858 Label done;
2859 StringCharCodeAtGenerator generator(object,
2860 index,
2861 scratch,
2862 result,
2863 &need_conversion,
2864 &need_conversion,
2865 &index_out_of_range,
2866 STRING_INDEX_IS_NUMBER);
2867 generator.GenerateFast(masm_);
2868 __ jmp(&done);
2869
2870 __ bind(&index_out_of_range);
2871 // When the index is out of range, the spec requires us to return
2872 // NaN.
2873 __ Set(result, Immediate(Factory::nan_value()));
2874 __ jmp(&done);
2875
2876 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002877 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002878 // trigger conversion.
2879 __ Set(result, Immediate(Factory::undefined_value()));
2880 __ jmp(&done);
2881
2882 NopRuntimeCallHelper call_helper;
2883 generator.GenerateSlow(masm_, call_helper);
2884
2885 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002886 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002887}
2888
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002889
2890void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2891 ASSERT(args->length() == 2);
2892
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002893 VisitForStackValue(args->at(0));
2894 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002895
2896 Register object = ebx;
2897 Register index = eax;
2898 Register scratch1 = ecx;
2899 Register scratch2 = edx;
2900 Register result = eax;
2901
2902 __ pop(object);
2903
2904 Label need_conversion;
2905 Label index_out_of_range;
2906 Label done;
2907 StringCharAtGenerator generator(object,
2908 index,
2909 scratch1,
2910 scratch2,
2911 result,
2912 &need_conversion,
2913 &need_conversion,
2914 &index_out_of_range,
2915 STRING_INDEX_IS_NUMBER);
2916 generator.GenerateFast(masm_);
2917 __ jmp(&done);
2918
2919 __ bind(&index_out_of_range);
2920 // When the index is out of range, the spec requires us to return
2921 // the empty string.
2922 __ Set(result, Immediate(Factory::empty_string()));
2923 __ jmp(&done);
2924
2925 __ bind(&need_conversion);
2926 // Move smi zero into the result register, which will trigger
2927 // conversion.
2928 __ Set(result, Immediate(Smi::FromInt(0)));
2929 __ jmp(&done);
2930
2931 NopRuntimeCallHelper call_helper;
2932 generator.GenerateSlow(masm_, call_helper);
2933
2934 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002935 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002936}
2937
2938
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002939void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2940 ASSERT_EQ(2, args->length());
2941
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002942 VisitForStackValue(args->at(0));
2943 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002944
2945 StringAddStub stub(NO_STRING_ADD_FLAGS);
2946 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002947 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002948}
2949
2950
2951void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2952 ASSERT_EQ(2, args->length());
2953
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002954 VisitForStackValue(args->at(0));
2955 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002956
2957 StringCompareStub stub;
2958 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002959 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002960}
2961
2962
2963void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2964 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00002965 TranscendentalCacheStub stub(TranscendentalCache::SIN,
2966 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002967 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002968 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002969 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002970 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002971}
2972
2973
2974void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2975 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00002976 TranscendentalCacheStub stub(TranscendentalCache::COS,
2977 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002978 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002979 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002980 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002981 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002982}
2983
2984
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002985void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
2986 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00002987 TranscendentalCacheStub stub(TranscendentalCache::LOG,
2988 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002989 ASSERT(args->length() == 1);
2990 VisitForStackValue(args->at(0));
2991 __ CallStub(&stub);
2992 context()->Plug(eax);
2993}
2994
2995
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002996void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2997 // Load the argument on the stack and call the runtime function.
2998 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002999 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003000 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003001 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003002}
3003
3004
3005void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
3006 ASSERT(args->length() >= 2);
3007
3008 int arg_count = args->length() - 2; // For receiver and function.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003009 VisitForStackValue(args->at(0)); // Receiver.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003010 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003011 VisitForStackValue(args->at(i + 1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003012 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003013 VisitForAccumulatorValue(args->at(arg_count + 1)); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003014
3015 // InvokeFunction requires function in edi. Move it in there.
3016 if (!result_register().is(edi)) __ mov(edi, result_register());
3017 ParameterCount count(arg_count);
3018 __ InvokeFunction(edi, count, CALL_FUNCTION);
3019 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003020 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003021}
3022
3023
3024void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003025 // Load the arguments on the stack and call the stub.
3026 RegExpConstructResultStub stub;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003027 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003028 VisitForStackValue(args->at(0));
3029 VisitForStackValue(args->at(1));
3030 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003031 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003032 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003033}
3034
3035
3036void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
3037 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003038 VisitForStackValue(args->at(0));
3039 VisitForStackValue(args->at(1));
3040 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003041 Label done;
3042 Label slow_case;
3043 Register object = eax;
3044 Register index_1 = ebx;
3045 Register index_2 = ecx;
3046 Register elements = edi;
3047 Register temp = edx;
3048 __ mov(object, Operand(esp, 2 * kPointerSize));
3049 // Fetch the map and check if array is in fast case.
3050 // Check that object doesn't require security checks and
3051 // has no indexed interceptor.
3052 __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp);
3053 __ j(below, &slow_case);
3054 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
3055 KeyedLoadIC::kSlowCaseBitFieldMask);
3056 __ j(not_zero, &slow_case);
3057
3058 // Check the object's elements are in fast case and writable.
3059 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
3060 __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
3061 Immediate(Factory::fixed_array_map()));
3062 __ j(not_equal, &slow_case);
3063
3064 // Check that both indices are smis.
3065 __ mov(index_1, Operand(esp, 1 * kPointerSize));
3066 __ mov(index_2, Operand(esp, 0));
3067 __ mov(temp, index_1);
3068 __ or_(temp, Operand(index_2));
3069 __ test(temp, Immediate(kSmiTagMask));
3070 __ j(not_zero, &slow_case);
3071
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003072 // Check that both indices are valid.
3073 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
3074 __ cmp(temp, Operand(index_1));
3075 __ j(below_equal, &slow_case);
3076 __ cmp(temp, Operand(index_2));
3077 __ j(below_equal, &slow_case);
3078
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003079 // Bring addresses into index1 and index2.
3080 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1));
3081 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2));
3082
3083 // Swap elements. Use object and temp as scratch registers.
3084 __ mov(object, Operand(index_1, 0));
3085 __ mov(temp, Operand(index_2, 0));
3086 __ mov(Operand(index_2, 0), object);
3087 __ mov(Operand(index_1, 0), temp);
3088
3089 Label new_space;
3090 __ InNewSpace(elements, temp, equal, &new_space);
3091
3092 __ mov(object, elements);
3093 __ RecordWriteHelper(object, index_1, temp);
3094 __ RecordWriteHelper(elements, index_2, temp);
3095
3096 __ bind(&new_space);
3097 // We are done. Drop elements from the stack, and return undefined.
3098 __ add(Operand(esp), Immediate(3 * kPointerSize));
3099 __ mov(eax, Factory::undefined_value());
3100 __ jmp(&done);
3101
3102 __ bind(&slow_case);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003103 __ CallRuntime(Runtime::kSwapElements, 3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003104
3105 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003106 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003107}
3108
3109
3110void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3111 ASSERT_EQ(2, args->length());
3112
3113 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3114 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3115
3116 Handle<FixedArray> jsfunction_result_caches(
3117 Top::global_context()->jsfunction_result_caches());
3118 if (jsfunction_result_caches->length() <= cache_id) {
3119 __ Abort("Attempt to use undefined cache.");
3120 __ mov(eax, Factory::undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003121 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003122 return;
3123 }
3124
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003125 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003126
3127 Register key = eax;
3128 Register cache = ebx;
3129 Register tmp = ecx;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003130 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003131 __ mov(cache,
3132 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003133 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003134 __ mov(cache,
3135 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3136
3137 Label done, not_found;
3138 // tmp now holds finger offset as a smi.
3139 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3140 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3141 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3142 __ j(not_equal, &not_found);
3143
3144 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3145 __ jmp(&done);
3146
3147 __ bind(&not_found);
3148 // Call runtime to perform the lookup.
3149 __ push(cache);
3150 __ push(key);
3151 __ CallRuntime(Runtime::kGetFromCache, 2);
3152
3153 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003154 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003155}
3156
3157
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003158void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3159 ASSERT_EQ(2, args->length());
3160
3161 Register right = eax;
3162 Register left = ebx;
3163 Register tmp = ecx;
3164
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003165 VisitForStackValue(args->at(0));
3166 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003167 __ pop(left);
3168
3169 Label done, fail, ok;
3170 __ cmp(left, Operand(right));
3171 __ j(equal, &ok);
3172 // Fail if either is a non-HeapObject.
3173 __ mov(tmp, left);
3174 __ and_(Operand(tmp), right);
3175 __ test(Operand(tmp), Immediate(kSmiTagMask));
3176 __ j(zero, &fail);
lrn@chromium.org19375882010-08-09 12:49:57 +00003177 __ CmpObjectType(left, JS_REGEXP_TYPE, tmp);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003178 __ j(not_equal, &fail);
3179 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3180 __ j(not_equal, &fail);
3181 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3182 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3183 __ j(equal, &ok);
3184 __ bind(&fail);
3185 __ mov(eax, Immediate(Factory::false_value()));
3186 __ jmp(&done);
3187 __ bind(&ok);
3188 __ mov(eax, Immediate(Factory::true_value()));
3189 __ bind(&done);
3190
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003191 context()->Plug(eax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003192}
3193
3194
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003195void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
3196 ASSERT(args->length() == 1);
3197
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003198 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003199
3200 if (FLAG_debug_code) {
3201 __ AbortIfNotString(eax);
3202 }
3203
3204 Label materialize_true, materialize_false;
3205 Label* if_true = NULL;
3206 Label* if_false = NULL;
3207 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003208 context()->PrepareTest(&materialize_true, &materialize_false,
3209 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003210
3211 __ test(FieldOperand(eax, String::kHashFieldOffset),
3212 Immediate(String::kContainsCachedArrayIndexMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003213 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003214 Split(zero, if_true, if_false, fall_through);
3215
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003216 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003217}
3218
3219
3220void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3221 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003222 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003223
3224 if (FLAG_debug_code) {
3225 __ AbortIfNotString(eax);
3226 }
3227
3228 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3229 __ IndexFromHash(eax, eax);
3230
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003231 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003232}
3233
3234
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003235void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003236 Label bailout, done, one_char_separator, long_separator,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003237 non_trivial_array, not_size_one_array, loop,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003238 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003239
3240 ASSERT(args->length() == 2);
3241 // We will leave the separator on the stack until the end of the function.
3242 VisitForStackValue(args->at(1));
3243 // Load this to eax (= array)
3244 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003245 // All aliases of the same register have disjoint lifetimes.
3246 Register array = eax;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003247 Register elements = no_reg; // Will be eax.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003248
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003249 Register index = edx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003250
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003251 Register string_length = ecx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003252
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003253 Register string = esi;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003254
3255 Register scratch = ebx;
3256
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003257 Register array_length = edi;
3258 Register result_pos = no_reg; // Will be edi.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003259
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003260 // Separator operand is already pushed.
3261 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3262 Operand result_operand = Operand(esp, 1 * kPointerSize);
3263 Operand array_length_operand = Operand(esp, 0);
3264 __ sub(Operand(esp), Immediate(2 * kPointerSize));
3265 __ cld();
3266 // Check that the array is a JSArray
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003267 __ test(array, Immediate(kSmiTagMask));
3268 __ j(zero, &bailout);
3269 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3270 __ j(not_equal, &bailout);
3271
3272 // Check that the array has fast elements.
3273 __ test_b(FieldOperand(scratch, Map::kBitField2Offset),
3274 1 << Map::kHasFastElements);
3275 __ j(zero, &bailout);
3276
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003277 // If the array has length zero, return the empty string.
3278 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003279 __ SmiUntag(array_length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003280 __ j(not_zero, &non_trivial_array);
3281 __ mov(result_operand, Factory::empty_string());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003282 __ jmp(&done);
3283
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003284 // Save the array length.
3285 __ bind(&non_trivial_array);
3286 __ mov(array_length_operand, array_length);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003287
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003288 // Save the FixedArray containing array's elements.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003289 // End of array's live range.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003290 elements = array;
3291 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003292 array = no_reg;
3293
3294
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003295 // Check that all array elements are sequential ASCII strings, and
3296 // accumulate the sum of their lengths, as a smi-encoded value.
3297 __ Set(index, Immediate(0));
3298 __ Set(string_length, Immediate(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003299 // Loop condition: while (index < length).
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003300 // Live loop registers: index, array_length, string,
3301 // scratch, string_length, elements.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003302 if (FLAG_debug_code) {
3303 __ cmp(index, Operand(array_length));
3304 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
3305 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003306 __ bind(&loop);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003307 __ mov(string, FieldOperand(elements,
3308 index,
3309 times_pointer_size,
3310 FixedArray::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003311 __ test(string, Immediate(kSmiTagMask));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003312 __ j(zero, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003313 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3314 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3315 __ and_(scratch, Immediate(
3316 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3317 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3318 __ j(not_equal, &bailout);
3319 __ add(string_length,
3320 FieldOperand(string, SeqAsciiString::kLengthOffset));
3321 __ j(overflow, &bailout);
3322 __ add(Operand(index), Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003323 __ cmp(index, Operand(array_length));
3324 __ j(less, &loop);
3325
3326 // If array_length is 1, return elements[0], a string.
3327 __ cmp(array_length, 1);
3328 __ j(not_equal, &not_size_one_array);
3329 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3330 __ mov(result_operand, scratch);
3331 __ jmp(&done);
3332
3333 __ bind(&not_size_one_array);
3334
3335 // End of array_length live range.
3336 result_pos = array_length;
3337 array_length = no_reg;
3338
3339 // Live registers:
3340 // string_length: Sum of string lengths, as a smi.
3341 // elements: FixedArray of strings.
3342
3343 // Check that the separator is a flat ASCII string.
3344 __ mov(string, separator_operand);
3345 __ test(string, Immediate(kSmiTagMask));
3346 __ j(zero, &bailout);
3347 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3348 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003349 __ and_(scratch, Immediate(
3350 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003351 __ cmp(scratch, ASCII_STRING_TYPE);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003352 __ j(not_equal, &bailout);
3353
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003354 // Add (separator length times array_length) - separator length
3355 // to string_length.
3356 __ mov(scratch, separator_operand);
3357 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset));
3358 __ sub(string_length, Operand(scratch)); // May be negative, temporarily.
3359 __ imul(scratch, array_length_operand);
3360 __ j(overflow, &bailout);
3361 __ add(string_length, Operand(scratch));
3362 __ j(overflow, &bailout);
3363
3364 __ shr(string_length, 1);
3365 // Live registers and stack values:
3366 // string_length
3367 // elements
3368 __ AllocateAsciiString(result_pos, string_length, scratch,
3369 index, string, &bailout);
3370 __ mov(result_operand, result_pos);
3371 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3372
3373
3374 __ mov(string, separator_operand);
3375 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset),
3376 Immediate(Smi::FromInt(1)));
3377 __ j(equal, &one_char_separator);
3378 __ j(greater, &long_separator);
3379
3380
3381 // Empty separator case
3382 __ mov(index, Immediate(0));
3383 __ jmp(&loop_1_condition);
3384 // Loop condition: while (index < length).
3385 __ bind(&loop_1);
3386 // Each iteration of the loop concatenates one string to the result.
3387 // Live values in registers:
3388 // index: which element of the elements array we are adding to the result.
3389 // result_pos: the position to which we are currently copying characters.
3390 // elements: the FixedArray of strings we are joining.
3391
3392 // Get string = array[index].
3393 __ mov(string, FieldOperand(elements, index,
3394 times_pointer_size,
3395 FixedArray::kHeaderSize));
3396 __ mov(string_length,
3397 FieldOperand(string, String::kLengthOffset));
3398 __ shr(string_length, 1);
3399 __ lea(string,
3400 FieldOperand(string, SeqAsciiString::kHeaderSize));
3401 __ CopyBytes(string, result_pos, string_length, scratch);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003402 __ add(Operand(index), Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003403 __ bind(&loop_1_condition);
3404 __ cmp(index, array_length_operand);
3405 __ j(less, &loop_1); // End while (index < length).
3406 __ jmp(&done);
3407
3408
3409
3410 // One-character separator case
3411 __ bind(&one_char_separator);
3412 // Replace separator with its ascii character value.
3413 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3414 __ mov_b(separator_operand, scratch);
3415
3416 __ Set(index, Immediate(0));
3417 // Jump into the loop after the code that copies the separator, so the first
3418 // element is not preceded by a separator
3419 __ jmp(&loop_2_entry);
3420 // Loop condition: while (index < length).
3421 __ bind(&loop_2);
3422 // Each iteration of the loop concatenates one string to the result.
3423 // Live values in registers:
3424 // index: which element of the elements array we are adding to the result.
3425 // result_pos: the position to which we are currently copying characters.
3426
3427 // Copy the separator character to the result.
3428 __ mov_b(scratch, separator_operand);
3429 __ mov_b(Operand(result_pos, 0), scratch);
3430 __ inc(result_pos);
3431
3432 __ bind(&loop_2_entry);
3433 // Get string = array[index].
3434 __ mov(string, FieldOperand(elements, index,
3435 times_pointer_size,
3436 FixedArray::kHeaderSize));
3437 __ mov(string_length,
3438 FieldOperand(string, String::kLengthOffset));
3439 __ shr(string_length, 1);
3440 __ lea(string,
3441 FieldOperand(string, SeqAsciiString::kHeaderSize));
3442 __ CopyBytes(string, result_pos, string_length, scratch);
3443 __ add(Operand(index), Immediate(1));
3444
3445 __ cmp(index, array_length_operand);
3446 __ j(less, &loop_2); // End while (index < length).
3447 __ jmp(&done);
3448
3449
3450 // Long separator case (separator is more than one character).
3451 __ bind(&long_separator);
3452
3453 __ Set(index, Immediate(0));
3454 // Jump into the loop after the code that copies the separator, so the first
3455 // element is not preceded by a separator
3456 __ jmp(&loop_3_entry);
3457 // Loop condition: while (index < length).
3458 __ bind(&loop_3);
3459 // Each iteration of the loop concatenates one string to the result.
3460 // Live values in registers:
3461 // index: which element of the elements array we are adding to the result.
3462 // result_pos: the position to which we are currently copying characters.
3463
3464 // Copy the separator to the result.
3465 __ mov(string, separator_operand);
3466 __ mov(string_length,
3467 FieldOperand(string, String::kLengthOffset));
3468 __ shr(string_length, 1);
3469 __ lea(string,
3470 FieldOperand(string, SeqAsciiString::kHeaderSize));
3471 __ CopyBytes(string, result_pos, string_length, scratch);
3472
3473 __ bind(&loop_3_entry);
3474 // Get string = array[index].
3475 __ mov(string, FieldOperand(elements, index,
3476 times_pointer_size,
3477 FixedArray::kHeaderSize));
3478 __ mov(string_length,
3479 FieldOperand(string, String::kLengthOffset));
3480 __ shr(string_length, 1);
3481 __ lea(string,
3482 FieldOperand(string, SeqAsciiString::kHeaderSize));
3483 __ CopyBytes(string, result_pos, string_length, scratch);
3484 __ add(Operand(index), Immediate(1));
3485
3486 __ cmp(index, array_length_operand);
3487 __ j(less, &loop_3); // End while (index < length).
3488 __ jmp(&done);
3489
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003490
3491 __ bind(&bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003492 __ mov(result_operand, Factory::undefined_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003493 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003494 __ mov(eax, result_operand);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003495 // Drop temp values from the stack, and restore context register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003496 __ add(Operand(esp), Immediate(3 * kPointerSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003497
3498 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3499 context()->Plug(eax);
3500}
3501
3502
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003503void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003504 Handle<String> name = expr->name();
3505 if (name->length() > 0 && name->Get(0) == '_') {
3506 Comment cmnt(masm_, "[ InlineRuntimeCall");
3507 EmitInlineRuntimeCall(expr);
3508 return;
3509 }
3510
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003511 Comment cmnt(masm_, "[ CallRuntime");
3512 ZoneList<Expression*>* args = expr->arguments();
3513
3514 if (expr->is_jsruntime()) {
3515 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003516 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003517 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3518 }
3519
3520 // Push the arguments ("left-to-right").
3521 int arg_count = args->length();
3522 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003523 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003524 }
3525
3526 if (expr->is_jsruntime()) {
3527 // Call the JS runtime function via a call IC.
3528 __ Set(ecx, Immediate(expr->name()));
3529 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003530 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003531 EmitCallIC(ic, RelocInfo::CODE_TARGET);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003532 // Restore context register.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003533 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3534 } else {
3535 // Call the C runtime function.
3536 __ CallRuntime(expr->function(), arg_count);
3537 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003538 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003539}
3540
3541
3542void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3543 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003544 case Token::DELETE: {
3545 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3546 Property* prop = expr->expression()->AsProperty();
3547 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003548
3549 if (prop != NULL) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003550 if (prop->is_synthetic()) {
3551 // Result of deleting parameters is false, even when they rewrite
3552 // to accesses on the arguments object.
3553 context()->Plug(false);
3554 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003555 VisitForStackValue(prop->obj());
3556 VisitForStackValue(prop->key());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003557 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003558 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003559 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003560 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003561 } else if (var != NULL) {
3562 // Delete of an unqualified identifier is disallowed in strict mode
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003563 // but "delete this" is.
3564 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003565 if (var->is_global()) {
3566 __ push(GlobalObjectOperand());
3567 __ push(Immediate(var->name()));
3568 __ push(Immediate(Smi::FromInt(kNonStrictMode)));
3569 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3570 context()->Plug(eax);
3571 } else if (var->AsSlot() != NULL &&
3572 var->AsSlot()->type() != Slot::LOOKUP) {
3573 // Result of deleting non-global, non-dynamic variables is false.
3574 // The subexpression does not have side effects.
3575 context()->Plug(false);
3576 } else {
3577 // Non-global variable. Call the runtime to try to delete from the
3578 // context where the variable was introduced.
3579 __ push(context_register());
3580 __ push(Immediate(var->name()));
3581 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3582 context()->Plug(eax);
3583 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003584 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003585 // Result of deleting non-property, non-variable reference is true.
3586 // The subexpression may have side effects.
3587 VisitForEffect(expr->expression());
3588 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003589 }
3590 break;
3591 }
3592
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003593 case Token::VOID: {
3594 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3595 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003596 context()->Plug(Factory::undefined_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003597 break;
3598 }
3599
3600 case Token::NOT: {
3601 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003602 if (context()->IsEffect()) {
3603 // Unary NOT has no side effects so it's only necessary to visit the
3604 // subexpression. Match the optimizing compiler by not branching.
3605 VisitForEffect(expr->expression());
3606 } else {
3607 Label materialize_true, materialize_false;
3608 Label* if_true = NULL;
3609 Label* if_false = NULL;
3610 Label* fall_through = NULL;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003611
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003612 // Notice that the labels are swapped.
3613 context()->PrepareTest(&materialize_true, &materialize_false,
3614 &if_false, &if_true, &fall_through);
3615 if (context()->IsTest()) ForwardBailoutToChild(expr);
3616 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3617 context()->Plug(if_false, if_true); // Labels swapped.
3618 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003619 break;
3620 }
3621
3622 case Token::TYPEOF: {
3623 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003624 { StackValueContext context(this);
3625 VisitForTypeofValue(expr->expression());
3626 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003627 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003628 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003629 break;
3630 }
3631
3632 case Token::ADD: {
3633 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003634 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003635 Label no_conversion;
3636 __ test(result_register(), Immediate(kSmiTagMask));
3637 __ j(zero, &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003638 ToNumberStub convert_stub;
3639 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003640 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003641 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003642 break;
3643 }
3644
3645 case Token::SUB: {
3646 Comment cmt(masm_, "[ UnaryOperation (SUB)");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003647 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003648 UnaryOverwriteMode overwrite =
3649 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003650 GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003651 // GenericUnaryOpStub expects the argument to be in the
3652 // accumulator register eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003653 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003654 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003655 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003656 break;
3657 }
3658
3659 case Token::BIT_NOT: {
3660 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003661 // The generic unary operation stub expects the argument to be
3662 // in the accumulator register eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003663 VisitForAccumulatorValue(expr->expression());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003664 Label done;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003665 bool inline_smi_case = ShouldInlineSmiCase(expr->op());
3666 if (inline_smi_case) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003667 NearLabel call_stub;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003668 __ test(eax, Immediate(kSmiTagMask));
3669 __ j(not_zero, &call_stub);
3670 __ lea(eax, Operand(eax, kSmiTagMask));
3671 __ not_(eax);
3672 __ jmp(&done);
3673 __ bind(&call_stub);
3674 }
3675 bool overwrite = expr->expression()->ResultOverwriteAllowed();
3676 UnaryOverwriteMode mode =
3677 overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003678 UnaryOpFlags flags = inline_smi_case
3679 ? NO_UNARY_SMI_CODE_IN_STUB
3680 : NO_UNARY_FLAGS;
3681 GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003682 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003683 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003684 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003685 break;
3686 }
3687
3688 default:
3689 UNREACHABLE();
3690 }
3691}
3692
3693
3694void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3695 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003696 SetSourcePosition(expr->position());
3697
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003698 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3699 // as the left-hand side.
3700 if (!expr->expression()->IsValidLeftHandSide()) {
3701 VisitForEffect(expr->expression());
3702 return;
3703 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003704
3705 // Expression can only be a property, a global or a (parameter or local)
3706 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
3707 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3708 LhsKind assign_type = VARIABLE;
3709 Property* prop = expr->expression()->AsProperty();
3710 // In case of a property we use the uninitialized expression context
3711 // of the key to detect a named property.
3712 if (prop != NULL) {
3713 assign_type =
3714 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3715 }
3716
3717 // Evaluate expression and get value.
3718 if (assign_type == VARIABLE) {
3719 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003720 AccumulatorValueContext context(this);
3721 EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003722 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003723 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003724 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003725 __ push(Immediate(Smi::FromInt(0)));
3726 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003727 if (assign_type == NAMED_PROPERTY) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003728 // Put the object both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003729 VisitForAccumulatorValue(prop->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00003730 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003731 EmitNamedPropertyLoad(prop);
3732 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003733 if (prop->is_arguments_access()) {
3734 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003735 MemOperand slot_operand =
3736 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
3737 __ push(slot_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003738 __ mov(eax, Immediate(prop->key()->AsLiteral()->handle()));
3739 } else {
3740 VisitForStackValue(prop->obj());
3741 VisitForAccumulatorValue(prop->key());
3742 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003743 __ mov(edx, Operand(esp, 0));
3744 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003745 EmitKeyedPropertyLoad(prop);
3746 }
3747 }
3748
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003749 // We need a second deoptimization point after loading the value
3750 // in case evaluating the property load my have a side effect.
3751 PrepareForBailout(expr->increment(), TOS_REG);
3752
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003753 // Call ToNumber only if operand is not a smi.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003754 NearLabel no_conversion;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003755 if (ShouldInlineSmiCase(expr->op())) {
3756 __ test(eax, Immediate(kSmiTagMask));
3757 __ j(zero, &no_conversion);
3758 }
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003759 ToNumberStub convert_stub;
3760 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003761 __ bind(&no_conversion);
3762
3763 // Save result for postfix expressions.
3764 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003765 if (!context()->IsEffect()) {
3766 // Save the result on the stack. If we have a named or keyed property
3767 // we store the result under the receiver that is currently on top
3768 // of the stack.
3769 switch (assign_type) {
3770 case VARIABLE:
3771 __ push(eax);
3772 break;
3773 case NAMED_PROPERTY:
3774 __ mov(Operand(esp, kPointerSize), eax);
3775 break;
3776 case KEYED_PROPERTY:
3777 __ mov(Operand(esp, 2 * kPointerSize), eax);
3778 break;
3779 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003780 }
3781 }
3782
3783 // Inline smi case if we are in a loop.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003784 NearLabel stub_call, done;
3785 JumpPatchSite patch_site(masm_);
3786
ricow@chromium.org65fae842010-08-25 15:26:24 +00003787 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003788 if (expr->op() == Token::INC) {
3789 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3790 } else {
3791 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3792 }
3793 __ j(overflow, &stub_call);
3794 // We could eliminate this smi check if we split the code at
3795 // the first smi check before calling ToNumber.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003796 patch_site.EmitJumpIfSmi(eax, &done);
3797
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003798 __ bind(&stub_call);
3799 // Call stub. Undo operation first.
3800 if (expr->op() == Token::INC) {
3801 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3802 } else {
3803 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3804 }
3805 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003806
3807 // Record position before stub call.
3808 SetSourcePosition(expr->position());
3809
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003810 // Call stub for +1/-1.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003811 __ mov(edx, eax);
3812 __ mov(eax, Immediate(Smi::FromInt(1)));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003813 TypeRecordingBinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003814 EmitCallIC(stub.GetCode(), &patch_site);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003815 __ bind(&done);
3816
3817 // Store the value returned in eax.
3818 switch (assign_type) {
3819 case VARIABLE:
3820 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003821 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003822 { EffectContext context(this);
3823 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3824 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003825 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3826 context.Plug(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003827 }
3828 // For all contexts except EffectContext We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003829 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003830 if (!context()->IsEffect()) {
3831 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003832 }
3833 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003834 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003835 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003836 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003837 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3838 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003839 }
3840 break;
3841 case NAMED_PROPERTY: {
3842 __ mov(ecx, prop->key()->AsLiteral()->handle());
3843 __ pop(edx);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003844 Handle<Code> ic(Builtins::builtin(
3845 is_strict() ? Builtins::StoreIC_Initialize_Strict
3846 : Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003847 EmitCallIC(ic, RelocInfo::CODE_TARGET);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003848 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003849 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003850 if (!context()->IsEffect()) {
3851 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003852 }
3853 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003854 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003855 }
3856 break;
3857 }
3858 case KEYED_PROPERTY: {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003859 __ pop(ecx);
3860 __ pop(edx);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003861 Handle<Code> ic(Builtins::builtin(
3862 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
3863 : Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003864 EmitCallIC(ic, RelocInfo::CODE_TARGET);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003865 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003866 if (expr->is_postfix()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003867 // Result is on the stack
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003868 if (!context()->IsEffect()) {
3869 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003870 }
3871 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003872 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003873 }
3874 break;
3875 }
3876 }
3877}
3878
3879
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003880void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003881 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003882 ASSERT(!context()->IsEffect());
3883 ASSERT(!context()->IsTest());
3884
ricow@chromium.org65fae842010-08-25 15:26:24 +00003885 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3886 Comment cmnt(masm_, "Global variable");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003887 __ mov(eax, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003888 __ mov(ecx, Immediate(proxy->name()));
3889 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
3890 // Use a regular load, not a contextual load, to avoid a reference
3891 // error.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003892 EmitCallIC(ic, RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003893 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003894 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003895 } else if (proxy != NULL &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003896 proxy->var()->AsSlot() != NULL &&
3897 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003898 Label done, slow;
3899
3900 // Generate code for loading from variables potentially shadowed
3901 // by eval-introduced variables.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003902 Slot* slot = proxy->var()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003903 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3904
3905 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003906 __ push(esi);
3907 __ push(Immediate(proxy->name()));
3908 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003909 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003910 __ bind(&done);
3911
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003912 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003913 } else {
3914 // This expression cannot throw a reference error at the top level.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003915 context()->HandleExpression(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003916 }
3917}
3918
3919
ricow@chromium.org65fae842010-08-25 15:26:24 +00003920bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
3921 Expression* left,
3922 Expression* right,
3923 Label* if_true,
3924 Label* if_false,
3925 Label* fall_through) {
3926 if (op != Token::EQ && op != Token::EQ_STRICT) return false;
3927
3928 // Check for the pattern: typeof <expression> == <string literal>.
3929 Literal* right_literal = right->AsLiteral();
3930 if (right_literal == NULL) return false;
3931 Handle<Object> right_literal_value = right_literal->handle();
3932 if (!right_literal_value->IsString()) return false;
3933 UnaryOperation* left_unary = left->AsUnaryOperation();
3934 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
3935 Handle<String> check = Handle<String>::cast(right_literal_value);
3936
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003937 { AccumulatorValueContext context(this);
3938 VisitForTypeofValue(left_unary->expression());
3939 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003940 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003941
ricow@chromium.org65fae842010-08-25 15:26:24 +00003942 if (check->Equals(Heap::number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003943 __ JumpIfSmi(eax, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003944 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3945 Factory::heap_number_map());
3946 Split(equal, if_true, if_false, fall_through);
3947 } else if (check->Equals(Heap::string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003948 __ JumpIfSmi(eax, if_false);
3949 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
3950 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003951 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003952 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
3953 1 << Map::kIsUndetectable);
3954 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003955 } else if (check->Equals(Heap::boolean_symbol())) {
3956 __ cmp(eax, Factory::true_value());
3957 __ j(equal, if_true);
3958 __ cmp(eax, Factory::false_value());
3959 Split(equal, if_true, if_false, fall_through);
3960 } else if (check->Equals(Heap::undefined_symbol())) {
3961 __ cmp(eax, Factory::undefined_value());
3962 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003963 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003964 // Check for undetectable objects => true.
3965 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3966 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3967 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3968 Split(not_zero, if_true, if_false, fall_through);
3969 } else if (check->Equals(Heap::function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003970 __ JumpIfSmi(eax, if_false);
3971 __ CmpObjectType(eax, FIRST_FUNCTION_CLASS_TYPE, edx);
3972 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003973 } else if (check->Equals(Heap::object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003974 __ JumpIfSmi(eax, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003975 __ cmp(eax, Factory::null_value());
3976 __ j(equal, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003977 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, edx);
3978 __ j(below, if_false);
3979 __ CmpInstanceType(edx, FIRST_FUNCTION_CLASS_TYPE);
3980 __ j(above_equal, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003981 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003982 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
3983 1 << Map::kIsUndetectable);
3984 Split(zero, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003985 } else {
3986 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003987 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003988
3989 return true;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003990}
3991
3992
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003993void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3994 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003995 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003996
3997 // Always perform the comparison for its control flow. Pack the result
3998 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003999
4000 Label materialize_true, materialize_false;
4001 Label* if_true = NULL;
4002 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004003 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004004 context()->PrepareTest(&materialize_true, &materialize_false,
4005 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004006
4007 // First we try a fast inlined version of the compare when one of
4008 // the operands is a literal.
4009 Token::Value op = expr->op();
4010 Expression* left = expr->left();
4011 Expression* right = expr->right();
4012 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004013 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004014 return;
4015 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004016
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004017 VisitForStackValue(expr->left());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004018 switch (expr->op()) {
4019 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004020 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004021 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004022 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004023 __ cmp(eax, Factory::true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004024 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004025 break;
4026
4027 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004028 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004029 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004030 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004031 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004032 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004033 // The stub returns 0 for true.
4034 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004035 break;
4036 }
4037
4038 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004039 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004040 Condition cc = no_condition;
4041 bool strict = false;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004042 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004043 case Token::EQ_STRICT:
4044 strict = true;
4045 // Fall through
ricow@chromium.org65fae842010-08-25 15:26:24 +00004046 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004047 cc = equal;
4048 __ pop(edx);
4049 break;
4050 case Token::LT:
4051 cc = less;
4052 __ pop(edx);
4053 break;
4054 case Token::GT:
4055 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4056 cc = less;
4057 __ mov(edx, result_register());
4058 __ pop(eax);
4059 break;
4060 case Token::LTE:
4061 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4062 cc = greater_equal;
4063 __ mov(edx, result_register());
4064 __ pop(eax);
4065 break;
4066 case Token::GTE:
4067 cc = greater_equal;
4068 __ pop(edx);
4069 break;
4070 case Token::IN:
4071 case Token::INSTANCEOF:
4072 default:
4073 UNREACHABLE();
4074 }
4075
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004076 bool inline_smi_code = ShouldInlineSmiCase(op);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004077 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004078 if (inline_smi_code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004079 NearLabel slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004080 __ mov(ecx, Operand(edx));
4081 __ or_(ecx, Operand(eax));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004082 patch_site.EmitJumpIfNotSmi(ecx, &slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004083 __ cmp(edx, Operand(eax));
4084 Split(cc, if_true, if_false, NULL);
4085 __ bind(&slow_case);
4086 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004087
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004088 // Record position and call the compare IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004089 SetSourcePosition(expr->position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004090 Handle<Code> ic = CompareIC::GetUninitialized(op);
4091 EmitCallIC(ic, &patch_site);
4092
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004093 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004094 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004095 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004096 }
4097 }
4098
4099 // Convert the result of the comparison into one expected for this
4100 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004101 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004102}
4103
4104
ricow@chromium.org65fae842010-08-25 15:26:24 +00004105void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4106 Label materialize_true, materialize_false;
4107 Label* if_true = NULL;
4108 Label* if_false = NULL;
4109 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004110 context()->PrepareTest(&materialize_true, &materialize_false,
4111 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004112
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004113 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004114 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4115
ricow@chromium.org65fae842010-08-25 15:26:24 +00004116 __ cmp(eax, Factory::null_value());
4117 if (expr->is_strict()) {
4118 Split(equal, if_true, if_false, fall_through);
4119 } else {
4120 __ j(equal, if_true);
4121 __ cmp(eax, Factory::undefined_value());
4122 __ j(equal, if_true);
4123 __ test(eax, Immediate(kSmiTagMask));
4124 __ j(zero, if_false);
4125 // It can be an undetectable object.
4126 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4127 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
4128 __ test(edx, Immediate(1 << Map::kIsUndetectable));
4129 Split(not_zero, if_true, if_false, fall_through);
4130 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004131 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004132}
4133
4134
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004135void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4136 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004137 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004138}
4139
4140
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004141Register FullCodeGenerator::result_register() {
4142 return eax;
4143}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004144
4145
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004146Register FullCodeGenerator::context_register() {
4147 return esi;
4148}
4149
4150
4151void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
4152 ASSERT(mode == RelocInfo::CODE_TARGET ||
4153 mode == RelocInfo::CODE_TARGET_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004154 switch (ic->kind()) {
4155 case Code::LOAD_IC:
4156 __ IncrementCounter(&Counters::named_load_full, 1);
4157 break;
4158 case Code::KEYED_LOAD_IC:
4159 __ IncrementCounter(&Counters::keyed_load_full, 1);
4160 break;
4161 case Code::STORE_IC:
4162 __ IncrementCounter(&Counters::named_store_full, 1);
4163 break;
4164 case Code::KEYED_STORE_IC:
4165 __ IncrementCounter(&Counters::keyed_store_full, 1);
4166 default:
4167 break;
4168 }
4169
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004170 __ call(ic, mode);
4171
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004172 // Crankshaft doesn't need patching of inlined loads and stores.
4173 // When compiling the snapshot we need to produce code that works
4174 // with and without Crankshaft.
4175 if (V8::UseCrankshaft() && !Serializer::enabled()) {
4176 return;
4177 }
4178
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004179 // If we're calling a (keyed) load or store stub, we have to mark
4180 // the call as containing no inlined code so we will not attempt to
4181 // patch it.
4182 switch (ic->kind()) {
4183 case Code::LOAD_IC:
4184 case Code::KEYED_LOAD_IC:
4185 case Code::STORE_IC:
4186 case Code::KEYED_STORE_IC:
4187 __ nop(); // Signals no inlined code.
4188 break;
4189 default:
4190 // Do nothing.
4191 break;
4192 }
4193}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004194
4195
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004196void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004197 switch (ic->kind()) {
4198 case Code::LOAD_IC:
4199 __ IncrementCounter(&Counters::named_load_full, 1);
4200 break;
4201 case Code::KEYED_LOAD_IC:
4202 __ IncrementCounter(&Counters::keyed_load_full, 1);
4203 break;
4204 case Code::STORE_IC:
4205 __ IncrementCounter(&Counters::named_store_full, 1);
4206 break;
4207 case Code::KEYED_STORE_IC:
4208 __ IncrementCounter(&Counters::keyed_store_full, 1);
4209 default:
4210 break;
4211 }
4212
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004213 __ call(ic, RelocInfo::CODE_TARGET);
4214 if (patch_site != NULL && patch_site->is_bound()) {
4215 patch_site->EmitPatchInfo();
4216 } else {
4217 __ nop(); // Signals no inlined code.
4218 }
4219}
4220
4221
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004222void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4223 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4224 __ mov(Operand(ebp, frame_offset), value);
4225}
4226
4227
4228void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004229 __ mov(dst, ContextOperand(esi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004230}
4231
4232
4233// ----------------------------------------------------------------------------
4234// Non-local control flow support.
4235
4236void FullCodeGenerator::EnterFinallyBlock() {
4237 // Cook return address on top of stack (smi encoded Code* delta)
4238 ASSERT(!result_register().is(edx));
4239 __ mov(edx, Operand(esp, 0));
4240 __ sub(Operand(edx), Immediate(masm_->CodeObject()));
4241 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4242 ASSERT_EQ(0, kSmiTag);
4243 __ add(edx, Operand(edx)); // Convert to smi.
4244 __ mov(Operand(esp, 0), edx);
4245 // Store result register while executing finally block.
4246 __ push(result_register());
4247}
4248
4249
4250void FullCodeGenerator::ExitFinallyBlock() {
4251 ASSERT(!result_register().is(edx));
4252 // Restore result register from stack.
4253 __ pop(result_register());
4254 // Uncook return address.
4255 __ mov(edx, Operand(esp, 0));
4256 __ sar(edx, 1); // Convert smi to int.
4257 __ add(Operand(edx), Immediate(masm_->CodeObject()));
4258 __ mov(Operand(esp, 0), edx);
4259 // And return.
4260 __ ret(0);
4261}
4262
4263
4264#undef __
4265
4266} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004267
4268#endif // V8_TARGET_ARCH_IA32