blob: 4255347bad94a383e53ed212d85519c9023a867c [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);
202 __ mov(ecx, eax); // Duplicate result.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000203 Move(arguments->AsSlot(), eax, ebx, edx);
204 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000205 Move(dot_arguments_slot, ecx, ebx, edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000206 }
207
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000208 if (FLAG_trace) {
209 __ CallRuntime(Runtime::kTraceEnter, 0);
210 }
211
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000212 // Visit the declarations and body unless there is an illegal
213 // redeclaration.
214 if (scope()->HasIllegalRedeclaration()) {
215 Comment cmnt(masm_, "[ Declarations");
216 scope()->VisitIllegalRedeclaration(this);
217
218 } else {
219 { Comment cmnt(masm_, "[ Declarations");
220 // For named function expressions, declare the function name as a
221 // constant.
222 if (scope()->is_function_scope() && scope()->function() != NULL) {
223 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
224 }
225 VisitDeclarations(scope()->declarations());
226 }
227
228 { Comment cmnt(masm_, "[ Stack check");
229 PrepareForBailout(info->function(), NO_REGISTERS);
230 NearLabel ok;
231 ExternalReference stack_limit =
232 ExternalReference::address_of_stack_limit();
233 __ cmp(esp, Operand::StaticVariable(stack_limit));
234 __ j(above_equal, &ok, taken);
235 StackCheckStub stub;
236 __ CallStub(&stub);
237 __ bind(&ok);
238 }
239
240 { Comment cmnt(masm_, "[ Body");
241 ASSERT(loop_depth() == 0);
242 VisitStatements(function()->body());
243 ASSERT(loop_depth() == 0);
244 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000245 }
246
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000247 // Always emit a 'return undefined' in case control fell off the end of
248 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000249 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000250 __ mov(eax, Factory::undefined_value());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000251 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000252 }
253}
254
255
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000256void FullCodeGenerator::ClearAccumulator() {
257 __ Set(eax, Immediate(Smi::FromInt(0)));
258}
259
260
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000261void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
262 Comment cmnt(masm_, "[ Stack check");
263 NearLabel ok;
264 ExternalReference stack_limit = ExternalReference::address_of_stack_limit();
265 __ cmp(esp, Operand::StaticVariable(stack_limit));
266 __ j(above_equal, &ok, taken);
267 StackCheckStub stub;
268 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000269 // Record a mapping of this PC offset to the OSR id. This is used to find
270 // the AST id from the unoptimized code in order to use it as a key into
271 // the deoptimization input data found in the optimized code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000272 RecordStackCheck(stmt->OsrEntryId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000273
274 // Loop stack checks can be patched to perform on-stack replacement. In
275 // order to decide whether or not to perform OSR we embed the loop depth
276 // in a test instruction after the call so we can extract it from the OSR
277 // builtin.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000278 ASSERT(loop_depth() > 0);
279 __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000280
281 __ bind(&ok);
282 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
283 // Record a mapping of the OSR id to this PC. This is used if the OSR
284 // entry becomes the target of a bailout. We don't expect it to be, but
285 // we want it to work if it is.
286 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000287}
288
289
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000290void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000291 Comment cmnt(masm_, "[ Return sequence");
292 if (return_label_.is_bound()) {
293 __ jmp(&return_label_);
294 } else {
295 // Common return label
296 __ bind(&return_label_);
297 if (FLAG_trace) {
298 __ push(eax);
299 __ CallRuntime(Runtime::kTraceExit, 1);
300 }
301#ifdef DEBUG
302 // Add a label for checking the size of the code used for returning.
303 Label check_exit_codesize;
304 masm_->bind(&check_exit_codesize);
305#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000306 SetSourcePosition(function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000307 __ RecordJSReturn();
308 // Do not use the leave instruction here because it is too short to
309 // patch with the code required by the debugger.
310 __ mov(esp, ebp);
311 __ pop(ebp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000312
313 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize;
314 __ Ret(arguments_bytes, ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000315#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000316 // Check that the size of the code used for returning is large enough
317 // for the debugger's requirements.
318 ASSERT(Assembler::kJSReturnSequenceLength <=
319 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000320#endif
321 }
322}
323
324
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000325FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
326 Token::Value op, Expression* left, Expression* right) {
327 ASSERT(ShouldInlineSmiCase(op));
328 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) {
329 // We never generate inlined constant smi operations for these.
330 return kNoConstants;
331 } else if (right->IsSmiLiteral()) {
332 return kRightConstant;
333 } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000334 // Don't inline shifts with constant left hand side.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000335 return kLeftConstant;
336 } else {
337 return kNoConstants;
338 }
339}
340
341
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000342void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000343}
344
345
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000346void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
347 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
348 __ mov(result_register(), slot_operand);
349}
350
351
352void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
353 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
354 // Memory operands can be pushed directly.
355 __ push(slot_operand);
356}
357
358
359void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
360 // For simplicity we always test the accumulator register.
361 codegen()->Move(result_register(), slot);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000362 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000363 codegen()->DoTest(true_label_, false_label_, fall_through_);
364}
365
366
367void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
368 UNREACHABLE(); // Not used on IA32.
369}
370
371
372void FullCodeGenerator::AccumulatorValueContext::Plug(
373 Heap::RootListIndex index) const {
374 UNREACHABLE(); // Not used on IA32.
375}
376
377
378void FullCodeGenerator::StackValueContext::Plug(
379 Heap::RootListIndex index) const {
380 UNREACHABLE(); // Not used on IA32.
381}
382
383
384void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
385 UNREACHABLE(); // Not used on IA32.
386}
387
388
389void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
390}
391
392
393void FullCodeGenerator::AccumulatorValueContext::Plug(
394 Handle<Object> lit) const {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000395 __ Set(result_register(), Immediate(lit));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000396}
397
398
399void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
400 // Immediates can be pushed directly.
401 __ push(Immediate(lit));
402}
403
404
405void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000406 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
407 true,
408 true_label_,
409 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000410 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
411 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000412 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000413 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000414 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000415 } else if (lit->IsString()) {
416 if (String::cast(*lit)->length() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000417 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000418 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000419 if (true_label_ != fall_through_) __ jmp(true_label_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000420 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000421 } else if (lit->IsSmi()) {
422 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000423 if (false_label_ != fall_through_) __ jmp(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000424 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000425 if (true_label_ != fall_through_) __ jmp(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000426 }
427 } else {
428 // For simplicity we always test the accumulator register.
429 __ mov(result_register(), lit);
430 codegen()->DoTest(true_label_, false_label_, fall_through_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000431 }
432}
433
434
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000435void FullCodeGenerator::EffectContext::DropAndPlug(int count,
436 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000437 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000438 __ Drop(count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000439}
440
441
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000442void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
443 int count,
444 Register reg) const {
445 ASSERT(count > 0);
446 __ Drop(count);
447 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000448}
449
450
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000451void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
452 Register reg) const {
453 ASSERT(count > 0);
454 if (count > 1) __ Drop(count - 1);
455 __ mov(Operand(esp, 0), reg);
456}
457
458
459void FullCodeGenerator::TestContext::DropAndPlug(int count,
460 Register reg) const {
461 ASSERT(count > 0);
462 // For simplicity we always test the accumulator register.
463 __ Drop(count);
464 __ Move(result_register(), reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000465 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000466 codegen()->DoTest(true_label_, false_label_, fall_through_);
467}
468
469
470void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
471 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000472 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000473 __ bind(materialize_true);
474}
475
476
477void FullCodeGenerator::AccumulatorValueContext::Plug(
478 Label* materialize_true,
479 Label* materialize_false) const {
480 NearLabel done;
481 __ bind(materialize_true);
482 __ mov(result_register(), Factory::true_value());
483 __ jmp(&done);
484 __ bind(materialize_false);
485 __ mov(result_register(), Factory::false_value());
486 __ bind(&done);
487}
488
489
490void FullCodeGenerator::StackValueContext::Plug(
491 Label* materialize_true,
492 Label* materialize_false) const {
493 NearLabel done;
494 __ bind(materialize_true);
495 __ push(Immediate(Factory::true_value()));
496 __ jmp(&done);
497 __ bind(materialize_false);
498 __ push(Immediate(Factory::false_value()));
499 __ bind(&done);
500}
501
502
503void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
504 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000505 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000506 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000507}
508
509
510void FullCodeGenerator::EffectContext::Plug(bool flag) const {
511}
512
513
514void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
515 Handle<Object> value =
516 flag ? Factory::true_value() : Factory::false_value();
517 __ mov(result_register(), value);
518}
519
520
521void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
522 Handle<Object> value =
523 flag ? Factory::true_value() : Factory::false_value();
524 __ push(Immediate(value));
525}
526
527
528void FullCodeGenerator::TestContext::Plug(bool flag) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000529 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
530 true,
531 true_label_,
532 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000533 if (flag) {
534 if (true_label_ != fall_through_) __ jmp(true_label_);
535 } else {
536 if (false_label_ != fall_through_) __ jmp(false_label_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000537 }
538}
539
540
ricow@chromium.org65fae842010-08-25 15:26:24 +0000541void FullCodeGenerator::DoTest(Label* if_true,
542 Label* if_false,
543 Label* fall_through) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000544 // Emit the inlined tests assumed by the stub.
545 __ cmp(result_register(), Factory::undefined_value());
546 __ j(equal, if_false);
547 __ cmp(result_register(), Factory::true_value());
548 __ j(equal, if_true);
549 __ cmp(result_register(), Factory::false_value());
550 __ j(equal, if_false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000551 STATIC_ASSERT(kSmiTag == 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000552 __ test(result_register(), Operand(result_register()));
553 __ j(zero, if_false);
554 __ test(result_register(), Immediate(kSmiTagMask));
555 __ j(zero, if_true);
556
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000557 // Call the ToBoolean stub for all other cases.
558 ToBooleanStub stub;
559 __ push(result_register());
560 __ CallStub(&stub);
561 __ test(eax, Operand(eax));
562
ricow@chromium.org65fae842010-08-25 15:26:24 +0000563 // The stub returns nonzero for true.
564 Split(not_zero, if_true, if_false, fall_through);
565}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000566
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000567
ricow@chromium.org65fae842010-08-25 15:26:24 +0000568void FullCodeGenerator::Split(Condition cc,
569 Label* if_true,
570 Label* if_false,
571 Label* fall_through) {
572 if (if_false == fall_through) {
573 __ j(cc, if_true);
574 } else if (if_true == fall_through) {
575 __ j(NegateCondition(cc), if_false);
576 } else {
577 __ j(cc, if_true);
578 __ jmp(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000579 }
580}
581
582
583MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
584 switch (slot->type()) {
585 case Slot::PARAMETER:
586 case Slot::LOCAL:
587 return Operand(ebp, SlotOffset(slot));
588 case Slot::CONTEXT: {
589 int context_chain_length =
ager@chromium.org5c838252010-02-19 08:53:10 +0000590 scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000591 __ LoadContext(scratch, context_chain_length);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000592 return ContextOperand(scratch, slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000593 }
594 case Slot::LOOKUP:
595 UNREACHABLE();
596 }
597 UNREACHABLE();
598 return Operand(eax, 0);
599}
600
601
602void FullCodeGenerator::Move(Register destination, Slot* source) {
603 MemOperand location = EmitSlotSearch(source, destination);
604 __ mov(destination, location);
605}
606
607
608void FullCodeGenerator::Move(Slot* dst,
609 Register src,
610 Register scratch1,
611 Register scratch2) {
612 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
613 ASSERT(!scratch1.is(src) && !scratch2.is(src));
614 MemOperand location = EmitSlotSearch(dst, scratch1);
615 __ mov(location, src);
616 // Emit the write barrier code if the location is in the heap.
617 if (dst->type() == Slot::CONTEXT) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000618 int offset = Context::SlotOffset(dst->index());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000619 ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000620 __ RecordWrite(scratch1, offset, src, scratch2);
621 }
622}
623
624
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000625void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
626 bool should_normalize,
627 Label* if_true,
628 Label* if_false) {
629 // Only prepare for bailouts before splits if we're in a test
630 // context. Otherwise, we let the Visit function deal with the
631 // preparation to avoid preparing with the same AST id twice.
632 if (!context()->IsTest() || !info_->IsOptimizable()) return;
633
634 NearLabel skip;
635 if (should_normalize) __ jmp(&skip);
636
637 ForwardBailoutStack* current = forward_bailout_stack_;
638 while (current != NULL) {
639 PrepareForBailout(current->expr(), state);
640 current = current->parent();
641 }
642
643 if (should_normalize) {
644 __ cmp(eax, Factory::true_value());
645 Split(equal, if_true, if_false, NULL);
646 __ bind(&skip);
647 }
648}
649
650
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000651void FullCodeGenerator::EmitDeclaration(Variable* variable,
652 Variable::Mode mode,
653 FunctionLiteral* function) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000654 Comment cmnt(masm_, "[ Declaration");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000655 ASSERT(variable != NULL); // Must have been resolved.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000656 Slot* slot = variable->AsSlot();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000657 Property* prop = variable->AsProperty();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000658
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000659 if (slot != NULL) {
660 switch (slot->type()) {
661 case Slot::PARAMETER:
662 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000663 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000664 __ mov(Operand(ebp, SlotOffset(slot)),
665 Immediate(Factory::the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000666 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000667 VisitForAccumulatorValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000668 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
669 }
670 break;
671
672 case Slot::CONTEXT:
673 // We bypass the general EmitSlotSearch because we know more about
674 // this specific context.
675
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000676 // The variable in the decl always resides in the current function
677 // context.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000678 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000679 if (FLAG_debug_code) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000680 // Check that we're not inside a 'with'.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000681 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000682 __ cmp(ebx, Operand(esi));
683 __ Check(equal, "Unexpected declaration in current context.");
684 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000685 if (mode == Variable::CONST) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000686 __ mov(ContextOperand(esi, slot->index()),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000687 Immediate(Factory::the_hole_value()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000688 // No write barrier since the hole value is in old space.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000689 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000690 VisitForAccumulatorValue(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000691 __ mov(ContextOperand(esi, slot->index()), result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000692 int offset = Context::SlotOffset(slot->index());
693 __ mov(ebx, esi);
694 __ RecordWrite(ebx, offset, result_register(), ecx);
695 }
696 break;
697
698 case Slot::LOOKUP: {
699 __ push(esi);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000700 __ push(Immediate(variable->name()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000701 // Declaration nodes are always introduced in one of two modes.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000702 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
703 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000704 __ push(Immediate(Smi::FromInt(attr)));
705 // Push initial value, if any.
706 // Note: For variables we must not push an initial value (such as
707 // 'undefined') because we may have a (legal) redeclaration and we
708 // must not destroy the current value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000709 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000710 __ push(Immediate(Factory::the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000711 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000712 VisitForStackValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000713 } else {
714 __ push(Immediate(Smi::FromInt(0))); // No initial value!
715 }
716 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
717 break;
718 }
719 }
720
721 } else if (prop != NULL) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000722 if (function != NULL || mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000723 // We are declaring a function or constant that rewrites to a
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000724 // property. Use (keyed) IC to set the initial value. We cannot
725 // visit the rewrite because it's shared and we risk recording
726 // duplicate AST IDs for bailouts from optimized code.
727 ASSERT(prop->obj()->AsVariableProxy() != NULL);
728 { AccumulatorValueContext for_object(this);
729 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000730 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000731
732 if (function != NULL) {
733 __ push(eax);
734 VisitForAccumulatorValue(function);
735 __ pop(edx);
736 } else {
737 __ mov(edx, eax);
738 __ mov(eax, Factory::the_hole_value());
739 }
740 ASSERT(prop->key()->AsLiteral() != NULL &&
741 prop->key()->AsLiteral()->handle()->IsSmi());
742 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000743
744 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000745 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000746 }
747 }
748}
749
750
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000751void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
752 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
753}
754
755
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000756void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
757 // Call the runtime to declare the globals.
758 __ push(esi); // The context is the first argument.
759 __ push(Immediate(pairs));
ager@chromium.org5c838252010-02-19 08:53:10 +0000760 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000761 __ CallRuntime(Runtime::kDeclareGlobals, 3);
762 // Return value is ignored.
763}
764
765
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000766void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
767 Comment cmnt(masm_, "[ SwitchStatement");
768 Breakable nested_statement(this, stmt);
769 SetStatementPosition(stmt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000770
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000771 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000772 VisitForStackValue(stmt->tag());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000773 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000774
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000775 ZoneList<CaseClause*>* clauses = stmt->cases();
776 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000777
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000778 Label next_test; // Recycled for each test.
779 // Compile all the tests with branches to their bodies.
780 for (int i = 0; i < clauses->length(); i++) {
781 CaseClause* clause = clauses->at(i);
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000782 clause->body_target()->entry_label()->Unuse();
783
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000784 // The default is not a test, but remember it as final fall through.
785 if (clause->is_default()) {
786 default_clause = clause;
787 continue;
788 }
789
790 Comment cmnt(masm_, "[ Case comparison");
791 __ bind(&next_test);
792 next_test.Unuse();
793
794 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000795 VisitForAccumulatorValue(clause->label());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000796
ricow@chromium.org65fae842010-08-25 15:26:24 +0000797 // Perform the comparison as if via '==='.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000798 __ mov(edx, Operand(esp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000799 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000800 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000801 if (inline_smi_code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000802 NearLabel slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000803 __ mov(ecx, edx);
804 __ or_(ecx, Operand(eax));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000805 patch_site.EmitJumpIfNotSmi(ecx, &slow_case);
806
ricow@chromium.org65fae842010-08-25 15:26:24 +0000807 __ cmp(edx, 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 __ bind(&slow_case);
812 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000813
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000814 // Record position before stub call for type feedback.
815 SetSourcePosition(clause->position());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000816 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000817 EmitCallIC(ic, &patch_site);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000818 __ test(eax, Operand(eax));
819 __ j(not_equal, &next_test);
820 __ Drop(1); // Switch value is no longer needed.
821 __ jmp(clause->body_target()->entry_label());
822 }
823
824 // Discard the test value and jump to the default if present, otherwise to
825 // the end of the statement.
826 __ bind(&next_test);
827 __ Drop(1); // Switch value is no longer needed.
828 if (default_clause == NULL) {
829 __ jmp(nested_statement.break_target());
830 } else {
831 __ jmp(default_clause->body_target()->entry_label());
832 }
833
834 // Compile all the case bodies.
835 for (int i = 0; i < clauses->length(); i++) {
836 Comment cmnt(masm_, "[ Case body");
837 CaseClause* clause = clauses->at(i);
838 __ bind(clause->body_target()->entry_label());
839 VisitStatements(clause->statements());
840 }
841
842 __ bind(nested_statement.break_target());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000843 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000844}
845
846
847void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
848 Comment cmnt(masm_, "[ ForInStatement");
849 SetStatementPosition(stmt);
850
851 Label loop, exit;
852 ForIn loop_statement(this, stmt);
853 increment_loop_depth();
854
855 // Get the object to enumerate over. Both SpiderMonkey and JSC
856 // ignore null and undefined in contrast to the specification; see
857 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000858 VisitForAccumulatorValue(stmt->enumerable());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000859 __ cmp(eax, Factory::undefined_value());
860 __ j(equal, &exit);
861 __ cmp(eax, Factory::null_value());
862 __ j(equal, &exit);
863
864 // Convert the object to a JS object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000865 NearLabel convert, done_convert;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000866 __ test(eax, Immediate(kSmiTagMask));
867 __ j(zero, &convert);
868 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
869 __ j(above_equal, &done_convert);
870 __ bind(&convert);
871 __ push(eax);
872 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
873 __ bind(&done_convert);
874 __ push(eax);
875
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000876 // Check cache validity in generated code. This is a fast case for
877 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
878 // guarantee cache validity, call the runtime system to check cache
879 // validity or get the property names in a fixed array.
880 Label next, call_runtime;
881 __ mov(ecx, eax);
882 __ bind(&next);
883
884 // Check that there are no elements. Register ecx contains the
885 // current JS object we've reached through the prototype chain.
886 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset),
887 Factory::empty_fixed_array());
888 __ j(not_equal, &call_runtime);
889
890 // Check that instance descriptors are not empty so that we can
891 // check for an enum cache. Leave the map in ebx for the subsequent
892 // prototype load.
893 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
894 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
895 __ cmp(edx, Factory::empty_descriptor_array());
896 __ j(equal, &call_runtime);
897
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000898 // Check that there is an enum cache in the non-empty instance
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000899 // descriptors (edx). This is the case if the next enumeration
900 // index field does not contain a smi.
901 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
902 __ test(edx, Immediate(kSmiTagMask));
903 __ j(zero, &call_runtime);
904
905 // For all objects but the receiver, check that the cache is empty.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000906 NearLabel check_prototype;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000907 __ cmp(ecx, Operand(eax));
908 __ j(equal, &check_prototype);
909 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
910 __ cmp(edx, Factory::empty_fixed_array());
911 __ j(not_equal, &call_runtime);
912
913 // Load the prototype from the map and loop if non-null.
914 __ bind(&check_prototype);
915 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
916 __ cmp(ecx, Factory::null_value());
917 __ j(not_equal, &next);
918
919 // The enum cache is valid. Load the map of the object being
920 // iterated over and use the cache for the iteration.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000921 NearLabel use_cache;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000922 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
923 __ jmp(&use_cache);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000924
925 // Get the set of properties to enumerate.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000926 __ bind(&call_runtime);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000927 __ push(eax); // Duplicate the enumerable object on the stack.
928 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
929
930 // If we got a map from the runtime call, we can do a fast
931 // modification check. Otherwise, we got a fixed array, and we have
932 // to do a slow check.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000933 NearLabel fixed_array;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000934 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map());
935 __ j(not_equal, &fixed_array);
936
937 // We got a map in register eax. Get the enumeration cache from it.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000938 __ bind(&use_cache);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000939 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset));
940 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
941 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
942
943 // Setup the four remaining stack slots.
944 __ push(eax); // Map.
945 __ push(edx); // Enumeration cache.
946 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000947 __ push(eax); // Enumeration cache length (as smi).
948 __ push(Immediate(Smi::FromInt(0))); // Initial index.
949 __ jmp(&loop);
950
951 // We got a fixed array in register eax. Iterate through that.
952 __ bind(&fixed_array);
953 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
954 __ push(eax);
955 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000956 __ push(eax); // Fixed array length (as smi).
957 __ push(Immediate(Smi::FromInt(0))); // Initial index.
958
959 // Generate code for doing the condition check.
960 __ bind(&loop);
961 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
962 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
963 __ j(above_equal, loop_statement.break_target());
964
965 // Get the current entry of the array into register ebx.
966 __ mov(ebx, Operand(esp, 2 * kPointerSize));
967 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
968
969 // Get the expected map from the stack or a zero map in the
970 // permanent slow case into register edx.
971 __ mov(edx, Operand(esp, 3 * kPointerSize));
972
973 // Check if the expected map still matches that of the enumerable.
974 // If not, we have to filter the key.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000975 NearLabel update_each;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000976 __ mov(ecx, Operand(esp, 4 * kPointerSize));
977 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
978 __ j(equal, &update_each);
979
980 // Convert the entry to a string or null if it isn't a property
981 // anymore. If the property has been removed while iterating, we
982 // just skip it.
983 __ push(ecx); // Enumerable.
984 __ push(ebx); // Current entry.
985 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000986 __ test(eax, Operand(eax));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000987 __ j(equal, loop_statement.continue_target());
988 __ mov(ebx, Operand(eax));
989
990 // Update the 'each' property or variable from the possibly filtered
991 // entry in register ebx.
992 __ bind(&update_each);
993 __ mov(result_register(), ebx);
994 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000995 { EffectContext context(this);
996 EmitAssignment(stmt->each(), stmt->AssignmentId());
997 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000998
999 // Generate code for the body of the loop.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001000 Visit(stmt->body());
1001
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001002 // Generate code for going to the next element by incrementing the
1003 // index (smi) stored on top of the stack.
1004 __ bind(loop_statement.continue_target());
1005 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001006
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001007 EmitStackCheck(stmt);
1008 __ jmp(&loop);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001009
1010 // Remove the pointers stored on the stack.
1011 __ bind(loop_statement.break_target());
1012 __ add(Operand(esp), Immediate(5 * kPointerSize));
1013
1014 // Exit and decrement the loop depth.
1015 __ bind(&exit);
1016 decrement_loop_depth();
1017}
1018
1019
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001020void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1021 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001022 // Use the fast case closure allocation code that allocates in new
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001023 // space for nested functions that don't need literals cloning. If
1024 // we're running with the --always-opt or the --prepare-always-opt
1025 // flag, we need to use the runtime function so that the new function
1026 // we are creating here gets a chance to have its code optimized and
1027 // doesn't just get a copy of the existing unoptimized code.
1028 if (!FLAG_always_opt &&
1029 !FLAG_prepare_always_opt &&
1030 scope()->is_function_scope() &&
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001031 info->num_literals() == 0 &&
1032 !pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001033 FastNewClosureStub stub;
1034 __ push(Immediate(info));
1035 __ CallStub(&stub);
1036 } else {
1037 __ push(esi);
1038 __ push(Immediate(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001039 __ push(Immediate(pretenure
1040 ? Factory::true_value()
1041 : Factory::false_value()));
1042 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001043 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001044 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001045}
1046
1047
1048void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1049 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001050 EmitVariableLoad(expr->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001051}
1052
1053
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001054void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
1055 Slot* slot,
1056 TypeofState typeof_state,
1057 Label* slow) {
1058 Register context = esi;
1059 Register temp = edx;
1060
1061 Scope* s = scope();
1062 while (s != NULL) {
1063 if (s->num_heap_slots() > 0) {
1064 if (s->calls_eval()) {
1065 // Check that extension is NULL.
1066 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1067 Immediate(0));
1068 __ j(not_equal, slow);
1069 }
1070 // Load next context in chain.
1071 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1072 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1073 // Walk the rest of the chain without clobbering esi.
1074 context = temp;
1075 }
1076 // If no outer scope calls eval, we do not need to check more
1077 // context extensions. If we have reached an eval scope, we check
1078 // all extensions from this point.
1079 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1080 s = s->outer_scope();
1081 }
1082
1083 if (s != NULL && s->is_eval_scope()) {
1084 // Loop up the context chain. There is no frame effect so it is
1085 // safe to use raw labels here.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001086 NearLabel next, fast;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001087 if (!context.is(temp)) {
1088 __ mov(temp, context);
1089 }
1090 __ bind(&next);
1091 // Terminate at global context.
1092 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
1093 Immediate(Factory::global_context_map()));
1094 __ j(equal, &fast);
1095 // Check that extension is NULL.
1096 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1097 __ j(not_equal, slow);
1098 // Load next context in chain.
1099 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX));
1100 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1101 __ jmp(&next);
1102 __ bind(&fast);
1103 }
1104
1105 // All extension objects were empty and it is safe to use a global
1106 // load IC call.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001107 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001108 __ mov(ecx, slot->var()->name());
1109 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1110 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1111 ? RelocInfo::CODE_TARGET
1112 : RelocInfo::CODE_TARGET_CONTEXT;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001113 EmitCallIC(ic, mode);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001114}
1115
1116
1117MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1118 Slot* slot,
1119 Label* slow) {
1120 ASSERT(slot->type() == Slot::CONTEXT);
1121 Register context = esi;
1122 Register temp = ebx;
1123
1124 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1125 if (s->num_heap_slots() > 0) {
1126 if (s->calls_eval()) {
1127 // Check that extension is NULL.
1128 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1129 Immediate(0));
1130 __ j(not_equal, slow);
1131 }
1132 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1133 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1134 // Walk the rest of the chain without clobbering esi.
1135 context = temp;
1136 }
1137 }
1138 // Check that last extension is NULL.
1139 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1140 __ j(not_equal, slow);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001141
1142 // This function is used only for loads, not stores, so it's safe to
1143 // return an esi-based operand (the write barrier cannot be allowed to
1144 // destroy the esi register).
1145 return ContextOperand(context, slot->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001146}
1147
1148
1149void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1150 Slot* slot,
1151 TypeofState typeof_state,
1152 Label* slow,
1153 Label* done) {
1154 // Generate fast-case code for variables that might be shadowed by
1155 // eval-introduced variables. Eval is used a lot without
1156 // introducing variables. In those cases, we do not want to
1157 // perform a runtime call for all variables in the scope
1158 // containing the eval.
1159 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1160 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1161 __ jmp(done);
1162 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001163 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001164 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1165 if (potential_slot != NULL) {
1166 // Generate fast case for locals that rewrite to slots.
1167 __ mov(eax,
1168 ContextSlotOperandCheckExtensions(potential_slot, slow));
1169 if (potential_slot->var()->mode() == Variable::CONST) {
1170 __ cmp(eax, Factory::the_hole_value());
1171 __ j(not_equal, done);
1172 __ mov(eax, Factory::undefined_value());
1173 }
1174 __ jmp(done);
1175 } else if (rewrite != NULL) {
1176 // Generate fast case for calls of an argument function.
1177 Property* property = rewrite->AsProperty();
1178 if (property != NULL) {
1179 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1180 Literal* key_literal = property->key()->AsLiteral();
1181 if (obj_proxy != NULL &&
1182 key_literal != NULL &&
1183 obj_proxy->IsArguments() &&
1184 key_literal->handle()->IsSmi()) {
1185 // Load arguments object if there are no eval-introduced
1186 // variables. Then load the argument from the arguments
1187 // object using keyed load.
1188 __ mov(edx,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001189 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001190 slow));
1191 __ mov(eax, Immediate(key_literal->handle()));
1192 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001193 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001194 __ jmp(done);
1195 }
1196 }
1197 }
1198 }
1199}
1200
1201
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001202void FullCodeGenerator::EmitVariableLoad(Variable* var) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001203 // Four cases: non-this global variables, lookup slots, all other
1204 // types of slots, and parameters that rewrite to explicit property
1205 // accesses on the arguments object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001206 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001207 Property* property = var->AsProperty();
1208
1209 if (var->is_global() && !var->is_this()) {
1210 Comment cmnt(masm_, "Global variable");
1211 // Use inline caching. Variable name is passed in ecx and the global
1212 // object on the stack.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001213 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001214 __ mov(ecx, var->name());
1215 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001216 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001217 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001218
1219 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001220 Label done, slow;
1221
1222 // Generate code for loading from variables potentially shadowed
1223 // by eval-introduced variables.
1224 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1225
1226 __ bind(&slow);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001227 Comment cmnt(masm_, "Lookup slot");
1228 __ push(esi); // Context.
1229 __ push(Immediate(var->name()));
1230 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001231 __ bind(&done);
1232
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001233 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001234
1235 } else if (slot != NULL) {
1236 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1237 ? "Context slot"
1238 : "Stack slot");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001239 if (var->mode() == Variable::CONST) {
1240 // Constants may be the hole value if they have not been initialized.
1241 // Unhole them.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001242 NearLabel done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001243 MemOperand slot_operand = EmitSlotSearch(slot, eax);
1244 __ mov(eax, slot_operand);
1245 __ cmp(eax, Factory::the_hole_value());
1246 __ j(not_equal, &done);
1247 __ mov(eax, Factory::undefined_value());
1248 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001249 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001250 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001251 context()->Plug(slot);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001252 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001253
1254 } else {
1255 Comment cmnt(masm_, "Rewritten parameter");
1256 ASSERT_NOT_NULL(property);
1257 // Rewritten parameter accesses are of the form "slot[literal]".
1258
1259 // Assert that the object is in a slot.
1260 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1261 ASSERT_NOT_NULL(object_var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001262 Slot* object_slot = object_var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001263 ASSERT_NOT_NULL(object_slot);
1264
1265 // Load the object.
1266 MemOperand object_loc = EmitSlotSearch(object_slot, eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001267 __ mov(edx, object_loc);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001268
1269 // Assert that the key is a smi.
1270 Literal* key_literal = property->key()->AsLiteral();
1271 ASSERT_NOT_NULL(key_literal);
1272 ASSERT(key_literal->handle()->IsSmi());
1273
1274 // Load the key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001275 __ mov(eax, Immediate(key_literal->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001276
1277 // Do a keyed property load.
1278 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001279 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1280
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001281 // Drop key and object left on the stack by IC.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001282 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001283 }
1284}
1285
1286
1287void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1288 Comment cmnt(masm_, "[ RegExpLiteral");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001289 NearLabel materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001290 // Registers will be used as follows:
1291 // edi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001292 // ecx = literals array.
1293 // ebx = regexp literal.
1294 // eax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001295 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001296 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001297 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001298 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001299 __ mov(ebx, FieldOperand(ecx, literal_offset));
1300 __ cmp(ebx, Factory::undefined_value());
1301 __ j(not_equal, &materialized);
1302
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001303 // Create regexp literal using runtime function
1304 // Result will be in eax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001305 __ push(ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001306 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1307 __ push(Immediate(expr->pattern()));
1308 __ push(Immediate(expr->flags()));
1309 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001310 __ mov(ebx, eax);
1311
1312 __ bind(&materialized);
1313 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1314 Label allocated, runtime_allocate;
1315 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1316 __ jmp(&allocated);
1317
1318 __ bind(&runtime_allocate);
1319 __ push(ebx);
1320 __ push(Immediate(Smi::FromInt(size)));
1321 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1322 __ pop(ebx);
1323
1324 __ bind(&allocated);
1325 // Copy the content into the newly allocated memory.
1326 // (Unroll copy loop once for better throughput).
1327 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1328 __ mov(edx, FieldOperand(ebx, i));
1329 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1330 __ mov(FieldOperand(eax, i), edx);
1331 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1332 }
1333 if ((size % (2 * kPointerSize)) != 0) {
1334 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1335 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1336 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001337 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001338}
1339
1340
1341void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1342 Comment cmnt(masm_, "[ ObjectLiteral");
1343 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1344 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1345 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1346 __ push(Immediate(expr->constant_properties()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001347 __ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001348 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001349 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001350 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001351 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001352 }
1353
1354 // If result_saved is true the result is on top of the stack. If
1355 // result_saved is false the result is in eax.
1356 bool result_saved = false;
1357
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001358 // Mark all computed expressions that are bound to a key that
1359 // is shadowed by a later occurrence of the same key. For the
1360 // marked expressions, no store code is emitted.
1361 expr->CalculateEmitStore();
1362
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001363 for (int i = 0; i < expr->properties()->length(); i++) {
1364 ObjectLiteral::Property* property = expr->properties()->at(i);
1365 if (property->IsCompileTimeValue()) continue;
1366
1367 Literal* key = property->key();
1368 Expression* value = property->value();
1369 if (!result_saved) {
1370 __ push(eax); // Save result on the stack
1371 result_saved = true;
1372 }
1373 switch (property->kind()) {
1374 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1375 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1376 // Fall through.
1377 case ObjectLiteral::Property::COMPUTED:
1378 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001379 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001380 VisitForAccumulatorValue(value);
1381 __ mov(ecx, Immediate(key->handle()));
1382 __ mov(edx, Operand(esp, 0));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001383 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1384 EmitCallIC(ic, RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001385 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1386 } else {
1387 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001388 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001389 break;
1390 }
1391 // Fall through.
1392 case ObjectLiteral::Property::PROTOTYPE:
1393 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001394 VisitForStackValue(key);
1395 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001396 if (property->emit_store()) {
1397 __ CallRuntime(Runtime::kSetProperty, 3);
1398 } else {
1399 __ Drop(3);
1400 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001401 break;
1402 case ObjectLiteral::Property::SETTER:
1403 case ObjectLiteral::Property::GETTER:
1404 __ push(Operand(esp, 0)); // Duplicate receiver.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001405 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001406 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
1407 Smi::FromInt(1) :
1408 Smi::FromInt(0)));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001409 VisitForStackValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001410 __ CallRuntime(Runtime::kDefineAccessor, 4);
1411 break;
1412 default: UNREACHABLE();
1413 }
1414 }
1415
1416 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001417 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001418 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001419 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001420 }
1421}
1422
1423
1424void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1425 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001426
1427 ZoneList<Expression*>* subexprs = expr->values();
1428 int length = subexprs->length();
1429
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001430 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1431 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1432 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1433 __ push(Immediate(expr->constant_elements()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001434 if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001435 ASSERT(expr->depth() == 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001436 FastCloneShallowArrayStub stub(
1437 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1438 __ CallStub(&stub);
1439 __ IncrementCounter(&Counters::cow_arrays_created_stub, 1);
1440 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001441 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001442 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001443 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001444 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001445 FastCloneShallowArrayStub stub(
1446 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001447 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001448 }
1449
1450 bool result_saved = false; // Is the result saved to the stack?
1451
1452 // Emit code to evaluate all the non-constant subexpressions and to store
1453 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001454 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001455 Expression* subexpr = subexprs->at(i);
1456 // If the subexpression is a literal or a simple materialized literal it
1457 // is already set in the cloned array.
1458 if (subexpr->AsLiteral() != NULL ||
1459 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1460 continue;
1461 }
1462
1463 if (!result_saved) {
1464 __ push(eax);
1465 result_saved = true;
1466 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001467 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001468
1469 // Store the subexpression value in the array's elements.
1470 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1471 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1472 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1473 __ mov(FieldOperand(ebx, offset), result_register());
1474
1475 // Update the write barrier for the array store.
1476 __ RecordWrite(ebx, offset, result_register(), ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001477
1478 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001479 }
1480
1481 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001482 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001483 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001484 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001485 }
1486}
1487
1488
ager@chromium.org5c838252010-02-19 08:53:10 +00001489void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1490 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001491 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1492 // on the left-hand side.
1493 if (!expr->target()->IsValidLeftHandSide()) {
1494 VisitForEffect(expr->target());
1495 return;
1496 }
1497
ager@chromium.org5c838252010-02-19 08:53:10 +00001498 // Left-hand side can only be a property, a global or a (parameter or local)
1499 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1500 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1501 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001502 Property* property = expr->target()->AsProperty();
1503 if (property != NULL) {
1504 assign_type = (property->key()->IsPropertyName())
1505 ? NAMED_PROPERTY
1506 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001507 }
1508
1509 // Evaluate LHS expression.
1510 switch (assign_type) {
1511 case VARIABLE:
1512 // Nothing to do here.
1513 break;
1514 case NAMED_PROPERTY:
1515 if (expr->is_compound()) {
1516 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001517 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001518 __ push(result_register());
1519 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001520 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001521 }
1522 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001523 case KEYED_PROPERTY: {
ager@chromium.org5c838252010-02-19 08:53:10 +00001524 if (expr->is_compound()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001525 if (property->is_arguments_access()) {
1526 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001527 MemOperand slot_operand =
1528 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
1529 __ push(slot_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001530 __ mov(eax, Immediate(property->key()->AsLiteral()->handle()));
1531 } else {
1532 VisitForStackValue(property->obj());
1533 VisitForAccumulatorValue(property->key());
1534 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001535 __ mov(edx, Operand(esp, 0));
1536 __ push(eax);
1537 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001538 if (property->is_arguments_access()) {
1539 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001540 MemOperand slot_operand =
1541 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
1542 __ push(slot_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001543 __ push(Immediate(property->key()->AsLiteral()->handle()));
1544 } else {
1545 VisitForStackValue(property->obj());
1546 VisitForStackValue(property->key());
1547 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001548 }
1549 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001550 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001551 }
1552
ager@chromium.org5c838252010-02-19 08:53:10 +00001553 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001554 { AccumulatorValueContext context(this);
1555 switch (assign_type) {
1556 case VARIABLE:
1557 EmitVariableLoad(expr->target()->AsVariableProxy()->var());
1558 break;
1559 case NAMED_PROPERTY:
1560 EmitNamedPropertyLoad(property);
1561 break;
1562 case KEYED_PROPERTY:
1563 EmitKeyedPropertyLoad(property);
1564 break;
1565 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001566 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001567
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001568 // For property compound assignments we need another deoptimization
1569 // point after the property load.
1570 if (property != NULL) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001571 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001572 }
1573
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001574 Token::Value op = expr->binary_op();
1575 ConstantOperand constant = ShouldInlineSmiCase(op)
1576 ? GetConstantOperand(op, expr->target(), expr->value())
1577 : kNoConstants;
1578 ASSERT(constant == kRightConstant || constant == kNoConstants);
1579 if (constant == kNoConstants) {
1580 __ push(eax); // Left operand goes on the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001581 VisitForAccumulatorValue(expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001582 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001583
ricow@chromium.org65fae842010-08-25 15:26:24 +00001584 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1585 ? OVERWRITE_RIGHT
1586 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001587 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001588 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001589 if (ShouldInlineSmiCase(op)) {
1590 EmitInlineSmiBinaryOp(expr,
1591 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001592 mode,
1593 expr->target(),
1594 expr->value(),
1595 constant);
1596 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001597 EmitBinaryOp(op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001598 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001599
1600 // Deoptimization point in case the binary operation may have side effects.
1601 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001602 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001603 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001604 }
1605
1606 // Record source position before possible IC call.
1607 SetSourcePosition(expr->position());
1608
1609 // Store the value.
1610 switch (assign_type) {
1611 case VARIABLE:
1612 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001613 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001614 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1615 context()->Plug(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001616 break;
1617 case NAMED_PROPERTY:
1618 EmitNamedPropertyAssignment(expr);
1619 break;
1620 case KEYED_PROPERTY:
1621 EmitKeyedPropertyAssignment(expr);
1622 break;
1623 }
1624}
1625
1626
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001627void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1628 SetSourcePosition(prop->position());
1629 Literal* key = prop->key()->AsLiteral();
1630 __ mov(ecx, Immediate(key->handle()));
1631 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001632 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001633}
1634
1635
1636void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1637 SetSourcePosition(prop->position());
1638 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001639 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001640}
1641
1642
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001643void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001644 OverwriteMode mode,
1645 bool left_is_constant_smi,
1646 Smi* value) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001647 NearLabel call_stub, done;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001648 // Optimistically add smi value with unknown object. If result overflows or is
1649 // not a smi then we had either a smi overflow or added a smi with a tagged
1650 // pointer.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001651 __ add(Operand(eax), Immediate(value));
1652 __ j(overflow, &call_stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001653 JumpPatchSite patch_site(masm_);
1654 patch_site.EmitJumpIfSmi(eax, &done);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001655
1656 // Undo the optimistic add operation and call the shared stub.
1657 __ bind(&call_stub);
1658 __ sub(Operand(eax), Immediate(value));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001659 TypeRecordingBinaryOpStub stub(Token::ADD, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001660 if (left_is_constant_smi) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001661 __ mov(edx, Immediate(value));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001662 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001663 __ mov(edx, eax);
1664 __ mov(eax, Immediate(value));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001665 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001666 EmitCallIC(stub.GetCode(), &patch_site);
1667
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001668 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001669 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001670}
1671
1672
1673void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001674 OverwriteMode mode,
1675 bool left_is_constant_smi,
1676 Smi* value) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001677 NearLabel call_stub, done;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001678 // Optimistically subtract smi value with unknown object. If result overflows
1679 // or is not a smi then we had either a smi overflow or added a smi with a
1680 // tagged pointer.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001681 if (left_is_constant_smi) {
1682 __ mov(ecx, eax);
1683 __ mov(eax, Immediate(value));
1684 __ sub(Operand(eax), ecx);
1685 } else {
1686 __ sub(Operand(eax), Immediate(value));
1687 }
1688 __ j(overflow, &call_stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001689 JumpPatchSite patch_site(masm_);
1690 patch_site.EmitJumpIfSmi(eax, &done);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001691
1692 __ bind(&call_stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001693 if (left_is_constant_smi) {
1694 __ mov(edx, Immediate(value));
1695 __ mov(eax, ecx);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001696 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001697 __ add(Operand(eax), Immediate(value)); // Undo the subtraction.
1698 __ mov(edx, eax);
1699 __ mov(eax, Immediate(value));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001700 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001701 TypeRecordingBinaryOpStub stub(Token::SUB, mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001702 EmitCallIC(stub.GetCode(), &patch_site);
1703
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001704 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001705 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001706}
1707
1708
1709void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
1710 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001711 OverwriteMode mode,
1712 Smi* value) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001713 NearLabel call_stub, smi_case, done;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001714 int shift_value = value->value() & 0x1f;
1715
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001716 JumpPatchSite patch_site(masm_);
1717 patch_site.EmitJumpIfSmi(eax, &smi_case);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001718
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001719 // Call stub.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001720 __ bind(&call_stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001721 __ mov(edx, eax);
1722 __ mov(eax, Immediate(value));
1723 TypeRecordingBinaryOpStub stub(op, mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001724 EmitCallIC(stub.GetCode(), &patch_site);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001725 __ jmp(&done);
1726
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001727 // Smi case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001728 __ bind(&smi_case);
1729 switch (op) {
1730 case Token::SHL:
1731 if (shift_value != 0) {
1732 __ mov(edx, eax);
1733 if (shift_value > 1) {
1734 __ shl(edx, shift_value - 1);
1735 }
1736 // Convert int result to smi, checking that it is in int range.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001737 STATIC_ASSERT(kSmiTagSize == 1); // Adjust code if not the case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001738 __ add(edx, Operand(edx));
1739 __ j(overflow, &call_stub);
1740 __ mov(eax, edx); // Put result back into eax.
1741 }
1742 break;
1743 case Token::SAR:
1744 if (shift_value != 0) {
1745 __ sar(eax, shift_value);
1746 __ and_(eax, ~kSmiTagMask);
1747 }
1748 break;
1749 case Token::SHR:
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001750 // SHR must return a positive value. When shifting by 0 or 1 we need to
1751 // check that smi tagging the result will not create a negative value.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001752 if (shift_value < 2) {
1753 __ mov(edx, eax);
1754 __ SmiUntag(edx);
1755 __ shr(edx, shift_value);
1756 __ test(edx, Immediate(0xc0000000));
1757 __ j(not_zero, &call_stub);
1758 __ SmiTag(edx);
1759 __ mov(eax, edx); // Put result back into eax.
1760 } else {
1761 __ SmiUntag(eax);
1762 __ shr(eax, shift_value);
1763 __ SmiTag(eax);
1764 }
1765 break;
1766 default:
1767 UNREACHABLE();
1768 }
1769
1770 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001771 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001772}
1773
1774
1775void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
1776 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001777 OverwriteMode mode,
1778 Smi* value) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001779 NearLabel smi_case, done;
1780
1781 JumpPatchSite patch_site(masm_);
1782 patch_site.EmitJumpIfSmi(eax, &smi_case);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001783
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001784 // The order of the arguments does not matter for bit-ops with a
1785 // constant operand.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001786 __ mov(edx, Immediate(value));
1787 TypeRecordingBinaryOpStub stub(op, mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001788 EmitCallIC(stub.GetCode(), &patch_site);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001789 __ jmp(&done);
1790
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001791 // Smi case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001792 __ bind(&smi_case);
1793 switch (op) {
1794 case Token::BIT_OR:
1795 __ or_(Operand(eax), Immediate(value));
1796 break;
1797 case Token::BIT_XOR:
1798 __ xor_(Operand(eax), Immediate(value));
1799 break;
1800 case Token::BIT_AND:
1801 __ and_(Operand(eax), Immediate(value));
1802 break;
1803 default:
1804 UNREACHABLE();
1805 }
1806
1807 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001808 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001809}
1810
1811
1812void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
1813 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001814 OverwriteMode mode,
1815 bool left_is_constant_smi,
1816 Smi* value) {
1817 switch (op) {
1818 case Token::BIT_OR:
1819 case Token::BIT_XOR:
1820 case Token::BIT_AND:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001821 EmitConstantSmiBitOp(expr, op, mode, value);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001822 break;
1823 case Token::SHL:
1824 case Token::SAR:
1825 case Token::SHR:
1826 ASSERT(!left_is_constant_smi);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001827 EmitConstantSmiShiftOp(expr, op, mode, value);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001828 break;
1829 case Token::ADD:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001830 EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001831 break;
1832 case Token::SUB:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001833 EmitConstantSmiSub(expr, mode, left_is_constant_smi, value);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001834 break;
1835 default:
1836 UNREACHABLE();
1837 }
1838}
1839
1840
1841void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1842 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001843 OverwriteMode mode,
1844 Expression* left,
1845 Expression* right,
1846 ConstantOperand constant) {
1847 if (constant == kRightConstant) {
1848 Smi* value = Smi::cast(*right->AsLiteral()->handle());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001849 EmitConstantSmiBinaryOp(expr, op, mode, false, value);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001850 return;
1851 } else if (constant == kLeftConstant) {
1852 Smi* value = Smi::cast(*left->AsLiteral()->handle());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001853 EmitConstantSmiBinaryOp(expr, op, mode, true, value);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001854 return;
1855 }
1856
1857 // Do combined smi check of the operands. Left operand is on the
1858 // stack. Right operand is in eax.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001859 NearLabel done, smi_case, stub_call;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001860 __ pop(edx);
1861 __ mov(ecx, eax);
1862 __ or_(eax, Operand(edx));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001863 JumpPatchSite patch_site(masm_);
1864 patch_site.EmitJumpIfSmi(eax, &smi_case);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001865
1866 __ bind(&stub_call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001867 __ mov(eax, ecx);
1868 TypeRecordingBinaryOpStub stub(op, mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001869 EmitCallIC(stub.GetCode(), &patch_site);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001870 __ jmp(&done);
1871
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001872 // Smi case.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001873 __ bind(&smi_case);
1874 __ mov(eax, edx); // Copy left operand in case of a stub call.
1875
1876 switch (op) {
1877 case Token::SAR:
1878 __ SmiUntag(eax);
1879 __ SmiUntag(ecx);
1880 __ sar_cl(eax); // No checks of result necessary
1881 __ SmiTag(eax);
1882 break;
1883 case Token::SHL: {
1884 Label result_ok;
1885 __ SmiUntag(eax);
1886 __ SmiUntag(ecx);
1887 __ shl_cl(eax);
1888 // Check that the *signed* result fits in a smi.
1889 __ cmp(eax, 0xc0000000);
1890 __ j(positive, &result_ok);
1891 __ SmiTag(ecx);
1892 __ jmp(&stub_call);
1893 __ bind(&result_ok);
1894 __ SmiTag(eax);
1895 break;
1896 }
1897 case Token::SHR: {
1898 Label result_ok;
1899 __ SmiUntag(eax);
1900 __ SmiUntag(ecx);
1901 __ shr_cl(eax);
1902 __ test(eax, Immediate(0xc0000000));
1903 __ j(zero, &result_ok);
1904 __ SmiTag(ecx);
1905 __ jmp(&stub_call);
1906 __ bind(&result_ok);
1907 __ SmiTag(eax);
1908 break;
1909 }
1910 case Token::ADD:
1911 __ add(eax, Operand(ecx));
1912 __ j(overflow, &stub_call);
1913 break;
1914 case Token::SUB:
1915 __ sub(eax, Operand(ecx));
1916 __ j(overflow, &stub_call);
1917 break;
1918 case Token::MUL: {
1919 __ SmiUntag(eax);
1920 __ imul(eax, Operand(ecx));
1921 __ j(overflow, &stub_call);
1922 __ test(eax, Operand(eax));
1923 __ j(not_zero, &done, taken);
1924 __ mov(ebx, edx);
1925 __ or_(ebx, Operand(ecx));
1926 __ j(negative, &stub_call);
1927 break;
1928 }
1929 case Token::BIT_OR:
1930 __ or_(eax, Operand(ecx));
1931 break;
1932 case Token::BIT_AND:
1933 __ and_(eax, Operand(ecx));
1934 break;
1935 case Token::BIT_XOR:
1936 __ xor_(eax, Operand(ecx));
1937 break;
1938 default:
1939 UNREACHABLE();
1940 }
1941
1942 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001943 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001944}
1945
1946
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001947void FullCodeGenerator::EmitBinaryOp(Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001948 OverwriteMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001949 __ pop(edx);
1950 TypeRecordingBinaryOpStub stub(op, mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001951 EmitCallIC(stub.GetCode(), NULL); // NULL signals no inlined smi code.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001952 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001953}
1954
1955
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001956void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001957 // Invalid left-hand sides are rewritten to have a 'throw
1958 // ReferenceError' on the left-hand side.
1959 if (!expr->IsValidLeftHandSide()) {
1960 VisitForEffect(expr);
1961 return;
1962 }
1963
1964 // Left-hand side can only be a property, a global or a (parameter or local)
1965 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1966 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1967 LhsKind assign_type = VARIABLE;
1968 Property* prop = expr->AsProperty();
1969 if (prop != NULL) {
1970 assign_type = (prop->key()->IsPropertyName())
1971 ? NAMED_PROPERTY
1972 : KEYED_PROPERTY;
1973 }
1974
1975 switch (assign_type) {
1976 case VARIABLE: {
1977 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001978 EffectContext context(this);
1979 EmitVariableAssignment(var, Token::ASSIGN);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001980 break;
1981 }
1982 case NAMED_PROPERTY: {
1983 __ push(eax); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001984 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001985 __ mov(edx, eax);
1986 __ pop(eax); // Restore value.
1987 __ mov(ecx, prop->key()->AsLiteral()->handle());
1988 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001989 EmitCallIC(ic, RelocInfo::CODE_TARGET);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001990 break;
1991 }
1992 case KEYED_PROPERTY: {
1993 __ push(eax); // Preserve value.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001994 if (prop->is_synthetic()) {
1995 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1996 ASSERT(prop->key()->AsLiteral() != NULL);
1997 { AccumulatorValueContext for_object(this);
1998 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1999 }
2000 __ mov(edx, eax);
2001 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
2002 } else {
2003 VisitForStackValue(prop->obj());
2004 VisitForAccumulatorValue(prop->key());
2005 __ mov(ecx, eax);
2006 __ pop(edx);
2007 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002008 __ pop(eax); // Restore value.
2009 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002010 EmitCallIC(ic, RelocInfo::CODE_TARGET);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002011 break;
2012 }
2013 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002014 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
2015 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002016}
2017
2018
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002019void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002020 Token::Value op) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002021 // Left-hand sides that rewrite to explicit property accesses do not reach
2022 // here.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002023 ASSERT(var != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002024 ASSERT(var->is_global() || var->AsSlot() != NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002025
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002026 if (var->is_global()) {
2027 ASSERT(!var->is_this());
2028 // Assignment to a global variable. Use inline caching for the
2029 // assignment. Right-hand-side value is passed in eax, variable name in
2030 // ecx, and the global object on the stack.
2031 __ mov(ecx, var->name());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002032 __ mov(edx, GlobalObjectOperand());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002033 Handle<Code> ic(Builtins::builtin(
2034 is_strict() ? Builtins::StoreIC_Initialize_Strict
2035 : Builtins::StoreIC_Initialize));
2036 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002037
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002038 } else if (op == Token::INIT_CONST) {
2039 // Like var declarations, const declarations are hoisted to function
2040 // scope. However, unlike var initializers, const initializers are able
2041 // to drill a hole to that function context, even from inside a 'with'
2042 // context. We thus bypass the normal static scope lookup.
2043 Slot* slot = var->AsSlot();
2044 Label skip;
2045 switch (slot->type()) {
2046 case Slot::PARAMETER:
2047 // No const parameters.
2048 UNREACHABLE();
2049 break;
2050 case Slot::LOCAL:
2051 __ mov(edx, Operand(ebp, SlotOffset(slot)));
2052 __ cmp(edx, Factory::the_hole_value());
2053 __ j(not_equal, &skip);
2054 __ mov(Operand(ebp, SlotOffset(slot)), eax);
2055 break;
2056 case Slot::CONTEXT: {
2057 __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX));
2058 __ mov(edx, ContextOperand(ecx, slot->index()));
2059 __ cmp(edx, Factory::the_hole_value());
2060 __ j(not_equal, &skip);
2061 __ mov(ContextOperand(ecx, slot->index()), eax);
2062 int offset = Context::SlotOffset(slot->index());
2063 __ mov(edx, eax); // Preserve the stored value in eax.
2064 __ RecordWrite(ecx, offset, edx, ebx);
2065 break;
2066 }
2067 case Slot::LOOKUP:
2068 __ push(eax);
2069 __ push(esi);
2070 __ push(Immediate(var->name()));
2071 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
2072 break;
2073 }
2074 __ bind(&skip);
2075
2076 } else if (var->mode() != Variable::CONST) {
2077 // Perform the assignment for non-const variables. Const assignments
2078 // are simply skipped.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002079 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002080 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002081 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002082 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002083 // Perform the assignment.
2084 __ mov(Operand(ebp, SlotOffset(slot)), eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002085 break;
2086
2087 case Slot::CONTEXT: {
2088 MemOperand target = EmitSlotSearch(slot, ecx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002089 // Perform the assignment and issue the write barrier.
2090 __ mov(target, eax);
2091 // The value of the assignment is in eax. RecordWrite clobbers its
2092 // register arguments.
2093 __ mov(edx, eax);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002094 int offset = Context::SlotOffset(slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002095 __ RecordWrite(ecx, offset, edx, ebx);
2096 break;
2097 }
2098
2099 case Slot::LOOKUP:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002100 // Call the runtime for the assignment.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002101 __ push(eax); // Value.
2102 __ push(esi); // Context.
2103 __ push(Immediate(var->name()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002104 __ CallRuntime(Runtime::kStoreContextSlot, 3);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002105 break;
2106 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002107 }
2108}
2109
2110
2111void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2112 // Assignment to a property, using a named store IC.
2113 Property* prop = expr->target()->AsProperty();
2114 ASSERT(prop != NULL);
2115 ASSERT(prop->key()->AsLiteral() != NULL);
2116
2117 // If the assignment starts a block of assignments to the same object,
2118 // change to slow case to avoid the quadratic behavior of repeatedly
2119 // adding fast properties.
2120 if (expr->starts_initialization_block()) {
2121 __ push(result_register());
2122 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
2123 __ CallRuntime(Runtime::kToSlowProperties, 1);
2124 __ pop(result_register());
2125 }
2126
2127 // Record source code position before IC call.
2128 SetSourcePosition(expr->position());
2129 __ mov(ecx, prop->key()->AsLiteral()->handle());
2130 if (expr->ends_initialization_block()) {
2131 __ mov(edx, Operand(esp, 0));
2132 } else {
2133 __ pop(edx);
2134 }
2135 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002136 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002137
2138 // If the assignment ends an initialization block, revert to fast case.
2139 if (expr->ends_initialization_block()) {
2140 __ push(eax); // Result of assignment, saved even if not needed.
2141 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
2142 __ CallRuntime(Runtime::kToFastProperties, 1);
2143 __ pop(eax);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002144 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002145 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002146 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2147 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002148}
2149
2150
2151void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2152 // Assignment to a property, using a keyed store IC.
2153
2154 // If the assignment starts a block of assignments to the same object,
2155 // change to slow case to avoid the quadratic behavior of repeatedly
2156 // adding fast properties.
2157 if (expr->starts_initialization_block()) {
2158 __ push(result_register());
2159 // Receiver is now under the key and value.
2160 __ push(Operand(esp, 2 * kPointerSize));
2161 __ CallRuntime(Runtime::kToSlowProperties, 1);
2162 __ pop(result_register());
2163 }
2164
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002165 __ pop(ecx);
2166 if (expr->ends_initialization_block()) {
2167 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
2168 } else {
2169 __ pop(edx);
2170 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002171 // Record source code position before IC call.
2172 SetSourcePosition(expr->position());
2173 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002174 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002175
2176 // If the assignment ends an initialization block, revert to fast case.
2177 if (expr->ends_initialization_block()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002178 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002179 __ push(eax); // Result of assignment, saved even if not needed.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002180 __ push(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002181 __ CallRuntime(Runtime::kToFastProperties, 1);
2182 __ pop(eax);
2183 }
2184
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002185 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002186 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002187}
2188
2189
2190void FullCodeGenerator::VisitProperty(Property* expr) {
2191 Comment cmnt(masm_, "[ Property");
2192 Expression* key = expr->key();
2193
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002194 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002195 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002196 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002197 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002198 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002199 VisitForStackValue(expr->obj());
2200 VisitForAccumulatorValue(expr->key());
ager@chromium.org5c838252010-02-19 08:53:10 +00002201 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002202 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002203 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002204 }
2205}
2206
2207
2208void FullCodeGenerator::EmitCallWithIC(Call* expr,
2209 Handle<Object> name,
2210 RelocInfo::Mode mode) {
2211 // Code common for calls using the IC.
2212 ZoneList<Expression*>* args = expr->arguments();
2213 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002214 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002215 for (int i = 0; i < arg_count; i++) {
2216 VisitForStackValue(args->at(i));
2217 }
2218 __ Set(ecx, Immediate(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002219 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002220 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002221 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002222 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002223 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002224 EmitCallIC(ic, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002225 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002226 // Restore context register.
2227 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002228 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002229}
2230
2231
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002232void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
2233 Expression* key,
2234 RelocInfo::Mode mode) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002235 // Load the key.
2236 VisitForAccumulatorValue(key);
2237
2238 // Swap the name of the function and the receiver on the stack to follow
2239 // the calling convention for call ICs.
2240 __ pop(ecx);
2241 __ push(eax);
2242 __ push(ecx);
2243
2244 // Load the arguments.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002245 ZoneList<Expression*>* args = expr->arguments();
2246 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002247 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002248 for (int i = 0; i < arg_count; i++) {
2249 VisitForStackValue(args->at(i));
2250 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002251 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002252 // Record source position of the IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002253 SetSourcePosition(expr->position());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002254 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002255 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
2256 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002257 EmitCallIC(ic, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002258 RecordJSReturnSite(expr);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002259 // Restore context register.
2260 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002261 context()->DropAndPlug(1, eax); // Drop the key still on the stack.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002262}
2263
2264
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002265void FullCodeGenerator::EmitCallWithStub(Call* expr) {
2266 // Code common for calls using the call stub.
2267 ZoneList<Expression*>* args = expr->arguments();
2268 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002269 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002270 for (int i = 0; i < arg_count; i++) {
2271 VisitForStackValue(args->at(i));
2272 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002273 }
2274 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002275 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002276 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2277 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002278 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002279 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002280 // Restore context register.
2281 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002282 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002283}
2284
2285
2286void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002287#ifdef DEBUG
2288 // We want to verify that RecordJSReturnSite gets called on all paths
2289 // through this function. Avoid early returns.
2290 expr->return_is_recorded_ = false;
2291#endif
2292
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002293 Comment cmnt(masm_, "[ Call");
2294 Expression* fun = expr->expression();
2295 Variable* var = fun->AsVariableProxy()->AsVariable();
2296
2297 if (var != NULL && var->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002298 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2299 // resolve the function we need to call and the receiver of the
2300 // call. Then we call the resolved function using the given
2301 // arguments.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002302 ZoneList<Expression*>* args = expr->arguments();
2303 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002304 { PreservePositionScope pos_scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002305 VisitForStackValue(fun);
2306 // Reserved receiver slot.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002307 __ push(Immediate(Factory::undefined_value()));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002308
2309 // Push the arguments.
2310 for (int i = 0; i < arg_count; i++) {
2311 VisitForStackValue(args->at(i));
2312 }
2313
2314 // Push copy of the function - found below the arguments.
2315 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2316
2317 // Push copy of the first argument or undefined if it doesn't exist.
2318 if (arg_count > 0) {
2319 __ push(Operand(esp, arg_count * kPointerSize));
2320 } else {
2321 __ push(Immediate(Factory::undefined_value()));
2322 }
2323
2324 // Push the receiver of the enclosing function and do runtime call.
2325 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002326 // Push the strict mode flag.
2327 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
2328 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002329
2330 // The runtime call returns a pair of values in eax (function) and
2331 // edx (receiver). Touch up the stack with the right values.
2332 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2333 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002334 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002335 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002336 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002337 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2338 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
2339 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002340 RecordJSReturnSite(expr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002341 // Restore context register.
2342 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002343 context()->DropAndPlug(1, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002344 } else if (var != NULL && !var->is_this() && var->is_global()) {
2345 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002346 __ push(GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002347 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002348 } else if (var != NULL && var->AsSlot() != NULL &&
2349 var->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002350 // Call to a lookup slot (dynamically introduced variable).
2351 Label slow, done;
2352
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002353 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002354 // Generate code for loading from variables potentially shadowed
2355 // by eval-introduced variables.
2356 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
2357 NOT_INSIDE_TYPEOF,
2358 &slow,
2359 &done);
2360 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002361
2362 __ bind(&slow);
2363 // Call the runtime to find the function to call (returned in eax)
2364 // and the object holding it (returned in edx).
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002365 __ push(context_register());
2366 __ push(Immediate(var->name()));
2367 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2368 __ push(eax); // Function.
2369 __ push(edx); // Receiver.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002370
2371 // If fast case code has been generated, emit code to push the
2372 // function and receiver and have the slow path jump around this
2373 // code.
2374 if (done.is_linked()) {
2375 Label call;
2376 __ jmp(&call);
2377 __ bind(&done);
2378 // Push function.
2379 __ push(eax);
2380 // Push global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002381 __ mov(ebx, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002382 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2383 __ bind(&call);
2384 }
2385
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002386 EmitCallWithStub(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002387 } else if (fun->AsProperty() != NULL) {
2388 // Call to an object property.
2389 Property* prop = fun->AsProperty();
2390 Literal* key = prop->key()->AsLiteral();
2391 if (key != NULL && key->handle()->IsSymbol()) {
2392 // Call to a named property, use call IC.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002393 { PreservePositionScope scope(masm()->positions_recorder());
2394 VisitForStackValue(prop->obj());
2395 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002396 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
2397 } else {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002398 // Call to a keyed property.
2399 // For a synthetic property use keyed load IC followed by function call,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002400 // for a regular property use keyed EmitCallIC.
ager@chromium.org5c838252010-02-19 08:53:10 +00002401 if (prop->is_synthetic()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002402 // Do not visit the object and key subexpressions (they are shared
2403 // by all occurrences of the same rewritten parameter).
2404 ASSERT(prop->obj()->AsVariableProxy() != NULL);
2405 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
2406 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
2407 MemOperand operand = EmitSlotSearch(slot, edx);
2408 __ mov(edx, operand);
2409
2410 ASSERT(prop->key()->AsLiteral() != NULL);
2411 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
2412 __ mov(eax, prop->key()->AsLiteral()->handle());
2413
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002414 // Record source code position for IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002415 SetSourcePosition(prop->position());
ager@chromium.org5c838252010-02-19 08:53:10 +00002416
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002417 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002418 EmitCallIC(ic, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +00002419 // Push result (function).
2420 __ push(eax);
2421 // Push Global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002422 __ mov(ecx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002423 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002424 EmitCallWithStub(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002425 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002426 { PreservePositionScope scope(masm()->positions_recorder());
2427 VisitForStackValue(prop->obj());
2428 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002429 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002430 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002431 }
2432 } else {
2433 // Call to some other expression. If the expression is an anonymous
2434 // function literal not called in a loop, mark it as one that should
2435 // also use the full code generator.
2436 FunctionLiteral* lit = fun->AsFunctionLiteral();
2437 if (lit != NULL &&
2438 lit->name()->Equals(Heap::empty_string()) &&
2439 loop_depth() == 0) {
2440 lit->set_try_full_codegen(true);
2441 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002442 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002443 VisitForStackValue(fun);
2444 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002445 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002446 __ mov(ebx, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002447 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2448 // Emit function call.
2449 EmitCallWithStub(expr);
2450 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002451
2452#ifdef DEBUG
2453 // RecordJSReturnSite should have been called.
2454 ASSERT(expr->return_is_recorded_);
2455#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002456}
2457
2458
2459void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2460 Comment cmnt(masm_, "[ CallNew");
2461 // According to ECMA-262, section 11.2.2, page 44, the function
2462 // expression in new calls must be evaluated before the
2463 // arguments.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002464
ricow@chromium.org65fae842010-08-25 15:26:24 +00002465 // Push constructor on the stack. If it's not a function it's used as
2466 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2467 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002468 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002469
2470 // Push the arguments ("left-to-right") on the stack.
2471 ZoneList<Expression*>* args = expr->arguments();
2472 int arg_count = args->length();
2473 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002474 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002475 }
2476
2477 // Call the construct call builtin that handles allocation and
2478 // constructor invocation.
2479 SetSourcePosition(expr->position());
2480
ricow@chromium.org65fae842010-08-25 15:26:24 +00002481 // Load function and argument count into edi and eax.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002482 __ Set(eax, Immediate(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002483 __ mov(edi, Operand(esp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002484
2485 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
2486 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002487 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002488}
2489
2490
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002491void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2492 ASSERT(args->length() == 1);
2493
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002494 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002495
2496 Label materialize_true, materialize_false;
2497 Label* if_true = NULL;
2498 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002499 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002500 context()->PrepareTest(&materialize_true, &materialize_false,
2501 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002502
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002503 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002504 __ test(eax, Immediate(kSmiTagMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002505 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002506
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002507 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002508}
2509
2510
2511void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2512 ASSERT(args->length() == 1);
2513
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002514 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002515
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
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002523 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002524 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002525 Split(zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002526
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002527 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002528}
2529
2530
2531void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2532 ASSERT(args->length() == 1);
2533
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002534 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002535
2536 Label materialize_true, materialize_false;
2537 Label* if_true = NULL;
2538 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002539 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002540 context()->PrepareTest(&materialize_true, &materialize_false,
2541 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002542
2543 __ test(eax, Immediate(kSmiTagMask));
2544 __ j(zero, if_false);
2545 __ cmp(eax, Factory::null_value());
2546 __ j(equal, if_true);
2547 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2548 // Undetectable objects behave like undefined when tested with typeof.
2549 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2550 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2551 __ j(not_zero, if_false);
2552 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2553 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
2554 __ j(below, if_false);
2555 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002556 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002557 Split(below_equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002558
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002559 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002560}
2561
2562
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002563void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2564 ASSERT(args->length() == 1);
2565
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002566 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002567
2568 Label materialize_true, materialize_false;
2569 Label* if_true = NULL;
2570 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002571 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002572 context()->PrepareTest(&materialize_true, &materialize_false,
2573 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002574
2575 __ test(eax, Immediate(kSmiTagMask));
2576 __ j(equal, if_false);
2577 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002578 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002579 Split(above_equal, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002580
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002581 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002582}
2583
2584
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002585void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2586 ASSERT(args->length() == 1);
2587
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002588 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002589
2590 Label materialize_true, materialize_false;
2591 Label* if_true = NULL;
2592 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002593 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002594 context()->PrepareTest(&materialize_true, &materialize_false,
2595 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002596
2597 __ test(eax, Immediate(kSmiTagMask));
2598 __ j(zero, if_false);
2599 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2600 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2601 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002602 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002603 Split(not_zero, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002604
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002605 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002606}
2607
2608
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002609void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2610 ZoneList<Expression*>* args) {
2611 ASSERT(args->length() == 1);
2612
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002613 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002614
2615 Label materialize_true, materialize_false;
2616 Label* if_true = NULL;
2617 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002618 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002619 context()->PrepareTest(&materialize_true, &materialize_false,
2620 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002621
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002622 // TODO(3110205): Implement this.
2623 // Currently unimplemented. Emit false, a safe choice.
2624 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002625 __ jmp(if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002626 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002627}
2628
2629
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002630void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2631 ASSERT(args->length() == 1);
2632
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002633 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002634
2635 Label materialize_true, materialize_false;
2636 Label* if_true = NULL;
2637 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002638 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002639 context()->PrepareTest(&materialize_true, &materialize_false,
2640 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002641
2642 __ test(eax, Immediate(kSmiTagMask));
2643 __ j(zero, if_false);
2644 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002645 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002646 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002647
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002648 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002649}
2650
2651
2652void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2653 ASSERT(args->length() == 1);
2654
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002655 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002656
2657 Label materialize_true, materialize_false;
2658 Label* if_true = NULL;
2659 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002660 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002661 context()->PrepareTest(&materialize_true, &materialize_false,
2662 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002663
2664 __ test(eax, Immediate(kSmiTagMask));
2665 __ j(equal, if_false);
2666 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002667 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002668 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002669
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002670 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002671}
2672
2673
2674void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2675 ASSERT(args->length() == 1);
2676
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002677 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002678
2679 Label materialize_true, materialize_false;
2680 Label* if_true = NULL;
2681 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002682 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002683 context()->PrepareTest(&materialize_true, &materialize_false,
2684 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002685
2686 __ test(eax, Immediate(kSmiTagMask));
2687 __ j(equal, if_false);
2688 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002689 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002690 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002691
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002692 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002693}
2694
2695
2696
2697void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2698 ASSERT(args->length() == 0);
2699
2700 Label materialize_true, materialize_false;
2701 Label* if_true = NULL;
2702 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002703 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002704 context()->PrepareTest(&materialize_true, &materialize_false,
2705 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002706
2707 // Get the frame pointer for the calling frame.
2708 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2709
2710 // Skip the arguments adaptor frame if it exists.
2711 Label check_frame_marker;
2712 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2713 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2714 __ j(not_equal, &check_frame_marker);
2715 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2716
2717 // Check the marker in the calling frame.
2718 __ bind(&check_frame_marker);
2719 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2720 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002721 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002722 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002723
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002724 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002725}
2726
2727
2728void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2729 ASSERT(args->length() == 2);
2730
2731 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002732 VisitForStackValue(args->at(0));
2733 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002734
2735 Label materialize_true, materialize_false;
2736 Label* if_true = NULL;
2737 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002738 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002739 context()->PrepareTest(&materialize_true, &materialize_false,
2740 &if_true, &if_false, &fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002741
2742 __ pop(ebx);
2743 __ cmp(eax, Operand(ebx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002744 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002745 Split(equal, if_true, if_false, fall_through);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002746
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002747 context()->Plug(if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002748}
2749
2750
2751void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2752 ASSERT(args->length() == 1);
2753
2754 // ArgumentsAccessStub expects the key in edx and the formal
2755 // parameter count in eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002756 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002757 __ mov(edx, eax);
2758 __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2759 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2760 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002761 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002762}
2763
2764
2765void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2766 ASSERT(args->length() == 0);
2767
2768 Label exit;
2769 // Get the number of formal parameters.
2770 __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2771
2772 // Check if the calling frame is an arguments adaptor frame.
2773 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2774 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2775 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2776 __ j(not_equal, &exit);
2777
2778 // Arguments adaptor case: Read the arguments length from the
2779 // adaptor frame.
2780 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2781
2782 __ bind(&exit);
2783 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002784 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002785}
2786
2787
2788void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2789 ASSERT(args->length() == 1);
2790 Label done, null, function, non_function_constructor;
2791
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002792 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002793
2794 // If the object is a smi, we return null.
2795 __ test(eax, Immediate(kSmiTagMask));
2796 __ j(zero, &null);
2797
2798 // Check that the object is a JS object but take special care of JS
2799 // functions to make sure they have 'Function' as their class.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002800 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, eax); // Map is now in eax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002801 __ j(below, &null);
2802
2803 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2804 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2805 // LAST_JS_OBJECT_TYPE.
2806 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2807 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002808 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002809 __ j(equal, &function);
2810
2811 // Check if the constructor in the map is a function.
2812 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2813 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2814 __ j(not_equal, &non_function_constructor);
2815
2816 // eax now contains the constructor function. Grab the
2817 // instance class name from there.
2818 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2819 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2820 __ jmp(&done);
2821
2822 // Functions have class 'Function'.
2823 __ bind(&function);
2824 __ mov(eax, Factory::function_class_symbol());
2825 __ jmp(&done);
2826
2827 // Objects with a non-function constructor have class 'Object'.
2828 __ bind(&non_function_constructor);
2829 __ mov(eax, Factory::Object_symbol());
2830 __ jmp(&done);
2831
2832 // Non-JS objects have class null.
2833 __ bind(&null);
2834 __ mov(eax, Factory::null_value());
2835
2836 // All done.
2837 __ bind(&done);
2838
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002839 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002840}
2841
2842
2843void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2844 // Conditionally generate a log call.
2845 // Args:
2846 // 0 (literal string): The type of logging (corresponds to the flags).
2847 // This is used to determine whether or not to generate the log call.
2848 // 1 (string): Format string. Access the string at argument index 2
2849 // with '%2s' (see Logger::LogRuntime for all the formats).
2850 // 2 (array): Arguments to the format string.
2851 ASSERT_EQ(args->length(), 3);
2852#ifdef ENABLE_LOGGING_AND_PROFILING
2853 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002854 VisitForStackValue(args->at(1));
2855 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002856 __ CallRuntime(Runtime::kLog, 2);
2857 }
2858#endif
2859 // Finally, we're expected to leave a value on the top of the stack.
2860 __ mov(eax, Factory::undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002861 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002862}
2863
2864
2865void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2866 ASSERT(args->length() == 0);
2867
2868 Label slow_allocate_heapnumber;
2869 Label heapnumber_allocated;
2870
2871 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2872 __ jmp(&heapnumber_allocated);
2873
2874 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002875 // Allocate a heap number.
2876 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002877 __ mov(edi, eax);
2878
2879 __ bind(&heapnumber_allocated);
2880
2881 __ PrepareCallCFunction(0, ebx);
2882 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2883
2884 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2885 // by computing:
2886 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2887 // This is implemented on both SSE2 and FPU.
2888 if (CpuFeatures::IsSupported(SSE2)) {
2889 CpuFeatures::Scope fscope(SSE2);
2890 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2891 __ movd(xmm1, Operand(ebx));
2892 __ movd(xmm0, Operand(eax));
2893 __ cvtss2sd(xmm1, xmm1);
2894 __ pxor(xmm0, xmm1);
2895 __ subsd(xmm0, xmm1);
2896 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2897 } else {
2898 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2899 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2900 Immediate(0x41300000));
2901 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2902 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2903 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2904 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2905 __ fsubp(1);
2906 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2907 }
2908 __ mov(eax, edi);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002909 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002910}
2911
2912
2913void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2914 // Load the arguments on the stack and call the stub.
2915 SubStringStub stub;
2916 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002917 VisitForStackValue(args->at(0));
2918 VisitForStackValue(args->at(1));
2919 VisitForStackValue(args->at(2));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002920 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002921 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002922}
2923
2924
2925void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2926 // Load the arguments on the stack and call the stub.
2927 RegExpExecStub stub;
2928 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002929 VisitForStackValue(args->at(0));
2930 VisitForStackValue(args->at(1));
2931 VisitForStackValue(args->at(2));
2932 VisitForStackValue(args->at(3));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002933 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002934 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002935}
2936
2937
2938void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2939 ASSERT(args->length() == 1);
2940
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002941 VisitForAccumulatorValue(args->at(0)); // Load the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002942
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002943 NearLabel done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002944 // If the object is a smi return the object.
2945 __ test(eax, Immediate(kSmiTagMask));
2946 __ j(zero, &done);
2947 // If the object is not a value type, return the object.
2948 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
2949 __ j(not_equal, &done);
2950 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2951
2952 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002953 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002954}
2955
2956
2957void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2958 // Load the arguments on the stack and call the runtime function.
2959 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002960 VisitForStackValue(args->at(0));
2961 VisitForStackValue(args->at(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002962
2963 MathPowStub stub;
2964 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002965 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002966}
2967
2968
2969void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2970 ASSERT(args->length() == 2);
2971
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002972 VisitForStackValue(args->at(0)); // Load the object.
2973 VisitForAccumulatorValue(args->at(1)); // Load the value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002974 __ pop(ebx); // eax = value. ebx = object.
2975
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002976 NearLabel done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002977 // If the object is a smi, return the value.
2978 __ test(ebx, Immediate(kSmiTagMask));
2979 __ j(zero, &done);
2980
2981 // If the object is not a value type, return the value.
2982 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
2983 __ j(not_equal, &done);
2984
2985 // Store the value.
2986 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
2987 // Update the write barrier. Save the value as it will be
2988 // overwritten by the write barrier code and is needed afterward.
2989 __ mov(edx, eax);
2990 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
2991
2992 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002993 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002994}
2995
2996
2997void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2998 ASSERT_EQ(args->length(), 1);
2999
3000 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003001 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003002
3003 NumberToStringStub stub;
3004 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003005 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003006}
3007
3008
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003009void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003010 ASSERT(args->length() == 1);
3011
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003012 VisitForAccumulatorValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003013
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003014 Label done;
3015 StringCharFromCodeGenerator generator(eax, ebx);
3016 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003017 __ jmp(&done);
3018
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003019 NopRuntimeCallHelper call_helper;
3020 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003021
3022 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003023 context()->Plug(ebx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003024}
3025
3026
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003027void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
3028 ASSERT(args->length() == 2);
3029
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003030 VisitForStackValue(args->at(0));
3031 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003032
3033 Register object = ebx;
3034 Register index = eax;
3035 Register scratch = ecx;
3036 Register result = edx;
3037
3038 __ pop(object);
3039
3040 Label need_conversion;
3041 Label index_out_of_range;
3042 Label done;
3043 StringCharCodeAtGenerator generator(object,
3044 index,
3045 scratch,
3046 result,
3047 &need_conversion,
3048 &need_conversion,
3049 &index_out_of_range,
3050 STRING_INDEX_IS_NUMBER);
3051 generator.GenerateFast(masm_);
3052 __ jmp(&done);
3053
3054 __ bind(&index_out_of_range);
3055 // When the index is out of range, the spec requires us to return
3056 // NaN.
3057 __ Set(result, Immediate(Factory::nan_value()));
3058 __ jmp(&done);
3059
3060 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003061 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003062 // trigger conversion.
3063 __ Set(result, Immediate(Factory::undefined_value()));
3064 __ jmp(&done);
3065
3066 NopRuntimeCallHelper call_helper;
3067 generator.GenerateSlow(masm_, call_helper);
3068
3069 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003070 context()->Plug(result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003071}
3072
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003073
3074void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
3075 ASSERT(args->length() == 2);
3076
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003077 VisitForStackValue(args->at(0));
3078 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003079
3080 Register object = ebx;
3081 Register index = eax;
3082 Register scratch1 = ecx;
3083 Register scratch2 = edx;
3084 Register result = eax;
3085
3086 __ pop(object);
3087
3088 Label need_conversion;
3089 Label index_out_of_range;
3090 Label done;
3091 StringCharAtGenerator generator(object,
3092 index,
3093 scratch1,
3094 scratch2,
3095 result,
3096 &need_conversion,
3097 &need_conversion,
3098 &index_out_of_range,
3099 STRING_INDEX_IS_NUMBER);
3100 generator.GenerateFast(masm_);
3101 __ jmp(&done);
3102
3103 __ bind(&index_out_of_range);
3104 // When the index is out of range, the spec requires us to return
3105 // the empty string.
3106 __ Set(result, Immediate(Factory::empty_string()));
3107 __ jmp(&done);
3108
3109 __ bind(&need_conversion);
3110 // Move smi zero into the result register, which will trigger
3111 // conversion.
3112 __ Set(result, Immediate(Smi::FromInt(0)));
3113 __ jmp(&done);
3114
3115 NopRuntimeCallHelper call_helper;
3116 generator.GenerateSlow(masm_, call_helper);
3117
3118 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003119 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003120}
3121
3122
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003123void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
3124 ASSERT_EQ(2, args->length());
3125
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003126 VisitForStackValue(args->at(0));
3127 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003128
3129 StringAddStub stub(NO_STRING_ADD_FLAGS);
3130 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003131 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003132}
3133
3134
3135void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
3136 ASSERT_EQ(2, args->length());
3137
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003138 VisitForStackValue(args->at(0));
3139 VisitForStackValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003140
3141 StringCompareStub stub;
3142 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003143 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003144}
3145
3146
3147void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
3148 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003149 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3150 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003151 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003152 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003153 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003154 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003155}
3156
3157
3158void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
3159 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003160 TranscendentalCacheStub stub(TranscendentalCache::COS,
3161 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003162 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003163 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003164 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003165 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003166}
3167
3168
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003169void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3170 // Load the argument on the stack and call the stub.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003171 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3172 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003173 ASSERT(args->length() == 1);
3174 VisitForStackValue(args->at(0));
3175 __ CallStub(&stub);
3176 context()->Plug(eax);
3177}
3178
3179
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003180void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
3181 // Load the argument on the stack and call the runtime function.
3182 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003183 VisitForStackValue(args->at(0));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003184 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003185 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003186}
3187
3188
3189void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
3190 ASSERT(args->length() >= 2);
3191
3192 int arg_count = args->length() - 2; // For receiver and function.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003193 VisitForStackValue(args->at(0)); // Receiver.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003194 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003195 VisitForStackValue(args->at(i + 1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003196 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003197 VisitForAccumulatorValue(args->at(arg_count + 1)); // Function.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003198
3199 // InvokeFunction requires function in edi. Move it in there.
3200 if (!result_register().is(edi)) __ mov(edi, result_register());
3201 ParameterCount count(arg_count);
3202 __ InvokeFunction(edi, count, CALL_FUNCTION);
3203 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003204 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003205}
3206
3207
3208void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003209 // Load the arguments on the stack and call the stub.
3210 RegExpConstructResultStub stub;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003211 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003212 VisitForStackValue(args->at(0));
3213 VisitForStackValue(args->at(1));
3214 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003215 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003216 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003217}
3218
3219
3220void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
3221 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003222 VisitForStackValue(args->at(0));
3223 VisitForStackValue(args->at(1));
3224 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003225 Label done;
3226 Label slow_case;
3227 Register object = eax;
3228 Register index_1 = ebx;
3229 Register index_2 = ecx;
3230 Register elements = edi;
3231 Register temp = edx;
3232 __ mov(object, Operand(esp, 2 * kPointerSize));
3233 // Fetch the map and check if array is in fast case.
3234 // Check that object doesn't require security checks and
3235 // has no indexed interceptor.
3236 __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp);
3237 __ j(below, &slow_case);
3238 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
3239 KeyedLoadIC::kSlowCaseBitFieldMask);
3240 __ j(not_zero, &slow_case);
3241
3242 // Check the object's elements are in fast case and writable.
3243 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
3244 __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
3245 Immediate(Factory::fixed_array_map()));
3246 __ j(not_equal, &slow_case);
3247
3248 // Check that both indices are smis.
3249 __ mov(index_1, Operand(esp, 1 * kPointerSize));
3250 __ mov(index_2, Operand(esp, 0));
3251 __ mov(temp, index_1);
3252 __ or_(temp, Operand(index_2));
3253 __ test(temp, Immediate(kSmiTagMask));
3254 __ j(not_zero, &slow_case);
3255
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003256 // Check that both indices are valid.
3257 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
3258 __ cmp(temp, Operand(index_1));
3259 __ j(below_equal, &slow_case);
3260 __ cmp(temp, Operand(index_2));
3261 __ j(below_equal, &slow_case);
3262
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003263 // Bring addresses into index1 and index2.
3264 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1));
3265 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2));
3266
3267 // Swap elements. Use object and temp as scratch registers.
3268 __ mov(object, Operand(index_1, 0));
3269 __ mov(temp, Operand(index_2, 0));
3270 __ mov(Operand(index_2, 0), object);
3271 __ mov(Operand(index_1, 0), temp);
3272
3273 Label new_space;
3274 __ InNewSpace(elements, temp, equal, &new_space);
3275
3276 __ mov(object, elements);
3277 __ RecordWriteHelper(object, index_1, temp);
3278 __ RecordWriteHelper(elements, index_2, temp);
3279
3280 __ bind(&new_space);
3281 // We are done. Drop elements from the stack, and return undefined.
3282 __ add(Operand(esp), Immediate(3 * kPointerSize));
3283 __ mov(eax, Factory::undefined_value());
3284 __ jmp(&done);
3285
3286 __ bind(&slow_case);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003287 __ CallRuntime(Runtime::kSwapElements, 3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003288
3289 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003290 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003291}
3292
3293
3294void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3295 ASSERT_EQ(2, args->length());
3296
3297 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3298 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3299
3300 Handle<FixedArray> jsfunction_result_caches(
3301 Top::global_context()->jsfunction_result_caches());
3302 if (jsfunction_result_caches->length() <= cache_id) {
3303 __ Abort("Attempt to use undefined cache.");
3304 __ mov(eax, Factory::undefined_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003305 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003306 return;
3307 }
3308
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003309 VisitForAccumulatorValue(args->at(1));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003310
3311 Register key = eax;
3312 Register cache = ebx;
3313 Register tmp = ecx;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003314 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003315 __ mov(cache,
3316 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003317 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003318 __ mov(cache,
3319 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3320
3321 Label done, not_found;
3322 // tmp now holds finger offset as a smi.
3323 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3324 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3325 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3326 __ j(not_equal, &not_found);
3327
3328 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3329 __ jmp(&done);
3330
3331 __ bind(&not_found);
3332 // Call runtime to perform the lookup.
3333 __ push(cache);
3334 __ push(key);
3335 __ CallRuntime(Runtime::kGetFromCache, 2);
3336
3337 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003338 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003339}
3340
3341
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003342void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3343 ASSERT_EQ(2, args->length());
3344
3345 Register right = eax;
3346 Register left = ebx;
3347 Register tmp = ecx;
3348
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003349 VisitForStackValue(args->at(0));
3350 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003351 __ pop(left);
3352
3353 Label done, fail, ok;
3354 __ cmp(left, Operand(right));
3355 __ j(equal, &ok);
3356 // Fail if either is a non-HeapObject.
3357 __ mov(tmp, left);
3358 __ and_(Operand(tmp), right);
3359 __ test(Operand(tmp), Immediate(kSmiTagMask));
3360 __ j(zero, &fail);
lrn@chromium.org19375882010-08-09 12:49:57 +00003361 __ CmpObjectType(left, JS_REGEXP_TYPE, tmp);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003362 __ j(not_equal, &fail);
3363 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3364 __ j(not_equal, &fail);
3365 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3366 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3367 __ j(equal, &ok);
3368 __ bind(&fail);
3369 __ mov(eax, Immediate(Factory::false_value()));
3370 __ jmp(&done);
3371 __ bind(&ok);
3372 __ mov(eax, Immediate(Factory::true_value()));
3373 __ bind(&done);
3374
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003375 context()->Plug(eax);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003376}
3377
3378
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003379void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
3380 ASSERT(args->length() == 1);
3381
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003382 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003383
3384 if (FLAG_debug_code) {
3385 __ AbortIfNotString(eax);
3386 }
3387
3388 Label materialize_true, materialize_false;
3389 Label* if_true = NULL;
3390 Label* if_false = NULL;
3391 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003392 context()->PrepareTest(&materialize_true, &materialize_false,
3393 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003394
3395 __ test(FieldOperand(eax, String::kHashFieldOffset),
3396 Immediate(String::kContainsCachedArrayIndexMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003397 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003398 Split(zero, if_true, if_false, fall_through);
3399
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003400 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003401}
3402
3403
3404void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3405 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003406 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003407
3408 if (FLAG_debug_code) {
3409 __ AbortIfNotString(eax);
3410 }
3411
3412 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3413 __ IndexFromHash(eax, eax);
3414
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003415 context()->Plug(eax);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003416}
3417
3418
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003419void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003420 Label bailout, done, one_char_separator, long_separator,
3421 non_trivial_array, not_size_one_array, loop, loop_condition,
3422 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003423
3424 ASSERT(args->length() == 2);
3425 // We will leave the separator on the stack until the end of the function.
3426 VisitForStackValue(args->at(1));
3427 // Load this to eax (= array)
3428 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003429 // All aliases of the same register have disjoint lifetimes.
3430 Register array = eax;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003431 Register elements = no_reg; // Will be eax.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003432
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003433 Register index = edx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003434
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003435 Register string_length = ecx;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003436
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003437 Register string = esi;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003438
3439 Register scratch = ebx;
3440
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003441 Register array_length = edi;
3442 Register result_pos = no_reg; // Will be edi.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003443
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003444 // Separator operand is already pushed.
3445 Operand separator_operand = Operand(esp, 2 * kPointerSize);
3446 Operand result_operand = Operand(esp, 1 * kPointerSize);
3447 Operand array_length_operand = Operand(esp, 0);
3448 __ sub(Operand(esp), Immediate(2 * kPointerSize));
3449 __ cld();
3450 // Check that the array is a JSArray
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003451 __ test(array, Immediate(kSmiTagMask));
3452 __ j(zero, &bailout);
3453 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3454 __ j(not_equal, &bailout);
3455
3456 // Check that the array has fast elements.
3457 __ test_b(FieldOperand(scratch, Map::kBitField2Offset),
3458 1 << Map::kHasFastElements);
3459 __ j(zero, &bailout);
3460
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003461 // If the array has length zero, return the empty string.
3462 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
3463 __ sar(array_length, 1);
3464 __ j(not_zero, &non_trivial_array);
3465 __ mov(result_operand, Factory::empty_string());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003466 __ jmp(&done);
3467
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003468 // Save the array length.
3469 __ bind(&non_trivial_array);
3470 __ mov(array_length_operand, array_length);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003471
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003472 // Save the FixedArray containing array's elements.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003473 // End of array's live range.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003474 elements = array;
3475 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003476 array = no_reg;
3477
3478
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003479 // Check that all array elements are sequential ASCII strings, and
3480 // accumulate the sum of their lengths, as a smi-encoded value.
3481 __ Set(index, Immediate(0));
3482 __ Set(string_length, Immediate(0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003483 // Loop condition: while (index < length).
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003484 // Live loop registers: index, array_length, string,
3485 // scratch, string_length, elements.
3486 __ jmp(&loop_condition);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003487 __ bind(&loop);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003488 __ cmp(index, Operand(array_length));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003489 __ j(greater_equal, &done);
3490
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003491 __ mov(string, FieldOperand(elements, index,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003492 times_pointer_size,
3493 FixedArray::kHeaderSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003494 __ test(string, Immediate(kSmiTagMask));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003495 __ j(zero, &bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003496 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3497 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3498 __ and_(scratch, Immediate(
3499 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3500 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3501 __ j(not_equal, &bailout);
3502 __ add(string_length,
3503 FieldOperand(string, SeqAsciiString::kLengthOffset));
3504 __ j(overflow, &bailout);
3505 __ add(Operand(index), Immediate(1));
3506 __ bind(&loop_condition);
3507 __ cmp(index, Operand(array_length));
3508 __ j(less, &loop);
3509
3510 // If array_length is 1, return elements[0], a string.
3511 __ cmp(array_length, 1);
3512 __ j(not_equal, &not_size_one_array);
3513 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3514 __ mov(result_operand, scratch);
3515 __ jmp(&done);
3516
3517 __ bind(&not_size_one_array);
3518
3519 // End of array_length live range.
3520 result_pos = array_length;
3521 array_length = no_reg;
3522
3523 // Live registers:
3524 // string_length: Sum of string lengths, as a smi.
3525 // elements: FixedArray of strings.
3526
3527 // Check that the separator is a flat ASCII string.
3528 __ mov(string, separator_operand);
3529 __ test(string, Immediate(kSmiTagMask));
3530 __ j(zero, &bailout);
3531 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3532 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003533 __ and_(scratch, Immediate(
3534 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3535 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3536 __ j(not_equal, &bailout);
3537
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003538 // Add (separator length times array_length) - separator length
3539 // to string_length.
3540 __ mov(scratch, separator_operand);
3541 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset));
3542 __ sub(string_length, Operand(scratch)); // May be negative, temporarily.
3543 __ imul(scratch, array_length_operand);
3544 __ j(overflow, &bailout);
3545 __ add(string_length, Operand(scratch));
3546 __ j(overflow, &bailout);
3547
3548 __ shr(string_length, 1);
3549 // Live registers and stack values:
3550 // string_length
3551 // elements
3552 __ AllocateAsciiString(result_pos, string_length, scratch,
3553 index, string, &bailout);
3554 __ mov(result_operand, result_pos);
3555 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
3556
3557
3558 __ mov(string, separator_operand);
3559 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset),
3560 Immediate(Smi::FromInt(1)));
3561 __ j(equal, &one_char_separator);
3562 __ j(greater, &long_separator);
3563
3564
3565 // Empty separator case
3566 __ mov(index, Immediate(0));
3567 __ jmp(&loop_1_condition);
3568 // Loop condition: while (index < length).
3569 __ bind(&loop_1);
3570 // Each iteration of the loop concatenates one string to the result.
3571 // Live values in registers:
3572 // index: which element of the elements array we are adding to the result.
3573 // result_pos: the position to which we are currently copying characters.
3574 // elements: the FixedArray of strings we are joining.
3575
3576 // Get string = array[index].
3577 __ mov(string, FieldOperand(elements, index,
3578 times_pointer_size,
3579 FixedArray::kHeaderSize));
3580 __ mov(string_length,
3581 FieldOperand(string, String::kLengthOffset));
3582 __ shr(string_length, 1);
3583 __ lea(string,
3584 FieldOperand(string, SeqAsciiString::kHeaderSize));
3585 __ CopyBytes(string, result_pos, string_length, scratch);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003586 __ add(Operand(index), Immediate(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003587 __ bind(&loop_1_condition);
3588 __ cmp(index, array_length_operand);
3589 __ j(less, &loop_1); // End while (index < length).
3590 __ jmp(&done);
3591
3592
3593
3594 // One-character separator case
3595 __ bind(&one_char_separator);
3596 // Replace separator with its ascii character value.
3597 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3598 __ mov_b(separator_operand, scratch);
3599
3600 __ Set(index, Immediate(0));
3601 // Jump into the loop after the code that copies the separator, so the first
3602 // element is not preceded by a separator
3603 __ jmp(&loop_2_entry);
3604 // Loop condition: while (index < length).
3605 __ bind(&loop_2);
3606 // Each iteration of the loop concatenates one string to the result.
3607 // Live values in registers:
3608 // index: which element of the elements array we are adding to the result.
3609 // result_pos: the position to which we are currently copying characters.
3610
3611 // Copy the separator character to the result.
3612 __ mov_b(scratch, separator_operand);
3613 __ mov_b(Operand(result_pos, 0), scratch);
3614 __ inc(result_pos);
3615
3616 __ bind(&loop_2_entry);
3617 // Get string = array[index].
3618 __ mov(string, FieldOperand(elements, index,
3619 times_pointer_size,
3620 FixedArray::kHeaderSize));
3621 __ mov(string_length,
3622 FieldOperand(string, String::kLengthOffset));
3623 __ shr(string_length, 1);
3624 __ lea(string,
3625 FieldOperand(string, SeqAsciiString::kHeaderSize));
3626 __ CopyBytes(string, result_pos, string_length, scratch);
3627 __ add(Operand(index), Immediate(1));
3628
3629 __ cmp(index, array_length_operand);
3630 __ j(less, &loop_2); // End while (index < length).
3631 __ jmp(&done);
3632
3633
3634 // Long separator case (separator is more than one character).
3635 __ bind(&long_separator);
3636
3637 __ Set(index, Immediate(0));
3638 // Jump into the loop after the code that copies the separator, so the first
3639 // element is not preceded by a separator
3640 __ jmp(&loop_3_entry);
3641 // Loop condition: while (index < length).
3642 __ bind(&loop_3);
3643 // Each iteration of the loop concatenates one string to the result.
3644 // Live values in registers:
3645 // index: which element of the elements array we are adding to the result.
3646 // result_pos: the position to which we are currently copying characters.
3647
3648 // Copy the separator to the result.
3649 __ mov(string, separator_operand);
3650 __ mov(string_length,
3651 FieldOperand(string, String::kLengthOffset));
3652 __ shr(string_length, 1);
3653 __ lea(string,
3654 FieldOperand(string, SeqAsciiString::kHeaderSize));
3655 __ CopyBytes(string, result_pos, string_length, scratch);
3656
3657 __ bind(&loop_3_entry);
3658 // Get string = array[index].
3659 __ mov(string, FieldOperand(elements, index,
3660 times_pointer_size,
3661 FixedArray::kHeaderSize));
3662 __ mov(string_length,
3663 FieldOperand(string, String::kLengthOffset));
3664 __ shr(string_length, 1);
3665 __ lea(string,
3666 FieldOperand(string, SeqAsciiString::kHeaderSize));
3667 __ CopyBytes(string, result_pos, string_length, scratch);
3668 __ add(Operand(index), Immediate(1));
3669
3670 __ cmp(index, array_length_operand);
3671 __ j(less, &loop_3); // End while (index < length).
3672 __ jmp(&done);
3673
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003674
3675 __ bind(&bailout);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003676 __ mov(result_operand, Factory::undefined_value());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003677 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003678 __ mov(eax, result_operand);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003679 // Drop temp values from the stack, and restore context register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003680 __ add(Operand(esp), Immediate(3 * kPointerSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003681
3682 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3683 context()->Plug(eax);
3684}
3685
3686
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003687void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003688 Handle<String> name = expr->name();
3689 if (name->length() > 0 && name->Get(0) == '_') {
3690 Comment cmnt(masm_, "[ InlineRuntimeCall");
3691 EmitInlineRuntimeCall(expr);
3692 return;
3693 }
3694
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003695 Comment cmnt(masm_, "[ CallRuntime");
3696 ZoneList<Expression*>* args = expr->arguments();
3697
3698 if (expr->is_jsruntime()) {
3699 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003700 __ mov(eax, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003701 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3702 }
3703
3704 // Push the arguments ("left-to-right").
3705 int arg_count = args->length();
3706 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003707 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003708 }
3709
3710 if (expr->is_jsruntime()) {
3711 // Call the JS runtime function via a call IC.
3712 __ Set(ecx, Immediate(expr->name()));
3713 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003714 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003715 EmitCallIC(ic, RelocInfo::CODE_TARGET);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003716 // Restore context register.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003717 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3718 } else {
3719 // Call the C runtime function.
3720 __ CallRuntime(expr->function(), arg_count);
3721 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003722 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003723}
3724
3725
3726void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3727 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003728 case Token::DELETE: {
3729 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3730 Property* prop = expr->expression()->AsProperty();
3731 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003732
3733 if (prop != NULL) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003734 if (prop->is_synthetic()) {
3735 // Result of deleting parameters is false, even when they rewrite
3736 // to accesses on the arguments object.
3737 context()->Plug(false);
3738 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003739 VisitForStackValue(prop->obj());
3740 VisitForStackValue(prop->key());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003741 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003742 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003743 context()->Plug(eax);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003744 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003745 } else if (var != NULL) {
3746 // Delete of an unqualified identifier is disallowed in strict mode
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003747 // but "delete this" is.
3748 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003749 if (var->is_global()) {
3750 __ push(GlobalObjectOperand());
3751 __ push(Immediate(var->name()));
3752 __ push(Immediate(Smi::FromInt(kNonStrictMode)));
3753 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3754 context()->Plug(eax);
3755 } else if (var->AsSlot() != NULL &&
3756 var->AsSlot()->type() != Slot::LOOKUP) {
3757 // Result of deleting non-global, non-dynamic variables is false.
3758 // The subexpression does not have side effects.
3759 context()->Plug(false);
3760 } else {
3761 // Non-global variable. Call the runtime to try to delete from the
3762 // context where the variable was introduced.
3763 __ push(context_register());
3764 __ push(Immediate(var->name()));
3765 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3766 context()->Plug(eax);
3767 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003768 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003769 // Result of deleting non-property, non-variable reference is true.
3770 // The subexpression may have side effects.
3771 VisitForEffect(expr->expression());
3772 context()->Plug(true);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003773 }
3774 break;
3775 }
3776
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003777 case Token::VOID: {
3778 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3779 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003780 context()->Plug(Factory::undefined_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003781 break;
3782 }
3783
3784 case Token::NOT: {
3785 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003786 if (context()->IsEffect()) {
3787 // Unary NOT has no side effects so it's only necessary to visit the
3788 // subexpression. Match the optimizing compiler by not branching.
3789 VisitForEffect(expr->expression());
3790 } else {
3791 Label materialize_true, materialize_false;
3792 Label* if_true = NULL;
3793 Label* if_false = NULL;
3794 Label* fall_through = NULL;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003795
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003796 // Notice that the labels are swapped.
3797 context()->PrepareTest(&materialize_true, &materialize_false,
3798 &if_false, &if_true, &fall_through);
3799 if (context()->IsTest()) ForwardBailoutToChild(expr);
3800 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3801 context()->Plug(if_false, if_true); // Labels swapped.
3802 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003803 break;
3804 }
3805
3806 case Token::TYPEOF: {
3807 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003808 { StackValueContext context(this);
3809 VisitForTypeofValue(expr->expression());
3810 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003811 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003812 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003813 break;
3814 }
3815
3816 case Token::ADD: {
3817 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003818 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003819 Label no_conversion;
3820 __ test(result_register(), Immediate(kSmiTagMask));
3821 __ j(zero, &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003822 ToNumberStub convert_stub;
3823 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003824 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003825 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003826 break;
3827 }
3828
3829 case Token::SUB: {
3830 Comment cmt(masm_, "[ UnaryOperation (SUB)");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003831 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003832 UnaryOverwriteMode overwrite =
3833 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003834 GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003835 // GenericUnaryOpStub expects the argument to be in the
3836 // accumulator register eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003837 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003838 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003839 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003840 break;
3841 }
3842
3843 case Token::BIT_NOT: {
3844 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003845 // The generic unary operation stub expects the argument to be
3846 // in the accumulator register eax.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003847 VisitForAccumulatorValue(expr->expression());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003848 Label done;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003849 bool inline_smi_case = ShouldInlineSmiCase(expr->op());
3850 if (inline_smi_case) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003851 NearLabel call_stub;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003852 __ test(eax, Immediate(kSmiTagMask));
3853 __ j(not_zero, &call_stub);
3854 __ lea(eax, Operand(eax, kSmiTagMask));
3855 __ not_(eax);
3856 __ jmp(&done);
3857 __ bind(&call_stub);
3858 }
3859 bool overwrite = expr->expression()->ResultOverwriteAllowed();
3860 UnaryOverwriteMode mode =
3861 overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003862 UnaryOpFlags flags = inline_smi_case
3863 ? NO_UNARY_SMI_CODE_IN_STUB
3864 : NO_UNARY_FLAGS;
3865 GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003866 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003867 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003868 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003869 break;
3870 }
3871
3872 default:
3873 UNREACHABLE();
3874 }
3875}
3876
3877
3878void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3879 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003880 SetSourcePosition(expr->position());
3881
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003882 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3883 // as the left-hand side.
3884 if (!expr->expression()->IsValidLeftHandSide()) {
3885 VisitForEffect(expr->expression());
3886 return;
3887 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003888
3889 // Expression can only be a property, a global or a (parameter or local)
3890 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
3891 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3892 LhsKind assign_type = VARIABLE;
3893 Property* prop = expr->expression()->AsProperty();
3894 // In case of a property we use the uninitialized expression context
3895 // of the key to detect a named property.
3896 if (prop != NULL) {
3897 assign_type =
3898 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3899 }
3900
3901 // Evaluate expression and get value.
3902 if (assign_type == VARIABLE) {
3903 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003904 AccumulatorValueContext context(this);
3905 EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003906 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003907 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003908 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003909 __ push(Immediate(Smi::FromInt(0)));
3910 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003911 if (assign_type == NAMED_PROPERTY) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003912 // Put the object both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003913 VisitForAccumulatorValue(prop->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00003914 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003915 EmitNamedPropertyLoad(prop);
3916 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003917 if (prop->is_arguments_access()) {
3918 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003919 MemOperand slot_operand =
3920 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
3921 __ push(slot_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003922 __ mov(eax, Immediate(prop->key()->AsLiteral()->handle()));
3923 } else {
3924 VisitForStackValue(prop->obj());
3925 VisitForAccumulatorValue(prop->key());
3926 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003927 __ mov(edx, Operand(esp, 0));
3928 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003929 EmitKeyedPropertyLoad(prop);
3930 }
3931 }
3932
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003933 // We need a second deoptimization point after loading the value
3934 // in case evaluating the property load my have a side effect.
3935 PrepareForBailout(expr->increment(), TOS_REG);
3936
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003937 // Call ToNumber only if operand is not a smi.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003938 NearLabel no_conversion;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003939 if (ShouldInlineSmiCase(expr->op())) {
3940 __ test(eax, Immediate(kSmiTagMask));
3941 __ j(zero, &no_conversion);
3942 }
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003943 ToNumberStub convert_stub;
3944 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003945 __ bind(&no_conversion);
3946
3947 // Save result for postfix expressions.
3948 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003949 if (!context()->IsEffect()) {
3950 // Save the result on the stack. If we have a named or keyed property
3951 // we store the result under the receiver that is currently on top
3952 // of the stack.
3953 switch (assign_type) {
3954 case VARIABLE:
3955 __ push(eax);
3956 break;
3957 case NAMED_PROPERTY:
3958 __ mov(Operand(esp, kPointerSize), eax);
3959 break;
3960 case KEYED_PROPERTY:
3961 __ mov(Operand(esp, 2 * kPointerSize), eax);
3962 break;
3963 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003964 }
3965 }
3966
3967 // Inline smi case if we are in a loop.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003968 NearLabel stub_call, done;
3969 JumpPatchSite patch_site(masm_);
3970
ricow@chromium.org65fae842010-08-25 15:26:24 +00003971 if (ShouldInlineSmiCase(expr->op())) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003972 if (expr->op() == Token::INC) {
3973 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3974 } else {
3975 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3976 }
3977 __ j(overflow, &stub_call);
3978 // We could eliminate this smi check if we split the code at
3979 // the first smi check before calling ToNumber.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003980 patch_site.EmitJumpIfSmi(eax, &done);
3981
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003982 __ bind(&stub_call);
3983 // Call stub. Undo operation first.
3984 if (expr->op() == Token::INC) {
3985 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3986 } else {
3987 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3988 }
3989 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003990
3991 // Record position before stub call.
3992 SetSourcePosition(expr->position());
3993
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003994 // Call stub for +1/-1.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003995 __ mov(edx, eax);
3996 __ mov(eax, Immediate(Smi::FromInt(1)));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003997 TypeRecordingBinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003998 EmitCallIC(stub.GetCode(), &patch_site);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003999 __ bind(&done);
4000
4001 // Store the value returned in eax.
4002 switch (assign_type) {
4003 case VARIABLE:
4004 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004005 // Perform the assignment as if via '='.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004006 { EffectContext context(this);
4007 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4008 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004009 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4010 context.Plug(eax);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004011 }
4012 // For all contexts except EffectContext We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004013 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004014 if (!context()->IsEffect()) {
4015 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004016 }
4017 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004018 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004019 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004020 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004021 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4022 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004023 }
4024 break;
4025 case NAMED_PROPERTY: {
4026 __ mov(ecx, prop->key()->AsLiteral()->handle());
4027 __ pop(edx);
4028 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004029 EmitCallIC(ic, RelocInfo::CODE_TARGET);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004030 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004031 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004032 if (!context()->IsEffect()) {
4033 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004034 }
4035 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004036 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004037 }
4038 break;
4039 }
4040 case KEYED_PROPERTY: {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004041 __ pop(ecx);
4042 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004043 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004044 EmitCallIC(ic, RelocInfo::CODE_TARGET);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004045 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004046 if (expr->is_postfix()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004047 // Result is on the stack
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004048 if (!context()->IsEffect()) {
4049 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004050 }
4051 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004052 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004053 }
4054 break;
4055 }
4056 }
4057}
4058
4059
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004060void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004061 VariableProxy* proxy = expr->AsVariableProxy();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004062 ASSERT(!context()->IsEffect());
4063 ASSERT(!context()->IsTest());
4064
ricow@chromium.org65fae842010-08-25 15:26:24 +00004065 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
4066 Comment cmnt(masm_, "Global variable");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004067 __ mov(eax, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004068 __ mov(ecx, Immediate(proxy->name()));
4069 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
4070 // Use a regular load, not a contextual load, to avoid a reference
4071 // error.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004072 EmitCallIC(ic, RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004073 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004074 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004075 } else if (proxy != NULL &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004076 proxy->var()->AsSlot() != NULL &&
4077 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004078 Label done, slow;
4079
4080 // Generate code for loading from variables potentially shadowed
4081 // by eval-introduced variables.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004082 Slot* slot = proxy->var()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004083 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
4084
4085 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004086 __ push(esi);
4087 __ push(Immediate(proxy->name()));
4088 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004089 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004090 __ bind(&done);
4091
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004092 context()->Plug(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004093 } else {
4094 // This expression cannot throw a reference error at the top level.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004095 context()->HandleExpression(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004096 }
4097}
4098
4099
ricow@chromium.org65fae842010-08-25 15:26:24 +00004100bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
4101 Expression* left,
4102 Expression* right,
4103 Label* if_true,
4104 Label* if_false,
4105 Label* fall_through) {
4106 if (op != Token::EQ && op != Token::EQ_STRICT) return false;
4107
4108 // Check for the pattern: typeof <expression> == <string literal>.
4109 Literal* right_literal = right->AsLiteral();
4110 if (right_literal == NULL) return false;
4111 Handle<Object> right_literal_value = right_literal->handle();
4112 if (!right_literal_value->IsString()) return false;
4113 UnaryOperation* left_unary = left->AsUnaryOperation();
4114 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
4115 Handle<String> check = Handle<String>::cast(right_literal_value);
4116
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004117 { AccumulatorValueContext context(this);
4118 VisitForTypeofValue(left_unary->expression());
4119 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004120 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004121
ricow@chromium.org65fae842010-08-25 15:26:24 +00004122 if (check->Equals(Heap::number_symbol())) {
4123 __ test(eax, Immediate(kSmiTagMask));
4124 __ j(zero, if_true);
4125 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4126 Factory::heap_number_map());
4127 Split(equal, if_true, if_false, fall_through);
4128 } else if (check->Equals(Heap::string_symbol())) {
4129 __ test(eax, Immediate(kSmiTagMask));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004130 __ j(zero, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004131 // Check for undetectable objects => false.
4132 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4133 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4134 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4135 __ j(not_zero, if_false);
4136 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE);
4137 Split(below, if_true, if_false, fall_through);
4138 } else if (check->Equals(Heap::boolean_symbol())) {
4139 __ cmp(eax, Factory::true_value());
4140 __ j(equal, if_true);
4141 __ cmp(eax, Factory::false_value());
4142 Split(equal, if_true, if_false, fall_through);
4143 } else if (check->Equals(Heap::undefined_symbol())) {
4144 __ cmp(eax, Factory::undefined_value());
4145 __ j(equal, if_true);
4146 __ test(eax, Immediate(kSmiTagMask));
4147 __ j(zero, if_false);
4148 // Check for undetectable objects => true.
4149 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4150 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4151 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4152 Split(not_zero, if_true, if_false, fall_through);
4153 } else if (check->Equals(Heap::function_symbol())) {
4154 __ test(eax, Immediate(kSmiTagMask));
4155 __ j(zero, if_false);
4156 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
4157 __ j(equal, if_true);
4158 // Regular expressions => 'function' (they are callable).
4159 __ CmpInstanceType(edx, JS_REGEXP_TYPE);
4160 Split(equal, if_true, if_false, fall_through);
4161 } else if (check->Equals(Heap::object_symbol())) {
4162 __ test(eax, Immediate(kSmiTagMask));
4163 __ j(zero, if_false);
4164 __ cmp(eax, Factory::null_value());
4165 __ j(equal, if_true);
4166 // Regular expressions => 'function', not 'object'.
4167 __ CmpObjectType(eax, JS_REGEXP_TYPE, edx);
4168 __ j(equal, if_false);
4169 // Check for undetectable objects => false.
4170 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4171 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4172 __ j(not_zero, if_false);
4173 // Check for JS objects => true.
4174 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
4175 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
4176 __ j(less, if_false);
4177 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
4178 Split(less_equal, if_true, if_false, fall_through);
4179 } else {
4180 if (if_false != fall_through) __ jmp(if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004181 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004182
4183 return true;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004184}
4185
4186
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004187void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4188 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004189 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004190
4191 // Always perform the comparison for its control flow. Pack the result
4192 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004193
4194 Label materialize_true, materialize_false;
4195 Label* if_true = NULL;
4196 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004197 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004198 context()->PrepareTest(&materialize_true, &materialize_false,
4199 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004200
4201 // First we try a fast inlined version of the compare when one of
4202 // the operands is a literal.
4203 Token::Value op = expr->op();
4204 Expression* left = expr->left();
4205 Expression* right = expr->right();
4206 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004207 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004208 return;
4209 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004210
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004211 VisitForStackValue(expr->left());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004212 switch (expr->op()) {
4213 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004214 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004215 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004216 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004217 __ cmp(eax, Factory::true_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004218 Split(equal, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004219 break;
4220
4221 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004222 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004223 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004224 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004225 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004226 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004227 // The stub returns 0 for true.
4228 Split(zero, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004229 break;
4230 }
4231
4232 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004233 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004234 Condition cc = no_condition;
4235 bool strict = false;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004236 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004237 case Token::EQ_STRICT:
4238 strict = true;
4239 // Fall through
ricow@chromium.org65fae842010-08-25 15:26:24 +00004240 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004241 cc = equal;
4242 __ pop(edx);
4243 break;
4244 case Token::LT:
4245 cc = less;
4246 __ pop(edx);
4247 break;
4248 case Token::GT:
4249 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4250 cc = less;
4251 __ mov(edx, result_register());
4252 __ pop(eax);
4253 break;
4254 case Token::LTE:
4255 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4256 cc = greater_equal;
4257 __ mov(edx, result_register());
4258 __ pop(eax);
4259 break;
4260 case Token::GTE:
4261 cc = greater_equal;
4262 __ pop(edx);
4263 break;
4264 case Token::IN:
4265 case Token::INSTANCEOF:
4266 default:
4267 UNREACHABLE();
4268 }
4269
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004270 bool inline_smi_code = ShouldInlineSmiCase(op);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004271 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004272 if (inline_smi_code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004273 NearLabel slow_case;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004274 __ mov(ecx, Operand(edx));
4275 __ or_(ecx, Operand(eax));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004276 patch_site.EmitJumpIfNotSmi(ecx, &slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004277 __ cmp(edx, Operand(eax));
4278 Split(cc, if_true, if_false, NULL);
4279 __ bind(&slow_case);
4280 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004281
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004282 // Record position and call the compare IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004283 SetSourcePosition(expr->position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004284 Handle<Code> ic = CompareIC::GetUninitialized(op);
4285 EmitCallIC(ic, &patch_site);
4286
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004287 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004288 __ test(eax, Operand(eax));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004289 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004290 }
4291 }
4292
4293 // Convert the result of the comparison into one expected for this
4294 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004295 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004296}
4297
4298
ricow@chromium.org65fae842010-08-25 15:26:24 +00004299void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4300 Label materialize_true, materialize_false;
4301 Label* if_true = NULL;
4302 Label* if_false = NULL;
4303 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004304 context()->PrepareTest(&materialize_true, &materialize_false,
4305 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004306
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004307 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004308 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4309
ricow@chromium.org65fae842010-08-25 15:26:24 +00004310 __ cmp(eax, Factory::null_value());
4311 if (expr->is_strict()) {
4312 Split(equal, if_true, if_false, fall_through);
4313 } else {
4314 __ j(equal, if_true);
4315 __ cmp(eax, Factory::undefined_value());
4316 __ j(equal, if_true);
4317 __ test(eax, Immediate(kSmiTagMask));
4318 __ j(zero, if_false);
4319 // It can be an undetectable object.
4320 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4321 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
4322 __ test(edx, Immediate(1 << Map::kIsUndetectable));
4323 Split(not_zero, if_true, if_false, fall_through);
4324 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004325 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004326}
4327
4328
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004329void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4330 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004331 context()->Plug(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004332}
4333
4334
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004335Register FullCodeGenerator::result_register() {
4336 return eax;
4337}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004338
4339
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004340Register FullCodeGenerator::context_register() {
4341 return esi;
4342}
4343
4344
4345void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
4346 ASSERT(mode == RelocInfo::CODE_TARGET ||
4347 mode == RelocInfo::CODE_TARGET_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004348 switch (ic->kind()) {
4349 case Code::LOAD_IC:
4350 __ IncrementCounter(&Counters::named_load_full, 1);
4351 break;
4352 case Code::KEYED_LOAD_IC:
4353 __ IncrementCounter(&Counters::keyed_load_full, 1);
4354 break;
4355 case Code::STORE_IC:
4356 __ IncrementCounter(&Counters::named_store_full, 1);
4357 break;
4358 case Code::KEYED_STORE_IC:
4359 __ IncrementCounter(&Counters::keyed_store_full, 1);
4360 default:
4361 break;
4362 }
4363
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004364 __ call(ic, mode);
4365
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004366 // Crankshaft doesn't need patching of inlined loads and stores.
4367 // When compiling the snapshot we need to produce code that works
4368 // with and without Crankshaft.
4369 if (V8::UseCrankshaft() && !Serializer::enabled()) {
4370 return;
4371 }
4372
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004373 // If we're calling a (keyed) load or store stub, we have to mark
4374 // the call as containing no inlined code so we will not attempt to
4375 // patch it.
4376 switch (ic->kind()) {
4377 case Code::LOAD_IC:
4378 case Code::KEYED_LOAD_IC:
4379 case Code::STORE_IC:
4380 case Code::KEYED_STORE_IC:
4381 __ nop(); // Signals no inlined code.
4382 break;
4383 default:
4384 // Do nothing.
4385 break;
4386 }
4387}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004388
4389
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004390void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00004391 switch (ic->kind()) {
4392 case Code::LOAD_IC:
4393 __ IncrementCounter(&Counters::named_load_full, 1);
4394 break;
4395 case Code::KEYED_LOAD_IC:
4396 __ IncrementCounter(&Counters::keyed_load_full, 1);
4397 break;
4398 case Code::STORE_IC:
4399 __ IncrementCounter(&Counters::named_store_full, 1);
4400 break;
4401 case Code::KEYED_STORE_IC:
4402 __ IncrementCounter(&Counters::keyed_store_full, 1);
4403 default:
4404 break;
4405 }
4406
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004407 __ call(ic, RelocInfo::CODE_TARGET);
4408 if (patch_site != NULL && patch_site->is_bound()) {
4409 patch_site->EmitPatchInfo();
4410 } else {
4411 __ nop(); // Signals no inlined code.
4412 }
4413}
4414
4415
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004416void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4417 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4418 __ mov(Operand(ebp, frame_offset), value);
4419}
4420
4421
4422void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004423 __ mov(dst, ContextOperand(esi, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004424}
4425
4426
4427// ----------------------------------------------------------------------------
4428// Non-local control flow support.
4429
4430void FullCodeGenerator::EnterFinallyBlock() {
4431 // Cook return address on top of stack (smi encoded Code* delta)
4432 ASSERT(!result_register().is(edx));
4433 __ mov(edx, Operand(esp, 0));
4434 __ sub(Operand(edx), Immediate(masm_->CodeObject()));
4435 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4436 ASSERT_EQ(0, kSmiTag);
4437 __ add(edx, Operand(edx)); // Convert to smi.
4438 __ mov(Operand(esp, 0), edx);
4439 // Store result register while executing finally block.
4440 __ push(result_register());
4441}
4442
4443
4444void FullCodeGenerator::ExitFinallyBlock() {
4445 ASSERT(!result_register().is(edx));
4446 // Restore result register from stack.
4447 __ pop(result_register());
4448 // Uncook return address.
4449 __ mov(edx, Operand(esp, 0));
4450 __ sar(edx, 1); // Convert smi to int.
4451 __ add(Operand(edx), Immediate(masm_->CodeObject()));
4452 __ mov(Operand(esp, 0), edx);
4453 // And return.
4454 __ ret(0);
4455}
4456
4457
4458#undef __
4459
4460} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004461
4462#endif // V8_TARGET_ARCH_IA32