blob: 13a11777ab6ebec10d9c74bcaafd9c8f972ce0c3 [file] [log] [blame]
Leon Clarkef7060e22010-06-03 12:02:55 +01001// Copyright 2010 the V8 project authors. All rights reserved.
Steve Block3ce2e202009-11-05 08:53:23 +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
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_IA32)
31
Kristian Monsen80d68ea2010-09-08 11:05:35 +010032#include "code-stubs.h"
Steve Block3ce2e202009-11-05 08:53:23 +000033#include "codegen-inl.h"
Steve Blockd0582a62009-12-15 09:54:21 +000034#include "compiler.h"
Leon Clarkee46be812010-01-19 14:06:41 +000035#include "debug.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000036#include "full-codegen.h"
Steve Block3ce2e202009-11-05 08:53:23 +000037#include "parser.h"
Steve Block6ded16b2010-05-10 14:33:55 +010038#include "scopes.h"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080039#include "stub-cache.h"
Steve Block3ce2e202009-11-05 08:53:23 +000040
41namespace v8 {
42namespace internal {
43
Ben Murdochb0fe1622011-05-05 13:52:32 +010044
Steve Block3ce2e202009-11-05 08:53:23 +000045#define __ ACCESS_MASM(masm_)
46
Ben Murdochb0fe1622011-05-05 13:52:32 +010047
48class JumpPatchSite BASE_EMBEDDED {
49 public:
50 explicit JumpPatchSite(MacroAssembler* masm)
51 : masm_(masm) {
52#ifdef DEBUG
53 info_emitted_ = false;
54#endif
55 }
56
57 ~JumpPatchSite() {
58 ASSERT(patch_site_.is_bound() == info_emitted_);
59 }
60
61 void EmitJumpIfNotSmi(Register reg, NearLabel* target) {
62 __ test(reg, Immediate(kSmiTagMask));
63 EmitJump(not_carry, target); // Always taken before patched.
64 }
65
66 void EmitJumpIfSmi(Register reg, NearLabel* target) {
67 __ test(reg, Immediate(kSmiTagMask));
68 EmitJump(carry, target); // Never taken before patched.
69 }
70
71 void EmitPatchInfo() {
72 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
73 ASSERT(is_int8(delta_to_patch_site));
74 __ test(eax, Immediate(delta_to_patch_site));
75#ifdef DEBUG
76 info_emitted_ = true;
77#endif
78 }
79
80 bool is_bound() const { return patch_site_.is_bound(); }
81
82 private:
83 // jc will be patched with jz, jnc will become jnz.
84 void EmitJump(Condition cc, NearLabel* target) {
85 ASSERT(!patch_site_.is_bound() && !info_emitted_);
86 ASSERT(cc == carry || cc == not_carry);
87 __ bind(&patch_site_);
88 __ j(cc, target);
89 }
90
91 MacroAssembler* masm_;
92 Label patch_site_;
93#ifdef DEBUG
94 bool info_emitted_;
95#endif
96};
97
98
Steve Block3ce2e202009-11-05 08:53:23 +000099// Generate code for a JS function. On entry to the function the receiver
100// and arguments have been pushed on the stack left to right, with the
101// return address on top of them. The actual argument count matches the
102// formal parameter count expected by the function.
103//
104// The live registers are:
105// o edi: the JS function object being called (ie, ourselves)
106// o esi: our context
107// o ebp: our caller's frame pointer
108// o esp: stack pointer (pointing to return address)
109//
110// The function builds a JS frame. Please see JavaScriptFrameConstants in
111// frames-ia32.h for its layout.
Iain Merrick75681382010-08-19 15:07:18 +0100112void FullCodeGenerator::Generate(CompilationInfo* info) {
Andrei Popescu31002712010-02-23 13:46:05 +0000113 ASSERT(info_ == NULL);
114 info_ = info;
115 SetFunctionPosition(function());
Steve Block6ded16b2010-05-10 14:33:55 +0100116 Comment cmnt(masm_, "[ function compiled by full code generator");
Steve Block3ce2e202009-11-05 08:53:23 +0000117
Ben Murdochf87a2032010-10-22 12:50:53 +0100118#ifdef DEBUG
119 if (strlen(FLAG_stop_at) > 0 &&
120 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
121 __ int3();
122 }
123#endif
124
Iain Merrick75681382010-08-19 15:07:18 +0100125 __ push(ebp); // Caller's frame pointer.
126 __ mov(ebp, esp);
127 __ push(esi); // Callee's context.
128 __ push(edi); // Callee's JS Function.
Steve Block3ce2e202009-11-05 08:53:23 +0000129
Iain Merrick75681382010-08-19 15:07:18 +0100130 { Comment cmnt(masm_, "[ Allocate locals");
131 int locals_count = scope()->num_stack_slots();
132 if (locals_count == 1) {
133 __ push(Immediate(Factory::undefined_value()));
134 } else if (locals_count > 1) {
135 __ mov(eax, Immediate(Factory::undefined_value()));
136 for (int i = 0; i < locals_count; i++) {
137 __ push(eax);
Steve Blockd0582a62009-12-15 09:54:21 +0000138 }
Steve Block3ce2e202009-11-05 08:53:23 +0000139 }
Iain Merrick75681382010-08-19 15:07:18 +0100140 }
Steve Block3ce2e202009-11-05 08:53:23 +0000141
Iain Merrick75681382010-08-19 15:07:18 +0100142 bool function_in_register = true;
Steve Blockd0582a62009-12-15 09:54:21 +0000143
Iain Merrick75681382010-08-19 15:07:18 +0100144 // Possibly allocate a local context.
145 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
146 if (heap_slots > 0) {
147 Comment cmnt(masm_, "[ Allocate local context");
148 // Argument to NewContext is the function, which is still in edi.
149 __ push(edi);
150 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
151 FastNewContextStub stub(heap_slots);
Leon Clarke4515c472010-02-03 11:58:03 +0000152 __ CallStub(&stub);
Iain Merrick75681382010-08-19 15:07:18 +0100153 } else {
154 __ CallRuntime(Runtime::kNewContext, 1);
Leon Clarke4515c472010-02-03 11:58:03 +0000155 }
Iain Merrick75681382010-08-19 15:07:18 +0100156 function_in_register = false;
157 // Context is returned in both eax and esi. It replaces the context
158 // passed to us. It's saved in the stack and kept live in esi.
159 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
160
161 // Copy parameters into context if necessary.
162 int num_parameters = scope()->num_parameters();
163 for (int i = 0; i < num_parameters; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100164 Slot* slot = scope()->parameter(i)->AsSlot();
Iain Merrick75681382010-08-19 15:07:18 +0100165 if (slot != NULL && slot->type() == Slot::CONTEXT) {
166 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
167 (num_parameters - 1 - i) * kPointerSize;
168 // Load parameter from stack.
169 __ mov(eax, Operand(ebp, parameter_offset));
170 // Store it in the context.
171 int context_offset = Context::SlotOffset(slot->index());
172 __ mov(Operand(esi, context_offset), eax);
173 // Update the write barrier. This clobbers all involved
174 // registers, so we have use a third register to avoid
175 // clobbering esi.
176 __ mov(ecx, esi);
177 __ RecordWrite(ecx, context_offset, eax, ebx);
178 }
179 }
180 }
181
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100182 Variable* arguments = scope()->arguments();
Iain Merrick75681382010-08-19 15:07:18 +0100183 if (arguments != NULL) {
184 // Function uses arguments object.
185 Comment cmnt(masm_, "[ Allocate arguments object");
186 if (function_in_register) {
187 __ push(edi);
188 } else {
189 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
190 }
191 // Receiver is just before the parameters on the caller's stack.
192 int offset = scope()->num_parameters() * kPointerSize;
193 __ lea(edx,
194 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
195 __ push(edx);
196 __ push(Immediate(Smi::FromInt(scope()->num_parameters())));
197 // Arguments to ArgumentsAccessStub:
198 // function, receiver address, parameter count.
199 // The stub will rewrite receiver and parameter count if the previous
200 // stack frame was an arguments adapter frame.
201 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
202 __ CallStub(&stub);
203 __ mov(ecx, eax); // Duplicate result.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100204 Move(arguments->AsSlot(), eax, ebx, edx);
205 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
Iain Merrick75681382010-08-19 15:07:18 +0100206 Move(dot_arguments_slot, ecx, ebx, edx);
Steve Blockd0582a62009-12-15 09:54:21 +0000207 }
208
Steve Blockd0582a62009-12-15 09:54:21 +0000209 { Comment cmnt(masm_, "[ Declarations");
Leon Clarkef7060e22010-06-03 12:02:55 +0100210 // For named function expressions, declare the function name as a
211 // constant.
212 if (scope()->is_function_scope() && scope()->function() != NULL) {
213 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
214 }
215 // Visit all the explicit declarations unless there is an illegal
216 // redeclaration.
217 if (scope()->HasIllegalRedeclaration()) {
218 scope()->VisitIllegalRedeclaration(this);
219 } else {
220 VisitDeclarations(scope()->declarations());
221 }
Steve Blockd0582a62009-12-15 09:54:21 +0000222 }
223
Ben Murdochb0fe1622011-05-05 13:52:32 +0100224 if (FLAG_trace) {
225 __ CallRuntime(Runtime::kTraceEnter, 0);
226 }
227
Steve Block3ce2e202009-11-05 08:53:23 +0000228 { Comment cmnt(masm_, "[ Stack check");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100229 PrepareForBailout(info->function(), NO_REGISTERS);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100230 NearLabel ok;
Steve Blockd0582a62009-12-15 09:54:21 +0000231 ExternalReference stack_limit =
232 ExternalReference::address_of_stack_limit();
233 __ cmp(esp, Operand::StaticVariable(stack_limit));
Steve Block3ce2e202009-11-05 08:53:23 +0000234 __ j(above_equal, &ok, taken);
235 StackCheckStub stub;
236 __ CallStub(&stub);
237 __ bind(&ok);
238 }
239
Steve Block3ce2e202009-11-05 08:53:23 +0000240 { Comment cmnt(masm_, "[ Body");
Steve Blockd0582a62009-12-15 09:54:21 +0000241 ASSERT(loop_depth() == 0);
Andrei Popescu31002712010-02-23 13:46:05 +0000242 VisitStatements(function()->body());
Steve Blockd0582a62009-12-15 09:54:21 +0000243 ASSERT(loop_depth() == 0);
Steve Block3ce2e202009-11-05 08:53:23 +0000244 }
245
246 { Comment cmnt(masm_, "[ return <undefined>;");
Steve Blockd0582a62009-12-15 09:54:21 +0000247 // Emit a 'return undefined' in case control fell off the end of the body.
Steve Block3ce2e202009-11-05 08:53:23 +0000248 __ mov(eax, Factory::undefined_value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100249 EmitReturnSequence();
Steve Blockd0582a62009-12-15 09:54:21 +0000250 }
251}
Steve Block3ce2e202009-11-05 08:53:23 +0000252
Steve Blockd0582a62009-12-15 09:54:21 +0000253
Ben Murdochdb5a90a2011-01-06 18:27:03 +0000254void FullCodeGenerator::ClearAccumulator() {
255 __ Set(eax, Immediate(Smi::FromInt(0)));
256}
257
258
Ben Murdochb0fe1622011-05-05 13:52:32 +0100259void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
260 Comment cmnt(masm_, "[ Stack check");
261 NearLabel ok;
262 ExternalReference stack_limit = ExternalReference::address_of_stack_limit();
263 __ cmp(esp, Operand::StaticVariable(stack_limit));
264 __ j(above_equal, &ok, taken);
265 StackCheckStub stub;
266 __ CallStub(&stub);
267 __ bind(&ok);
268 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
269 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
270 RecordStackCheck(stmt->OsrEntryId());
271 // Loop stack checks can be patched to perform on-stack
272 // replacement. In order to decide whether or not to perform OSR we
273 // embed the loop depth in a test instruction after the call so we
274 // can extract it from the OSR builtin.
275 ASSERT(loop_depth() > 0);
276 __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
277}
278
279
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100280void FullCodeGenerator::EmitReturnSequence() {
Steve Blockd0582a62009-12-15 09:54:21 +0000281 Comment cmnt(masm_, "[ Return sequence");
282 if (return_label_.is_bound()) {
283 __ jmp(&return_label_);
284 } else {
285 // Common return label
286 __ bind(&return_label_);
Steve Block3ce2e202009-11-05 08:53:23 +0000287 if (FLAG_trace) {
288 __ push(eax);
289 __ CallRuntime(Runtime::kTraceExit, 1);
290 }
Steve Blockd0582a62009-12-15 09:54:21 +0000291#ifdef DEBUG
292 // Add a label for checking the size of the code used for returning.
293 Label check_exit_codesize;
294 masm_->bind(&check_exit_codesize);
295#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100296 SetSourcePosition(function()->end_position() - 1);
Steve Block3ce2e202009-11-05 08:53:23 +0000297 __ RecordJSReturn();
298 // Do not use the leave instruction here because it is too short to
299 // patch with the code required by the debugger.
300 __ mov(esp, ebp);
301 __ pop(ebp);
Andrei Popescu31002712010-02-23 13:46:05 +0000302 __ ret((scope()->num_parameters() + 1) * kPointerSize);
Steve Blockd0582a62009-12-15 09:54:21 +0000303#ifdef ENABLE_DEBUGGER_SUPPORT
304 // Check that the size of the code used for returning matches what is
305 // expected by the debugger.
306 ASSERT_EQ(Assembler::kJSReturnSequenceLength,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100307 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
Steve Blockd0582a62009-12-15 09:54:21 +0000308#endif
309 }
310}
311
312
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100313FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
314 Token::Value op, Expression* left, Expression* right) {
315 ASSERT(ShouldInlineSmiCase(op));
316 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) {
317 // We never generate inlined constant smi operations for these.
318 return kNoConstants;
319 } else if (right->IsSmiLiteral()) {
320 return kRightConstant;
321 } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) {
322 return kLeftConstant;
323 } else {
324 return kNoConstants;
325 }
326}
327
328
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100329void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
Steve Blockd0582a62009-12-15 09:54:21 +0000330}
331
332
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100333void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
334 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
335 __ mov(result_register(), slot_operand);
336}
337
338
339void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
340 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
341 // Memory operands can be pushed directly.
342 __ push(slot_operand);
343}
344
345
346void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
347 // For simplicity we always test the accumulator register.
348 codegen()->Move(result_register(), slot);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100349 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100350 codegen()->DoTest(true_label_, false_label_, fall_through_);
351}
352
353
354void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
355 UNREACHABLE(); // Not used on IA32.
356}
357
358
359void FullCodeGenerator::AccumulatorValueContext::Plug(
360 Heap::RootListIndex index) const {
361 UNREACHABLE(); // Not used on IA32.
362}
363
364
365void FullCodeGenerator::StackValueContext::Plug(
366 Heap::RootListIndex index) const {
367 UNREACHABLE(); // Not used on IA32.
368}
369
370
371void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
372 UNREACHABLE(); // Not used on IA32.
373}
374
375
376void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
377}
378
379
380void FullCodeGenerator::AccumulatorValueContext::Plug(
381 Handle<Object> lit) const {
382 __ mov(result_register(), lit);
383}
384
385
386void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
387 // Immediates can be pushed directly.
388 __ push(Immediate(lit));
389}
390
391
392void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100393 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
394 true,
395 true_label_,
396 false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100397 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
398 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100399 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100400 } else if (lit->IsTrue() || lit->IsJSObject()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100401 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100402 } else if (lit->IsString()) {
403 if (String::cast(*lit)->length() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100404 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100405 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100406 if (true_label_ != fall_through_) __ jmp(true_label_);
Steve Blockd0582a62009-12-15 09:54:21 +0000407 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100408 } else if (lit->IsSmi()) {
409 if (Smi::cast(*lit)->value() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100410 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100411 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100412 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100413 }
414 } else {
415 // For simplicity we always test the accumulator register.
416 __ mov(result_register(), lit);
417 codegen()->DoTest(true_label_, false_label_, fall_through_);
Steve Blockd0582a62009-12-15 09:54:21 +0000418 }
419}
420
421
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100422void FullCodeGenerator::EffectContext::DropAndPlug(int count,
423 Register reg) const {
Leon Clarkee46be812010-01-19 14:06:41 +0000424 ASSERT(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100425 __ Drop(count);
Leon Clarkef7060e22010-06-03 12:02:55 +0100426}
427
428
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100429void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
430 int count,
431 Register reg) const {
432 ASSERT(count > 0);
433 __ Drop(count);
434 __ Move(result_register(), reg);
Leon Clarkee46be812010-01-19 14:06:41 +0000435}
436
437
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100438void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
439 Register reg) const {
440 ASSERT(count > 0);
441 if (count > 1) __ Drop(count - 1);
442 __ mov(Operand(esp, 0), reg);
443}
444
445
446void FullCodeGenerator::TestContext::DropAndPlug(int count,
447 Register reg) const {
448 ASSERT(count > 0);
449 // For simplicity we always test the accumulator register.
450 __ Drop(count);
451 __ Move(result_register(), reg);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100452 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100453 codegen()->DoTest(true_label_, false_label_, fall_through_);
454}
455
456
457void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
458 Label* materialize_false) const {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100459 ASSERT(materialize_true == materialize_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100460 __ bind(materialize_true);
461}
462
463
464void FullCodeGenerator::AccumulatorValueContext::Plug(
465 Label* materialize_true,
466 Label* materialize_false) const {
467 NearLabel done;
468 __ bind(materialize_true);
469 __ mov(result_register(), Factory::true_value());
470 __ jmp(&done);
471 __ bind(materialize_false);
472 __ mov(result_register(), Factory::false_value());
473 __ bind(&done);
474}
475
476
477void FullCodeGenerator::StackValueContext::Plug(
478 Label* materialize_true,
479 Label* materialize_false) const {
480 NearLabel done;
481 __ bind(materialize_true);
482 __ push(Immediate(Factory::true_value()));
483 __ jmp(&done);
484 __ bind(materialize_false);
485 __ push(Immediate(Factory::false_value()));
486 __ bind(&done);
487}
488
489
490void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
491 Label* materialize_false) const {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100492 ASSERT(materialize_true == true_label_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100493 ASSERT(materialize_false == false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100494}
495
496
497void FullCodeGenerator::EffectContext::Plug(bool flag) const {
498}
499
500
501void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
502 Handle<Object> value =
503 flag ? Factory::true_value() : Factory::false_value();
504 __ mov(result_register(), value);
505}
506
507
508void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
509 Handle<Object> value =
510 flag ? Factory::true_value() : Factory::false_value();
511 __ push(Immediate(value));
512}
513
514
515void FullCodeGenerator::TestContext::Plug(bool flag) const {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100516 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
517 true,
518 true_label_,
519 false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100520 if (flag) {
521 if (true_label_ != fall_through_) __ jmp(true_label_);
522 } else {
523 if (false_label_ != fall_through_) __ jmp(false_label_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100524 }
525}
526
527
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100528void FullCodeGenerator::DoTest(Label* if_true,
529 Label* if_false,
530 Label* fall_through) {
Leon Clarkee46be812010-01-19 14:06:41 +0000531 // Emit the inlined tests assumed by the stub.
532 __ cmp(result_register(), Factory::undefined_value());
533 __ j(equal, if_false);
534 __ cmp(result_register(), Factory::true_value());
535 __ j(equal, if_true);
536 __ cmp(result_register(), Factory::false_value());
537 __ j(equal, if_false);
538 ASSERT_EQ(0, kSmiTag);
539 __ test(result_register(), Operand(result_register()));
540 __ j(zero, if_false);
541 __ test(result_register(), Immediate(kSmiTagMask));
542 __ j(zero, if_true);
543
Leon Clarkee46be812010-01-19 14:06:41 +0000544 // Call the ToBoolean stub for all other cases.
545 ToBooleanStub stub;
546 __ push(result_register());
547 __ CallStub(&stub);
548 __ test(eax, Operand(eax));
549
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100550 // The stub returns nonzero for true.
551 Split(not_zero, if_true, if_false, fall_through);
552}
Leon Clarkee46be812010-01-19 14:06:41 +0000553
Leon Clarkee46be812010-01-19 14:06:41 +0000554
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100555void FullCodeGenerator::Split(Condition cc,
556 Label* if_true,
557 Label* if_false,
558 Label* fall_through) {
559 if (if_false == fall_through) {
560 __ j(cc, if_true);
561 } else if (if_true == fall_through) {
562 __ j(NegateCondition(cc), if_false);
563 } else {
564 __ j(cc, if_true);
565 __ jmp(if_false);
Leon Clarkee46be812010-01-19 14:06:41 +0000566 }
567}
568
569
Leon Clarked91b9f72010-01-27 17:25:45 +0000570MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
Leon Clarkee46be812010-01-19 14:06:41 +0000571 switch (slot->type()) {
572 case Slot::PARAMETER:
573 case Slot::LOCAL:
574 return Operand(ebp, SlotOffset(slot));
575 case Slot::CONTEXT: {
576 int context_chain_length =
Andrei Popescu31002712010-02-23 13:46:05 +0000577 scope()->ContextChainLength(slot->var()->scope());
Leon Clarkee46be812010-01-19 14:06:41 +0000578 __ LoadContext(scratch, context_chain_length);
Steve Block59151502010-09-22 15:07:15 +0100579 return ContextOperand(scratch, slot->index());
Leon Clarkee46be812010-01-19 14:06:41 +0000580 }
581 case Slot::LOOKUP:
582 UNREACHABLE();
583 }
584 UNREACHABLE();
585 return Operand(eax, 0);
586}
587
588
Leon Clarked91b9f72010-01-27 17:25:45 +0000589void FullCodeGenerator::Move(Register destination, Slot* source) {
Leon Clarkee46be812010-01-19 14:06:41 +0000590 MemOperand location = EmitSlotSearch(source, destination);
591 __ mov(destination, location);
592}
593
594
Leon Clarked91b9f72010-01-27 17:25:45 +0000595void FullCodeGenerator::Move(Slot* dst,
Steve Blockd0582a62009-12-15 09:54:21 +0000596 Register src,
597 Register scratch1,
598 Register scratch2) {
Leon Clarkee46be812010-01-19 14:06:41 +0000599 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
600 ASSERT(!scratch1.is(src) && !scratch2.is(src));
601 MemOperand location = EmitSlotSearch(dst, scratch1);
602 __ mov(location, src);
603 // Emit the write barrier code if the location is in the heap.
604 if (dst->type() == Slot::CONTEXT) {
605 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
606 __ RecordWrite(scratch1, offset, src, scratch2);
Steve Blockd0582a62009-12-15 09:54:21 +0000607 }
608}
609
610
Ben Murdochb0fe1622011-05-05 13:52:32 +0100611void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
612 bool should_normalize,
613 Label* if_true,
614 Label* if_false) {
615 // Only prepare for bailouts before splits if we're in a test
616 // context. Otherwise, we let the Visit function deal with the
617 // preparation to avoid preparing with the same AST id twice.
618 if (!context()->IsTest() || !info_->IsOptimizable()) return;
619
620 NearLabel skip;
621 if (should_normalize) __ jmp(&skip);
622
623 ForwardBailoutStack* current = forward_bailout_stack_;
624 while (current != NULL) {
625 PrepareForBailout(current->expr(), state);
626 current = current->parent();
627 }
628
629 if (should_normalize) {
630 __ cmp(eax, Factory::true_value());
631 Split(equal, if_true, if_false, NULL);
632 __ bind(&skip);
633 }
634}
635
636
Leon Clarkef7060e22010-06-03 12:02:55 +0100637void FullCodeGenerator::EmitDeclaration(Variable* variable,
638 Variable::Mode mode,
639 FunctionLiteral* function) {
Steve Blockd0582a62009-12-15 09:54:21 +0000640 Comment cmnt(masm_, "[ Declaration");
Leon Clarkef7060e22010-06-03 12:02:55 +0100641 ASSERT(variable != NULL); // Must have been resolved.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100642 Slot* slot = variable->AsSlot();
Leon Clarkef7060e22010-06-03 12:02:55 +0100643 Property* prop = variable->AsProperty();
Steve Blockd0582a62009-12-15 09:54:21 +0000644 if (slot != NULL) {
645 switch (slot->type()) {
Leon Clarkee46be812010-01-19 14:06:41 +0000646 case Slot::PARAMETER:
Steve Blockd0582a62009-12-15 09:54:21 +0000647 case Slot::LOCAL:
Leon Clarkef7060e22010-06-03 12:02:55 +0100648 if (mode == Variable::CONST) {
Leon Clarkee46be812010-01-19 14:06:41 +0000649 __ mov(Operand(ebp, SlotOffset(slot)),
Steve Blockd0582a62009-12-15 09:54:21 +0000650 Immediate(Factory::the_hole_value()));
Leon Clarkef7060e22010-06-03 12:02:55 +0100651 } else if (function != NULL) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100652 VisitForAccumulatorValue(function);
Leon Clarkee46be812010-01-19 14:06:41 +0000653 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
Steve Blockd0582a62009-12-15 09:54:21 +0000654 }
655 break;
656
657 case Slot::CONTEXT:
Leon Clarkee46be812010-01-19 14:06:41 +0000658 // We bypass the general EmitSlotSearch because we know more about
659 // this specific context.
660
Steve Blockd0582a62009-12-15 09:54:21 +0000661 // The variable in the decl always resides in the current context.
Leon Clarkef7060e22010-06-03 12:02:55 +0100662 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
Steve Blockd0582a62009-12-15 09:54:21 +0000663 if (FLAG_debug_code) {
664 // Check if we have the correct context pointer.
Steve Block59151502010-09-22 15:07:15 +0100665 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX));
Steve Blockd0582a62009-12-15 09:54:21 +0000666 __ cmp(ebx, Operand(esi));
667 __ Check(equal, "Unexpected declaration in current context.");
668 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100669 if (mode == Variable::CONST) {
Steve Block59151502010-09-22 15:07:15 +0100670 __ mov(ContextOperand(esi, slot->index()),
Leon Clarkef7060e22010-06-03 12:02:55 +0100671 Immediate(Factory::the_hole_value()));
Steve Blockd0582a62009-12-15 09:54:21 +0000672 // No write barrier since the hole value is in old space.
Leon Clarkef7060e22010-06-03 12:02:55 +0100673 } else if (function != NULL) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100674 VisitForAccumulatorValue(function);
Steve Block59151502010-09-22 15:07:15 +0100675 __ mov(ContextOperand(esi, slot->index()), result_register());
Steve Blockd0582a62009-12-15 09:54:21 +0000676 int offset = Context::SlotOffset(slot->index());
Leon Clarke4515c472010-02-03 11:58:03 +0000677 __ mov(ebx, esi);
678 __ RecordWrite(ebx, offset, result_register(), ecx);
Steve Blockd0582a62009-12-15 09:54:21 +0000679 }
680 break;
681
682 case Slot::LOOKUP: {
683 __ push(esi);
Leon Clarkef7060e22010-06-03 12:02:55 +0100684 __ push(Immediate(variable->name()));
Steve Blockd0582a62009-12-15 09:54:21 +0000685 // Declaration nodes are always introduced in one of two modes.
Leon Clarkef7060e22010-06-03 12:02:55 +0100686 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
687 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
Steve Blockd0582a62009-12-15 09:54:21 +0000688 __ push(Immediate(Smi::FromInt(attr)));
689 // Push initial value, if any.
690 // Note: For variables we must not push an initial value (such as
691 // 'undefined') because we may have a (legal) redeclaration and we
692 // must not destroy the current value.
Leon Clarkef7060e22010-06-03 12:02:55 +0100693 if (mode == Variable::CONST) {
Steve Blockd0582a62009-12-15 09:54:21 +0000694 __ push(Immediate(Factory::the_hole_value()));
Leon Clarkef7060e22010-06-03 12:02:55 +0100695 } else if (function != NULL) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100696 VisitForStackValue(function);
Steve Blockd0582a62009-12-15 09:54:21 +0000697 } else {
698 __ push(Immediate(Smi::FromInt(0))); // No initial value!
699 }
700 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
701 break;
702 }
703 }
704
705 } else if (prop != NULL) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100706 if (function != NULL || mode == Variable::CONST) {
Steve Blockd0582a62009-12-15 09:54:21 +0000707 // We are declaring a function or constant that rewrites to a
708 // property. Use (keyed) IC to set the initial value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100709 VisitForStackValue(prop->obj());
Leon Clarkef7060e22010-06-03 12:02:55 +0100710 if (function != NULL) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100711 VisitForStackValue(prop->key());
712 VisitForAccumulatorValue(function);
Steve Block6ded16b2010-05-10 14:33:55 +0100713 __ pop(ecx);
Steve Blockd0582a62009-12-15 09:54:21 +0000714 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100715 VisitForAccumulatorValue(prop->key());
Steve Block6ded16b2010-05-10 14:33:55 +0100716 __ mov(ecx, result_register());
Leon Clarkee46be812010-01-19 14:06:41 +0000717 __ mov(result_register(), Factory::the_hole_value());
Steve Blockd0582a62009-12-15 09:54:21 +0000718 }
Steve Block6ded16b2010-05-10 14:33:55 +0100719 __ pop(edx);
Steve Blockd0582a62009-12-15 09:54:21 +0000720
721 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100722 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Steve Blockd0582a62009-12-15 09:54:21 +0000723 }
Steve Block3ce2e202009-11-05 08:53:23 +0000724 }
725}
726
727
Leon Clarkef7060e22010-06-03 12:02:55 +0100728void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
729 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
730}
731
732
Leon Clarked91b9f72010-01-27 17:25:45 +0000733void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
Steve Block3ce2e202009-11-05 08:53:23 +0000734 // Call the runtime to declare the globals.
735 __ push(esi); // The context is the first argument.
736 __ push(Immediate(pairs));
Andrei Popescu31002712010-02-23 13:46:05 +0000737 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
Steve Block3ce2e202009-11-05 08:53:23 +0000738 __ CallRuntime(Runtime::kDeclareGlobals, 3);
739 // Return value is ignored.
740}
741
742
Leon Clarkef7060e22010-06-03 12:02:55 +0100743void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
744 Comment cmnt(masm_, "[ SwitchStatement");
745 Breakable nested_statement(this, stmt);
746 SetStatementPosition(stmt);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100747
Leon Clarkef7060e22010-06-03 12:02:55 +0100748 // Keep the switch value on the stack until a case matches.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100749 VisitForStackValue(stmt->tag());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100750 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +0000751
Leon Clarkef7060e22010-06-03 12:02:55 +0100752 ZoneList<CaseClause*>* clauses = stmt->cases();
753 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
Steve Block3ce2e202009-11-05 08:53:23 +0000754
Leon Clarkef7060e22010-06-03 12:02:55 +0100755 Label next_test; // Recycled for each test.
756 // Compile all the tests with branches to their bodies.
757 for (int i = 0; i < clauses->length(); i++) {
758 CaseClause* clause = clauses->at(i);
759 // The default is not a test, but remember it as final fall through.
760 if (clause->is_default()) {
761 default_clause = clause;
762 continue;
763 }
764
765 Comment cmnt(masm_, "[ Case comparison");
766 __ bind(&next_test);
767 next_test.Unuse();
768
769 // Compile the label expression.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100770 VisitForAccumulatorValue(clause->label());
Leon Clarkef7060e22010-06-03 12:02:55 +0100771
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100772 // Perform the comparison as if via '==='.
Leon Clarkef7060e22010-06-03 12:02:55 +0100773 __ mov(edx, Operand(esp, 0)); // Switch value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100774 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100775 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100776 if (inline_smi_code) {
777 NearLabel slow_case;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100778 __ mov(ecx, edx);
779 __ or_(ecx, Operand(eax));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100780 patch_site.EmitJumpIfNotSmi(ecx, &slow_case);
781
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100782 __ cmp(edx, Operand(eax));
783 __ j(not_equal, &next_test);
784 __ Drop(1); // Switch value is no longer needed.
785 __ jmp(clause->body_target()->entry_label());
786 __ bind(&slow_case);
787 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100788
Ben Murdochb0fe1622011-05-05 13:52:32 +0100789 // Record position before stub call for type feedback.
790 SetSourcePosition(clause->position());
791 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
792 EmitCallIC(ic, &patch_site);
793
Leon Clarkef7060e22010-06-03 12:02:55 +0100794 __ test(eax, Operand(eax));
795 __ j(not_equal, &next_test);
796 __ Drop(1); // Switch value is no longer needed.
797 __ jmp(clause->body_target()->entry_label());
798 }
799
800 // Discard the test value and jump to the default if present, otherwise to
801 // the end of the statement.
802 __ bind(&next_test);
803 __ Drop(1); // Switch value is no longer needed.
804 if (default_clause == NULL) {
805 __ jmp(nested_statement.break_target());
806 } else {
807 __ jmp(default_clause->body_target()->entry_label());
808 }
809
810 // Compile all the case bodies.
811 for (int i = 0; i < clauses->length(); i++) {
812 Comment cmnt(masm_, "[ Case body");
813 CaseClause* clause = clauses->at(i);
814 __ bind(clause->body_target()->entry_label());
815 VisitStatements(clause->statements());
816 }
817
818 __ bind(nested_statement.break_target());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100819 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +0100820}
821
822
823void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
824 Comment cmnt(masm_, "[ ForInStatement");
825 SetStatementPosition(stmt);
826
827 Label loop, exit;
828 ForIn loop_statement(this, stmt);
829 increment_loop_depth();
830
831 // Get the object to enumerate over. Both SpiderMonkey and JSC
832 // ignore null and undefined in contrast to the specification; see
833 // ECMA-262 section 12.6.4.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100834 VisitForAccumulatorValue(stmt->enumerable());
Leon Clarkef7060e22010-06-03 12:02:55 +0100835 __ cmp(eax, Factory::undefined_value());
836 __ j(equal, &exit);
837 __ cmp(eax, Factory::null_value());
838 __ j(equal, &exit);
839
840 // Convert the object to a JS object.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100841 NearLabel convert, done_convert;
Leon Clarkef7060e22010-06-03 12:02:55 +0100842 __ test(eax, Immediate(kSmiTagMask));
843 __ j(zero, &convert);
844 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
845 __ j(above_equal, &done_convert);
846 __ bind(&convert);
847 __ push(eax);
848 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
849 __ bind(&done_convert);
850 __ push(eax);
851
Steve Block59151502010-09-22 15:07:15 +0100852 // Check cache validity in generated code. This is a fast case for
853 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
854 // guarantee cache validity, call the runtime system to check cache
855 // validity or get the property names in a fixed array.
856 Label next, call_runtime;
857 __ mov(ecx, eax);
858 __ bind(&next);
859
860 // Check that there are no elements. Register ecx contains the
861 // current JS object we've reached through the prototype chain.
862 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset),
863 Factory::empty_fixed_array());
864 __ j(not_equal, &call_runtime);
865
866 // Check that instance descriptors are not empty so that we can
867 // check for an enum cache. Leave the map in ebx for the subsequent
868 // prototype load.
869 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
870 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
871 __ cmp(edx, Factory::empty_descriptor_array());
872 __ j(equal, &call_runtime);
873
874 // Check that there in an enum cache in the non-empty instance
875 // descriptors (edx). This is the case if the next enumeration
876 // index field does not contain a smi.
877 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
878 __ test(edx, Immediate(kSmiTagMask));
879 __ j(zero, &call_runtime);
880
881 // For all objects but the receiver, check that the cache is empty.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100882 NearLabel check_prototype;
Steve Block59151502010-09-22 15:07:15 +0100883 __ cmp(ecx, Operand(eax));
884 __ j(equal, &check_prototype);
885 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
886 __ cmp(edx, Factory::empty_fixed_array());
887 __ j(not_equal, &call_runtime);
888
889 // Load the prototype from the map and loop if non-null.
890 __ bind(&check_prototype);
891 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
892 __ cmp(ecx, Factory::null_value());
893 __ j(not_equal, &next);
894
895 // The enum cache is valid. Load the map of the object being
896 // iterated over and use the cache for the iteration.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100897 NearLabel use_cache;
Steve Block59151502010-09-22 15:07:15 +0100898 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
899 __ jmp(&use_cache);
Leon Clarkef7060e22010-06-03 12:02:55 +0100900
901 // Get the set of properties to enumerate.
Steve Block59151502010-09-22 15:07:15 +0100902 __ bind(&call_runtime);
Leon Clarkef7060e22010-06-03 12:02:55 +0100903 __ push(eax); // Duplicate the enumerable object on the stack.
904 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
905
906 // If we got a map from the runtime call, we can do a fast
907 // modification check. Otherwise, we got a fixed array, and we have
908 // to do a slow check.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100909 NearLabel fixed_array;
Leon Clarkef7060e22010-06-03 12:02:55 +0100910 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map());
911 __ j(not_equal, &fixed_array);
912
913 // We got a map in register eax. Get the enumeration cache from it.
Steve Block59151502010-09-22 15:07:15 +0100914 __ bind(&use_cache);
Leon Clarkef7060e22010-06-03 12:02:55 +0100915 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset));
916 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
917 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
918
919 // Setup the four remaining stack slots.
920 __ push(eax); // Map.
921 __ push(edx); // Enumeration cache.
922 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +0100923 __ push(eax); // Enumeration cache length (as smi).
924 __ push(Immediate(Smi::FromInt(0))); // Initial index.
925 __ jmp(&loop);
926
927 // We got a fixed array in register eax. Iterate through that.
928 __ bind(&fixed_array);
929 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
930 __ push(eax);
931 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +0100932 __ push(eax); // Fixed array length (as smi).
933 __ push(Immediate(Smi::FromInt(0))); // Initial index.
934
935 // Generate code for doing the condition check.
936 __ bind(&loop);
937 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
938 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
939 __ j(above_equal, loop_statement.break_target());
940
941 // Get the current entry of the array into register ebx.
942 __ mov(ebx, Operand(esp, 2 * kPointerSize));
943 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
944
945 // Get the expected map from the stack or a zero map in the
946 // permanent slow case into register edx.
947 __ mov(edx, Operand(esp, 3 * kPointerSize));
948
949 // Check if the expected map still matches that of the enumerable.
950 // If not, we have to filter the key.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100951 NearLabel update_each;
Leon Clarkef7060e22010-06-03 12:02:55 +0100952 __ mov(ecx, Operand(esp, 4 * kPointerSize));
953 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
954 __ j(equal, &update_each);
955
956 // Convert the entry to a string or null if it isn't a property
957 // anymore. If the property has been removed while iterating, we
958 // just skip it.
959 __ push(ecx); // Enumerable.
960 __ push(ebx); // Current entry.
961 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
Iain Merrick75681382010-08-19 15:07:18 +0100962 __ test(eax, Operand(eax));
Leon Clarkef7060e22010-06-03 12:02:55 +0100963 __ j(equal, loop_statement.continue_target());
964 __ mov(ebx, Operand(eax));
965
966 // Update the 'each' property or variable from the possibly filtered
967 // entry in register ebx.
968 __ bind(&update_each);
969 __ mov(result_register(), ebx);
970 // Perform the assignment as if via '='.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100971 { EffectContext context(this);
972 EmitAssignment(stmt->each(), stmt->AssignmentId());
973 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100974
975 // Generate code for the body of the loop.
Leon Clarkef7060e22010-06-03 12:02:55 +0100976 Visit(stmt->body());
977
Leon Clarkef7060e22010-06-03 12:02:55 +0100978 // Generate code for going to the next element by incrementing the
979 // index (smi) stored on top of the stack.
980 __ bind(loop_statement.continue_target());
981 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
Leon Clarkef7060e22010-06-03 12:02:55 +0100982
Ben Murdochb0fe1622011-05-05 13:52:32 +0100983 EmitStackCheck(stmt);
984 __ jmp(&loop);
Leon Clarkef7060e22010-06-03 12:02:55 +0100985
986 // Remove the pointers stored on the stack.
987 __ bind(loop_statement.break_target());
988 __ add(Operand(esp), Immediate(5 * kPointerSize));
989
990 // Exit and decrement the loop depth.
991 __ bind(&exit);
992 decrement_loop_depth();
993}
994
995
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800996void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
997 bool pretenure) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100998 // Use the fast case closure allocation code that allocates in new
Ben Murdochb0fe1622011-05-05 13:52:32 +0100999 // space for nested functions that don't need literals cloning. If
1000 // we're running with the --always-opt or the --prepare-always-opt
1001 // flag, we need to use the runtime function so that the new function
1002 // we are creating here gets a chance to have its code optimized and
1003 // doesn't just get a copy of the existing unoptimized code.
1004 if (!FLAG_always_opt &&
1005 !FLAG_prepare_always_opt &&
1006 scope()->is_function_scope() &&
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001007 info->num_literals() == 0 &&
1008 !pretenure) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001009 FastNewClosureStub stub;
1010 __ push(Immediate(info));
1011 __ CallStub(&stub);
1012 } else {
1013 __ push(esi);
1014 __ push(Immediate(info));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001015 __ push(Immediate(pretenure
1016 ? Factory::true_value()
1017 : Factory::false_value()));
1018 __ CallRuntime(Runtime::kNewClosure, 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01001019 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001020 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001021}
1022
1023
Leon Clarked91b9f72010-01-27 17:25:45 +00001024void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001025 Comment cmnt(masm_, "[ VariableProxy");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001026 EmitVariableLoad(expr->var());
Leon Clarkee46be812010-01-19 14:06:41 +00001027}
1028
1029
Steve Block59151502010-09-22 15:07:15 +01001030void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
1031 Slot* slot,
1032 TypeofState typeof_state,
1033 Label* slow) {
1034 Register context = esi;
1035 Register temp = edx;
1036
1037 Scope* s = scope();
1038 while (s != NULL) {
1039 if (s->num_heap_slots() > 0) {
1040 if (s->calls_eval()) {
1041 // Check that extension is NULL.
1042 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1043 Immediate(0));
1044 __ j(not_equal, slow);
1045 }
1046 // Load next context in chain.
1047 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1048 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1049 // Walk the rest of the chain without clobbering esi.
1050 context = temp;
1051 }
1052 // If no outer scope calls eval, we do not need to check more
1053 // context extensions. If we have reached an eval scope, we check
1054 // all extensions from this point.
1055 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1056 s = s->outer_scope();
1057 }
1058
1059 if (s != NULL && s->is_eval_scope()) {
1060 // Loop up the context chain. There is no frame effect so it is
1061 // safe to use raw labels here.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001062 NearLabel next, fast;
Steve Block59151502010-09-22 15:07:15 +01001063 if (!context.is(temp)) {
1064 __ mov(temp, context);
1065 }
1066 __ bind(&next);
1067 // Terminate at global context.
1068 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
1069 Immediate(Factory::global_context_map()));
1070 __ j(equal, &fast);
1071 // Check that extension is NULL.
1072 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1073 __ j(not_equal, slow);
1074 // Load next context in chain.
1075 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX));
1076 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1077 __ jmp(&next);
1078 __ bind(&fast);
1079 }
1080
1081 // All extension objects were empty and it is safe to use a global
1082 // load IC call.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001083 __ mov(eax, GlobalObjectOperand());
Steve Block59151502010-09-22 15:07:15 +01001084 __ mov(ecx, slot->var()->name());
1085 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1086 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1087 ? RelocInfo::CODE_TARGET
1088 : RelocInfo::CODE_TARGET_CONTEXT;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001089 EmitCallIC(ic, mode);
Steve Block59151502010-09-22 15:07:15 +01001090}
1091
1092
1093MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1094 Slot* slot,
1095 Label* slow) {
1096 ASSERT(slot->type() == Slot::CONTEXT);
1097 Register context = esi;
1098 Register temp = ebx;
1099
1100 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1101 if (s->num_heap_slots() > 0) {
1102 if (s->calls_eval()) {
1103 // Check that extension is NULL.
1104 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1105 Immediate(0));
1106 __ j(not_equal, slow);
1107 }
1108 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1109 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1110 // Walk the rest of the chain without clobbering esi.
1111 context = temp;
1112 }
1113 }
1114 // Check that last extension is NULL.
1115 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1116 __ j(not_equal, slow);
1117 __ mov(temp, ContextOperand(context, Context::FCONTEXT_INDEX));
1118 return ContextOperand(temp, slot->index());
1119}
1120
1121
1122void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1123 Slot* slot,
1124 TypeofState typeof_state,
1125 Label* slow,
1126 Label* done) {
1127 // Generate fast-case code for variables that might be shadowed by
1128 // eval-introduced variables. Eval is used a lot without
1129 // introducing variables. In those cases, we do not want to
1130 // perform a runtime call for all variables in the scope
1131 // containing the eval.
1132 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1133 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1134 __ jmp(done);
1135 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001136 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
Steve Block59151502010-09-22 15:07:15 +01001137 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1138 if (potential_slot != NULL) {
1139 // Generate fast case for locals that rewrite to slots.
1140 __ mov(eax,
1141 ContextSlotOperandCheckExtensions(potential_slot, slow));
1142 if (potential_slot->var()->mode() == Variable::CONST) {
1143 __ cmp(eax, Factory::the_hole_value());
1144 __ j(not_equal, done);
1145 __ mov(eax, Factory::undefined_value());
1146 }
1147 __ jmp(done);
1148 } else if (rewrite != NULL) {
1149 // Generate fast case for calls of an argument function.
1150 Property* property = rewrite->AsProperty();
1151 if (property != NULL) {
1152 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1153 Literal* key_literal = property->key()->AsLiteral();
1154 if (obj_proxy != NULL &&
1155 key_literal != NULL &&
1156 obj_proxy->IsArguments() &&
1157 key_literal->handle()->IsSmi()) {
1158 // Load arguments object if there are no eval-introduced
1159 // variables. Then load the argument from the arguments
1160 // object using keyed load.
1161 __ mov(edx,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001162 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
Steve Block59151502010-09-22 15:07:15 +01001163 slow));
1164 __ mov(eax, Immediate(key_literal->handle()));
1165 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001166 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Steve Block59151502010-09-22 15:07:15 +01001167 __ jmp(done);
1168 }
1169 }
1170 }
1171 }
1172}
1173
1174
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001175void FullCodeGenerator::EmitVariableLoad(Variable* var) {
Leon Clarked91b9f72010-01-27 17:25:45 +00001176 // Four cases: non-this global variables, lookup slots, all other
1177 // types of slots, and parameters that rewrite to explicit property
1178 // accesses on the arguments object.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001179 Slot* slot = var->AsSlot();
Leon Clarked91b9f72010-01-27 17:25:45 +00001180 Property* property = var->AsProperty();
1181
1182 if (var->is_global() && !var->is_this()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001183 Comment cmnt(masm_, "Global variable");
1184 // Use inline caching. Variable name is passed in ecx and the global
1185 // object on the stack.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001186 __ mov(eax, GlobalObjectOperand());
Leon Clarkee46be812010-01-19 14:06:41 +00001187 __ mov(ecx, var->name());
Steve Block3ce2e202009-11-05 08:53:23 +00001188 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001189 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
1190 context()->Plug(eax);
Leon Clarkeeab96aa2010-01-27 16:31:12 +00001191
Leon Clarked91b9f72010-01-27 17:25:45 +00001192 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
Steve Block59151502010-09-22 15:07:15 +01001193 Label done, slow;
1194
1195 // Generate code for loading from variables potentially shadowed
1196 // by eval-introduced variables.
1197 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1198
1199 __ bind(&slow);
Leon Clarked91b9f72010-01-27 17:25:45 +00001200 Comment cmnt(masm_, "Lookup slot");
1201 __ push(esi); // Context.
1202 __ push(Immediate(var->name()));
1203 __ CallRuntime(Runtime::kLoadContextSlot, 2);
Steve Block59151502010-09-22 15:07:15 +01001204 __ bind(&done);
1205
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001206 context()->Plug(eax);
Leon Clarked91b9f72010-01-27 17:25:45 +00001207
1208 } else if (slot != NULL) {
1209 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1210 ? "Context slot"
1211 : "Stack slot");
Leon Clarkef7060e22010-06-03 12:02:55 +01001212 if (var->mode() == Variable::CONST) {
1213 // Constants may be the hole value if they have not been initialized.
1214 // Unhole them.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001215 NearLabel done;
Leon Clarkef7060e22010-06-03 12:02:55 +01001216 MemOperand slot_operand = EmitSlotSearch(slot, eax);
1217 __ mov(eax, slot_operand);
1218 __ cmp(eax, Factory::the_hole_value());
1219 __ j(not_equal, &done);
1220 __ mov(eax, Factory::undefined_value());
1221 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001222 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001223 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001224 context()->Plug(slot);
Leon Clarkef7060e22010-06-03 12:02:55 +01001225 }
Leon Clarked91b9f72010-01-27 17:25:45 +00001226
1227 } else {
1228 Comment cmnt(masm_, "Rewritten parameter");
1229 ASSERT_NOT_NULL(property);
1230 // Rewritten parameter accesses are of the form "slot[literal]".
Steve Blockd0582a62009-12-15 09:54:21 +00001231
Leon Clarkee46be812010-01-19 14:06:41 +00001232 // Assert that the object is in a slot.
Steve Blockd0582a62009-12-15 09:54:21 +00001233 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1234 ASSERT_NOT_NULL(object_var);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001235 Slot* object_slot = object_var->AsSlot();
Steve Blockd0582a62009-12-15 09:54:21 +00001236 ASSERT_NOT_NULL(object_slot);
1237
1238 // Load the object.
Leon Clarkee46be812010-01-19 14:06:41 +00001239 MemOperand object_loc = EmitSlotSearch(object_slot, eax);
Andrei Popescu402d9372010-02-26 13:31:12 +00001240 __ mov(edx, object_loc);
Steve Blockd0582a62009-12-15 09:54:21 +00001241
Leon Clarkee46be812010-01-19 14:06:41 +00001242 // Assert that the key is a smi.
Steve Blockd0582a62009-12-15 09:54:21 +00001243 Literal* key_literal = property->key()->AsLiteral();
1244 ASSERT_NOT_NULL(key_literal);
1245 ASSERT(key_literal->handle()->IsSmi());
1246
1247 // Load the key.
Andrei Popescu402d9372010-02-26 13:31:12 +00001248 __ mov(eax, Immediate(key_literal->handle()));
Steve Blockd0582a62009-12-15 09:54:21 +00001249
Leon Clarkee46be812010-01-19 14:06:41 +00001250 // Do a keyed property load.
Steve Blockd0582a62009-12-15 09:54:21 +00001251 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001252 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1253
Leon Clarkee46be812010-01-19 14:06:41 +00001254 // Drop key and object left on the stack by IC.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001255 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001256 }
1257}
1258
1259
Leon Clarked91b9f72010-01-27 17:25:45 +00001260void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001261 Comment cmnt(masm_, "[ RegExpLiteral");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001262 NearLabel materialized;
Steve Block3ce2e202009-11-05 08:53:23 +00001263 // Registers will be used as follows:
1264 // edi = JS function.
Ben Murdochbb769b22010-08-11 14:56:33 +01001265 // ecx = literals array.
1266 // ebx = regexp literal.
1267 // eax = regexp literal clone.
Steve Block3ce2e202009-11-05 08:53:23 +00001268 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdochbb769b22010-08-11 14:56:33 +01001269 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001270 int literal_offset =
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001271 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
Ben Murdochbb769b22010-08-11 14:56:33 +01001272 __ mov(ebx, FieldOperand(ecx, literal_offset));
1273 __ cmp(ebx, Factory::undefined_value());
1274 __ j(not_equal, &materialized);
1275
Steve Block3ce2e202009-11-05 08:53:23 +00001276 // Create regexp literal using runtime function
1277 // Result will be in eax.
Ben Murdochbb769b22010-08-11 14:56:33 +01001278 __ push(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001279 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1280 __ push(Immediate(expr->pattern()));
1281 __ push(Immediate(expr->flags()));
1282 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
Ben Murdochbb769b22010-08-11 14:56:33 +01001283 __ mov(ebx, eax);
1284
1285 __ bind(&materialized);
1286 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1287 Label allocated, runtime_allocate;
1288 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1289 __ jmp(&allocated);
1290
1291 __ bind(&runtime_allocate);
1292 __ push(ebx);
1293 __ push(Immediate(Smi::FromInt(size)));
1294 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1295 __ pop(ebx);
1296
1297 __ bind(&allocated);
1298 // Copy the content into the newly allocated memory.
1299 // (Unroll copy loop once for better throughput).
1300 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1301 __ mov(edx, FieldOperand(ebx, i));
1302 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1303 __ mov(FieldOperand(eax, i), edx);
1304 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1305 }
1306 if ((size % (2 * kPointerSize)) != 0) {
1307 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1308 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1309 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001310 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00001311}
1312
1313
Leon Clarked91b9f72010-01-27 17:25:45 +00001314void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001315 Comment cmnt(masm_, "[ ObjectLiteral");
Steve Blockd0582a62009-12-15 09:54:21 +00001316 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00001317 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
Steve Blockd0582a62009-12-15 09:54:21 +00001318 __ push(Immediate(Smi::FromInt(expr->literal_index())));
Steve Blockd0582a62009-12-15 09:54:21 +00001319 __ push(Immediate(expr->constant_properties()));
Steve Block6ded16b2010-05-10 14:33:55 +01001320 __ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
Leon Clarkee46be812010-01-19 14:06:41 +00001321 if (expr->depth() > 1) {
Steve Block6ded16b2010-05-10 14:33:55 +01001322 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
Steve Block3ce2e202009-11-05 08:53:23 +00001323 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001324 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
Steve Blockd0582a62009-12-15 09:54:21 +00001325 }
1326
Leon Clarkee46be812010-01-19 14:06:41 +00001327 // If result_saved is true the result is on top of the stack. If
1328 // result_saved is false the result is in eax.
Steve Blockd0582a62009-12-15 09:54:21 +00001329 bool result_saved = false;
1330
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001331 // Mark all computed expressions that are bound to a key that
1332 // is shadowed by a later occurrence of the same key. For the
1333 // marked expressions, no store code is emitted.
1334 expr->CalculateEmitStore();
1335
Steve Blockd0582a62009-12-15 09:54:21 +00001336 for (int i = 0; i < expr->properties()->length(); i++) {
1337 ObjectLiteral::Property* property = expr->properties()->at(i);
1338 if (property->IsCompileTimeValue()) continue;
1339
1340 Literal* key = property->key();
1341 Expression* value = property->value();
1342 if (!result_saved) {
1343 __ push(eax); // Save result on the stack
1344 result_saved = true;
1345 }
1346 switch (property->kind()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001347 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
Steve Blockd0582a62009-12-15 09:54:21 +00001348 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
Leon Clarkee46be812010-01-19 14:06:41 +00001349 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001350 case ObjectLiteral::Property::COMPUTED:
1351 if (key->handle()->IsSymbol()) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001352 if (property->emit_store()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001353 VisitForAccumulatorValue(value);
1354 __ mov(ecx, Immediate(key->handle()));
1355 __ mov(edx, Operand(esp, 0));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001356 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1357 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001358 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1359 } else {
1360 VisitForEffect(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001361 }
Steve Blockd0582a62009-12-15 09:54:21 +00001362 break;
1363 }
Leon Clarkee46be812010-01-19 14:06:41 +00001364 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001365 case ObjectLiteral::Property::PROTOTYPE:
Leon Clarkee46be812010-01-19 14:06:41 +00001366 __ push(Operand(esp, 0)); // Duplicate receiver.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001367 VisitForStackValue(key);
1368 VisitForStackValue(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001369 if (property->emit_store()) {
1370 __ CallRuntime(Runtime::kSetProperty, 3);
1371 } else {
1372 __ Drop(3);
1373 }
Steve Blockd0582a62009-12-15 09:54:21 +00001374 break;
Leon Clarkee46be812010-01-19 14:06:41 +00001375 case ObjectLiteral::Property::SETTER:
Steve Blockd0582a62009-12-15 09:54:21 +00001376 case ObjectLiteral::Property::GETTER:
Leon Clarkee46be812010-01-19 14:06:41 +00001377 __ push(Operand(esp, 0)); // Duplicate receiver.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001378 VisitForStackValue(key);
Steve Blockd0582a62009-12-15 09:54:21 +00001379 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
1380 Smi::FromInt(1) :
1381 Smi::FromInt(0)));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001382 VisitForStackValue(value);
Steve Blockd0582a62009-12-15 09:54:21 +00001383 __ CallRuntime(Runtime::kDefineAccessor, 4);
Steve Blockd0582a62009-12-15 09:54:21 +00001384 break;
1385 default: UNREACHABLE();
1386 }
1387 }
Leon Clarkee46be812010-01-19 14:06:41 +00001388
1389 if (result_saved) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001390 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001391 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001392 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001393 }
1394}
1395
1396
Leon Clarked91b9f72010-01-27 17:25:45 +00001397void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001398 Comment cmnt(masm_, "[ ArrayLiteral");
Leon Clarkef7060e22010-06-03 12:02:55 +01001399
1400 ZoneList<Expression*>* subexprs = expr->values();
1401 int length = subexprs->length();
1402
Steve Block3ce2e202009-11-05 08:53:23 +00001403 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00001404 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001405 __ push(Immediate(Smi::FromInt(expr->literal_index())));
Leon Clarkee46be812010-01-19 14:06:41 +00001406 __ push(Immediate(expr->constant_elements()));
Iain Merrick75681382010-08-19 15:07:18 +01001407 if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001408 ASSERT(expr->depth() == 1);
Iain Merrick75681382010-08-19 15:07:18 +01001409 FastCloneShallowArrayStub stub(
1410 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1411 __ CallStub(&stub);
1412 __ IncrementCounter(&Counters::cow_arrays_created_stub, 1);
1413 } else if (expr->depth() > 1) {
Leon Clarkee46be812010-01-19 14:06:41 +00001414 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
Iain Merrick75681382010-08-19 15:07:18 +01001415 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
Leon Clarkee46be812010-01-19 14:06:41 +00001416 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01001417 } else {
Iain Merrick75681382010-08-19 15:07:18 +01001418 FastCloneShallowArrayStub stub(
1419 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
Leon Clarkef7060e22010-06-03 12:02:55 +01001420 __ CallStub(&stub);
Steve Block3ce2e202009-11-05 08:53:23 +00001421 }
1422
1423 bool result_saved = false; // Is the result saved to the stack?
1424
1425 // Emit code to evaluate all the non-constant subexpressions and to store
1426 // them into the newly cloned array.
Leon Clarkef7060e22010-06-03 12:02:55 +01001427 for (int i = 0; i < length; i++) {
Steve Block3ce2e202009-11-05 08:53:23 +00001428 Expression* subexpr = subexprs->at(i);
1429 // If the subexpression is a literal or a simple materialized literal it
1430 // is already set in the cloned array.
1431 if (subexpr->AsLiteral() != NULL ||
1432 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1433 continue;
1434 }
1435
1436 if (!result_saved) {
1437 __ push(eax);
1438 result_saved = true;
1439 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001440 VisitForAccumulatorValue(subexpr);
Steve Block3ce2e202009-11-05 08:53:23 +00001441
1442 // Store the subexpression value in the array's elements.
Steve Block3ce2e202009-11-05 08:53:23 +00001443 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1444 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1445 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
Leon Clarkee46be812010-01-19 14:06:41 +00001446 __ mov(FieldOperand(ebx, offset), result_register());
Steve Block3ce2e202009-11-05 08:53:23 +00001447
1448 // Update the write barrier for the array store.
Leon Clarkee46be812010-01-19 14:06:41 +00001449 __ RecordWrite(ebx, offset, result_register(), ecx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001450
1451 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +00001452 }
1453
Leon Clarkee46be812010-01-19 14:06:41 +00001454 if (result_saved) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001455 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001456 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001457 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001458 }
1459}
1460
1461
Andrei Popescu402d9372010-02-26 13:31:12 +00001462void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1463 Comment cmnt(masm_, "[ Assignment");
Leon Clarkef7060e22010-06-03 12:02:55 +01001464 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1465 // on the left-hand side.
1466 if (!expr->target()->IsValidLeftHandSide()) {
1467 VisitForEffect(expr->target());
1468 return;
1469 }
1470
Andrei Popescu402d9372010-02-26 13:31:12 +00001471 // Left-hand side can only be a property, a global or a (parameter or local)
1472 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1473 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1474 LhsKind assign_type = VARIABLE;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001475 Property* property = expr->target()->AsProperty();
1476 if (property != NULL) {
1477 assign_type = (property->key()->IsPropertyName())
1478 ? NAMED_PROPERTY
1479 : KEYED_PROPERTY;
Andrei Popescu402d9372010-02-26 13:31:12 +00001480 }
1481
1482 // Evaluate LHS expression.
1483 switch (assign_type) {
1484 case VARIABLE:
1485 // Nothing to do here.
1486 break;
1487 case NAMED_PROPERTY:
1488 if (expr->is_compound()) {
1489 // We need the receiver both on the stack and in the accumulator.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001490 VisitForAccumulatorValue(property->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00001491 __ push(result_register());
1492 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001493 VisitForStackValue(property->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00001494 }
1495 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001496 case KEYED_PROPERTY: {
Andrei Popescu402d9372010-02-26 13:31:12 +00001497 if (expr->is_compound()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001498 if (property->is_arguments_access()) {
1499 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1500 __ push(EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx));
1501 __ mov(eax, Immediate(property->key()->AsLiteral()->handle()));
1502 } else {
1503 VisitForStackValue(property->obj());
1504 VisitForAccumulatorValue(property->key());
1505 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001506 __ mov(edx, Operand(esp, 0));
1507 __ push(eax);
1508 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001509 if (property->is_arguments_access()) {
1510 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1511 __ push(EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx));
1512 __ push(Immediate(property->key()->AsLiteral()->handle()));
1513 } else {
1514 VisitForStackValue(property->obj());
1515 VisitForStackValue(property->key());
1516 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001517 }
1518 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001519 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001520 }
1521
Andrei Popescu402d9372010-02-26 13:31:12 +00001522 if (expr->is_compound()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001523 { AccumulatorValueContext context(this);
1524 switch (assign_type) {
1525 case VARIABLE:
1526 EmitVariableLoad(expr->target()->AsVariableProxy()->var());
1527 break;
1528 case NAMED_PROPERTY:
1529 EmitNamedPropertyLoad(property);
1530 break;
1531 case KEYED_PROPERTY:
1532 EmitKeyedPropertyLoad(property);
1533 break;
1534 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001535 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001536
Ben Murdochb0fe1622011-05-05 13:52:32 +01001537 // For property compound assignments we need another deoptimization
1538 // point after the property load.
1539 if (property != NULL) {
1540 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
1541 }
1542
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001543 Token::Value op = expr->binary_op();
1544 ConstantOperand constant = ShouldInlineSmiCase(op)
1545 ? GetConstantOperand(op, expr->target(), expr->value())
1546 : kNoConstants;
1547 ASSERT(constant == kRightConstant || constant == kNoConstants);
1548 if (constant == kNoConstants) {
1549 __ push(eax); // Left operand goes on the stack.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001550 VisitForAccumulatorValue(expr->value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001551 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001552
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001553 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1554 ? OVERWRITE_RIGHT
1555 : NO_OVERWRITE;
1556 SetSourcePosition(expr->position() + 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001557 AccumulatorValueContext context(this);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001558 if (ShouldInlineSmiCase(op)) {
1559 EmitInlineSmiBinaryOp(expr,
1560 op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001561 mode,
1562 expr->target(),
1563 expr->value(),
1564 constant);
1565 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001566 EmitBinaryOp(op, mode);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001567 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001568
1569 // Deoptimization point in case the binary operation may have side effects.
1570 PrepareForBailout(expr->binary_operation(), TOS_REG);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001571 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001572 VisitForAccumulatorValue(expr->value());
Andrei Popescu402d9372010-02-26 13:31:12 +00001573 }
1574
1575 // Record source position before possible IC call.
1576 SetSourcePosition(expr->position());
1577
1578 // Store the value.
1579 switch (assign_type) {
1580 case VARIABLE:
1581 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001582 expr->op());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001583 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1584 context()->Plug(eax);
Andrei Popescu402d9372010-02-26 13:31:12 +00001585 break;
1586 case NAMED_PROPERTY:
1587 EmitNamedPropertyAssignment(expr);
1588 break;
1589 case KEYED_PROPERTY:
1590 EmitKeyedPropertyAssignment(expr);
1591 break;
1592 }
1593}
1594
1595
Leon Clarked91b9f72010-01-27 17:25:45 +00001596void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00001597 SetSourcePosition(prop->position());
1598 Literal* key = prop->key()->AsLiteral();
1599 __ mov(ecx, Immediate(key->handle()));
1600 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001601 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Leon Clarkee46be812010-01-19 14:06:41 +00001602}
1603
1604
Leon Clarked91b9f72010-01-27 17:25:45 +00001605void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00001606 SetSourcePosition(prop->position());
1607 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001608 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Leon Clarkee46be812010-01-19 14:06:41 +00001609}
1610
1611
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001612void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001613 OverwriteMode mode,
1614 bool left_is_constant_smi,
1615 Smi* value) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001616 NearLabel call_stub, done;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001617 __ add(Operand(eax), Immediate(value));
1618 __ j(overflow, &call_stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001619 JumpPatchSite patch_site(masm_);
1620 patch_site.EmitJumpIfSmi(eax, &done);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001621
1622 // Undo the optimistic add operation and call the shared stub.
1623 __ bind(&call_stub);
1624 __ sub(Operand(eax), Immediate(value));
1625 Token::Value op = Token::ADD;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001626 TypeRecordingBinaryOpStub stub(op, mode);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001627 if (left_is_constant_smi) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001628 __ mov(edx, Immediate(value));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001629 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001630 __ mov(edx, eax);
1631 __ mov(eax, Immediate(value));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001632 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001633 EmitCallIC(stub.GetCode(), &patch_site);
1634
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001635 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001636 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001637}
1638
1639
1640void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001641 OverwriteMode mode,
1642 bool left_is_constant_smi,
1643 Smi* value) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001644 NearLabel call_stub, done;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001645 if (left_is_constant_smi) {
1646 __ mov(ecx, eax);
1647 __ mov(eax, Immediate(value));
1648 __ sub(Operand(eax), ecx);
1649 } else {
1650 __ sub(Operand(eax), Immediate(value));
1651 }
1652 __ j(overflow, &call_stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001653 JumpPatchSite patch_site(masm_);
1654 patch_site.EmitJumpIfSmi(eax, &done);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001655
1656 __ bind(&call_stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001657 if (left_is_constant_smi) {
1658 __ mov(edx, Immediate(value));
1659 __ mov(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001660 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001661 __ add(Operand(eax), Immediate(value)); // Undo the subtraction.
1662 __ mov(edx, eax);
1663 __ mov(eax, Immediate(value));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001664 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001665 Token::Value op = Token::SUB;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001666 TypeRecordingBinaryOpStub stub(op, mode);
1667 EmitCallIC(stub.GetCode(), &patch_site);
1668
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001669 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001670 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001671}
1672
1673
1674void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
1675 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001676 OverwriteMode mode,
1677 Smi* value) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001678 NearLabel call_stub, smi_case, done;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001679 int shift_value = value->value() & 0x1f;
1680
Ben Murdochb0fe1622011-05-05 13:52:32 +01001681 JumpPatchSite patch_site(masm_);
1682 patch_site.EmitJumpIfSmi(eax, &smi_case);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001683
Ben Murdochb0fe1622011-05-05 13:52:32 +01001684 // Call stub.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001685 __ bind(&call_stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001686 __ mov(edx, eax);
1687 __ mov(eax, Immediate(value));
1688 TypeRecordingBinaryOpStub stub(op, mode);
1689 EmitCallIC(stub.GetCode(), &patch_site);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001690 __ jmp(&done);
1691
Ben Murdochb0fe1622011-05-05 13:52:32 +01001692 // Smi case.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001693 __ bind(&smi_case);
1694 switch (op) {
1695 case Token::SHL:
1696 if (shift_value != 0) {
1697 __ mov(edx, eax);
1698 if (shift_value > 1) {
1699 __ shl(edx, shift_value - 1);
1700 }
1701 // Convert int result to smi, checking that it is in int range.
1702 ASSERT(kSmiTagSize == 1); // Adjust code if not the case.
1703 __ add(edx, Operand(edx));
1704 __ j(overflow, &call_stub);
1705 __ mov(eax, edx); // Put result back into eax.
1706 }
1707 break;
1708 case Token::SAR:
1709 if (shift_value != 0) {
1710 __ sar(eax, shift_value);
1711 __ and_(eax, ~kSmiTagMask);
1712 }
1713 break;
1714 case Token::SHR:
1715 if (shift_value < 2) {
1716 __ mov(edx, eax);
1717 __ SmiUntag(edx);
1718 __ shr(edx, shift_value);
1719 __ test(edx, Immediate(0xc0000000));
1720 __ j(not_zero, &call_stub);
1721 __ SmiTag(edx);
1722 __ mov(eax, edx); // Put result back into eax.
1723 } else {
1724 __ SmiUntag(eax);
1725 __ shr(eax, shift_value);
1726 __ SmiTag(eax);
1727 }
1728 break;
1729 default:
1730 UNREACHABLE();
1731 }
1732
1733 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001734 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001735}
1736
1737
1738void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
1739 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001740 OverwriteMode mode,
1741 Smi* value) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001742 NearLabel smi_case, done;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001743
Ben Murdochb0fe1622011-05-05 13:52:32 +01001744 JumpPatchSite patch_site(masm_);
1745 patch_site.EmitJumpIfSmi(eax, &smi_case);
1746
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001747 // The order of the arguments does not matter for bit-ops with a
1748 // constant operand.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001749 __ mov(edx, Immediate(value));
1750 TypeRecordingBinaryOpStub stub(op, mode);
1751 EmitCallIC(stub.GetCode(), &patch_site);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001752 __ jmp(&done);
1753
Ben Murdochb0fe1622011-05-05 13:52:32 +01001754 // Smi case.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001755 __ bind(&smi_case);
1756 switch (op) {
1757 case Token::BIT_OR:
1758 __ or_(Operand(eax), Immediate(value));
1759 break;
1760 case Token::BIT_XOR:
1761 __ xor_(Operand(eax), Immediate(value));
1762 break;
1763 case Token::BIT_AND:
1764 __ and_(Operand(eax), Immediate(value));
1765 break;
1766 default:
1767 UNREACHABLE();
1768 }
1769
1770 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001771 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001772}
1773
1774
1775void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
1776 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001777 OverwriteMode mode,
1778 bool left_is_constant_smi,
1779 Smi* value) {
1780 switch (op) {
1781 case Token::BIT_OR:
1782 case Token::BIT_XOR:
1783 case Token::BIT_AND:
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001784 EmitConstantSmiBitOp(expr, op, mode, value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001785 break;
1786 case Token::SHL:
1787 case Token::SAR:
1788 case Token::SHR:
1789 ASSERT(!left_is_constant_smi);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001790 EmitConstantSmiShiftOp(expr, op, mode, value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001791 break;
1792 case Token::ADD:
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001793 EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001794 break;
1795 case Token::SUB:
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001796 EmitConstantSmiSub(expr, mode, left_is_constant_smi, value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001797 break;
1798 default:
1799 UNREACHABLE();
1800 }
1801}
1802
1803
1804void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1805 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001806 OverwriteMode mode,
1807 Expression* left,
1808 Expression* right,
1809 ConstantOperand constant) {
1810 if (constant == kRightConstant) {
1811 Smi* value = Smi::cast(*right->AsLiteral()->handle());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001812 EmitConstantSmiBinaryOp(expr, op, mode, false, value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001813 return;
1814 } else if (constant == kLeftConstant) {
1815 Smi* value = Smi::cast(*left->AsLiteral()->handle());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001816 EmitConstantSmiBinaryOp(expr, op, mode, true, value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001817 return;
1818 }
1819
1820 // Do combined smi check of the operands. Left operand is on the
1821 // stack. Right operand is in eax.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001822 NearLabel done, smi_case, stub_call;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001823 __ pop(edx);
1824 __ mov(ecx, eax);
1825 __ or_(eax, Operand(edx));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001826 JumpPatchSite patch_site(masm_);
1827 patch_site.EmitJumpIfSmi(eax, &smi_case);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001828
1829 __ bind(&stub_call);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001830 __ mov(eax, ecx);
1831 TypeRecordingBinaryOpStub stub(op, mode);
1832 EmitCallIC(stub.GetCode(), &patch_site);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001833 __ jmp(&done);
1834
Ben Murdochb0fe1622011-05-05 13:52:32 +01001835 // Smi case.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001836 __ bind(&smi_case);
1837 __ mov(eax, edx); // Copy left operand in case of a stub call.
1838
1839 switch (op) {
1840 case Token::SAR:
1841 __ SmiUntag(eax);
1842 __ SmiUntag(ecx);
1843 __ sar_cl(eax); // No checks of result necessary
1844 __ SmiTag(eax);
1845 break;
1846 case Token::SHL: {
1847 Label result_ok;
1848 __ SmiUntag(eax);
1849 __ SmiUntag(ecx);
1850 __ shl_cl(eax);
1851 // Check that the *signed* result fits in a smi.
1852 __ cmp(eax, 0xc0000000);
1853 __ j(positive, &result_ok);
1854 __ SmiTag(ecx);
1855 __ jmp(&stub_call);
1856 __ bind(&result_ok);
1857 __ SmiTag(eax);
1858 break;
1859 }
1860 case Token::SHR: {
1861 Label result_ok;
1862 __ SmiUntag(eax);
1863 __ SmiUntag(ecx);
1864 __ shr_cl(eax);
1865 __ test(eax, Immediate(0xc0000000));
1866 __ j(zero, &result_ok);
1867 __ SmiTag(ecx);
1868 __ jmp(&stub_call);
1869 __ bind(&result_ok);
1870 __ SmiTag(eax);
1871 break;
1872 }
1873 case Token::ADD:
1874 __ add(eax, Operand(ecx));
1875 __ j(overflow, &stub_call);
1876 break;
1877 case Token::SUB:
1878 __ sub(eax, Operand(ecx));
1879 __ j(overflow, &stub_call);
1880 break;
1881 case Token::MUL: {
1882 __ SmiUntag(eax);
1883 __ imul(eax, Operand(ecx));
1884 __ j(overflow, &stub_call);
1885 __ test(eax, Operand(eax));
1886 __ j(not_zero, &done, taken);
1887 __ mov(ebx, edx);
1888 __ or_(ebx, Operand(ecx));
1889 __ j(negative, &stub_call);
1890 break;
1891 }
1892 case Token::BIT_OR:
1893 __ or_(eax, Operand(ecx));
1894 break;
1895 case Token::BIT_AND:
1896 __ and_(eax, Operand(ecx));
1897 break;
1898 case Token::BIT_XOR:
1899 __ xor_(eax, Operand(ecx));
1900 break;
1901 default:
1902 UNREACHABLE();
1903 }
1904
1905 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001906 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001907}
1908
1909
1910void FullCodeGenerator::EmitBinaryOp(Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001911 OverwriteMode mode) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001912 __ pop(edx);
1913 TypeRecordingBinaryOpStub stub(op, mode);
1914 EmitCallIC(stub.GetCode(), NULL); // NULL signals no inlined smi code.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001915 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00001916}
1917
1918
Ben Murdochb0fe1622011-05-05 13:52:32 +01001919void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001920 // Invalid left-hand sides are rewritten to have a 'throw
1921 // ReferenceError' on the left-hand side.
1922 if (!expr->IsValidLeftHandSide()) {
1923 VisitForEffect(expr);
1924 return;
1925 }
1926
1927 // Left-hand side can only be a property, a global or a (parameter or local)
1928 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1929 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1930 LhsKind assign_type = VARIABLE;
1931 Property* prop = expr->AsProperty();
1932 if (prop != NULL) {
1933 assign_type = (prop->key()->IsPropertyName())
1934 ? NAMED_PROPERTY
1935 : KEYED_PROPERTY;
1936 }
1937
1938 switch (assign_type) {
1939 case VARIABLE: {
1940 Variable* var = expr->AsVariableProxy()->var();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001941 EffectContext context(this);
1942 EmitVariableAssignment(var, Token::ASSIGN);
Leon Clarkef7060e22010-06-03 12:02:55 +01001943 break;
1944 }
1945 case NAMED_PROPERTY: {
1946 __ push(eax); // Preserve value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001947 VisitForAccumulatorValue(prop->obj());
Leon Clarkef7060e22010-06-03 12:02:55 +01001948 __ mov(edx, eax);
1949 __ pop(eax); // Restore value.
1950 __ mov(ecx, prop->key()->AsLiteral()->handle());
1951 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001952 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Leon Clarkef7060e22010-06-03 12:02:55 +01001953 break;
1954 }
1955 case KEYED_PROPERTY: {
1956 __ push(eax); // Preserve value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001957 VisitForStackValue(prop->obj());
1958 VisitForAccumulatorValue(prop->key());
Leon Clarkef7060e22010-06-03 12:02:55 +01001959 __ mov(ecx, eax);
1960 __ pop(edx);
1961 __ pop(eax); // Restore value.
1962 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001963 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Leon Clarkef7060e22010-06-03 12:02:55 +01001964 break;
1965 }
1966 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001967 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1968 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001969}
1970
1971
Leon Clarked91b9f72010-01-27 17:25:45 +00001972void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001973 Token::Value op) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001974 // Left-hand sides that rewrite to explicit property accesses do not reach
1975 // here.
Steve Block3ce2e202009-11-05 08:53:23 +00001976 ASSERT(var != NULL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001977 ASSERT(var->is_global() || var->AsSlot() != NULL);
Leon Clarked91b9f72010-01-27 17:25:45 +00001978
Steve Block3ce2e202009-11-05 08:53:23 +00001979 if (var->is_global()) {
Leon Clarked91b9f72010-01-27 17:25:45 +00001980 ASSERT(!var->is_this());
Steve Blockd0582a62009-12-15 09:54:21 +00001981 // Assignment to a global variable. Use inline caching for the
1982 // assignment. Right-hand-side value is passed in eax, variable name in
1983 // ecx, and the global object on the stack.
Steve Block3ce2e202009-11-05 08:53:23 +00001984 __ mov(ecx, var->name());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001985 __ mov(edx, GlobalObjectOperand());
Steve Block3ce2e202009-11-05 08:53:23 +00001986 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001987 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Steve Block3ce2e202009-11-05 08:53:23 +00001988
Leon Clarkef7060e22010-06-03 12:02:55 +01001989 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
1990 // Perform the assignment for non-const variables and for initialization
1991 // of const variables. Const assignments are simply skipped.
1992 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001993 Slot* slot = var->AsSlot();
Steve Blockd0582a62009-12-15 09:54:21 +00001994 switch (slot->type()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001995 case Slot::PARAMETER:
Leon Clarkef7060e22010-06-03 12:02:55 +01001996 case Slot::LOCAL:
1997 if (op == Token::INIT_CONST) {
1998 // Detect const reinitialization by checking for the hole value.
1999 __ mov(edx, Operand(ebp, SlotOffset(slot)));
2000 __ cmp(edx, Factory::the_hole_value());
2001 __ j(not_equal, &done);
2002 }
2003 // Perform the assignment.
2004 __ mov(Operand(ebp, SlotOffset(slot)), eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002005 break;
Steve Blockd0582a62009-12-15 09:54:21 +00002006
2007 case Slot::CONTEXT: {
Leon Clarkee46be812010-01-19 14:06:41 +00002008 MemOperand target = EmitSlotSearch(slot, ecx);
Leon Clarkef7060e22010-06-03 12:02:55 +01002009 if (op == Token::INIT_CONST) {
2010 // Detect const reinitialization by checking for the hole value.
2011 __ mov(edx, target);
2012 __ cmp(edx, Factory::the_hole_value());
2013 __ j(not_equal, &done);
2014 }
2015 // Perform the assignment and issue the write barrier.
2016 __ mov(target, eax);
2017 // The value of the assignment is in eax. RecordWrite clobbers its
2018 // register arguments.
2019 __ mov(edx, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002020 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
Leon Clarkee46be812010-01-19 14:06:41 +00002021 __ RecordWrite(ecx, offset, edx, ebx);
Steve Blockd0582a62009-12-15 09:54:21 +00002022 break;
Steve Block3ce2e202009-11-05 08:53:23 +00002023 }
Steve Blockd0582a62009-12-15 09:54:21 +00002024
2025 case Slot::LOOKUP:
Leon Clarkef7060e22010-06-03 12:02:55 +01002026 // Call the runtime for the assignment. The runtime will ignore
2027 // const reinitialization.
2028 __ push(eax); // Value.
2029 __ push(esi); // Context.
2030 __ push(Immediate(var->name()));
2031 if (op == Token::INIT_CONST) {
2032 // The runtime will ignore const redeclaration.
2033 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
2034 } else {
2035 __ CallRuntime(Runtime::kStoreContextSlot, 3);
2036 }
Steve Blockd0582a62009-12-15 09:54:21 +00002037 break;
Steve Block3ce2e202009-11-05 08:53:23 +00002038 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002039 __ bind(&done);
Steve Block3ce2e202009-11-05 08:53:23 +00002040 }
2041}
2042
2043
Leon Clarked91b9f72010-01-27 17:25:45 +00002044void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002045 // Assignment to a property, using a named store IC.
2046 Property* prop = expr->target()->AsProperty();
2047 ASSERT(prop != NULL);
2048 ASSERT(prop->key()->AsLiteral() != NULL);
Steve Block3ce2e202009-11-05 08:53:23 +00002049
Steve Blockd0582a62009-12-15 09:54:21 +00002050 // If the assignment starts a block of assignments to the same object,
2051 // change to slow case to avoid the quadratic behavior of repeatedly
2052 // adding fast properties.
2053 if (expr->starts_initialization_block()) {
Leon Clarkee46be812010-01-19 14:06:41 +00002054 __ push(result_register());
2055 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
Steve Blockd0582a62009-12-15 09:54:21 +00002056 __ CallRuntime(Runtime::kToSlowProperties, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00002057 __ pop(result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00002058 }
2059
Leon Clarkee46be812010-01-19 14:06:41 +00002060 // Record source code position before IC call.
2061 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00002062 __ mov(ecx, prop->key()->AsLiteral()->handle());
Leon Clarke4515c472010-02-03 11:58:03 +00002063 if (expr->ends_initialization_block()) {
2064 __ mov(edx, Operand(esp, 0));
2065 } else {
2066 __ pop(edx);
2067 }
Steve Blockd0582a62009-12-15 09:54:21 +00002068 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002069 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Steve Blockd0582a62009-12-15 09:54:21 +00002070
2071 // If the assignment ends an initialization block, revert to fast case.
2072 if (expr->ends_initialization_block()) {
2073 __ push(eax); // Result of assignment, saved even if not needed.
2074 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
2075 __ CallRuntime(Runtime::kToFastProperties, 1);
2076 __ pop(eax);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002077 __ Drop(1);
Steve Blockd0582a62009-12-15 09:54:21 +00002078 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002079 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2080 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002081}
2082
2083
Leon Clarked91b9f72010-01-27 17:25:45 +00002084void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002085 // Assignment to a property, using a keyed store IC.
2086
2087 // If the assignment starts a block of assignments to the same object,
2088 // change to slow case to avoid the quadratic behavior of repeatedly
2089 // adding fast properties.
2090 if (expr->starts_initialization_block()) {
Leon Clarkee46be812010-01-19 14:06:41 +00002091 __ push(result_register());
2092 // Receiver is now under the key and value.
Steve Blockd0582a62009-12-15 09:54:21 +00002093 __ push(Operand(esp, 2 * kPointerSize));
2094 __ CallRuntime(Runtime::kToSlowProperties, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00002095 __ pop(result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00002096 }
2097
Steve Block6ded16b2010-05-10 14:33:55 +01002098 __ pop(ecx);
2099 if (expr->ends_initialization_block()) {
2100 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
2101 } else {
2102 __ pop(edx);
2103 }
Leon Clarkee46be812010-01-19 14:06:41 +00002104 // Record source code position before IC call.
2105 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00002106 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002107 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Steve Blockd0582a62009-12-15 09:54:21 +00002108
2109 // If the assignment ends an initialization block, revert to fast case.
2110 if (expr->ends_initialization_block()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002111 __ pop(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00002112 __ push(eax); // Result of assignment, saved even if not needed.
Steve Block6ded16b2010-05-10 14:33:55 +01002113 __ push(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00002114 __ CallRuntime(Runtime::kToFastProperties, 1);
2115 __ pop(eax);
2116 }
2117
Ben Murdochb0fe1622011-05-05 13:52:32 +01002118 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002119 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002120}
2121
2122
Leon Clarked91b9f72010-01-27 17:25:45 +00002123void FullCodeGenerator::VisitProperty(Property* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002124 Comment cmnt(masm_, "[ Property");
2125 Expression* key = expr->key();
Steve Blockd0582a62009-12-15 09:54:21 +00002126
Leon Clarkee46be812010-01-19 14:06:41 +00002127 if (key->IsPropertyName()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002128 VisitForAccumulatorValue(expr->obj());
Leon Clarkee46be812010-01-19 14:06:41 +00002129 EmitNamedPropertyLoad(expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002130 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002131 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002132 VisitForStackValue(expr->obj());
2133 VisitForAccumulatorValue(expr->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00002134 __ pop(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00002135 EmitKeyedPropertyLoad(expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002136 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002137 }
Steve Blockd0582a62009-12-15 09:54:21 +00002138}
2139
2140
Leon Clarked91b9f72010-01-27 17:25:45 +00002141void FullCodeGenerator::EmitCallWithIC(Call* expr,
Leon Clarkee46be812010-01-19 14:06:41 +00002142 Handle<Object> name,
2143 RelocInfo::Mode mode) {
Steve Blockd0582a62009-12-15 09:54:21 +00002144 // Code common for calls using the IC.
2145 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00002146 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002147 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002148 for (int i = 0; i < arg_count; i++) {
2149 VisitForStackValue(args->at(i));
2150 }
2151 __ Set(ecx, Immediate(name));
Steve Block3ce2e202009-11-05 08:53:23 +00002152 }
Leon Clarkee46be812010-01-19 14:06:41 +00002153 // Record source position of the IC call.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002154 SetSourcePosition(expr->position());
Leon Clarkee46be812010-01-19 14:06:41 +00002155 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002156 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002157 EmitCallIC(ic, mode);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002158 RecordJSReturnSite(expr);
Steve Block3ce2e202009-11-05 08:53:23 +00002159 // Restore context register.
2160 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002161 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002162}
2163
2164
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002165void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
2166 Expression* key,
2167 RelocInfo::Mode mode) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002168 // Load the key.
2169 VisitForAccumulatorValue(key);
2170
2171 // Swap the name of the function and the receiver on the stack to follow
2172 // the calling convention for call ICs.
2173 __ pop(ecx);
2174 __ push(eax);
2175 __ push(ecx);
2176
2177 // Load the arguments.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002178 ZoneList<Expression*>* args = expr->arguments();
2179 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002180 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002181 for (int i = 0; i < arg_count; i++) {
2182 VisitForStackValue(args->at(i));
2183 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002184 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002185 // Record source position of the IC call.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002186 SetSourcePosition(expr->position());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002187 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002188 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
2189 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002190 EmitCallIC(ic, mode);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002191 RecordJSReturnSite(expr);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002192 // Restore context register.
2193 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002194 context()->DropAndPlug(1, eax); // Drop the key still on the stack.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002195}
2196
2197
Leon Clarked91b9f72010-01-27 17:25:45 +00002198void FullCodeGenerator::EmitCallWithStub(Call* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002199 // Code common for calls using the call stub.
2200 ZoneList<Expression*>* args = expr->arguments();
2201 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002202 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002203 for (int i = 0; i < arg_count; i++) {
2204 VisitForStackValue(args->at(i));
2205 }
Steve Block3ce2e202009-11-05 08:53:23 +00002206 }
Steve Blockd0582a62009-12-15 09:54:21 +00002207 // Record source position for debugger.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002208 SetSourcePosition(expr->position());
Leon Clarkef7060e22010-06-03 12:02:55 +01002209 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2210 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
Steve Blockd0582a62009-12-15 09:54:21 +00002211 __ CallStub(&stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002212 RecordJSReturnSite(expr);
Steve Blockd0582a62009-12-15 09:54:21 +00002213 // Restore context register.
2214 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002215 context()->DropAndPlug(1, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002216}
2217
2218
Leon Clarked91b9f72010-01-27 17:25:45 +00002219void FullCodeGenerator::VisitCall(Call* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002220#ifdef DEBUG
2221 // We want to verify that RecordJSReturnSite gets called on all paths
2222 // through this function. Avoid early returns.
2223 expr->return_is_recorded_ = false;
2224#endif
2225
Steve Blockd0582a62009-12-15 09:54:21 +00002226 Comment cmnt(masm_, "[ Call");
2227 Expression* fun = expr->expression();
2228 Variable* var = fun->AsVariableProxy()->AsVariable();
2229
2230 if (var != NULL && var->is_possibly_eval()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002231 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2232 // resolve the function we need to call and the receiver of the
2233 // call. Then we call the resolved function using the given
2234 // arguments.
Leon Clarkef7060e22010-06-03 12:02:55 +01002235 ZoneList<Expression*>* args = expr->arguments();
2236 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002237 { PreservePositionScope pos_scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002238 VisitForStackValue(fun);
2239 // Reserved receiver slot.
Leon Clarkef7060e22010-06-03 12:02:55 +01002240 __ push(Immediate(Factory::undefined_value()));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002241
2242 // Push the arguments.
2243 for (int i = 0; i < arg_count; i++) {
2244 VisitForStackValue(args->at(i));
2245 }
2246
2247 // Push copy of the function - found below the arguments.
2248 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2249
2250 // Push copy of the first argument or undefined if it doesn't exist.
2251 if (arg_count > 0) {
2252 __ push(Operand(esp, arg_count * kPointerSize));
2253 } else {
2254 __ push(Immediate(Factory::undefined_value()));
2255 }
2256
2257 // Push the receiver of the enclosing function and do runtime call.
2258 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
2259 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
2260
2261 // The runtime call returns a pair of values in eax (function) and
2262 // edx (receiver). Touch up the stack with the right values.
2263 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2264 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002265 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002266 // Record source position for debugger.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002267 SetSourcePosition(expr->position());
Leon Clarkef7060e22010-06-03 12:02:55 +01002268 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2269 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
2270 __ CallStub(&stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002271 RecordJSReturnSite(expr);
Leon Clarkef7060e22010-06-03 12:02:55 +01002272 // Restore context register.
2273 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002274 context()->DropAndPlug(1, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002275 } else if (var != NULL && !var->is_this() && var->is_global()) {
Leon Clarkee46be812010-01-19 14:06:41 +00002276 // Push global object as receiver for the call IC.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002277 __ push(GlobalObjectOperand());
Leon Clarkee46be812010-01-19 14:06:41 +00002278 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002279 } else if (var != NULL && var->AsSlot() != NULL &&
2280 var->AsSlot()->type() == Slot::LOOKUP) {
Steve Block59151502010-09-22 15:07:15 +01002281 // Call to a lookup slot (dynamically introduced variable).
2282 Label slow, done;
2283
Ben Murdochb0fe1622011-05-05 13:52:32 +01002284 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002285 // Generate code for loading from variables potentially shadowed
2286 // by eval-introduced variables.
2287 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
2288 NOT_INSIDE_TYPEOF,
2289 &slow,
2290 &done);
2291 }
Steve Block59151502010-09-22 15:07:15 +01002292
2293 __ bind(&slow);
2294 // Call the runtime to find the function to call (returned in eax)
2295 // and the object holding it (returned in edx).
Leon Clarkef7060e22010-06-03 12:02:55 +01002296 __ push(context_register());
2297 __ push(Immediate(var->name()));
2298 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2299 __ push(eax); // Function.
2300 __ push(edx); // Receiver.
Steve Block59151502010-09-22 15:07:15 +01002301
2302 // If fast case code has been generated, emit code to push the
2303 // function and receiver and have the slow path jump around this
2304 // code.
2305 if (done.is_linked()) {
2306 Label call;
2307 __ jmp(&call);
2308 __ bind(&done);
2309 // Push function.
2310 __ push(eax);
2311 // Push global receiver.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002312 __ mov(ebx, GlobalObjectOperand());
Steve Block59151502010-09-22 15:07:15 +01002313 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2314 __ bind(&call);
2315 }
2316
Leon Clarkef7060e22010-06-03 12:02:55 +01002317 EmitCallWithStub(expr);
Steve Blockd0582a62009-12-15 09:54:21 +00002318 } else if (fun->AsProperty() != NULL) {
2319 // Call to an object property.
2320 Property* prop = fun->AsProperty();
2321 Literal* key = prop->key()->AsLiteral();
2322 if (key != NULL && key->handle()->IsSymbol()) {
2323 // Call to a named property, use call IC.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002324 VisitForStackValue(prop->obj());
Leon Clarkee46be812010-01-19 14:06:41 +00002325 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
Steve Blockd0582a62009-12-15 09:54:21 +00002326 } else {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002327 // Call to a keyed property.
2328 // For a synthetic property use keyed load IC followed by function call,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002329 // for a regular property use keyed EmitCallIC.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002330 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002331 VisitForStackValue(prop->obj());
2332 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002333 if (prop->is_synthetic()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002334 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002335 VisitForAccumulatorValue(prop->key());
2336 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002337 // Record source code position for IC call.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002338 SetSourcePosition(prop->position());
Andrei Popescu402d9372010-02-26 13:31:12 +00002339 __ pop(edx); // We do not need to keep the receiver.
Andrei Popescu402d9372010-02-26 13:31:12 +00002340
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002341 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002342 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Andrei Popescu402d9372010-02-26 13:31:12 +00002343 // Push result (function).
2344 __ push(eax);
2345 // Push Global receiver.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002346 __ mov(ecx, GlobalObjectOperand());
Leon Clarkee46be812010-01-19 14:06:41 +00002347 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002348 EmitCallWithStub(expr);
Steve Blockd0582a62009-12-15 09:54:21 +00002349 } else {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002350 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
Steve Blockd0582a62009-12-15 09:54:21 +00002351 }
Steve Blockd0582a62009-12-15 09:54:21 +00002352 }
2353 } else {
2354 // Call to some other expression. If the expression is an anonymous
2355 // function literal not called in a loop, mark it as one that should
Leon Clarked91b9f72010-01-27 17:25:45 +00002356 // also use the full code generator.
Steve Blockd0582a62009-12-15 09:54:21 +00002357 FunctionLiteral* lit = fun->AsFunctionLiteral();
2358 if (lit != NULL &&
2359 lit->name()->Equals(Heap::empty_string()) &&
2360 loop_depth() == 0) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002361 lit->set_try_full_codegen(true);
Steve Blockd0582a62009-12-15 09:54:21 +00002362 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002363 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002364 VisitForStackValue(fun);
2365 }
Steve Blockd0582a62009-12-15 09:54:21 +00002366 // Load global receiver object.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002367 __ mov(ebx, GlobalObjectOperand());
Steve Blockd0582a62009-12-15 09:54:21 +00002368 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2369 // Emit function call.
2370 EmitCallWithStub(expr);
2371 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002372
2373#ifdef DEBUG
2374 // RecordJSReturnSite should have been called.
2375 ASSERT(expr->return_is_recorded_);
2376#endif
Steve Blockd0582a62009-12-15 09:54:21 +00002377}
2378
2379
Leon Clarked91b9f72010-01-27 17:25:45 +00002380void FullCodeGenerator::VisitCallNew(CallNew* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002381 Comment cmnt(masm_, "[ CallNew");
2382 // According to ECMA-262, section 11.2.2, page 44, the function
2383 // expression in new calls must be evaluated before the
2384 // arguments.
Steve Blockd0582a62009-12-15 09:54:21 +00002385
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002386 // Push constructor on the stack. If it's not a function it's used as
2387 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2388 // ignored.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002389 VisitForStackValue(expr->expression());
Steve Blockd0582a62009-12-15 09:54:21 +00002390
2391 // Push the arguments ("left-to-right") on the stack.
2392 ZoneList<Expression*>* args = expr->arguments();
2393 int arg_count = args->length();
2394 for (int i = 0; i < arg_count; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002395 VisitForStackValue(args->at(i));
Steve Blockd0582a62009-12-15 09:54:21 +00002396 }
2397
2398 // Call the construct call builtin that handles allocation and
2399 // constructor invocation.
2400 SetSourcePosition(expr->position());
2401
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002402 // Load function and argument count into edi and eax.
Steve Blockd0582a62009-12-15 09:54:21 +00002403 __ Set(eax, Immediate(arg_count));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002404 __ mov(edi, Operand(esp, arg_count * kPointerSize));
Steve Blockd0582a62009-12-15 09:54:21 +00002405
2406 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
2407 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002408 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00002409}
2410
2411
Leon Clarkef7060e22010-06-03 12:02:55 +01002412void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2413 ASSERT(args->length() == 1);
2414
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002415 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002416
2417 Label materialize_true, materialize_false;
2418 Label* if_true = NULL;
2419 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002420 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002421 context()->PrepareTest(&materialize_true, &materialize_false,
2422 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002423
Ben Murdochb0fe1622011-05-05 13:52:32 +01002424 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002425 __ test(eax, Immediate(kSmiTagMask));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002426 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002427
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002428 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002429}
2430
2431
2432void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2433 ASSERT(args->length() == 1);
2434
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002435 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002436
2437 Label materialize_true, materialize_false;
2438 Label* if_true = NULL;
2439 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002440 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002441 context()->PrepareTest(&materialize_true, &materialize_false,
2442 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002443
Ben Murdochb0fe1622011-05-05 13:52:32 +01002444 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002445 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002446 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002447
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002448 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002449}
2450
2451
2452void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2453 ASSERT(args->length() == 1);
2454
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002455 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002456
2457 Label materialize_true, materialize_false;
2458 Label* if_true = NULL;
2459 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002460 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002461 context()->PrepareTest(&materialize_true, &materialize_false,
2462 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002463
2464 __ test(eax, Immediate(kSmiTagMask));
2465 __ j(zero, if_false);
2466 __ cmp(eax, Factory::null_value());
2467 __ j(equal, if_true);
2468 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2469 // Undetectable objects behave like undefined when tested with typeof.
2470 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2471 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2472 __ j(not_zero, if_false);
2473 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2474 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
2475 __ j(below, if_false);
2476 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002477 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002478 Split(below_equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002479
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002480 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002481}
2482
2483
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002484void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2485 ASSERT(args->length() == 1);
2486
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002487 VisitForAccumulatorValue(args->at(0));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002488
2489 Label materialize_true, materialize_false;
2490 Label* if_true = NULL;
2491 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002492 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002493 context()->PrepareTest(&materialize_true, &materialize_false,
2494 &if_true, &if_false, &fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002495
2496 __ test(eax, Immediate(kSmiTagMask));
2497 __ j(equal, if_false);
2498 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002499 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002500 Split(above_equal, if_true, if_false, fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002501
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002502 context()->Plug(if_true, if_false);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002503}
2504
2505
Leon Clarkef7060e22010-06-03 12:02:55 +01002506void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2507 ASSERT(args->length() == 1);
2508
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002509 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002510
2511 Label materialize_true, materialize_false;
2512 Label* if_true = NULL;
2513 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002514 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002515 context()->PrepareTest(&materialize_true, &materialize_false,
2516 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002517
2518 __ test(eax, Immediate(kSmiTagMask));
2519 __ j(zero, if_false);
2520 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2521 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2522 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002523 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002524 Split(not_zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002525
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002526 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002527}
2528
2529
Iain Merrick75681382010-08-19 15:07:18 +01002530void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2531 ZoneList<Expression*>* args) {
2532 ASSERT(args->length() == 1);
2533
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002534 VisitForAccumulatorValue(args->at(0));
Iain Merrick75681382010-08-19 15:07:18 +01002535
2536 Label materialize_true, materialize_false;
2537 Label* if_true = NULL;
2538 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002539 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002540 context()->PrepareTest(&materialize_true, &materialize_false,
2541 &if_true, &if_false, &fall_through);
Iain Merrick75681382010-08-19 15:07:18 +01002542
Ben Murdochb0fe1622011-05-05 13:52:32 +01002543 // TODO(3110205): Implement this.
2544 // Currently unimplemented. Emit false, a safe choice.
2545 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Iain Merrick75681382010-08-19 15:07:18 +01002546 __ jmp(if_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002547 context()->Plug(if_true, if_false);
Iain Merrick75681382010-08-19 15:07:18 +01002548}
2549
2550
Leon Clarkef7060e22010-06-03 12:02:55 +01002551void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2552 ASSERT(args->length() == 1);
2553
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002554 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002555
2556 Label materialize_true, materialize_false;
2557 Label* if_true = NULL;
2558 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002559 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002560 context()->PrepareTest(&materialize_true, &materialize_false,
2561 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002562
2563 __ test(eax, Immediate(kSmiTagMask));
2564 __ j(zero, if_false);
2565 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002566 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002567 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002568
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002569 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002570}
2571
2572
2573void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2574 ASSERT(args->length() == 1);
2575
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002576 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002577
2578 Label materialize_true, materialize_false;
2579 Label* if_true = NULL;
2580 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002581 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002582 context()->PrepareTest(&materialize_true, &materialize_false,
2583 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002584
2585 __ test(eax, Immediate(kSmiTagMask));
2586 __ j(equal, if_false);
2587 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002588 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002589 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002590
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002591 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002592}
2593
2594
2595void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2596 ASSERT(args->length() == 1);
2597
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002598 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002599
2600 Label materialize_true, materialize_false;
2601 Label* if_true = NULL;
2602 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002603 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002604 context()->PrepareTest(&materialize_true, &materialize_false,
2605 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002606
2607 __ test(eax, Immediate(kSmiTagMask));
2608 __ j(equal, if_false);
2609 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002610 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002611 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002612
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002613 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002614}
2615
2616
2617
2618void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2619 ASSERT(args->length() == 0);
2620
2621 Label materialize_true, materialize_false;
2622 Label* if_true = NULL;
2623 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002624 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002625 context()->PrepareTest(&materialize_true, &materialize_false,
2626 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002627
2628 // Get the frame pointer for the calling frame.
2629 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2630
2631 // Skip the arguments adaptor frame if it exists.
2632 Label check_frame_marker;
2633 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2634 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2635 __ j(not_equal, &check_frame_marker);
2636 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2637
2638 // Check the marker in the calling frame.
2639 __ bind(&check_frame_marker);
2640 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2641 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002642 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002643 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002644
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002645 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002646}
2647
2648
2649void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2650 ASSERT(args->length() == 2);
2651
2652 // Load the two objects into registers and perform the comparison.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002653 VisitForStackValue(args->at(0));
2654 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01002655
2656 Label materialize_true, materialize_false;
2657 Label* if_true = NULL;
2658 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002659 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002660 context()->PrepareTest(&materialize_true, &materialize_false,
2661 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002662
2663 __ pop(ebx);
2664 __ cmp(eax, Operand(ebx));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002665 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002666 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002667
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002668 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01002669}
2670
2671
2672void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2673 ASSERT(args->length() == 1);
2674
2675 // ArgumentsAccessStub expects the key in edx and the formal
2676 // parameter count in eax.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002677 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002678 __ mov(edx, eax);
2679 __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2680 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2681 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002682 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002683}
2684
2685
2686void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2687 ASSERT(args->length() == 0);
2688
2689 Label exit;
2690 // Get the number of formal parameters.
2691 __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2692
2693 // Check if the calling frame is an arguments adaptor frame.
2694 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2695 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2696 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2697 __ j(not_equal, &exit);
2698
2699 // Arguments adaptor case: Read the arguments length from the
2700 // adaptor frame.
2701 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2702
2703 __ bind(&exit);
2704 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002705 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002706}
2707
2708
2709void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2710 ASSERT(args->length() == 1);
2711 Label done, null, function, non_function_constructor;
2712
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002713 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002714
2715 // If the object is a smi, we return null.
2716 __ test(eax, Immediate(kSmiTagMask));
2717 __ j(zero, &null);
2718
2719 // Check that the object is a JS object but take special care of JS
2720 // functions to make sure they have 'Function' as their class.
2721 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, eax); // Map is now in eax.
2722 __ j(below, &null);
2723
2724 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2725 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2726 // LAST_JS_OBJECT_TYPE.
2727 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2728 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
Steve Block8defd9f2010-07-08 12:39:36 +01002729 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
Leon Clarkef7060e22010-06-03 12:02:55 +01002730 __ j(equal, &function);
2731
2732 // Check if the constructor in the map is a function.
2733 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2734 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2735 __ j(not_equal, &non_function_constructor);
2736
2737 // eax now contains the constructor function. Grab the
2738 // instance class name from there.
2739 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2740 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2741 __ jmp(&done);
2742
2743 // Functions have class 'Function'.
2744 __ bind(&function);
2745 __ mov(eax, Factory::function_class_symbol());
2746 __ jmp(&done);
2747
2748 // Objects with a non-function constructor have class 'Object'.
2749 __ bind(&non_function_constructor);
2750 __ mov(eax, Factory::Object_symbol());
2751 __ jmp(&done);
2752
2753 // Non-JS objects have class null.
2754 __ bind(&null);
2755 __ mov(eax, Factory::null_value());
2756
2757 // All done.
2758 __ bind(&done);
2759
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002760 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002761}
2762
2763
2764void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2765 // Conditionally generate a log call.
2766 // Args:
2767 // 0 (literal string): The type of logging (corresponds to the flags).
2768 // This is used to determine whether or not to generate the log call.
2769 // 1 (string): Format string. Access the string at argument index 2
2770 // with '%2s' (see Logger::LogRuntime for all the formats).
2771 // 2 (array): Arguments to the format string.
2772 ASSERT_EQ(args->length(), 3);
2773#ifdef ENABLE_LOGGING_AND_PROFILING
2774 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002775 VisitForStackValue(args->at(1));
2776 VisitForStackValue(args->at(2));
Leon Clarkef7060e22010-06-03 12:02:55 +01002777 __ CallRuntime(Runtime::kLog, 2);
2778 }
2779#endif
2780 // Finally, we're expected to leave a value on the top of the stack.
2781 __ mov(eax, Factory::undefined_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002782 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002783}
2784
2785
2786void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2787 ASSERT(args->length() == 0);
2788
2789 Label slow_allocate_heapnumber;
2790 Label heapnumber_allocated;
2791
2792 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2793 __ jmp(&heapnumber_allocated);
2794
2795 __ bind(&slow_allocate_heapnumber);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002796 // Allocate a heap number.
2797 __ CallRuntime(Runtime::kNumberAlloc, 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002798 __ mov(edi, eax);
2799
2800 __ bind(&heapnumber_allocated);
2801
2802 __ PrepareCallCFunction(0, ebx);
2803 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2804
2805 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2806 // by computing:
2807 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2808 // This is implemented on both SSE2 and FPU.
2809 if (CpuFeatures::IsSupported(SSE2)) {
2810 CpuFeatures::Scope fscope(SSE2);
2811 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2812 __ movd(xmm1, Operand(ebx));
2813 __ movd(xmm0, Operand(eax));
2814 __ cvtss2sd(xmm1, xmm1);
2815 __ pxor(xmm0, xmm1);
2816 __ subsd(xmm0, xmm1);
2817 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2818 } else {
2819 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2820 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2821 Immediate(0x41300000));
2822 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2823 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2824 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2825 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2826 __ fsubp(1);
2827 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2828 }
2829 __ mov(eax, edi);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002830 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002831}
2832
2833
2834void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2835 // Load the arguments on the stack and call the stub.
2836 SubStringStub stub;
2837 ASSERT(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002838 VisitForStackValue(args->at(0));
2839 VisitForStackValue(args->at(1));
2840 VisitForStackValue(args->at(2));
Leon Clarkef7060e22010-06-03 12:02:55 +01002841 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002842 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002843}
2844
2845
2846void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2847 // Load the arguments on the stack and call the stub.
2848 RegExpExecStub stub;
2849 ASSERT(args->length() == 4);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002850 VisitForStackValue(args->at(0));
2851 VisitForStackValue(args->at(1));
2852 VisitForStackValue(args->at(2));
2853 VisitForStackValue(args->at(3));
Leon Clarkef7060e22010-06-03 12:02:55 +01002854 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002855 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002856}
2857
2858
2859void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2860 ASSERT(args->length() == 1);
2861
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002862 VisitForAccumulatorValue(args->at(0)); // Load the object.
Leon Clarkef7060e22010-06-03 12:02:55 +01002863
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002864 NearLabel done;
Leon Clarkef7060e22010-06-03 12:02:55 +01002865 // If the object is a smi return the object.
2866 __ test(eax, Immediate(kSmiTagMask));
2867 __ j(zero, &done);
2868 // If the object is not a value type, return the object.
2869 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
2870 __ j(not_equal, &done);
2871 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2872
2873 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002874 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002875}
2876
2877
2878void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2879 // Load the arguments on the stack and call the runtime function.
2880 ASSERT(args->length() == 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002881 VisitForStackValue(args->at(0));
2882 VisitForStackValue(args->at(1));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002883
2884 MathPowStub stub;
2885 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002886 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002887}
2888
2889
2890void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2891 ASSERT(args->length() == 2);
2892
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002893 VisitForStackValue(args->at(0)); // Load the object.
2894 VisitForAccumulatorValue(args->at(1)); // Load the value.
Leon Clarkef7060e22010-06-03 12:02:55 +01002895 __ pop(ebx); // eax = value. ebx = object.
2896
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002897 NearLabel done;
Leon Clarkef7060e22010-06-03 12:02:55 +01002898 // If the object is a smi, return the value.
2899 __ test(ebx, Immediate(kSmiTagMask));
2900 __ j(zero, &done);
2901
2902 // If the object is not a value type, return the value.
2903 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
2904 __ j(not_equal, &done);
2905
2906 // Store the value.
2907 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
2908 // Update the write barrier. Save the value as it will be
2909 // overwritten by the write barrier code and is needed afterward.
2910 __ mov(edx, eax);
2911 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
2912
2913 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002914 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002915}
2916
2917
2918void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2919 ASSERT_EQ(args->length(), 1);
2920
2921 // Load the argument on the stack and call the stub.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002922 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002923
2924 NumberToStringStub stub;
2925 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002926 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002927}
2928
2929
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002930void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002931 ASSERT(args->length() == 1);
2932
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002933 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01002934
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002935 Label done;
2936 StringCharFromCodeGenerator generator(eax, ebx);
2937 generator.GenerateFast(masm_);
Leon Clarkef7060e22010-06-03 12:02:55 +01002938 __ jmp(&done);
2939
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002940 NopRuntimeCallHelper call_helper;
2941 generator.GenerateSlow(masm_, call_helper);
Leon Clarkef7060e22010-06-03 12:02:55 +01002942
2943 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002944 context()->Plug(ebx);
Leon Clarkef7060e22010-06-03 12:02:55 +01002945}
2946
2947
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002948void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2949 ASSERT(args->length() == 2);
2950
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002951 VisitForStackValue(args->at(0));
2952 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002953
2954 Register object = ebx;
2955 Register index = eax;
2956 Register scratch = ecx;
2957 Register result = edx;
2958
2959 __ pop(object);
2960
2961 Label need_conversion;
2962 Label index_out_of_range;
2963 Label done;
2964 StringCharCodeAtGenerator generator(object,
2965 index,
2966 scratch,
2967 result,
2968 &need_conversion,
2969 &need_conversion,
2970 &index_out_of_range,
2971 STRING_INDEX_IS_NUMBER);
2972 generator.GenerateFast(masm_);
2973 __ jmp(&done);
2974
2975 __ bind(&index_out_of_range);
2976 // When the index is out of range, the spec requires us to return
2977 // NaN.
2978 __ Set(result, Immediate(Factory::nan_value()));
2979 __ jmp(&done);
2980
2981 __ bind(&need_conversion);
Leon Clarkef7060e22010-06-03 12:02:55 +01002982 // Move the undefined value into the result register, which will
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002983 // trigger conversion.
2984 __ Set(result, Immediate(Factory::undefined_value()));
2985 __ jmp(&done);
2986
2987 NopRuntimeCallHelper call_helper;
2988 generator.GenerateSlow(masm_, call_helper);
2989
2990 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002991 context()->Plug(result);
Leon Clarkef7060e22010-06-03 12:02:55 +01002992}
2993
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002994
2995void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2996 ASSERT(args->length() == 2);
2997
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002998 VisitForStackValue(args->at(0));
2999 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003000
3001 Register object = ebx;
3002 Register index = eax;
3003 Register scratch1 = ecx;
3004 Register scratch2 = edx;
3005 Register result = eax;
3006
3007 __ pop(object);
3008
3009 Label need_conversion;
3010 Label index_out_of_range;
3011 Label done;
3012 StringCharAtGenerator generator(object,
3013 index,
3014 scratch1,
3015 scratch2,
3016 result,
3017 &need_conversion,
3018 &need_conversion,
3019 &index_out_of_range,
3020 STRING_INDEX_IS_NUMBER);
3021 generator.GenerateFast(masm_);
3022 __ jmp(&done);
3023
3024 __ bind(&index_out_of_range);
3025 // When the index is out of range, the spec requires us to return
3026 // the empty string.
3027 __ Set(result, Immediate(Factory::empty_string()));
3028 __ jmp(&done);
3029
3030 __ bind(&need_conversion);
3031 // Move smi zero into the result register, which will trigger
3032 // conversion.
3033 __ Set(result, Immediate(Smi::FromInt(0)));
3034 __ jmp(&done);
3035
3036 NopRuntimeCallHelper call_helper;
3037 generator.GenerateSlow(masm_, call_helper);
3038
3039 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003040 context()->Plug(result);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003041}
3042
3043
Leon Clarkef7060e22010-06-03 12:02:55 +01003044void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
3045 ASSERT_EQ(2, args->length());
3046
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003047 VisitForStackValue(args->at(0));
3048 VisitForStackValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003049
3050 StringAddStub stub(NO_STRING_ADD_FLAGS);
3051 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003052 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003053}
3054
3055
3056void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
3057 ASSERT_EQ(2, args->length());
3058
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003059 VisitForStackValue(args->at(0));
3060 VisitForStackValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003061
3062 StringCompareStub stub;
3063 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003064 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003065}
3066
3067
3068void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
3069 // Load the argument on the stack and call the stub.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003070 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3071 TranscendentalCacheStub::TAGGED);
Leon Clarkef7060e22010-06-03 12:02:55 +01003072 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003073 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003074 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003075 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003076}
3077
3078
3079void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
3080 // Load the argument on the stack and call the stub.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003081 TranscendentalCacheStub stub(TranscendentalCache::COS,
3082 TranscendentalCacheStub::TAGGED);
3083 ASSERT(args->length() == 1);
3084 VisitForStackValue(args->at(0));
3085 __ CallStub(&stub);
3086 context()->Plug(eax);
3087}
3088
3089
3090void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3091 // Load the argument on the stack and call the stub.
3092 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3093 TranscendentalCacheStub::TAGGED);
Leon Clarkef7060e22010-06-03 12:02:55 +01003094 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003095 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003096 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003097 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003098}
3099
3100
3101void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
3102 // Load the argument on the stack and call the runtime function.
3103 ASSERT(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003104 VisitForStackValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003105 __ CallRuntime(Runtime::kMath_sqrt, 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003106 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003107}
3108
3109
3110void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
3111 ASSERT(args->length() >= 2);
3112
3113 int arg_count = args->length() - 2; // For receiver and function.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003114 VisitForStackValue(args->at(0)); // Receiver.
Leon Clarkef7060e22010-06-03 12:02:55 +01003115 for (int i = 0; i < arg_count; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003116 VisitForStackValue(args->at(i + 1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003117 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003118 VisitForAccumulatorValue(args->at(arg_count + 1)); // Function.
Leon Clarkef7060e22010-06-03 12:02:55 +01003119
3120 // InvokeFunction requires function in edi. Move it in there.
3121 if (!result_register().is(edi)) __ mov(edi, result_register());
3122 ParameterCount count(arg_count);
3123 __ InvokeFunction(edi, count, CALL_FUNCTION);
3124 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003125 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003126}
3127
3128
3129void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003130 // Load the arguments on the stack and call the stub.
3131 RegExpConstructResultStub stub;
Leon Clarkef7060e22010-06-03 12:02:55 +01003132 ASSERT(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003133 VisitForStackValue(args->at(0));
3134 VisitForStackValue(args->at(1));
3135 VisitForStackValue(args->at(2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003136 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003137 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003138}
3139
3140
3141void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
3142 ASSERT(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003143 VisitForStackValue(args->at(0));
3144 VisitForStackValue(args->at(1));
3145 VisitForStackValue(args->at(2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003146 Label done;
3147 Label slow_case;
3148 Register object = eax;
3149 Register index_1 = ebx;
3150 Register index_2 = ecx;
3151 Register elements = edi;
3152 Register temp = edx;
3153 __ mov(object, Operand(esp, 2 * kPointerSize));
3154 // Fetch the map and check if array is in fast case.
3155 // Check that object doesn't require security checks and
3156 // has no indexed interceptor.
3157 __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp);
3158 __ j(below, &slow_case);
3159 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
3160 KeyedLoadIC::kSlowCaseBitFieldMask);
3161 __ j(not_zero, &slow_case);
3162
3163 // Check the object's elements are in fast case and writable.
3164 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
3165 __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
3166 Immediate(Factory::fixed_array_map()));
3167 __ j(not_equal, &slow_case);
3168
3169 // Check that both indices are smis.
3170 __ mov(index_1, Operand(esp, 1 * kPointerSize));
3171 __ mov(index_2, Operand(esp, 0));
3172 __ mov(temp, index_1);
3173 __ or_(temp, Operand(index_2));
3174 __ test(temp, Immediate(kSmiTagMask));
3175 __ j(not_zero, &slow_case);
3176
3177 // Check that both indices are valid.
3178 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
3179 __ cmp(temp, Operand(index_1));
3180 __ j(below_equal, &slow_case);
3181 __ cmp(temp, Operand(index_2));
3182 __ j(below_equal, &slow_case);
3183
3184 // Bring addresses into index1 and index2.
3185 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1));
3186 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2));
3187
3188 // Swap elements. Use object and temp as scratch registers.
3189 __ mov(object, Operand(index_1, 0));
3190 __ mov(temp, Operand(index_2, 0));
3191 __ mov(Operand(index_2, 0), object);
3192 __ mov(Operand(index_1, 0), temp);
3193
3194 Label new_space;
3195 __ InNewSpace(elements, temp, equal, &new_space);
3196
3197 __ mov(object, elements);
3198 __ RecordWriteHelper(object, index_1, temp);
3199 __ RecordWriteHelper(elements, index_2, temp);
3200
3201 __ bind(&new_space);
3202 // We are done. Drop elements from the stack, and return undefined.
3203 __ add(Operand(esp), Immediate(3 * kPointerSize));
3204 __ mov(eax, Factory::undefined_value());
3205 __ jmp(&done);
3206
3207 __ bind(&slow_case);
Leon Clarkef7060e22010-06-03 12:02:55 +01003208 __ CallRuntime(Runtime::kSwapElements, 3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003209
3210 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003211 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003212}
3213
3214
3215void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3216 ASSERT_EQ(2, args->length());
3217
3218 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3219 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3220
3221 Handle<FixedArray> jsfunction_result_caches(
3222 Top::global_context()->jsfunction_result_caches());
3223 if (jsfunction_result_caches->length() <= cache_id) {
3224 __ Abort("Attempt to use undefined cache.");
3225 __ mov(eax, Factory::undefined_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003226 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003227 return;
3228 }
3229
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003230 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003231
3232 Register key = eax;
3233 Register cache = ebx;
3234 Register tmp = ecx;
Steve Block59151502010-09-22 15:07:15 +01003235 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003236 __ mov(cache,
3237 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
Steve Block59151502010-09-22 15:07:15 +01003238 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003239 __ mov(cache,
3240 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3241
3242 Label done, not_found;
3243 // tmp now holds finger offset as a smi.
3244 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3245 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3246 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3247 __ j(not_equal, &not_found);
3248
3249 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3250 __ jmp(&done);
3251
3252 __ bind(&not_found);
3253 // Call runtime to perform the lookup.
3254 __ push(cache);
3255 __ push(key);
3256 __ CallRuntime(Runtime::kGetFromCache, 2);
3257
3258 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003259 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003260}
3261
3262
Ben Murdochbb769b22010-08-11 14:56:33 +01003263void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3264 ASSERT_EQ(2, args->length());
3265
3266 Register right = eax;
3267 Register left = ebx;
3268 Register tmp = ecx;
3269
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003270 VisitForStackValue(args->at(0));
3271 VisitForAccumulatorValue(args->at(1));
Ben Murdochbb769b22010-08-11 14:56:33 +01003272 __ pop(left);
3273
3274 Label done, fail, ok;
3275 __ cmp(left, Operand(right));
3276 __ j(equal, &ok);
3277 // Fail if either is a non-HeapObject.
3278 __ mov(tmp, left);
3279 __ and_(Operand(tmp), right);
3280 __ test(Operand(tmp), Immediate(kSmiTagMask));
3281 __ j(zero, &fail);
3282 __ CmpObjectType(left, JS_REGEXP_TYPE, tmp);
3283 __ j(not_equal, &fail);
3284 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3285 __ j(not_equal, &fail);
3286 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3287 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3288 __ j(equal, &ok);
3289 __ bind(&fail);
3290 __ mov(eax, Immediate(Factory::false_value()));
3291 __ jmp(&done);
3292 __ bind(&ok);
3293 __ mov(eax, Immediate(Factory::true_value()));
3294 __ bind(&done);
3295
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003296 context()->Plug(eax);
Ben Murdochbb769b22010-08-11 14:56:33 +01003297}
3298
3299
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003300void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
3301 ASSERT(args->length() == 1);
3302
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003303 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003304
3305 if (FLAG_debug_code) {
3306 __ AbortIfNotString(eax);
3307 }
3308
3309 Label materialize_true, materialize_false;
3310 Label* if_true = NULL;
3311 Label* if_false = NULL;
3312 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003313 context()->PrepareTest(&materialize_true, &materialize_false,
3314 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003315
3316 __ test(FieldOperand(eax, String::kHashFieldOffset),
3317 Immediate(String::kContainsCachedArrayIndexMask));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003318 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003319 Split(zero, if_true, if_false, fall_through);
3320
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003321 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003322}
3323
3324
3325void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3326 ASSERT(args->length() == 1);
3327
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003328 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003329
3330 if (FLAG_debug_code) {
3331 __ AbortIfNotString(eax);
3332 }
3333
3334 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3335 __ IndexFromHash(eax, eax);
3336
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003337 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003338}
3339
3340
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003341void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
3342 Label bailout;
3343 Label done;
3344
3345 ASSERT(args->length() == 2);
3346 // We will leave the separator on the stack until the end of the function.
3347 VisitForStackValue(args->at(1));
3348 // Load this to eax (= array)
3349 VisitForAccumulatorValue(args->at(0));
3350
3351 // All aliases of the same register have disjoint lifetimes.
3352 Register array = eax;
3353 Register result_pos = no_reg;
3354
3355 Register index = edi;
3356
3357 Register current_string_length = ecx; // Will be ecx when live.
3358
3359 Register current_string = edx;
3360
3361 Register scratch = ebx;
3362
3363 Register scratch_2 = esi;
3364 Register new_padding_chars = scratch_2;
3365
3366 Operand separator = Operand(esp, 4 * kPointerSize); // Already pushed.
3367 Operand elements = Operand(esp, 3 * kPointerSize);
3368 Operand result = Operand(esp, 2 * kPointerSize);
3369 Operand padding_chars = Operand(esp, 1 * kPointerSize);
3370 Operand array_length = Operand(esp, 0);
3371 __ sub(Operand(esp), Immediate(4 * kPointerSize));
3372
3373
3374 // Check that eax is a JSArray
3375 __ test(array, Immediate(kSmiTagMask));
3376 __ j(zero, &bailout);
3377 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3378 __ j(not_equal, &bailout);
3379
3380 // Check that the array has fast elements.
3381 __ test_b(FieldOperand(scratch, Map::kBitField2Offset),
3382 1 << Map::kHasFastElements);
3383 __ j(zero, &bailout);
3384
3385 // If the array is empty, return the empty string.
3386 __ mov(scratch, FieldOperand(array, JSArray::kLengthOffset));
3387 __ sar(scratch, 1);
3388 Label non_trivial;
3389 __ j(not_zero, &non_trivial);
3390 __ mov(result, Factory::empty_string());
3391 __ jmp(&done);
3392
3393 __ bind(&non_trivial);
3394 __ mov(array_length, scratch);
3395
3396 __ mov(scratch, FieldOperand(array, JSArray::kElementsOffset));
3397 __ mov(elements, scratch);
3398
3399 // End of array's live range.
3400 result_pos = array;
3401 array = no_reg;
3402
3403
3404 // Check that the separator is a flat ascii string.
3405 __ mov(current_string, separator);
3406 __ test(current_string, Immediate(kSmiTagMask));
3407 __ j(zero, &bailout);
3408 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset));
3409 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3410 __ and_(scratch, Immediate(
3411 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3412 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3413 __ j(not_equal, &bailout);
3414 // If the separator is the empty string, replace it with NULL.
3415 // The test for NULL is quicker than the empty string test, in a loop.
3416 __ cmp(FieldOperand(current_string, SeqAsciiString::kLengthOffset),
3417 Immediate(0));
3418 Label separator_checked;
3419 __ j(not_zero, &separator_checked);
3420 __ mov(separator, Immediate(0));
3421 __ bind(&separator_checked);
3422
3423 // Check that elements[0] is a flat ascii string, and copy it in new space.
3424 __ mov(scratch, elements);
3425 __ mov(current_string, FieldOperand(scratch, FixedArray::kHeaderSize));
3426 __ test(current_string, Immediate(kSmiTagMask));
3427 __ j(zero, &bailout);
3428 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset));
3429 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3430 __ and_(scratch, Immediate(
3431 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3432 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3433 __ j(not_equal, &bailout);
3434
3435 // Allocate space to copy it. Round up the size to the alignment granularity.
3436 __ mov(current_string_length,
3437 FieldOperand(current_string, String::kLengthOffset));
3438 __ shr(current_string_length, 1);
3439
3440 // Live registers and stack values:
3441 // current_string_length: length of elements[0].
3442
3443 // New string result in new space = elements[0]
3444 __ AllocateAsciiString(result_pos, current_string_length, scratch_2,
3445 index, no_reg, &bailout);
3446 __ mov(result, result_pos);
3447
3448 // Adjust current_string_length to include padding bytes at end of string.
3449 // Keep track of the number of padding bytes.
3450 __ mov(new_padding_chars, current_string_length);
3451 __ add(Operand(current_string_length), Immediate(kObjectAlignmentMask));
3452 __ and_(Operand(current_string_length), Immediate(~kObjectAlignmentMask));
3453 __ sub(new_padding_chars, Operand(current_string_length));
3454 __ neg(new_padding_chars);
3455 __ mov(padding_chars, new_padding_chars);
3456
3457 Label copy_loop_1_done;
3458 Label copy_loop_1;
3459 __ test(current_string_length, Operand(current_string_length));
3460 __ j(zero, &copy_loop_1_done);
3461 __ bind(&copy_loop_1);
3462 __ sub(Operand(current_string_length), Immediate(kPointerSize));
3463 __ mov(scratch, FieldOperand(current_string, current_string_length,
3464 times_1, SeqAsciiString::kHeaderSize));
3465 __ mov(FieldOperand(result_pos, current_string_length,
3466 times_1, SeqAsciiString::kHeaderSize),
3467 scratch);
3468 __ j(not_zero, &copy_loop_1);
3469 __ bind(&copy_loop_1_done);
3470
3471 __ mov(index, Immediate(1));
3472 // Loop condition: while (index < length).
3473 Label loop;
3474 __ bind(&loop);
3475 __ cmp(index, array_length);
3476 __ j(greater_equal, &done);
3477
3478 // If the separator is the empty string, signalled by NULL, skip it.
3479 Label separator_done;
3480 __ mov(current_string, separator);
3481 __ test(current_string, Operand(current_string));
3482 __ j(zero, &separator_done);
3483
3484 // Append separator to result. It is known to be a flat ascii string.
3485 __ AppendStringToTopOfNewSpace(current_string, current_string_length,
3486 result_pos, scratch, scratch_2, result,
3487 padding_chars, &bailout);
3488 __ bind(&separator_done);
3489
3490 // Add next element of array to the end of the result.
3491 // Get current_string = array[index].
3492 __ mov(scratch, elements);
3493 __ mov(current_string, FieldOperand(scratch, index,
3494 times_pointer_size,
3495 FixedArray::kHeaderSize));
3496 // If current != flat ascii string drop result, return undefined.
3497 __ test(current_string, Immediate(kSmiTagMask));
3498 __ j(zero, &bailout);
3499 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset));
3500 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3501 __ and_(scratch, Immediate(
3502 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3503 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
3504 __ j(not_equal, &bailout);
3505
3506 // Append current to the result.
3507 __ AppendStringToTopOfNewSpace(current_string, current_string_length,
3508 result_pos, scratch, scratch_2, result,
3509 padding_chars, &bailout);
3510 __ add(Operand(index), Immediate(1));
3511 __ jmp(&loop); // End while (index < length).
3512
3513 __ bind(&bailout);
3514 __ mov(result, Factory::undefined_value());
3515 __ bind(&done);
3516 __ mov(eax, result);
3517 // Drop temp values from the stack, and restore context register.
3518 __ add(Operand(esp), Immediate(5 * kPointerSize));
3519
3520 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3521 context()->Plug(eax);
3522}
3523
3524
Leon Clarked91b9f72010-01-27 17:25:45 +00003525void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003526 Handle<String> name = expr->name();
3527 if (name->length() > 0 && name->Get(0) == '_') {
3528 Comment cmnt(masm_, "[ InlineRuntimeCall");
3529 EmitInlineRuntimeCall(expr);
3530 return;
3531 }
3532
Steve Block3ce2e202009-11-05 08:53:23 +00003533 Comment cmnt(masm_, "[ CallRuntime");
3534 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00003535
Steve Blockd0582a62009-12-15 09:54:21 +00003536 if (expr->is_jsruntime()) {
3537 // Prepare for calling JS runtime function.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003538 __ mov(eax, GlobalObjectOperand());
Steve Blockd0582a62009-12-15 09:54:21 +00003539 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3540 }
Steve Block3ce2e202009-11-05 08:53:23 +00003541
3542 // Push the arguments ("left-to-right").
3543 int arg_count = args->length();
3544 for (int i = 0; i < arg_count; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003545 VisitForStackValue(args->at(i));
Steve Block3ce2e202009-11-05 08:53:23 +00003546 }
3547
Steve Blockd0582a62009-12-15 09:54:21 +00003548 if (expr->is_jsruntime()) {
Leon Clarkee46be812010-01-19 14:06:41 +00003549 // Call the JS runtime function via a call IC.
3550 __ Set(ecx, Immediate(expr->name()));
3551 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003552 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003553 EmitCallIC(ic, RelocInfo::CODE_TARGET);
3554 // Restore context register.
Steve Blockd0582a62009-12-15 09:54:21 +00003555 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00003556 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00003557 // Call the C runtime function.
3558 __ CallRuntime(expr->function(), arg_count);
Steve Blockd0582a62009-12-15 09:54:21 +00003559 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003560 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003561}
3562
3563
Leon Clarked91b9f72010-01-27 17:25:45 +00003564void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003565 switch (expr->op()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003566 case Token::DELETE: {
3567 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3568 Property* prop = expr->expression()->AsProperty();
3569 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
3570 if (prop == NULL && var == NULL) {
3571 // Result of deleting non-property, non-variable reference is true.
3572 // The subexpression may have side effects.
3573 VisitForEffect(expr->expression());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003574 context()->Plug(true);
Leon Clarkef7060e22010-06-03 12:02:55 +01003575 } else if (var != NULL &&
3576 !var->is_global() &&
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003577 var->AsSlot() != NULL &&
3578 var->AsSlot()->type() != Slot::LOOKUP) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003579 // Result of deleting non-global, non-dynamic variables is false.
3580 // The subexpression does not have side effects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003581 context()->Plug(false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003582 } else {
3583 // Property or variable reference. Call the delete builtin with
3584 // object and property name as arguments.
3585 if (prop != NULL) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003586 VisitForStackValue(prop->obj());
3587 VisitForStackValue(prop->key());
Leon Clarkef7060e22010-06-03 12:02:55 +01003588 } else if (var->is_global()) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003589 __ push(GlobalObjectOperand());
Leon Clarkef7060e22010-06-03 12:02:55 +01003590 __ push(Immediate(var->name()));
3591 } else {
3592 // Non-global variable. Call the runtime to look up the context
3593 // where the variable was introduced.
3594 __ push(context_register());
3595 __ push(Immediate(var->name()));
3596 __ CallRuntime(Runtime::kLookupContext, 2);
3597 __ push(eax);
3598 __ push(Immediate(var->name()));
3599 }
3600 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003601 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003602 }
3603 break;
3604 }
3605
Steve Blockd0582a62009-12-15 09:54:21 +00003606 case Token::VOID: {
3607 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
Leon Clarkee46be812010-01-19 14:06:41 +00003608 VisitForEffect(expr->expression());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003609 context()->Plug(Factory::undefined_value());
Steve Blockd0582a62009-12-15 09:54:21 +00003610 break;
3611 }
3612
3613 case Token::NOT: {
3614 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003615
Leon Clarkef7060e22010-06-03 12:02:55 +01003616 Label materialize_true, materialize_false;
3617 Label* if_true = NULL;
3618 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003619 Label* fall_through = NULL;
Leon Clarkef7060e22010-06-03 12:02:55 +01003620 // Notice that the labels are swapped.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003621 context()->PrepareTest(&materialize_true, &materialize_false,
3622 &if_false, &if_true, &fall_through);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003623 if (context()->IsTest()) ForwardBailoutToChild(expr);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003624 VisitForControl(expr->expression(), if_true, if_false, fall_through);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003625 context()->Plug(if_false, if_true); // Labels swapped.
Steve Blockd0582a62009-12-15 09:54:21 +00003626 break;
3627 }
3628
3629 case Token::TYPEOF: {
3630 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003631 { StackValueContext context(this);
3632 VisitForTypeofValue(expr->expression());
3633 }
Steve Blockd0582a62009-12-15 09:54:21 +00003634 __ CallRuntime(Runtime::kTypeof, 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003635 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003636 break;
3637 }
3638
Leon Clarked91b9f72010-01-27 17:25:45 +00003639 case Token::ADD: {
3640 Comment cmt(masm_, "[ UnaryOperation (ADD)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003641 VisitForAccumulatorValue(expr->expression());
Leon Clarked91b9f72010-01-27 17:25:45 +00003642 Label no_conversion;
3643 __ test(result_register(), Immediate(kSmiTagMask));
3644 __ j(zero, &no_conversion);
3645 __ push(result_register());
3646 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
3647 __ bind(&no_conversion);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003648 context()->Plug(result_register());
Leon Clarked91b9f72010-01-27 17:25:45 +00003649 break;
3650 }
3651
Leon Clarke4515c472010-02-03 11:58:03 +00003652 case Token::SUB: {
3653 Comment cmt(masm_, "[ UnaryOperation (SUB)");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003654 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
Leon Clarkeac952652010-07-15 11:15:24 +01003655 UnaryOverwriteMode overwrite =
3656 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003657 GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
Leon Clarke4515c472010-02-03 11:58:03 +00003658 // GenericUnaryOpStub expects the argument to be in the
3659 // accumulator register eax.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003660 VisitForAccumulatorValue(expr->expression());
Leon Clarke4515c472010-02-03 11:58:03 +00003661 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003662 context()->Plug(eax);
Leon Clarke4515c472010-02-03 11:58:03 +00003663 break;
3664 }
3665
3666 case Token::BIT_NOT: {
3667 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003668 // The generic unary operation stub expects the argument to be
3669 // in the accumulator register eax.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003670 VisitForAccumulatorValue(expr->expression());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003671 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003672 bool inline_smi_case = ShouldInlineSmiCase(expr->op());
3673 if (inline_smi_case) {
3674 NearLabel call_stub;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003675 __ test(eax, Immediate(kSmiTagMask));
3676 __ j(not_zero, &call_stub);
3677 __ lea(eax, Operand(eax, kSmiTagMask));
3678 __ not_(eax);
3679 __ jmp(&done);
3680 __ bind(&call_stub);
3681 }
3682 bool overwrite = expr->expression()->ResultOverwriteAllowed();
3683 UnaryOverwriteMode mode =
3684 overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003685 UnaryOpFlags flags = inline_smi_case
3686 ? NO_UNARY_SMI_CODE_IN_STUB
3687 : NO_UNARY_FLAGS;
3688 GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
Leon Clarke4515c472010-02-03 11:58:03 +00003689 __ CallStub(&stub);
Leon Clarke4515c472010-02-03 11:58:03 +00003690 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003691 context()->Plug(eax);
Leon Clarke4515c472010-02-03 11:58:03 +00003692 break;
3693 }
3694
Steve Blockd0582a62009-12-15 09:54:21 +00003695 default:
3696 UNREACHABLE();
3697 }
3698}
3699
3700
Leon Clarked91b9f72010-01-27 17:25:45 +00003701void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003702 Comment cmnt(masm_, "[ CountOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003703 SetSourcePosition(expr->position());
3704
Leon Clarkef7060e22010-06-03 12:02:55 +01003705 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3706 // as the left-hand side.
3707 if (!expr->expression()->IsValidLeftHandSide()) {
3708 VisitForEffect(expr->expression());
3709 return;
3710 }
Steve Blockd0582a62009-12-15 09:54:21 +00003711
Leon Clarkee46be812010-01-19 14:06:41 +00003712 // Expression can only be a property, a global or a (parameter or local)
3713 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
3714 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3715 LhsKind assign_type = VARIABLE;
3716 Property* prop = expr->expression()->AsProperty();
3717 // In case of a property we use the uninitialized expression context
3718 // of the key to detect a named property.
3719 if (prop != NULL) {
3720 assign_type =
3721 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3722 }
3723
3724 // Evaluate expression and get value.
3725 if (assign_type == VARIABLE) {
3726 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003727 AccumulatorValueContext context(this);
3728 EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
Leon Clarkef7060e22010-06-03 12:02:55 +01003729 } else {
Leon Clarkee46be812010-01-19 14:06:41 +00003730 // Reserve space for result of postfix operation.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003731 if (expr->is_postfix() && !context()->IsEffect()) {
Leon Clarkee46be812010-01-19 14:06:41 +00003732 __ push(Immediate(Smi::FromInt(0)));
3733 }
Leon Clarkee46be812010-01-19 14:06:41 +00003734 if (assign_type == NAMED_PROPERTY) {
Andrei Popescu402d9372010-02-26 13:31:12 +00003735 // Put the object both on the stack and in the accumulator.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003736 VisitForAccumulatorValue(prop->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00003737 __ push(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003738 EmitNamedPropertyLoad(prop);
3739 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003740 if (prop->is_arguments_access()) {
3741 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy();
3742 __ push(EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx));
3743 __ mov(eax, Immediate(prop->key()->AsLiteral()->handle()));
3744 } else {
3745 VisitForStackValue(prop->obj());
3746 VisitForAccumulatorValue(prop->key());
3747 }
Andrei Popescu402d9372010-02-26 13:31:12 +00003748 __ mov(edx, Operand(esp, 0));
3749 __ push(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003750 EmitKeyedPropertyLoad(prop);
3751 }
Leon Clarkee46be812010-01-19 14:06:41 +00003752 }
3753
Ben Murdochb0fe1622011-05-05 13:52:32 +01003754 // We need a second deoptimization point after loading the value
3755 // in case evaluating the property load my have a side effect.
3756 PrepareForBailout(expr->increment(), TOS_REG);
3757
Leon Clarked91b9f72010-01-27 17:25:45 +00003758 // Call ToNumber only if operand is not a smi.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003759 NearLabel no_conversion;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003760 if (ShouldInlineSmiCase(expr->op())) {
3761 __ test(eax, Immediate(kSmiTagMask));
3762 __ j(zero, &no_conversion);
3763 }
Leon Clarked91b9f72010-01-27 17:25:45 +00003764 __ push(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003765 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
Leon Clarked91b9f72010-01-27 17:25:45 +00003766 __ bind(&no_conversion);
Steve Blockd0582a62009-12-15 09:54:21 +00003767
Leon Clarkee46be812010-01-19 14:06:41 +00003768 // Save result for postfix expressions.
3769 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003770 if (!context()->IsEffect()) {
3771 // Save the result on the stack. If we have a named or keyed property
3772 // we store the result under the receiver that is currently on top
3773 // of the stack.
3774 switch (assign_type) {
3775 case VARIABLE:
3776 __ push(eax);
3777 break;
3778 case NAMED_PROPERTY:
3779 __ mov(Operand(esp, kPointerSize), eax);
3780 break;
3781 case KEYED_PROPERTY:
3782 __ mov(Operand(esp, 2 * kPointerSize), eax);
3783 break;
3784 }
Leon Clarkee46be812010-01-19 14:06:41 +00003785 }
Steve Blockd0582a62009-12-15 09:54:21 +00003786 }
Leon Clarkee46be812010-01-19 14:06:41 +00003787
Leon Clarked91b9f72010-01-27 17:25:45 +00003788 // Inline smi case if we are in a loop.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003789 NearLabel stub_call, done;
3790 JumpPatchSite patch_site(masm_);
3791
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003792 if (ShouldInlineSmiCase(expr->op())) {
Leon Clarked91b9f72010-01-27 17:25:45 +00003793 if (expr->op() == Token::INC) {
3794 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3795 } else {
3796 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3797 }
3798 __ j(overflow, &stub_call);
3799 // We could eliminate this smi check if we split the code at
3800 // the first smi check before calling ToNumber.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003801 patch_site.EmitJumpIfSmi(eax, &done);
3802
Leon Clarked91b9f72010-01-27 17:25:45 +00003803 __ bind(&stub_call);
3804 // Call stub. Undo operation first.
3805 if (expr->op() == Token::INC) {
3806 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3807 } else {
3808 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3809 }
3810 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01003811
3812 // Record position before stub call.
3813 SetSourcePosition(expr->position());
3814
Leon Clarkee46be812010-01-19 14:06:41 +00003815 // Call stub for +1/-1.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003816 __ mov(edx, eax);
3817 __ mov(eax, Immediate(Smi::FromInt(1)));
3818 TypeRecordingBinaryOpStub stub(expr->binary_op(),
3819 NO_OVERWRITE);
3820 EmitCallIC(stub.GetCode(), &patch_site);
Leon Clarked91b9f72010-01-27 17:25:45 +00003821 __ bind(&done);
Steve Blockd0582a62009-12-15 09:54:21 +00003822
Leon Clarkee46be812010-01-19 14:06:41 +00003823 // Store the value returned in eax.
3824 switch (assign_type) {
3825 case VARIABLE:
3826 if (expr->is_postfix()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003827 // Perform the assignment as if via '='.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003828 { EffectContext context(this);
3829 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3830 Token::ASSIGN);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003831 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3832 context.Plug(eax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003833 }
3834 // For all contexts except EffectContext We have the result on
Leon Clarkee46be812010-01-19 14:06:41 +00003835 // top of the stack.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003836 if (!context()->IsEffect()) {
3837 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00003838 }
3839 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01003840 // Perform the assignment as if via '='.
Leon Clarkee46be812010-01-19 14:06:41 +00003841 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003842 Token::ASSIGN);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003843 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3844 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003845 }
Steve Blockd0582a62009-12-15 09:54:21 +00003846 break;
Leon Clarkee46be812010-01-19 14:06:41 +00003847 case NAMED_PROPERTY: {
3848 __ mov(ecx, prop->key()->AsLiteral()->handle());
Leon Clarke4515c472010-02-03 11:58:03 +00003849 __ pop(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00003850 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003851 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003852 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00003853 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003854 if (!context()->IsEffect()) {
3855 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00003856 }
3857 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003858 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003859 }
Steve Blockd0582a62009-12-15 09:54:21 +00003860 break;
3861 }
Leon Clarkee46be812010-01-19 14:06:41 +00003862 case KEYED_PROPERTY: {
Steve Block6ded16b2010-05-10 14:33:55 +01003863 __ pop(ecx);
3864 __ pop(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00003865 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003866 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003867 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00003868 if (expr->is_postfix()) {
Steve Block6ded16b2010-05-10 14:33:55 +01003869 // Result is on the stack
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003870 if (!context()->IsEffect()) {
3871 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00003872 }
3873 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003874 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003875 }
Steve Blockd0582a62009-12-15 09:54:21 +00003876 break;
3877 }
Steve Block3ce2e202009-11-05 08:53:23 +00003878 }
3879}
3880
3881
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003882void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003883 VariableProxy* proxy = expr->AsVariableProxy();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003884 ASSERT(!context()->IsEffect());
3885 ASSERT(!context()->IsTest());
3886
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003887 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3888 Comment cmnt(masm_, "Global variable");
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003889 __ mov(eax, GlobalObjectOperand());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003890 __ mov(ecx, Immediate(proxy->name()));
3891 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
3892 // Use a regular load, not a contextual load, to avoid a reference
3893 // error.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003894 EmitCallIC(ic, RelocInfo::CODE_TARGET);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003895 PrepareForBailout(expr, TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003896 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003897 } else if (proxy != NULL &&
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003898 proxy->var()->AsSlot() != NULL &&
3899 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
Steve Block59151502010-09-22 15:07:15 +01003900 Label done, slow;
3901
3902 // Generate code for loading from variables potentially shadowed
3903 // by eval-introduced variables.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003904 Slot* slot = proxy->var()->AsSlot();
Steve Block59151502010-09-22 15:07:15 +01003905 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3906
3907 __ bind(&slow);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003908 __ push(esi);
3909 __ push(Immediate(proxy->name()));
3910 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003911 PrepareForBailout(expr, TOS_REG);
Steve Block59151502010-09-22 15:07:15 +01003912 __ bind(&done);
3913
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003914 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003915 } else {
3916 // This expression cannot throw a reference error at the top level.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003917 context()->HandleExpression(expr);
Steve Block3ce2e202009-11-05 08:53:23 +00003918 }
Steve Block3ce2e202009-11-05 08:53:23 +00003919}
3920
3921
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003922bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
3923 Expression* left,
3924 Expression* right,
3925 Label* if_true,
3926 Label* if_false,
3927 Label* fall_through) {
3928 if (op != Token::EQ && op != Token::EQ_STRICT) return false;
3929
3930 // Check for the pattern: typeof <expression> == <string literal>.
3931 Literal* right_literal = right->AsLiteral();
3932 if (right_literal == NULL) return false;
3933 Handle<Object> right_literal_value = right_literal->handle();
3934 if (!right_literal_value->IsString()) return false;
3935 UnaryOperation* left_unary = left->AsUnaryOperation();
3936 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
3937 Handle<String> check = Handle<String>::cast(right_literal_value);
3938
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003939 { AccumulatorValueContext context(this);
3940 VisitForTypeofValue(left_unary->expression());
3941 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01003942 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003943
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003944 if (check->Equals(Heap::number_symbol())) {
3945 __ test(eax, Immediate(kSmiTagMask));
3946 __ j(zero, if_true);
3947 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3948 Factory::heap_number_map());
3949 Split(equal, if_true, if_false, fall_through);
3950 } else if (check->Equals(Heap::string_symbol())) {
3951 __ test(eax, Immediate(kSmiTagMask));
Leon Clarkef7060e22010-06-03 12:02:55 +01003952 __ j(zero, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003953 // Check for undetectable objects => false.
3954 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3955 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3956 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3957 __ j(not_zero, if_false);
3958 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE);
3959 Split(below, if_true, if_false, fall_through);
3960 } else if (check->Equals(Heap::boolean_symbol())) {
3961 __ cmp(eax, Factory::true_value());
3962 __ j(equal, if_true);
3963 __ cmp(eax, Factory::false_value());
3964 Split(equal, if_true, if_false, fall_through);
3965 } else if (check->Equals(Heap::undefined_symbol())) {
3966 __ cmp(eax, Factory::undefined_value());
3967 __ j(equal, if_true);
3968 __ test(eax, Immediate(kSmiTagMask));
3969 __ j(zero, if_false);
3970 // Check for undetectable objects => true.
3971 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3972 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3973 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3974 Split(not_zero, if_true, if_false, fall_through);
3975 } else if (check->Equals(Heap::function_symbol())) {
3976 __ test(eax, Immediate(kSmiTagMask));
3977 __ j(zero, if_false);
3978 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
3979 __ j(equal, if_true);
3980 // Regular expressions => 'function' (they are callable).
3981 __ CmpInstanceType(edx, JS_REGEXP_TYPE);
3982 Split(equal, if_true, if_false, fall_through);
3983 } else if (check->Equals(Heap::object_symbol())) {
3984 __ test(eax, Immediate(kSmiTagMask));
3985 __ j(zero, if_false);
3986 __ cmp(eax, Factory::null_value());
3987 __ j(equal, if_true);
3988 // Regular expressions => 'function', not 'object'.
3989 __ CmpObjectType(eax, JS_REGEXP_TYPE, edx);
3990 __ j(equal, if_false);
3991 // Check for undetectable objects => false.
3992 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3993 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3994 __ j(not_zero, if_false);
3995 // Check for JS objects => true.
3996 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
3997 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
3998 __ j(less, if_false);
3999 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
4000 Split(less_equal, if_true, if_false, fall_through);
4001 } else {
4002 if (if_false != fall_through) __ jmp(if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01004003 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004004
4005 return true;
Leon Clarkef7060e22010-06-03 12:02:55 +01004006}
4007
4008
Leon Clarked91b9f72010-01-27 17:25:45 +00004009void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004010 Comment cmnt(masm_, "[ CompareOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004011 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00004012
Leon Clarkee46be812010-01-19 14:06:41 +00004013 // Always perform the comparison for its control flow. Pack the result
4014 // into the expression's context after the comparison is performed.
Leon Clarkef7060e22010-06-03 12:02:55 +01004015
4016 Label materialize_true, materialize_false;
4017 Label* if_true = NULL;
4018 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004019 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004020 context()->PrepareTest(&materialize_true, &materialize_false,
4021 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004022
4023 // First we try a fast inlined version of the compare when one of
4024 // the operands is a literal.
4025 Token::Value op = expr->op();
4026 Expression* left = expr->left();
4027 Expression* right = expr->right();
4028 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004029 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004030 return;
4031 }
Steve Blockd0582a62009-12-15 09:54:21 +00004032
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004033 VisitForStackValue(expr->left());
Steve Blockd0582a62009-12-15 09:54:21 +00004034 switch (expr->op()) {
Leon Clarkee46be812010-01-19 14:06:41 +00004035 case Token::IN:
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004036 VisitForStackValue(expr->right());
Steve Blockd0582a62009-12-15 09:54:21 +00004037 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004038 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00004039 __ cmp(eax, Factory::true_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004040 Split(equal, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004041 break;
Steve Blockd0582a62009-12-15 09:54:21 +00004042
4043 case Token::INSTANCEOF: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004044 VisitForStackValue(expr->right());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004045 __ IncrementCounter(&Counters::instance_of_full, 1);
4046 InstanceofStub stub(InstanceofStub::kNoFlags);
Steve Blockd0582a62009-12-15 09:54:21 +00004047 __ CallStub(&stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004048 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Steve Blockd0582a62009-12-15 09:54:21 +00004049 __ test(eax, Operand(eax));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004050 // The stub returns 0 for true.
4051 Split(zero, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004052 break;
4053 }
4054
4055 default: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004056 VisitForAccumulatorValue(expr->right());
Steve Blockd0582a62009-12-15 09:54:21 +00004057 Condition cc = no_condition;
4058 bool strict = false;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004059 switch (op) {
Steve Blockd0582a62009-12-15 09:54:21 +00004060 case Token::EQ_STRICT:
4061 strict = true;
4062 // Fall through
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004063 case Token::EQ:
Steve Blockd0582a62009-12-15 09:54:21 +00004064 cc = equal;
Steve Blockd0582a62009-12-15 09:54:21 +00004065 __ pop(edx);
4066 break;
4067 case Token::LT:
4068 cc = less;
Steve Blockd0582a62009-12-15 09:54:21 +00004069 __ pop(edx);
4070 break;
4071 case Token::GT:
4072 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4073 cc = less;
Leon Clarkee46be812010-01-19 14:06:41 +00004074 __ mov(edx, result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00004075 __ pop(eax);
4076 break;
4077 case Token::LTE:
4078 // Reverse left and right sizes to obtain ECMA-262 conversion order.
4079 cc = greater_equal;
Leon Clarkee46be812010-01-19 14:06:41 +00004080 __ mov(edx, result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00004081 __ pop(eax);
4082 break;
4083 case Token::GTE:
4084 cc = greater_equal;
Steve Blockd0582a62009-12-15 09:54:21 +00004085 __ pop(edx);
4086 break;
4087 case Token::IN:
4088 case Token::INSTANCEOF:
4089 default:
4090 UNREACHABLE();
4091 }
4092
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004093 bool inline_smi_code = ShouldInlineSmiCase(op);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004094 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004095 if (inline_smi_code) {
4096 NearLabel slow_case;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004097 __ mov(ecx, Operand(edx));
4098 __ or_(ecx, Operand(eax));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004099 patch_site.EmitJumpIfNotSmi(ecx, &slow_case);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004100 __ cmp(edx, Operand(eax));
4101 Split(cc, if_true, if_false, NULL);
4102 __ bind(&slow_case);
4103 }
Steve Blockd0582a62009-12-15 09:54:21 +00004104
Ben Murdochb0fe1622011-05-05 13:52:32 +01004105 // Record position and call the compare IC.
4106 SetSourcePosition(expr->position());
4107 Handle<Code> ic = CompareIC::GetUninitialized(op);
4108 EmitCallIC(ic, &patch_site);
4109
4110 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Steve Blockd0582a62009-12-15 09:54:21 +00004111 __ test(eax, Operand(eax));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004112 Split(cc, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004113 }
4114 }
4115
Leon Clarkee46be812010-01-19 14:06:41 +00004116 // Convert the result of the comparison into one expected for this
4117 // expression's context.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004118 context()->Plug(if_true, if_false);
Steve Blockd0582a62009-12-15 09:54:21 +00004119}
4120
4121
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004122void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4123 Label materialize_true, materialize_false;
4124 Label* if_true = NULL;
4125 Label* if_false = NULL;
4126 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004127 context()->PrepareTest(&materialize_true, &materialize_false,
4128 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004129
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004130 VisitForAccumulatorValue(expr->expression());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004131 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4132
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004133 __ cmp(eax, Factory::null_value());
4134 if (expr->is_strict()) {
4135 Split(equal, if_true, if_false, fall_through);
4136 } else {
4137 __ j(equal, if_true);
4138 __ cmp(eax, Factory::undefined_value());
4139 __ j(equal, if_true);
4140 __ test(eax, Immediate(kSmiTagMask));
4141 __ j(zero, if_false);
4142 // It can be an undetectable object.
4143 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4144 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
4145 __ test(edx, Immediate(1 << Map::kIsUndetectable));
4146 Split(not_zero, if_true, if_false, fall_through);
4147 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004148 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004149}
4150
4151
Leon Clarked91b9f72010-01-27 17:25:45 +00004152void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004153 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004154 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00004155}
4156
Steve Blockd0582a62009-12-15 09:54:21 +00004157
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004158Register FullCodeGenerator::result_register() {
4159 return eax;
4160}
Leon Clarkee46be812010-01-19 14:06:41 +00004161
4162
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004163Register FullCodeGenerator::context_register() {
4164 return esi;
4165}
4166
4167
4168void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
4169 ASSERT(mode == RelocInfo::CODE_TARGET ||
4170 mode == RelocInfo::CODE_TARGET_CONTEXT);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004171 switch (ic->kind()) {
4172 case Code::LOAD_IC:
4173 __ IncrementCounter(&Counters::named_load_full, 1);
4174 break;
4175 case Code::KEYED_LOAD_IC:
4176 __ IncrementCounter(&Counters::keyed_load_full, 1);
4177 break;
4178 case Code::STORE_IC:
4179 __ IncrementCounter(&Counters::named_store_full, 1);
4180 break;
4181 case Code::KEYED_STORE_IC:
4182 __ IncrementCounter(&Counters::keyed_store_full, 1);
4183 default:
4184 break;
4185 }
4186
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004187 __ call(ic, mode);
4188
Ben Murdochb0fe1622011-05-05 13:52:32 +01004189 // Crankshaft doesn't need patching of inlined loads and stores.
4190 // When compiling the snapshot we need to produce code that works
4191 // with and without Crankshaft.
4192 if (V8::UseCrankshaft() && !Serializer::enabled()) {
4193 return;
4194 }
4195
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004196 // If we're calling a (keyed) load or store stub, we have to mark
4197 // the call as containing no inlined code so we will not attempt to
4198 // patch it.
4199 switch (ic->kind()) {
4200 case Code::LOAD_IC:
4201 case Code::KEYED_LOAD_IC:
4202 case Code::STORE_IC:
4203 case Code::KEYED_STORE_IC:
4204 __ nop(); // Signals no inlined code.
4205 break;
4206 default:
4207 // Do nothing.
4208 break;
4209 }
4210}
Leon Clarkee46be812010-01-19 14:06:41 +00004211
4212
Ben Murdochb0fe1622011-05-05 13:52:32 +01004213void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
4214 __ call(ic, RelocInfo::CODE_TARGET);
4215 if (patch_site != NULL && patch_site->is_bound()) {
4216 patch_site->EmitPatchInfo();
4217 } else {
4218 __ nop(); // Signals no inlined code.
4219 }
4220}
4221
4222
Leon Clarked91b9f72010-01-27 17:25:45 +00004223void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
Leon Clarkee46be812010-01-19 14:06:41 +00004224 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4225 __ mov(Operand(ebp, frame_offset), value);
4226}
4227
4228
Leon Clarked91b9f72010-01-27 17:25:45 +00004229void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
Steve Block59151502010-09-22 15:07:15 +01004230 __ mov(dst, ContextOperand(esi, context_index));
Leon Clarkee46be812010-01-19 14:06:41 +00004231}
4232
4233
4234// ----------------------------------------------------------------------------
4235// Non-local control flow support.
4236
Leon Clarked91b9f72010-01-27 17:25:45 +00004237void FullCodeGenerator::EnterFinallyBlock() {
Leon Clarkee46be812010-01-19 14:06:41 +00004238 // Cook return address on top of stack (smi encoded Code* delta)
4239 ASSERT(!result_register().is(edx));
4240 __ mov(edx, Operand(esp, 0));
4241 __ sub(Operand(edx), Immediate(masm_->CodeObject()));
4242 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4243 ASSERT_EQ(0, kSmiTag);
4244 __ add(edx, Operand(edx)); // Convert to smi.
4245 __ mov(Operand(esp, 0), edx);
4246 // Store result register while executing finally block.
4247 __ push(result_register());
4248}
4249
4250
Leon Clarked91b9f72010-01-27 17:25:45 +00004251void FullCodeGenerator::ExitFinallyBlock() {
Leon Clarkee46be812010-01-19 14:06:41 +00004252 ASSERT(!result_register().is(edx));
4253 // Restore result register from stack.
4254 __ pop(result_register());
4255 // Uncook return address.
4256 __ mov(edx, Operand(esp, 0));
4257 __ sar(edx, 1); // Convert smi to int.
4258 __ add(Operand(edx), Immediate(masm_->CodeObject()));
4259 __ mov(Operand(esp, 0), edx);
4260 // And return.
4261 __ ret(0);
4262}
4263
4264
4265#undef __
Steve Blockd0582a62009-12-15 09:54:21 +00004266
Steve Block3ce2e202009-11-05 08:53:23 +00004267} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01004268
4269#endif // V8_TARGET_ARCH_IA32