blob: 3d1653ce370f175139c0b8e2bfdd32f601f1a6a8 [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"
Steve Block3ce2e202009-11-05 08:53:23 +000039
40namespace v8 {
41namespace internal {
42
43#define __ ACCESS_MASM(masm_)
44
45// Generate code for a JS function. On entry to the function the receiver
46// and arguments have been pushed on the stack left to right, with the
47// return address on top of them. The actual argument count matches the
48// formal parameter count expected by the function.
49//
50// The live registers are:
51// o edi: the JS function object being called (ie, ourselves)
52// o esi: our context
53// o ebp: our caller's frame pointer
54// o esp: stack pointer (pointing to return address)
55//
56// The function builds a JS frame. Please see JavaScriptFrameConstants in
57// frames-ia32.h for its layout.
Iain Merrick75681382010-08-19 15:07:18 +010058void FullCodeGenerator::Generate(CompilationInfo* info) {
Andrei Popescu31002712010-02-23 13:46:05 +000059 ASSERT(info_ == NULL);
60 info_ = info;
61 SetFunctionPosition(function());
Steve Block6ded16b2010-05-10 14:33:55 +010062 Comment cmnt(masm_, "[ function compiled by full code generator");
Steve Block3ce2e202009-11-05 08:53:23 +000063
Iain Merrick75681382010-08-19 15:07:18 +010064 __ push(ebp); // Caller's frame pointer.
65 __ mov(ebp, esp);
66 __ push(esi); // Callee's context.
67 __ push(edi); // Callee's JS Function.
Steve Block3ce2e202009-11-05 08:53:23 +000068
Iain Merrick75681382010-08-19 15:07:18 +010069 { Comment cmnt(masm_, "[ Allocate locals");
70 int locals_count = scope()->num_stack_slots();
71 if (locals_count == 1) {
72 __ push(Immediate(Factory::undefined_value()));
73 } else if (locals_count > 1) {
74 __ mov(eax, Immediate(Factory::undefined_value()));
75 for (int i = 0; i < locals_count; i++) {
76 __ push(eax);
Steve Blockd0582a62009-12-15 09:54:21 +000077 }
Steve Block3ce2e202009-11-05 08:53:23 +000078 }
Iain Merrick75681382010-08-19 15:07:18 +010079 }
Steve Block3ce2e202009-11-05 08:53:23 +000080
Iain Merrick75681382010-08-19 15:07:18 +010081 bool function_in_register = true;
Steve Blockd0582a62009-12-15 09:54:21 +000082
Iain Merrick75681382010-08-19 15:07:18 +010083 // Possibly allocate a local context.
84 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
85 if (heap_slots > 0) {
86 Comment cmnt(masm_, "[ Allocate local context");
87 // Argument to NewContext is the function, which is still in edi.
88 __ push(edi);
89 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
90 FastNewContextStub stub(heap_slots);
Leon Clarke4515c472010-02-03 11:58:03 +000091 __ CallStub(&stub);
Iain Merrick75681382010-08-19 15:07:18 +010092 } else {
93 __ CallRuntime(Runtime::kNewContext, 1);
Leon Clarke4515c472010-02-03 11:58:03 +000094 }
Iain Merrick75681382010-08-19 15:07:18 +010095 function_in_register = false;
96 // Context is returned in both eax and esi. It replaces the context
97 // passed to us. It's saved in the stack and kept live in esi.
98 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
99
100 // Copy parameters into context if necessary.
101 int num_parameters = scope()->num_parameters();
102 for (int i = 0; i < num_parameters; i++) {
103 Slot* slot = scope()->parameter(i)->slot();
104 if (slot != NULL && slot->type() == Slot::CONTEXT) {
105 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
106 (num_parameters - 1 - i) * kPointerSize;
107 // Load parameter from stack.
108 __ mov(eax, Operand(ebp, parameter_offset));
109 // Store it in the context.
110 int context_offset = Context::SlotOffset(slot->index());
111 __ mov(Operand(esi, context_offset), eax);
112 // Update the write barrier. This clobbers all involved
113 // registers, so we have use a third register to avoid
114 // clobbering esi.
115 __ mov(ecx, esi);
116 __ RecordWrite(ecx, context_offset, eax, ebx);
117 }
118 }
119 }
120
121 Variable* arguments = scope()->arguments()->AsVariable();
122 if (arguments != NULL) {
123 // Function uses arguments object.
124 Comment cmnt(masm_, "[ Allocate arguments object");
125 if (function_in_register) {
126 __ push(edi);
127 } else {
128 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
129 }
130 // Receiver is just before the parameters on the caller's stack.
131 int offset = scope()->num_parameters() * kPointerSize;
132 __ lea(edx,
133 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
134 __ push(edx);
135 __ push(Immediate(Smi::FromInt(scope()->num_parameters())));
136 // Arguments to ArgumentsAccessStub:
137 // function, receiver address, parameter count.
138 // The stub will rewrite receiver and parameter count if the previous
139 // stack frame was an arguments adapter frame.
140 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
141 __ CallStub(&stub);
142 __ mov(ecx, eax); // Duplicate result.
143 Move(arguments->slot(), eax, ebx, edx);
144 Slot* dot_arguments_slot =
145 scope()->arguments_shadow()->AsVariable()->slot();
146 Move(dot_arguments_slot, ecx, ebx, edx);
Steve Blockd0582a62009-12-15 09:54:21 +0000147 }
148
Steve Blockd0582a62009-12-15 09:54:21 +0000149 { Comment cmnt(masm_, "[ Declarations");
Leon Clarkef7060e22010-06-03 12:02:55 +0100150 // For named function expressions, declare the function name as a
151 // constant.
152 if (scope()->is_function_scope() && scope()->function() != NULL) {
153 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
154 }
155 // Visit all the explicit declarations unless there is an illegal
156 // redeclaration.
157 if (scope()->HasIllegalRedeclaration()) {
158 scope()->VisitIllegalRedeclaration(this);
159 } else {
160 VisitDeclarations(scope()->declarations());
161 }
Steve Blockd0582a62009-12-15 09:54:21 +0000162 }
163
Steve Block3ce2e202009-11-05 08:53:23 +0000164 { Comment cmnt(masm_, "[ Stack check");
165 Label ok;
Steve Blockd0582a62009-12-15 09:54:21 +0000166 ExternalReference stack_limit =
167 ExternalReference::address_of_stack_limit();
168 __ cmp(esp, Operand::StaticVariable(stack_limit));
Steve Block3ce2e202009-11-05 08:53:23 +0000169 __ j(above_equal, &ok, taken);
170 StackCheckStub stub;
171 __ CallStub(&stub);
172 __ bind(&ok);
173 }
174
Steve Block3ce2e202009-11-05 08:53:23 +0000175 if (FLAG_trace) {
176 __ CallRuntime(Runtime::kTraceEnter, 0);
177 }
178
179 { Comment cmnt(masm_, "[ Body");
Steve Blockd0582a62009-12-15 09:54:21 +0000180 ASSERT(loop_depth() == 0);
Andrei Popescu31002712010-02-23 13:46:05 +0000181 VisitStatements(function()->body());
Steve Blockd0582a62009-12-15 09:54:21 +0000182 ASSERT(loop_depth() == 0);
Steve Block3ce2e202009-11-05 08:53:23 +0000183 }
184
185 { Comment cmnt(masm_, "[ return <undefined>;");
Steve Blockd0582a62009-12-15 09:54:21 +0000186 // Emit a 'return undefined' in case control fell off the end of the body.
Steve Block3ce2e202009-11-05 08:53:23 +0000187 __ mov(eax, Factory::undefined_value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100188 EmitReturnSequence();
Steve Blockd0582a62009-12-15 09:54:21 +0000189 }
190}
Steve Block3ce2e202009-11-05 08:53:23 +0000191
Steve Blockd0582a62009-12-15 09:54:21 +0000192
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100193void FullCodeGenerator::EmitReturnSequence() {
Steve Blockd0582a62009-12-15 09:54:21 +0000194 Comment cmnt(masm_, "[ Return sequence");
195 if (return_label_.is_bound()) {
196 __ jmp(&return_label_);
197 } else {
198 // Common return label
199 __ bind(&return_label_);
Steve Block3ce2e202009-11-05 08:53:23 +0000200 if (FLAG_trace) {
201 __ push(eax);
202 __ CallRuntime(Runtime::kTraceExit, 1);
203 }
Steve Blockd0582a62009-12-15 09:54:21 +0000204#ifdef DEBUG
205 // Add a label for checking the size of the code used for returning.
206 Label check_exit_codesize;
207 masm_->bind(&check_exit_codesize);
208#endif
Ben Murdochbb769b22010-08-11 14:56:33 +0100209 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
Steve Block3ce2e202009-11-05 08:53:23 +0000210 __ RecordJSReturn();
211 // Do not use the leave instruction here because it is too short to
212 // patch with the code required by the debugger.
213 __ mov(esp, ebp);
214 __ pop(ebp);
Andrei Popescu31002712010-02-23 13:46:05 +0000215 __ ret((scope()->num_parameters() + 1) * kPointerSize);
Steve Blockd0582a62009-12-15 09:54:21 +0000216#ifdef ENABLE_DEBUGGER_SUPPORT
217 // Check that the size of the code used for returning matches what is
218 // expected by the debugger.
219 ASSERT_EQ(Assembler::kJSReturnSequenceLength,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100220 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
Steve Blockd0582a62009-12-15 09:54:21 +0000221#endif
222 }
223}
224
225
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100226FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
227 Token::Value op, Expression* left, Expression* right) {
228 ASSERT(ShouldInlineSmiCase(op));
229 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) {
230 // We never generate inlined constant smi operations for these.
231 return kNoConstants;
232 } else if (right->IsSmiLiteral()) {
233 return kRightConstant;
234 } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) {
235 return kLeftConstant;
236 } else {
237 return kNoConstants;
238 }
239}
240
241
Leon Clarked91b9f72010-01-27 17:25:45 +0000242void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
Steve Blockd0582a62009-12-15 09:54:21 +0000243 switch (context) {
244 case Expression::kUninitialized:
245 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +0000246
Steve Blockd0582a62009-12-15 09:54:21 +0000247 case Expression::kEffect:
Leon Clarkee46be812010-01-19 14:06:41 +0000248 // Nothing to do.
Steve Blockd0582a62009-12-15 09:54:21 +0000249 break;
Leon Clarkee46be812010-01-19 14:06:41 +0000250
Steve Blockd0582a62009-12-15 09:54:21 +0000251 case Expression::kValue:
Leon Clarkee46be812010-01-19 14:06:41 +0000252 // Move value into place.
253 switch (location_) {
254 case kAccumulator:
255 if (!reg.is(result_register())) __ mov(result_register(), reg);
256 break;
257 case kStack:
258 __ push(reg);
259 break;
260 }
Steve Blockd0582a62009-12-15 09:54:21 +0000261 break;
Leon Clarkee46be812010-01-19 14:06:41 +0000262
Steve Blockd0582a62009-12-15 09:54:21 +0000263 case Expression::kTest:
Leon Clarkee46be812010-01-19 14:06:41 +0000264 // For simplicity we always test the accumulator register.
265 if (!reg.is(result_register())) __ mov(result_register(), reg);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100266 DoTest(true_label_, false_label_, fall_through_);
Steve Blockd0582a62009-12-15 09:54:21 +0000267 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000268 }
269}
270
271
Leon Clarked91b9f72010-01-27 17:25:45 +0000272void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
Steve Blockd0582a62009-12-15 09:54:21 +0000273 switch (context) {
274 case Expression::kUninitialized:
275 UNREACHABLE();
276 case Expression::kEffect:
Leon Clarkee46be812010-01-19 14:06:41 +0000277 // Nothing to do.
Steve Blockd0582a62009-12-15 09:54:21 +0000278 break;
279 case Expression::kValue: {
Leon Clarkee46be812010-01-19 14:06:41 +0000280 MemOperand slot_operand = EmitSlotSearch(slot, result_register());
281 switch (location_) {
282 case kAccumulator:
283 __ mov(result_register(), slot_operand);
284 break;
285 case kStack:
286 // Memory operands can be pushed directly.
287 __ push(slot_operand);
288 break;
289 }
Steve Blockd0582a62009-12-15 09:54:21 +0000290 break;
291 }
Leon Clarkee46be812010-01-19 14:06:41 +0000292
293 case Expression::kTest:
294 // For simplicity we always test the accumulator register.
295 Move(result_register(), slot);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100296 DoTest(true_label_, false_label_, fall_through_);
Steve Blockd0582a62009-12-15 09:54:21 +0000297 break;
298 }
299}
300
301
Leon Clarked91b9f72010-01-27 17:25:45 +0000302void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
Steve Blockd0582a62009-12-15 09:54:21 +0000303 switch (context) {
304 case Expression::kUninitialized:
305 UNREACHABLE();
306 case Expression::kEffect:
Leon Clarkee46be812010-01-19 14:06:41 +0000307 // Nothing to do.
Steve Blockd0582a62009-12-15 09:54:21 +0000308 break;
309 case Expression::kValue:
Leon Clarkee46be812010-01-19 14:06:41 +0000310 switch (location_) {
311 case kAccumulator:
312 __ mov(result_register(), lit->handle());
313 break;
314 case kStack:
315 // Immediates can be pushed directly.
316 __ push(Immediate(lit->handle()));
317 break;
318 }
Steve Blockd0582a62009-12-15 09:54:21 +0000319 break;
Leon Clarkee46be812010-01-19 14:06:41 +0000320
321 case Expression::kTest:
322 // For simplicity we always test the accumulator register.
323 __ mov(result_register(), lit->handle());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100324 DoTest(true_label_, false_label_, fall_through_);
Steve Blockd0582a62009-12-15 09:54:21 +0000325 break;
326 }
327}
328
329
Leon Clarked91b9f72010-01-27 17:25:45 +0000330void FullCodeGenerator::ApplyTOS(Expression::Context context) {
Leon Clarkee46be812010-01-19 14:06:41 +0000331 switch (context) {
332 case Expression::kUninitialized:
333 UNREACHABLE();
334
335 case Expression::kEffect:
336 __ Drop(1);
337 break;
338
339 case Expression::kValue:
340 switch (location_) {
341 case kAccumulator:
342 __ pop(result_register());
343 break;
344 case kStack:
345 break;
346 }
347 break;
348
349 case Expression::kTest:
350 // For simplicity we always test the accumulator register.
351 __ pop(result_register());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100352 DoTest(true_label_, false_label_, fall_through_);
Leon Clarkee46be812010-01-19 14:06:41 +0000353 break;
354 }
355}
356
357
Leon Clarked91b9f72010-01-27 17:25:45 +0000358void FullCodeGenerator::DropAndApply(int count,
Leon Clarkee46be812010-01-19 14:06:41 +0000359 Expression::Context context,
360 Register reg) {
361 ASSERT(count > 0);
362 ASSERT(!reg.is(esp));
363 switch (context) {
364 case Expression::kUninitialized:
365 UNREACHABLE();
366
367 case Expression::kEffect:
368 __ Drop(count);
369 break;
370
371 case Expression::kValue:
372 switch (location_) {
373 case kAccumulator:
374 __ Drop(count);
375 if (!reg.is(result_register())) __ mov(result_register(), reg);
376 break;
377 case kStack:
378 if (count > 1) __ Drop(count - 1);
379 __ mov(Operand(esp, 0), reg);
380 break;
381 }
382 break;
383
384 case Expression::kTest:
385 // For simplicity we always test the accumulator register.
386 __ Drop(count);
387 if (!reg.is(result_register())) __ mov(result_register(), reg);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100388 DoTest(true_label_, false_label_, fall_through_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100389 break;
390 }
391}
392
393
Leon Clarked91b9f72010-01-27 17:25:45 +0000394void FullCodeGenerator::Apply(Expression::Context context,
Leon Clarkee46be812010-01-19 14:06:41 +0000395 Label* materialize_true,
396 Label* materialize_false) {
397 switch (context) {
398 case Expression::kUninitialized:
399
400 case Expression::kEffect:
401 ASSERT_EQ(materialize_true, materialize_false);
402 __ bind(materialize_true);
403 break;
404
405 case Expression::kValue: {
406 Label done;
407 switch (location_) {
408 case kAccumulator:
409 __ bind(materialize_true);
410 __ mov(result_register(), Factory::true_value());
411 __ jmp(&done);
412 __ bind(materialize_false);
413 __ mov(result_register(), Factory::false_value());
414 break;
415 case kStack:
416 __ bind(materialize_true);
417 __ push(Immediate(Factory::true_value()));
418 __ jmp(&done);
419 __ bind(materialize_false);
420 __ push(Immediate(Factory::false_value()));
421 break;
422 }
423 __ bind(&done);
424 break;
425 }
426
427 case Expression::kTest:
428 break;
Leon Clarkee46be812010-01-19 14:06:41 +0000429 }
430}
431
432
Leon Clarkef7060e22010-06-03 12:02:55 +0100433// Convert constant control flow (true or false) to the result expected for
434// a given expression context.
435void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
436 switch (context) {
437 case Expression::kUninitialized:
438 UNREACHABLE();
439 break;
440 case Expression::kEffect:
441 break;
442 case Expression::kValue: {
443 Handle<Object> value =
444 flag ? Factory::true_value() : Factory::false_value();
445 switch (location_) {
446 case kAccumulator:
447 __ mov(result_register(), value);
448 break;
449 case kStack:
450 __ push(Immediate(value));
451 break;
452 }
453 break;
454 }
455 case Expression::kTest:
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100456 if (flag) {
457 if (true_label_ != fall_through_) __ jmp(true_label_);
458 } else {
459 if (false_label_ != fall_through_) __ jmp(false_label_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100460 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100461 break;
462 }
463}
464
465
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100466void FullCodeGenerator::DoTest(Label* if_true,
467 Label* if_false,
468 Label* fall_through) {
Leon Clarkee46be812010-01-19 14:06:41 +0000469 // Emit the inlined tests assumed by the stub.
470 __ cmp(result_register(), Factory::undefined_value());
471 __ j(equal, if_false);
472 __ cmp(result_register(), Factory::true_value());
473 __ j(equal, if_true);
474 __ cmp(result_register(), Factory::false_value());
475 __ j(equal, if_false);
476 ASSERT_EQ(0, kSmiTag);
477 __ test(result_register(), Operand(result_register()));
478 __ j(zero, if_false);
479 __ test(result_register(), Immediate(kSmiTagMask));
480 __ j(zero, if_true);
481
Leon Clarkee46be812010-01-19 14:06:41 +0000482 // Call the ToBoolean stub for all other cases.
483 ToBooleanStub stub;
484 __ push(result_register());
485 __ CallStub(&stub);
486 __ test(eax, Operand(eax));
487
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100488 // The stub returns nonzero for true.
489 Split(not_zero, if_true, if_false, fall_through);
490}
Leon Clarkee46be812010-01-19 14:06:41 +0000491
Leon Clarkee46be812010-01-19 14:06:41 +0000492
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100493void FullCodeGenerator::Split(Condition cc,
494 Label* if_true,
495 Label* if_false,
496 Label* fall_through) {
497 if (if_false == fall_through) {
498 __ j(cc, if_true);
499 } else if (if_true == fall_through) {
500 __ j(NegateCondition(cc), if_false);
501 } else {
502 __ j(cc, if_true);
503 __ jmp(if_false);
Leon Clarkee46be812010-01-19 14:06:41 +0000504 }
505}
506
507
Leon Clarked91b9f72010-01-27 17:25:45 +0000508MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
Leon Clarkee46be812010-01-19 14:06:41 +0000509 switch (slot->type()) {
510 case Slot::PARAMETER:
511 case Slot::LOCAL:
512 return Operand(ebp, SlotOffset(slot));
513 case Slot::CONTEXT: {
514 int context_chain_length =
Andrei Popescu31002712010-02-23 13:46:05 +0000515 scope()->ContextChainLength(slot->var()->scope());
Leon Clarkee46be812010-01-19 14:06:41 +0000516 __ LoadContext(scratch, context_chain_length);
Steve Block59151502010-09-22 15:07:15 +0100517 return ContextOperand(scratch, slot->index());
Leon Clarkee46be812010-01-19 14:06:41 +0000518 }
519 case Slot::LOOKUP:
520 UNREACHABLE();
521 }
522 UNREACHABLE();
523 return Operand(eax, 0);
524}
525
526
Leon Clarked91b9f72010-01-27 17:25:45 +0000527void FullCodeGenerator::Move(Register destination, Slot* source) {
Leon Clarkee46be812010-01-19 14:06:41 +0000528 MemOperand location = EmitSlotSearch(source, destination);
529 __ mov(destination, location);
530}
531
532
Leon Clarked91b9f72010-01-27 17:25:45 +0000533void FullCodeGenerator::Move(Slot* dst,
Steve Blockd0582a62009-12-15 09:54:21 +0000534 Register src,
535 Register scratch1,
536 Register scratch2) {
Leon Clarkee46be812010-01-19 14:06:41 +0000537 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
538 ASSERT(!scratch1.is(src) && !scratch2.is(src));
539 MemOperand location = EmitSlotSearch(dst, scratch1);
540 __ mov(location, src);
541 // Emit the write barrier code if the location is in the heap.
542 if (dst->type() == Slot::CONTEXT) {
543 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
544 __ RecordWrite(scratch1, offset, src, scratch2);
Steve Blockd0582a62009-12-15 09:54:21 +0000545 }
546}
547
548
Leon Clarkef7060e22010-06-03 12:02:55 +0100549void FullCodeGenerator::EmitDeclaration(Variable* variable,
550 Variable::Mode mode,
551 FunctionLiteral* function) {
Steve Blockd0582a62009-12-15 09:54:21 +0000552 Comment cmnt(masm_, "[ Declaration");
Leon Clarkef7060e22010-06-03 12:02:55 +0100553 ASSERT(variable != NULL); // Must have been resolved.
554 Slot* slot = variable->slot();
555 Property* prop = variable->AsProperty();
Steve Blockd0582a62009-12-15 09:54:21 +0000556 if (slot != NULL) {
557 switch (slot->type()) {
Leon Clarkee46be812010-01-19 14:06:41 +0000558 case Slot::PARAMETER:
Steve Blockd0582a62009-12-15 09:54:21 +0000559 case Slot::LOCAL:
Leon Clarkef7060e22010-06-03 12:02:55 +0100560 if (mode == Variable::CONST) {
Leon Clarkee46be812010-01-19 14:06:41 +0000561 __ mov(Operand(ebp, SlotOffset(slot)),
Steve Blockd0582a62009-12-15 09:54:21 +0000562 Immediate(Factory::the_hole_value()));
Leon Clarkef7060e22010-06-03 12:02:55 +0100563 } else if (function != NULL) {
564 VisitForValue(function, kAccumulator);
Leon Clarkee46be812010-01-19 14:06:41 +0000565 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
Steve Blockd0582a62009-12-15 09:54:21 +0000566 }
567 break;
568
569 case Slot::CONTEXT:
Leon Clarkee46be812010-01-19 14:06:41 +0000570 // We bypass the general EmitSlotSearch because we know more about
571 // this specific context.
572
Steve Blockd0582a62009-12-15 09:54:21 +0000573 // The variable in the decl always resides in the current context.
Leon Clarkef7060e22010-06-03 12:02:55 +0100574 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
Steve Blockd0582a62009-12-15 09:54:21 +0000575 if (FLAG_debug_code) {
576 // Check if we have the correct context pointer.
Steve Block59151502010-09-22 15:07:15 +0100577 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX));
Steve Blockd0582a62009-12-15 09:54:21 +0000578 __ cmp(ebx, Operand(esi));
579 __ Check(equal, "Unexpected declaration in current context.");
580 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100581 if (mode == Variable::CONST) {
Steve Block59151502010-09-22 15:07:15 +0100582 __ mov(ContextOperand(esi, slot->index()),
Leon Clarkef7060e22010-06-03 12:02:55 +0100583 Immediate(Factory::the_hole_value()));
Steve Blockd0582a62009-12-15 09:54:21 +0000584 // No write barrier since the hole value is in old space.
Leon Clarkef7060e22010-06-03 12:02:55 +0100585 } else if (function != NULL) {
586 VisitForValue(function, kAccumulator);
Steve Block59151502010-09-22 15:07:15 +0100587 __ mov(ContextOperand(esi, slot->index()), result_register());
Steve Blockd0582a62009-12-15 09:54:21 +0000588 int offset = Context::SlotOffset(slot->index());
Leon Clarke4515c472010-02-03 11:58:03 +0000589 __ mov(ebx, esi);
590 __ RecordWrite(ebx, offset, result_register(), ecx);
Steve Blockd0582a62009-12-15 09:54:21 +0000591 }
592 break;
593
594 case Slot::LOOKUP: {
595 __ push(esi);
Leon Clarkef7060e22010-06-03 12:02:55 +0100596 __ push(Immediate(variable->name()));
Steve Blockd0582a62009-12-15 09:54:21 +0000597 // Declaration nodes are always introduced in one of two modes.
Leon Clarkef7060e22010-06-03 12:02:55 +0100598 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
599 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
Steve Blockd0582a62009-12-15 09:54:21 +0000600 __ push(Immediate(Smi::FromInt(attr)));
601 // Push initial value, if any.
602 // Note: For variables we must not push an initial value (such as
603 // 'undefined') because we may have a (legal) redeclaration and we
604 // must not destroy the current value.
Leon Clarkef7060e22010-06-03 12:02:55 +0100605 if (mode == Variable::CONST) {
Steve Blockd0582a62009-12-15 09:54:21 +0000606 __ push(Immediate(Factory::the_hole_value()));
Leon Clarkef7060e22010-06-03 12:02:55 +0100607 } else if (function != NULL) {
608 VisitForValue(function, kStack);
Steve Blockd0582a62009-12-15 09:54:21 +0000609 } else {
610 __ push(Immediate(Smi::FromInt(0))); // No initial value!
611 }
612 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
613 break;
614 }
615 }
616
617 } else if (prop != NULL) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100618 if (function != NULL || mode == Variable::CONST) {
Steve Blockd0582a62009-12-15 09:54:21 +0000619 // We are declaring a function or constant that rewrites to a
620 // property. Use (keyed) IC to set the initial value.
Leon Clarkee46be812010-01-19 14:06:41 +0000621 VisitForValue(prop->obj(), kStack);
Leon Clarkef7060e22010-06-03 12:02:55 +0100622 if (function != NULL) {
Steve Block6ded16b2010-05-10 14:33:55 +0100623 VisitForValue(prop->key(), kStack);
Leon Clarkef7060e22010-06-03 12:02:55 +0100624 VisitForValue(function, kAccumulator);
Steve Block6ded16b2010-05-10 14:33:55 +0100625 __ pop(ecx);
Steve Blockd0582a62009-12-15 09:54:21 +0000626 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100627 VisitForValue(prop->key(), kAccumulator);
628 __ mov(ecx, result_register());
Leon Clarkee46be812010-01-19 14:06:41 +0000629 __ mov(result_register(), Factory::the_hole_value());
Steve Blockd0582a62009-12-15 09:54:21 +0000630 }
Steve Block6ded16b2010-05-10 14:33:55 +0100631 __ pop(edx);
Steve Blockd0582a62009-12-15 09:54:21 +0000632
633 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
634 __ call(ic, RelocInfo::CODE_TARGET);
635 // Absence of a test eax instruction following the call
636 // indicates that none of the load was inlined.
Leon Clarkee46be812010-01-19 14:06:41 +0000637 __ nop();
Steve Blockd0582a62009-12-15 09:54:21 +0000638 }
Steve Block3ce2e202009-11-05 08:53:23 +0000639 }
640}
641
642
Leon Clarkef7060e22010-06-03 12:02:55 +0100643void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
644 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
645}
646
647
Leon Clarked91b9f72010-01-27 17:25:45 +0000648void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
Steve Block3ce2e202009-11-05 08:53:23 +0000649 // Call the runtime to declare the globals.
650 __ push(esi); // The context is the first argument.
651 __ push(Immediate(pairs));
Andrei Popescu31002712010-02-23 13:46:05 +0000652 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
Steve Block3ce2e202009-11-05 08:53:23 +0000653 __ CallRuntime(Runtime::kDeclareGlobals, 3);
654 // Return value is ignored.
655}
656
657
Leon Clarkef7060e22010-06-03 12:02:55 +0100658void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
659 Comment cmnt(masm_, "[ SwitchStatement");
660 Breakable nested_statement(this, stmt);
661 SetStatementPosition(stmt);
662 // Keep the switch value on the stack until a case matches.
663 VisitForValue(stmt->tag(), kStack);
Steve Block3ce2e202009-11-05 08:53:23 +0000664
Leon Clarkef7060e22010-06-03 12:02:55 +0100665 ZoneList<CaseClause*>* clauses = stmt->cases();
666 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
Steve Block3ce2e202009-11-05 08:53:23 +0000667
Leon Clarkef7060e22010-06-03 12:02:55 +0100668 Label next_test; // Recycled for each test.
669 // Compile all the tests with branches to their bodies.
670 for (int i = 0; i < clauses->length(); i++) {
671 CaseClause* clause = clauses->at(i);
672 // The default is not a test, but remember it as final fall through.
673 if (clause->is_default()) {
674 default_clause = clause;
675 continue;
676 }
677
678 Comment cmnt(masm_, "[ Case comparison");
679 __ bind(&next_test);
680 next_test.Unuse();
681
682 // Compile the label expression.
683 VisitForValue(clause->label(), kAccumulator);
684
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100685 // Perform the comparison as if via '==='.
Leon Clarkef7060e22010-06-03 12:02:55 +0100686 __ mov(edx, Operand(esp, 0)); // Switch value.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100687 if (ShouldInlineSmiCase(Token::EQ_STRICT)) {
688 Label slow_case;
689 __ mov(ecx, edx);
690 __ or_(ecx, Operand(eax));
691 __ test(ecx, Immediate(kSmiTagMask));
692 __ j(not_zero, &slow_case, not_taken);
693 __ cmp(edx, Operand(eax));
694 __ j(not_equal, &next_test);
695 __ Drop(1); // Switch value is no longer needed.
696 __ jmp(clause->body_target()->entry_label());
697 __ bind(&slow_case);
698 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100699
Leon Clarkef7060e22010-06-03 12:02:55 +0100700 CompareStub stub(equal, true);
701 __ CallStub(&stub);
702 __ test(eax, Operand(eax));
703 __ j(not_equal, &next_test);
704 __ Drop(1); // Switch value is no longer needed.
705 __ jmp(clause->body_target()->entry_label());
706 }
707
708 // Discard the test value and jump to the default if present, otherwise to
709 // the end of the statement.
710 __ bind(&next_test);
711 __ Drop(1); // Switch value is no longer needed.
712 if (default_clause == NULL) {
713 __ jmp(nested_statement.break_target());
714 } else {
715 __ jmp(default_clause->body_target()->entry_label());
716 }
717
718 // Compile all the case bodies.
719 for (int i = 0; i < clauses->length(); i++) {
720 Comment cmnt(masm_, "[ Case body");
721 CaseClause* clause = clauses->at(i);
722 __ bind(clause->body_target()->entry_label());
723 VisitStatements(clause->statements());
724 }
725
726 __ bind(nested_statement.break_target());
727}
728
729
730void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
731 Comment cmnt(masm_, "[ ForInStatement");
732 SetStatementPosition(stmt);
733
734 Label loop, exit;
735 ForIn loop_statement(this, stmt);
736 increment_loop_depth();
737
738 // Get the object to enumerate over. Both SpiderMonkey and JSC
739 // ignore null and undefined in contrast to the specification; see
740 // ECMA-262 section 12.6.4.
741 VisitForValue(stmt->enumerable(), kAccumulator);
742 __ cmp(eax, Factory::undefined_value());
743 __ j(equal, &exit);
744 __ cmp(eax, Factory::null_value());
745 __ j(equal, &exit);
746
747 // Convert the object to a JS object.
748 Label convert, done_convert;
749 __ test(eax, Immediate(kSmiTagMask));
750 __ j(zero, &convert);
751 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
752 __ j(above_equal, &done_convert);
753 __ bind(&convert);
754 __ push(eax);
755 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
756 __ bind(&done_convert);
757 __ push(eax);
758
Steve Block59151502010-09-22 15:07:15 +0100759 // Check cache validity in generated code. This is a fast case for
760 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
761 // guarantee cache validity, call the runtime system to check cache
762 // validity or get the property names in a fixed array.
763 Label next, call_runtime;
764 __ mov(ecx, eax);
765 __ bind(&next);
766
767 // Check that there are no elements. Register ecx contains the
768 // current JS object we've reached through the prototype chain.
769 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset),
770 Factory::empty_fixed_array());
771 __ j(not_equal, &call_runtime);
772
773 // Check that instance descriptors are not empty so that we can
774 // check for an enum cache. Leave the map in ebx for the subsequent
775 // prototype load.
776 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
777 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
778 __ cmp(edx, Factory::empty_descriptor_array());
779 __ j(equal, &call_runtime);
780
781 // Check that there in an enum cache in the non-empty instance
782 // descriptors (edx). This is the case if the next enumeration
783 // index field does not contain a smi.
784 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
785 __ test(edx, Immediate(kSmiTagMask));
786 __ j(zero, &call_runtime);
787
788 // For all objects but the receiver, check that the cache is empty.
789 Label check_prototype;
790 __ cmp(ecx, Operand(eax));
791 __ j(equal, &check_prototype);
792 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
793 __ cmp(edx, Factory::empty_fixed_array());
794 __ j(not_equal, &call_runtime);
795
796 // Load the prototype from the map and loop if non-null.
797 __ bind(&check_prototype);
798 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
799 __ cmp(ecx, Factory::null_value());
800 __ j(not_equal, &next);
801
802 // The enum cache is valid. Load the map of the object being
803 // iterated over and use the cache for the iteration.
804 Label use_cache;
805 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
806 __ jmp(&use_cache);
Leon Clarkef7060e22010-06-03 12:02:55 +0100807
808 // Get the set of properties to enumerate.
Steve Block59151502010-09-22 15:07:15 +0100809 __ bind(&call_runtime);
Leon Clarkef7060e22010-06-03 12:02:55 +0100810 __ push(eax); // Duplicate the enumerable object on the stack.
811 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
812
813 // If we got a map from the runtime call, we can do a fast
814 // modification check. Otherwise, we got a fixed array, and we have
815 // to do a slow check.
816 Label fixed_array;
817 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map());
818 __ j(not_equal, &fixed_array);
819
820 // We got a map in register eax. Get the enumeration cache from it.
Steve Block59151502010-09-22 15:07:15 +0100821 __ bind(&use_cache);
Leon Clarkef7060e22010-06-03 12:02:55 +0100822 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset));
823 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
824 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
825
826 // Setup the four remaining stack slots.
827 __ push(eax); // Map.
828 __ push(edx); // Enumeration cache.
829 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +0100830 __ push(eax); // Enumeration cache length (as smi).
831 __ push(Immediate(Smi::FromInt(0))); // Initial index.
832 __ jmp(&loop);
833
834 // We got a fixed array in register eax. Iterate through that.
835 __ bind(&fixed_array);
836 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
837 __ push(eax);
838 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +0100839 __ push(eax); // Fixed array length (as smi).
840 __ push(Immediate(Smi::FromInt(0))); // Initial index.
841
842 // Generate code for doing the condition check.
843 __ bind(&loop);
844 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
845 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
846 __ j(above_equal, loop_statement.break_target());
847
848 // Get the current entry of the array into register ebx.
849 __ mov(ebx, Operand(esp, 2 * kPointerSize));
850 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
851
852 // Get the expected map from the stack or a zero map in the
853 // permanent slow case into register edx.
854 __ mov(edx, Operand(esp, 3 * kPointerSize));
855
856 // Check if the expected map still matches that of the enumerable.
857 // If not, we have to filter the key.
858 Label update_each;
859 __ mov(ecx, Operand(esp, 4 * kPointerSize));
860 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
861 __ j(equal, &update_each);
862
863 // Convert the entry to a string or null if it isn't a property
864 // anymore. If the property has been removed while iterating, we
865 // just skip it.
866 __ push(ecx); // Enumerable.
867 __ push(ebx); // Current entry.
868 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
Iain Merrick75681382010-08-19 15:07:18 +0100869 __ test(eax, Operand(eax));
Leon Clarkef7060e22010-06-03 12:02:55 +0100870 __ j(equal, loop_statement.continue_target());
871 __ mov(ebx, Operand(eax));
872
873 // Update the 'each' property or variable from the possibly filtered
874 // entry in register ebx.
875 __ bind(&update_each);
876 __ mov(result_register(), ebx);
877 // Perform the assignment as if via '='.
878 EmitAssignment(stmt->each());
879
880 // Generate code for the body of the loop.
881 Label stack_limit_hit, stack_check_done;
882 Visit(stmt->body());
883
884 __ StackLimitCheck(&stack_limit_hit);
885 __ bind(&stack_check_done);
886
887 // Generate code for going to the next element by incrementing the
888 // index (smi) stored on top of the stack.
889 __ bind(loop_statement.continue_target());
890 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
891 __ jmp(&loop);
892
893 // Slow case for the stack limit check.
894 StackCheckStub stack_check_stub;
895 __ bind(&stack_limit_hit);
896 __ CallStub(&stack_check_stub);
897 __ jmp(&stack_check_done);
898
899 // Remove the pointers stored on the stack.
900 __ bind(loop_statement.break_target());
901 __ add(Operand(esp), Immediate(5 * kPointerSize));
902
903 // Exit and decrement the loop depth.
904 __ bind(&exit);
905 decrement_loop_depth();
906}
907
908
909void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
910 // Use the fast case closure allocation code that allocates in new
911 // space for nested functions that don't need literals cloning.
912 if (scope()->is_function_scope() && info->num_literals() == 0) {
913 FastNewClosureStub stub;
914 __ push(Immediate(info));
915 __ CallStub(&stub);
916 } else {
917 __ push(esi);
918 __ push(Immediate(info));
919 __ CallRuntime(Runtime::kNewClosure, 2);
920 }
Leon Clarkee46be812010-01-19 14:06:41 +0000921 Apply(context_, eax);
Steve Block3ce2e202009-11-05 08:53:23 +0000922}
923
924
Leon Clarked91b9f72010-01-27 17:25:45 +0000925void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +0000926 Comment cmnt(masm_, "[ VariableProxy");
Leon Clarkee46be812010-01-19 14:06:41 +0000927 EmitVariableLoad(expr->var(), context_);
928}
929
930
Steve Block59151502010-09-22 15:07:15 +0100931void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
932 Slot* slot,
933 TypeofState typeof_state,
934 Label* slow) {
935 Register context = esi;
936 Register temp = edx;
937
938 Scope* s = scope();
939 while (s != NULL) {
940 if (s->num_heap_slots() > 0) {
941 if (s->calls_eval()) {
942 // Check that extension is NULL.
943 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
944 Immediate(0));
945 __ j(not_equal, slow);
946 }
947 // Load next context in chain.
948 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
949 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
950 // Walk the rest of the chain without clobbering esi.
951 context = temp;
952 }
953 // If no outer scope calls eval, we do not need to check more
954 // context extensions. If we have reached an eval scope, we check
955 // all extensions from this point.
956 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
957 s = s->outer_scope();
958 }
959
960 if (s != NULL && s->is_eval_scope()) {
961 // Loop up the context chain. There is no frame effect so it is
962 // safe to use raw labels here.
963 Label next, fast;
964 if (!context.is(temp)) {
965 __ mov(temp, context);
966 }
967 __ bind(&next);
968 // Terminate at global context.
969 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
970 Immediate(Factory::global_context_map()));
971 __ j(equal, &fast);
972 // Check that extension is NULL.
973 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
974 __ j(not_equal, slow);
975 // Load next context in chain.
976 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX));
977 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
978 __ jmp(&next);
979 __ bind(&fast);
980 }
981
982 // All extension objects were empty and it is safe to use a global
983 // load IC call.
984 __ mov(eax, CodeGenerator::GlobalObject());
985 __ mov(ecx, slot->var()->name());
986 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
987 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
988 ? RelocInfo::CODE_TARGET
989 : RelocInfo::CODE_TARGET_CONTEXT;
990 __ call(ic, mode);
991}
992
993
994MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
995 Slot* slot,
996 Label* slow) {
997 ASSERT(slot->type() == Slot::CONTEXT);
998 Register context = esi;
999 Register temp = ebx;
1000
1001 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1002 if (s->num_heap_slots() > 0) {
1003 if (s->calls_eval()) {
1004 // Check that extension is NULL.
1005 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1006 Immediate(0));
1007 __ j(not_equal, slow);
1008 }
1009 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1010 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
1011 // Walk the rest of the chain without clobbering esi.
1012 context = temp;
1013 }
1014 }
1015 // Check that last extension is NULL.
1016 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1017 __ j(not_equal, slow);
1018 __ mov(temp, ContextOperand(context, Context::FCONTEXT_INDEX));
1019 return ContextOperand(temp, slot->index());
1020}
1021
1022
1023void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1024 Slot* slot,
1025 TypeofState typeof_state,
1026 Label* slow,
1027 Label* done) {
1028 // Generate fast-case code for variables that might be shadowed by
1029 // eval-introduced variables. Eval is used a lot without
1030 // introducing variables. In those cases, we do not want to
1031 // perform a runtime call for all variables in the scope
1032 // containing the eval.
1033 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1034 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1035 __ jmp(done);
1036 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
1037 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
1038 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1039 if (potential_slot != NULL) {
1040 // Generate fast case for locals that rewrite to slots.
1041 __ mov(eax,
1042 ContextSlotOperandCheckExtensions(potential_slot, slow));
1043 if (potential_slot->var()->mode() == Variable::CONST) {
1044 __ cmp(eax, Factory::the_hole_value());
1045 __ j(not_equal, done);
1046 __ mov(eax, Factory::undefined_value());
1047 }
1048 __ jmp(done);
1049 } else if (rewrite != NULL) {
1050 // Generate fast case for calls of an argument function.
1051 Property* property = rewrite->AsProperty();
1052 if (property != NULL) {
1053 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1054 Literal* key_literal = property->key()->AsLiteral();
1055 if (obj_proxy != NULL &&
1056 key_literal != NULL &&
1057 obj_proxy->IsArguments() &&
1058 key_literal->handle()->IsSmi()) {
1059 // Load arguments object if there are no eval-introduced
1060 // variables. Then load the argument from the arguments
1061 // object using keyed load.
1062 __ mov(edx,
1063 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
1064 slow));
1065 __ mov(eax, Immediate(key_literal->handle()));
1066 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1067 __ call(ic, RelocInfo::CODE_TARGET);
1068 __ jmp(done);
1069 }
1070 }
1071 }
1072 }
1073}
1074
1075
Leon Clarked91b9f72010-01-27 17:25:45 +00001076void FullCodeGenerator::EmitVariableLoad(Variable* var,
Leon Clarkee46be812010-01-19 14:06:41 +00001077 Expression::Context context) {
Leon Clarked91b9f72010-01-27 17:25:45 +00001078 // Four cases: non-this global variables, lookup slots, all other
1079 // types of slots, and parameters that rewrite to explicit property
1080 // accesses on the arguments object.
1081 Slot* slot = var->slot();
1082 Property* property = var->AsProperty();
1083
1084 if (var->is_global() && !var->is_this()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001085 Comment cmnt(masm_, "Global variable");
1086 // Use inline caching. Variable name is passed in ecx and the global
1087 // object on the stack.
Andrei Popescu402d9372010-02-26 13:31:12 +00001088 __ mov(eax, CodeGenerator::GlobalObject());
Leon Clarkee46be812010-01-19 14:06:41 +00001089 __ mov(ecx, var->name());
Steve Block3ce2e202009-11-05 08:53:23 +00001090 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1091 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
Steve Blockd0582a62009-12-15 09:54:21 +00001092 // By emitting a nop we make sure that we do not have a test eax
1093 // instruction after the call it is treated specially by the LoadIC code
1094 // Remember that the assembler may choose to do peephole optimization
1095 // (eg, push/pop elimination).
1096 __ nop();
Andrei Popescu402d9372010-02-26 13:31:12 +00001097 Apply(context, eax);
Leon Clarkeeab96aa2010-01-27 16:31:12 +00001098
Leon Clarked91b9f72010-01-27 17:25:45 +00001099 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
Steve Block59151502010-09-22 15:07:15 +01001100 Label done, slow;
1101
1102 // Generate code for loading from variables potentially shadowed
1103 // by eval-introduced variables.
1104 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1105
1106 __ bind(&slow);
Leon Clarked91b9f72010-01-27 17:25:45 +00001107 Comment cmnt(masm_, "Lookup slot");
1108 __ push(esi); // Context.
1109 __ push(Immediate(var->name()));
1110 __ CallRuntime(Runtime::kLoadContextSlot, 2);
Steve Block59151502010-09-22 15:07:15 +01001111 __ bind(&done);
1112
Leon Clarked91b9f72010-01-27 17:25:45 +00001113 Apply(context, eax);
1114
1115 } else if (slot != NULL) {
1116 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1117 ? "Context slot"
1118 : "Stack slot");
Leon Clarkef7060e22010-06-03 12:02:55 +01001119 if (var->mode() == Variable::CONST) {
1120 // Constants may be the hole value if they have not been initialized.
1121 // Unhole them.
1122 Label done;
1123 MemOperand slot_operand = EmitSlotSearch(slot, eax);
1124 __ mov(eax, slot_operand);
1125 __ cmp(eax, Factory::the_hole_value());
1126 __ j(not_equal, &done);
1127 __ mov(eax, Factory::undefined_value());
1128 __ bind(&done);
1129 Apply(context, eax);
1130 } else {
1131 Apply(context, slot);
1132 }
Leon Clarked91b9f72010-01-27 17:25:45 +00001133
1134 } else {
1135 Comment cmnt(masm_, "Rewritten parameter");
1136 ASSERT_NOT_NULL(property);
1137 // Rewritten parameter accesses are of the form "slot[literal]".
Steve Blockd0582a62009-12-15 09:54:21 +00001138
Leon Clarkee46be812010-01-19 14:06:41 +00001139 // Assert that the object is in a slot.
Steve Blockd0582a62009-12-15 09:54:21 +00001140 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1141 ASSERT_NOT_NULL(object_var);
1142 Slot* object_slot = object_var->slot();
1143 ASSERT_NOT_NULL(object_slot);
1144
1145 // Load the object.
Leon Clarkee46be812010-01-19 14:06:41 +00001146 MemOperand object_loc = EmitSlotSearch(object_slot, eax);
Andrei Popescu402d9372010-02-26 13:31:12 +00001147 __ mov(edx, object_loc);
Steve Blockd0582a62009-12-15 09:54:21 +00001148
Leon Clarkee46be812010-01-19 14:06:41 +00001149 // Assert that the key is a smi.
Steve Blockd0582a62009-12-15 09:54:21 +00001150 Literal* key_literal = property->key()->AsLiteral();
1151 ASSERT_NOT_NULL(key_literal);
1152 ASSERT(key_literal->handle()->IsSmi());
1153
1154 // Load the key.
Andrei Popescu402d9372010-02-26 13:31:12 +00001155 __ mov(eax, Immediate(key_literal->handle()));
Steve Blockd0582a62009-12-15 09:54:21 +00001156
Leon Clarkee46be812010-01-19 14:06:41 +00001157 // Do a keyed property load.
Steve Blockd0582a62009-12-15 09:54:21 +00001158 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1159 __ call(ic, RelocInfo::CODE_TARGET);
Leon Clarkee46be812010-01-19 14:06:41 +00001160 // Notice: We must not have a "test eax, ..." instruction after the
1161 // call. It is treated specially by the LoadIC code.
Steve Blockd0582a62009-12-15 09:54:21 +00001162 __ nop();
Leon Clarkee46be812010-01-19 14:06:41 +00001163 // Drop key and object left on the stack by IC.
Andrei Popescu402d9372010-02-26 13:31:12 +00001164 Apply(context, eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001165 }
1166}
1167
1168
Leon Clarked91b9f72010-01-27 17:25:45 +00001169void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001170 Comment cmnt(masm_, "[ RegExpLiteral");
Ben Murdochbb769b22010-08-11 14:56:33 +01001171 Label materialized;
Steve Block3ce2e202009-11-05 08:53:23 +00001172 // Registers will be used as follows:
1173 // edi = JS function.
Ben Murdochbb769b22010-08-11 14:56:33 +01001174 // ecx = literals array.
1175 // ebx = regexp literal.
1176 // eax = regexp literal clone.
Steve Block3ce2e202009-11-05 08:53:23 +00001177 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdochbb769b22010-08-11 14:56:33 +01001178 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001179 int literal_offset =
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001180 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
Ben Murdochbb769b22010-08-11 14:56:33 +01001181 __ mov(ebx, FieldOperand(ecx, literal_offset));
1182 __ cmp(ebx, Factory::undefined_value());
1183 __ j(not_equal, &materialized);
1184
Steve Block3ce2e202009-11-05 08:53:23 +00001185 // Create regexp literal using runtime function
1186 // Result will be in eax.
Ben Murdochbb769b22010-08-11 14:56:33 +01001187 __ push(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001188 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1189 __ push(Immediate(expr->pattern()));
1190 __ push(Immediate(expr->flags()));
1191 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
Ben Murdochbb769b22010-08-11 14:56:33 +01001192 __ mov(ebx, eax);
1193
1194 __ bind(&materialized);
1195 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1196 Label allocated, runtime_allocate;
1197 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1198 __ jmp(&allocated);
1199
1200 __ bind(&runtime_allocate);
1201 __ push(ebx);
1202 __ push(Immediate(Smi::FromInt(size)));
1203 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1204 __ pop(ebx);
1205
1206 __ bind(&allocated);
1207 // Copy the content into the newly allocated memory.
1208 // (Unroll copy loop once for better throughput).
1209 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1210 __ mov(edx, FieldOperand(ebx, i));
1211 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1212 __ mov(FieldOperand(eax, i), edx);
1213 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1214 }
1215 if ((size % (2 * kPointerSize)) != 0) {
1216 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1217 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1218 }
Leon Clarkee46be812010-01-19 14:06:41 +00001219 Apply(context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00001220}
1221
1222
Leon Clarked91b9f72010-01-27 17:25:45 +00001223void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001224 Comment cmnt(masm_, "[ ObjectLiteral");
Steve Blockd0582a62009-12-15 09:54:21 +00001225 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00001226 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
Steve Blockd0582a62009-12-15 09:54:21 +00001227 __ push(Immediate(Smi::FromInt(expr->literal_index())));
Steve Blockd0582a62009-12-15 09:54:21 +00001228 __ push(Immediate(expr->constant_properties()));
Steve Block6ded16b2010-05-10 14:33:55 +01001229 __ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
Leon Clarkee46be812010-01-19 14:06:41 +00001230 if (expr->depth() > 1) {
Steve Block6ded16b2010-05-10 14:33:55 +01001231 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
Steve Block3ce2e202009-11-05 08:53:23 +00001232 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001233 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
Steve Blockd0582a62009-12-15 09:54:21 +00001234 }
1235
Leon Clarkee46be812010-01-19 14:06:41 +00001236 // If result_saved is true the result is on top of the stack. If
1237 // result_saved is false the result is in eax.
Steve Blockd0582a62009-12-15 09:54:21 +00001238 bool result_saved = false;
1239
1240 for (int i = 0; i < expr->properties()->length(); i++) {
1241 ObjectLiteral::Property* property = expr->properties()->at(i);
1242 if (property->IsCompileTimeValue()) continue;
1243
1244 Literal* key = property->key();
1245 Expression* value = property->value();
1246 if (!result_saved) {
1247 __ push(eax); // Save result on the stack
1248 result_saved = true;
1249 }
1250 switch (property->kind()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001251 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
Steve Blockd0582a62009-12-15 09:54:21 +00001252 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
Leon Clarkee46be812010-01-19 14:06:41 +00001253 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001254 case ObjectLiteral::Property::COMPUTED:
1255 if (key->handle()->IsSymbol()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001256 VisitForValue(value, kAccumulator);
Steve Blockd0582a62009-12-15 09:54:21 +00001257 __ mov(ecx, Immediate(key->handle()));
Leon Clarke4515c472010-02-03 11:58:03 +00001258 __ mov(edx, Operand(esp, 0));
Steve Blockd0582a62009-12-15 09:54:21 +00001259 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1260 __ call(ic, RelocInfo::CODE_TARGET);
Leon Clarkee46be812010-01-19 14:06:41 +00001261 __ nop();
Steve Blockd0582a62009-12-15 09:54:21 +00001262 break;
1263 }
Leon Clarkee46be812010-01-19 14:06:41 +00001264 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001265 case ObjectLiteral::Property::PROTOTYPE:
Leon Clarkee46be812010-01-19 14:06:41 +00001266 __ push(Operand(esp, 0)); // Duplicate receiver.
1267 VisitForValue(key, kStack);
1268 VisitForValue(value, kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00001269 __ CallRuntime(Runtime::kSetProperty, 3);
Steve Blockd0582a62009-12-15 09:54:21 +00001270 break;
Leon Clarkee46be812010-01-19 14:06:41 +00001271 case ObjectLiteral::Property::SETTER:
Steve Blockd0582a62009-12-15 09:54:21 +00001272 case ObjectLiteral::Property::GETTER:
Leon Clarkee46be812010-01-19 14:06:41 +00001273 __ push(Operand(esp, 0)); // Duplicate receiver.
1274 VisitForValue(key, kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00001275 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
1276 Smi::FromInt(1) :
1277 Smi::FromInt(0)));
Leon Clarkee46be812010-01-19 14:06:41 +00001278 VisitForValue(value, kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00001279 __ CallRuntime(Runtime::kDefineAccessor, 4);
Steve Blockd0582a62009-12-15 09:54:21 +00001280 break;
1281 default: UNREACHABLE();
1282 }
1283 }
Leon Clarkee46be812010-01-19 14:06:41 +00001284
1285 if (result_saved) {
1286 ApplyTOS(context_);
1287 } else {
1288 Apply(context_, eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001289 }
1290}
1291
1292
Leon Clarked91b9f72010-01-27 17:25:45 +00001293void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001294 Comment cmnt(masm_, "[ ArrayLiteral");
Leon Clarkef7060e22010-06-03 12:02:55 +01001295
1296 ZoneList<Expression*>* subexprs = expr->values();
1297 int length = subexprs->length();
1298
Steve Block3ce2e202009-11-05 08:53:23 +00001299 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00001300 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001301 __ push(Immediate(Smi::FromInt(expr->literal_index())));
Leon Clarkee46be812010-01-19 14:06:41 +00001302 __ push(Immediate(expr->constant_elements()));
Iain Merrick75681382010-08-19 15:07:18 +01001303 if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
1304 FastCloneShallowArrayStub stub(
1305 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1306 __ CallStub(&stub);
1307 __ IncrementCounter(&Counters::cow_arrays_created_stub, 1);
1308 } else if (expr->depth() > 1) {
Leon Clarkee46be812010-01-19 14:06:41 +00001309 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
Iain Merrick75681382010-08-19 15:07:18 +01001310 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
Leon Clarkee46be812010-01-19 14:06:41 +00001311 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01001312 } else {
Iain Merrick75681382010-08-19 15:07:18 +01001313 FastCloneShallowArrayStub stub(
1314 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
Leon Clarkef7060e22010-06-03 12:02:55 +01001315 __ CallStub(&stub);
Steve Block3ce2e202009-11-05 08:53:23 +00001316 }
1317
1318 bool result_saved = false; // Is the result saved to the stack?
1319
1320 // Emit code to evaluate all the non-constant subexpressions and to store
1321 // them into the newly cloned array.
Leon Clarkef7060e22010-06-03 12:02:55 +01001322 for (int i = 0; i < length; i++) {
Steve Block3ce2e202009-11-05 08:53:23 +00001323 Expression* subexpr = subexprs->at(i);
1324 // If the subexpression is a literal or a simple materialized literal it
1325 // is already set in the cloned array.
1326 if (subexpr->AsLiteral() != NULL ||
1327 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1328 continue;
1329 }
1330
1331 if (!result_saved) {
1332 __ push(eax);
1333 result_saved = true;
1334 }
Leon Clarkee46be812010-01-19 14:06:41 +00001335 VisitForValue(subexpr, kAccumulator);
Steve Block3ce2e202009-11-05 08:53:23 +00001336
1337 // Store the subexpression value in the array's elements.
Steve Block3ce2e202009-11-05 08:53:23 +00001338 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1339 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1340 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
Leon Clarkee46be812010-01-19 14:06:41 +00001341 __ mov(FieldOperand(ebx, offset), result_register());
Steve Block3ce2e202009-11-05 08:53:23 +00001342
1343 // Update the write barrier for the array store.
Leon Clarkee46be812010-01-19 14:06:41 +00001344 __ RecordWrite(ebx, offset, result_register(), ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001345 }
1346
Leon Clarkee46be812010-01-19 14:06:41 +00001347 if (result_saved) {
1348 ApplyTOS(context_);
1349 } else {
1350 Apply(context_, eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001351 }
1352}
1353
1354
Andrei Popescu402d9372010-02-26 13:31:12 +00001355void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1356 Comment cmnt(masm_, "[ Assignment");
Leon Clarkef7060e22010-06-03 12:02:55 +01001357 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1358 // on the left-hand side.
1359 if (!expr->target()->IsValidLeftHandSide()) {
1360 VisitForEffect(expr->target());
1361 return;
1362 }
1363
Andrei Popescu402d9372010-02-26 13:31:12 +00001364 // Left-hand side can only be a property, a global or a (parameter or local)
1365 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1366 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1367 LhsKind assign_type = VARIABLE;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001368 Property* property = expr->target()->AsProperty();
1369 if (property != NULL) {
1370 assign_type = (property->key()->IsPropertyName())
1371 ? NAMED_PROPERTY
1372 : KEYED_PROPERTY;
Andrei Popescu402d9372010-02-26 13:31:12 +00001373 }
1374
1375 // Evaluate LHS expression.
1376 switch (assign_type) {
1377 case VARIABLE:
1378 // Nothing to do here.
1379 break;
1380 case NAMED_PROPERTY:
1381 if (expr->is_compound()) {
1382 // We need the receiver both on the stack and in the accumulator.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001383 VisitForValue(property->obj(), kAccumulator);
Andrei Popescu402d9372010-02-26 13:31:12 +00001384 __ push(result_register());
1385 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001386 VisitForValue(property->obj(), kStack);
Andrei Popescu402d9372010-02-26 13:31:12 +00001387 }
1388 break;
1389 case KEYED_PROPERTY:
1390 if (expr->is_compound()) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001391 VisitForValue(property->obj(), kStack);
1392 VisitForValue(property->key(), kAccumulator);
Andrei Popescu402d9372010-02-26 13:31:12 +00001393 __ mov(edx, Operand(esp, 0));
1394 __ push(eax);
1395 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001396 VisitForValue(property->obj(), kStack);
1397 VisitForValue(property->key(), kStack);
Andrei Popescu402d9372010-02-26 13:31:12 +00001398 }
1399 break;
1400 }
1401
Andrei Popescu402d9372010-02-26 13:31:12 +00001402 if (expr->is_compound()) {
1403 Location saved_location = location_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001404 location_ = kAccumulator;
Andrei Popescu402d9372010-02-26 13:31:12 +00001405 switch (assign_type) {
1406 case VARIABLE:
1407 EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
1408 Expression::kValue);
1409 break;
1410 case NAMED_PROPERTY:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001411 EmitNamedPropertyLoad(property);
Andrei Popescu402d9372010-02-26 13:31:12 +00001412 break;
1413 case KEYED_PROPERTY:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001414 EmitKeyedPropertyLoad(property);
Andrei Popescu402d9372010-02-26 13:31:12 +00001415 break;
1416 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001417
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001418 Token::Value op = expr->binary_op();
1419 ConstantOperand constant = ShouldInlineSmiCase(op)
1420 ? GetConstantOperand(op, expr->target(), expr->value())
1421 : kNoConstants;
1422 ASSERT(constant == kRightConstant || constant == kNoConstants);
1423 if (constant == kNoConstants) {
1424 __ push(eax); // Left operand goes on the stack.
1425 VisitForValue(expr->value(), kAccumulator);
1426 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001427
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001428 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1429 ? OVERWRITE_RIGHT
1430 : NO_OVERWRITE;
1431 SetSourcePosition(expr->position() + 1);
1432 if (ShouldInlineSmiCase(op)) {
1433 EmitInlineSmiBinaryOp(expr,
1434 op,
1435 Expression::kValue,
1436 mode,
1437 expr->target(),
1438 expr->value(),
1439 constant);
1440 } else {
1441 EmitBinaryOp(op, Expression::kValue, mode);
1442 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001443 location_ = saved_location;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001444
1445 } else {
1446 VisitForValue(expr->value(), kAccumulator);
Andrei Popescu402d9372010-02-26 13:31:12 +00001447 }
1448
1449 // Record source position before possible IC call.
1450 SetSourcePosition(expr->position());
1451
1452 // Store the value.
1453 switch (assign_type) {
1454 case VARIABLE:
1455 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
Leon Clarkef7060e22010-06-03 12:02:55 +01001456 expr->op(),
Andrei Popescu402d9372010-02-26 13:31:12 +00001457 context_);
1458 break;
1459 case NAMED_PROPERTY:
1460 EmitNamedPropertyAssignment(expr);
1461 break;
1462 case KEYED_PROPERTY:
1463 EmitKeyedPropertyAssignment(expr);
1464 break;
1465 }
1466}
1467
1468
Leon Clarked91b9f72010-01-27 17:25:45 +00001469void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00001470 SetSourcePosition(prop->position());
1471 Literal* key = prop->key()->AsLiteral();
1472 __ mov(ecx, Immediate(key->handle()));
1473 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1474 __ call(ic, RelocInfo::CODE_TARGET);
1475 __ nop();
1476}
1477
1478
Leon Clarked91b9f72010-01-27 17:25:45 +00001479void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00001480 SetSourcePosition(prop->position());
1481 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1482 __ call(ic, RelocInfo::CODE_TARGET);
1483 __ nop();
1484}
1485
1486
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001487void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
1488 Expression::Context context,
1489 OverwriteMode mode,
1490 bool left_is_constant_smi,
1491 Smi* value) {
1492 Label call_stub, done;
1493 __ add(Operand(eax), Immediate(value));
1494 __ j(overflow, &call_stub);
1495 __ test(eax, Immediate(kSmiTagMask));
1496 __ j(zero, &done);
1497
1498 // Undo the optimistic add operation and call the shared stub.
1499 __ bind(&call_stub);
1500 __ sub(Operand(eax), Immediate(value));
1501 Token::Value op = Token::ADD;
1502 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1503 if (left_is_constant_smi) {
1504 __ push(Immediate(value));
1505 __ push(eax);
1506 } else {
1507 __ push(eax);
1508 __ push(Immediate(value));
1509 }
Leon Clarkee46be812010-01-19 14:06:41 +00001510 __ CallStub(&stub);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001511 __ bind(&done);
1512 Apply(context, eax);
1513}
1514
1515
1516void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
1517 Expression::Context context,
1518 OverwriteMode mode,
1519 bool left_is_constant_smi,
1520 Smi* value) {
1521 Label call_stub, done;
1522 if (left_is_constant_smi) {
1523 __ mov(ecx, eax);
1524 __ mov(eax, Immediate(value));
1525 __ sub(Operand(eax), ecx);
1526 } else {
1527 __ sub(Operand(eax), Immediate(value));
1528 }
1529 __ j(overflow, &call_stub);
1530 __ test(eax, Immediate(kSmiTagMask));
1531 __ j(zero, &done);
1532
1533 __ bind(&call_stub);
1534 if (left_is_constant_smi) {
1535 __ push(Immediate(value));
1536 __ push(ecx);
1537 } else {
1538 // Undo the optimistic sub operation.
1539 __ add(Operand(eax), Immediate(value));
1540
1541 __ push(eax);
1542 __ push(Immediate(value));
1543 }
1544
1545 Token::Value op = Token::SUB;
1546 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1547 __ CallStub(&stub);
1548 __ bind(&done);
1549 Apply(context, eax);
1550}
1551
1552
1553void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
1554 Token::Value op,
1555 Expression::Context context,
1556 OverwriteMode mode,
1557 Smi* value) {
1558 Label call_stub, smi_case, done;
1559 int shift_value = value->value() & 0x1f;
1560
1561 __ test(eax, Immediate(kSmiTagMask));
1562 __ j(zero, &smi_case);
1563
1564 __ bind(&call_stub);
1565 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1566 __ push(eax);
1567 __ push(Immediate(value));
1568 __ CallStub(&stub);
1569 __ jmp(&done);
1570
1571 __ bind(&smi_case);
1572 switch (op) {
1573 case Token::SHL:
1574 if (shift_value != 0) {
1575 __ mov(edx, eax);
1576 if (shift_value > 1) {
1577 __ shl(edx, shift_value - 1);
1578 }
1579 // Convert int result to smi, checking that it is in int range.
1580 ASSERT(kSmiTagSize == 1); // Adjust code if not the case.
1581 __ add(edx, Operand(edx));
1582 __ j(overflow, &call_stub);
1583 __ mov(eax, edx); // Put result back into eax.
1584 }
1585 break;
1586 case Token::SAR:
1587 if (shift_value != 0) {
1588 __ sar(eax, shift_value);
1589 __ and_(eax, ~kSmiTagMask);
1590 }
1591 break;
1592 case Token::SHR:
1593 if (shift_value < 2) {
1594 __ mov(edx, eax);
1595 __ SmiUntag(edx);
1596 __ shr(edx, shift_value);
1597 __ test(edx, Immediate(0xc0000000));
1598 __ j(not_zero, &call_stub);
1599 __ SmiTag(edx);
1600 __ mov(eax, edx); // Put result back into eax.
1601 } else {
1602 __ SmiUntag(eax);
1603 __ shr(eax, shift_value);
1604 __ SmiTag(eax);
1605 }
1606 break;
1607 default:
1608 UNREACHABLE();
1609 }
1610
1611 __ bind(&done);
1612 Apply(context, eax);
1613}
1614
1615
1616void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
1617 Token::Value op,
1618 Expression::Context context,
1619 OverwriteMode mode,
1620 Smi* value) {
1621 Label smi_case, done;
1622 __ test(eax, Immediate(kSmiTagMask));
1623 __ j(zero, &smi_case);
1624
1625 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1626 // The order of the arguments does not matter for bit-ops with a
1627 // constant operand.
1628 __ push(Immediate(value));
1629 __ push(eax);
1630 __ CallStub(&stub);
1631 __ jmp(&done);
1632
1633 __ bind(&smi_case);
1634 switch (op) {
1635 case Token::BIT_OR:
1636 __ or_(Operand(eax), Immediate(value));
1637 break;
1638 case Token::BIT_XOR:
1639 __ xor_(Operand(eax), Immediate(value));
1640 break;
1641 case Token::BIT_AND:
1642 __ and_(Operand(eax), Immediate(value));
1643 break;
1644 default:
1645 UNREACHABLE();
1646 }
1647
1648 __ bind(&done);
1649 Apply(context, eax);
1650}
1651
1652
1653void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
1654 Token::Value op,
1655 Expression::Context context,
1656 OverwriteMode mode,
1657 bool left_is_constant_smi,
1658 Smi* value) {
1659 switch (op) {
1660 case Token::BIT_OR:
1661 case Token::BIT_XOR:
1662 case Token::BIT_AND:
1663 EmitConstantSmiBitOp(expr, op, context, mode, value);
1664 break;
1665 case Token::SHL:
1666 case Token::SAR:
1667 case Token::SHR:
1668 ASSERT(!left_is_constant_smi);
1669 EmitConstantSmiShiftOp(expr, op, context, mode, value);
1670 break;
1671 case Token::ADD:
1672 EmitConstantSmiAdd(expr, context, mode, left_is_constant_smi, value);
1673 break;
1674 case Token::SUB:
1675 EmitConstantSmiSub(expr, context, mode, left_is_constant_smi, value);
1676 break;
1677 default:
1678 UNREACHABLE();
1679 }
1680}
1681
1682
1683void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1684 Token::Value op,
1685 Expression::Context context,
1686 OverwriteMode mode,
1687 Expression* left,
1688 Expression* right,
1689 ConstantOperand constant) {
1690 if (constant == kRightConstant) {
1691 Smi* value = Smi::cast(*right->AsLiteral()->handle());
1692 EmitConstantSmiBinaryOp(expr, op, context, mode, false, value);
1693 return;
1694 } else if (constant == kLeftConstant) {
1695 Smi* value = Smi::cast(*left->AsLiteral()->handle());
1696 EmitConstantSmiBinaryOp(expr, op, context, mode, true, value);
1697 return;
1698 }
1699
1700 // Do combined smi check of the operands. Left operand is on the
1701 // stack. Right operand is in eax.
1702 Label done, stub_call, smi_case;
1703 __ pop(edx);
1704 __ mov(ecx, eax);
1705 __ or_(eax, Operand(edx));
1706 __ test(eax, Immediate(kSmiTagMask));
1707 __ j(zero, &smi_case);
1708
1709 __ bind(&stub_call);
1710 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
1711 if (stub.ArgsInRegistersSupported()) {
1712 stub.GenerateCall(masm_, edx, ecx);
1713 } else {
1714 __ push(edx);
1715 __ push(ecx);
1716 __ CallStub(&stub);
1717 }
1718 __ jmp(&done);
1719
1720 __ bind(&smi_case);
1721 __ mov(eax, edx); // Copy left operand in case of a stub call.
1722
1723 switch (op) {
1724 case Token::SAR:
1725 __ SmiUntag(eax);
1726 __ SmiUntag(ecx);
1727 __ sar_cl(eax); // No checks of result necessary
1728 __ SmiTag(eax);
1729 break;
1730 case Token::SHL: {
1731 Label result_ok;
1732 __ SmiUntag(eax);
1733 __ SmiUntag(ecx);
1734 __ shl_cl(eax);
1735 // Check that the *signed* result fits in a smi.
1736 __ cmp(eax, 0xc0000000);
1737 __ j(positive, &result_ok);
1738 __ SmiTag(ecx);
1739 __ jmp(&stub_call);
1740 __ bind(&result_ok);
1741 __ SmiTag(eax);
1742 break;
1743 }
1744 case Token::SHR: {
1745 Label result_ok;
1746 __ SmiUntag(eax);
1747 __ SmiUntag(ecx);
1748 __ shr_cl(eax);
1749 __ test(eax, Immediate(0xc0000000));
1750 __ j(zero, &result_ok);
1751 __ SmiTag(ecx);
1752 __ jmp(&stub_call);
1753 __ bind(&result_ok);
1754 __ SmiTag(eax);
1755 break;
1756 }
1757 case Token::ADD:
1758 __ add(eax, Operand(ecx));
1759 __ j(overflow, &stub_call);
1760 break;
1761 case Token::SUB:
1762 __ sub(eax, Operand(ecx));
1763 __ j(overflow, &stub_call);
1764 break;
1765 case Token::MUL: {
1766 __ SmiUntag(eax);
1767 __ imul(eax, Operand(ecx));
1768 __ j(overflow, &stub_call);
1769 __ test(eax, Operand(eax));
1770 __ j(not_zero, &done, taken);
1771 __ mov(ebx, edx);
1772 __ or_(ebx, Operand(ecx));
1773 __ j(negative, &stub_call);
1774 break;
1775 }
1776 case Token::BIT_OR:
1777 __ or_(eax, Operand(ecx));
1778 break;
1779 case Token::BIT_AND:
1780 __ and_(eax, Operand(ecx));
1781 break;
1782 case Token::BIT_XOR:
1783 __ xor_(eax, Operand(ecx));
1784 break;
1785 default:
1786 UNREACHABLE();
1787 }
1788
1789 __ bind(&done);
1790 Apply(context, eax);
1791}
1792
1793
1794void FullCodeGenerator::EmitBinaryOp(Token::Value op,
1795 Expression::Context context,
1796 OverwriteMode mode) {
1797 TypeInfo type = TypeInfo::Unknown();
1798 GenericBinaryOpStub stub(op, mode, NO_GENERIC_BINARY_FLAGS, type);
1799 if (stub.ArgsInRegistersSupported()) {
1800 __ pop(edx);
1801 stub.GenerateCall(masm_, edx, eax);
1802 } else {
1803 __ push(result_register());
1804 __ CallStub(&stub);
1805 }
Leon Clarkee46be812010-01-19 14:06:41 +00001806 Apply(context, eax);
1807}
1808
1809
Leon Clarkef7060e22010-06-03 12:02:55 +01001810void FullCodeGenerator::EmitAssignment(Expression* expr) {
1811 // Invalid left-hand sides are rewritten to have a 'throw
1812 // ReferenceError' on the left-hand side.
1813 if (!expr->IsValidLeftHandSide()) {
1814 VisitForEffect(expr);
1815 return;
1816 }
1817
1818 // Left-hand side can only be a property, a global or a (parameter or local)
1819 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1820 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1821 LhsKind assign_type = VARIABLE;
1822 Property* prop = expr->AsProperty();
1823 if (prop != NULL) {
1824 assign_type = (prop->key()->IsPropertyName())
1825 ? NAMED_PROPERTY
1826 : KEYED_PROPERTY;
1827 }
1828
1829 switch (assign_type) {
1830 case VARIABLE: {
1831 Variable* var = expr->AsVariableProxy()->var();
1832 EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect);
1833 break;
1834 }
1835 case NAMED_PROPERTY: {
1836 __ push(eax); // Preserve value.
1837 VisitForValue(prop->obj(), kAccumulator);
1838 __ mov(edx, eax);
1839 __ pop(eax); // Restore value.
1840 __ mov(ecx, prop->key()->AsLiteral()->handle());
1841 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1842 __ call(ic, RelocInfo::CODE_TARGET);
1843 __ nop(); // Signal no inlined code.
1844 break;
1845 }
1846 case KEYED_PROPERTY: {
1847 __ push(eax); // Preserve value.
1848 VisitForValue(prop->obj(), kStack);
1849 VisitForValue(prop->key(), kAccumulator);
1850 __ mov(ecx, eax);
1851 __ pop(edx);
1852 __ pop(eax); // Restore value.
1853 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1854 __ call(ic, RelocInfo::CODE_TARGET);
1855 __ nop(); // Signal no inlined code.
1856 break;
1857 }
1858 }
1859}
1860
1861
Leon Clarked91b9f72010-01-27 17:25:45 +00001862void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Leon Clarkef7060e22010-06-03 12:02:55 +01001863 Token::Value op,
Leon Clarkee46be812010-01-19 14:06:41 +00001864 Expression::Context context) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001865 // Left-hand sides that rewrite to explicit property accesses do not reach
1866 // here.
Steve Block3ce2e202009-11-05 08:53:23 +00001867 ASSERT(var != NULL);
1868 ASSERT(var->is_global() || var->slot() != NULL);
Leon Clarked91b9f72010-01-27 17:25:45 +00001869
Steve Block3ce2e202009-11-05 08:53:23 +00001870 if (var->is_global()) {
Leon Clarked91b9f72010-01-27 17:25:45 +00001871 ASSERT(!var->is_this());
Steve Blockd0582a62009-12-15 09:54:21 +00001872 // Assignment to a global variable. Use inline caching for the
1873 // assignment. Right-hand-side value is passed in eax, variable name in
1874 // ecx, and the global object on the stack.
Steve Block3ce2e202009-11-05 08:53:23 +00001875 __ mov(ecx, var->name());
Leon Clarke4515c472010-02-03 11:58:03 +00001876 __ mov(edx, CodeGenerator::GlobalObject());
Steve Block3ce2e202009-11-05 08:53:23 +00001877 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1878 __ call(ic, RelocInfo::CODE_TARGET);
Leon Clarkee46be812010-01-19 14:06:41 +00001879 __ nop();
Steve Block3ce2e202009-11-05 08:53:23 +00001880
Leon Clarkef7060e22010-06-03 12:02:55 +01001881 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
1882 // Perform the assignment for non-const variables and for initialization
1883 // of const variables. Const assignments are simply skipped.
1884 Label done;
1885 Slot* slot = var->slot();
Steve Blockd0582a62009-12-15 09:54:21 +00001886 switch (slot->type()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001887 case Slot::PARAMETER:
Leon Clarkef7060e22010-06-03 12:02:55 +01001888 case Slot::LOCAL:
1889 if (op == Token::INIT_CONST) {
1890 // Detect const reinitialization by checking for the hole value.
1891 __ mov(edx, Operand(ebp, SlotOffset(slot)));
1892 __ cmp(edx, Factory::the_hole_value());
1893 __ j(not_equal, &done);
1894 }
1895 // Perform the assignment.
1896 __ mov(Operand(ebp, SlotOffset(slot)), eax);
Steve Blockd0582a62009-12-15 09:54:21 +00001897 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001898
1899 case Slot::CONTEXT: {
Leon Clarkee46be812010-01-19 14:06:41 +00001900 MemOperand target = EmitSlotSearch(slot, ecx);
Leon Clarkef7060e22010-06-03 12:02:55 +01001901 if (op == Token::INIT_CONST) {
1902 // Detect const reinitialization by checking for the hole value.
1903 __ mov(edx, target);
1904 __ cmp(edx, Factory::the_hole_value());
1905 __ j(not_equal, &done);
1906 }
1907 // Perform the assignment and issue the write barrier.
1908 __ mov(target, eax);
1909 // The value of the assignment is in eax. RecordWrite clobbers its
1910 // register arguments.
1911 __ mov(edx, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00001912 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
Leon Clarkee46be812010-01-19 14:06:41 +00001913 __ RecordWrite(ecx, offset, edx, ebx);
Steve Blockd0582a62009-12-15 09:54:21 +00001914 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001915 }
Steve Blockd0582a62009-12-15 09:54:21 +00001916
1917 case Slot::LOOKUP:
Leon Clarkef7060e22010-06-03 12:02:55 +01001918 // Call the runtime for the assignment. The runtime will ignore
1919 // const reinitialization.
1920 __ push(eax); // Value.
1921 __ push(esi); // Context.
1922 __ push(Immediate(var->name()));
1923 if (op == Token::INIT_CONST) {
1924 // The runtime will ignore const redeclaration.
1925 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1926 } else {
1927 __ CallRuntime(Runtime::kStoreContextSlot, 3);
1928 }
Steve Blockd0582a62009-12-15 09:54:21 +00001929 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001930 }
Leon Clarkef7060e22010-06-03 12:02:55 +01001931 __ bind(&done);
Steve Block3ce2e202009-11-05 08:53:23 +00001932 }
Leon Clarkef7060e22010-06-03 12:02:55 +01001933
1934 Apply(context, eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001935}
1936
1937
Leon Clarked91b9f72010-01-27 17:25:45 +00001938void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001939 // Assignment to a property, using a named store IC.
1940 Property* prop = expr->target()->AsProperty();
1941 ASSERT(prop != NULL);
1942 ASSERT(prop->key()->AsLiteral() != NULL);
Steve Block3ce2e202009-11-05 08:53:23 +00001943
Steve Blockd0582a62009-12-15 09:54:21 +00001944 // If the assignment starts a block of assignments to the same object,
1945 // change to slow case to avoid the quadratic behavior of repeatedly
1946 // adding fast properties.
1947 if (expr->starts_initialization_block()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001948 __ push(result_register());
1949 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
Steve Blockd0582a62009-12-15 09:54:21 +00001950 __ CallRuntime(Runtime::kToSlowProperties, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001951 __ pop(result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00001952 }
1953
Leon Clarkee46be812010-01-19 14:06:41 +00001954 // Record source code position before IC call.
1955 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00001956 __ mov(ecx, prop->key()->AsLiteral()->handle());
Leon Clarke4515c472010-02-03 11:58:03 +00001957 if (expr->ends_initialization_block()) {
1958 __ mov(edx, Operand(esp, 0));
1959 } else {
1960 __ pop(edx);
1961 }
Steve Blockd0582a62009-12-15 09:54:21 +00001962 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1963 __ call(ic, RelocInfo::CODE_TARGET);
Leon Clarkee46be812010-01-19 14:06:41 +00001964 __ nop();
Steve Blockd0582a62009-12-15 09:54:21 +00001965
1966 // If the assignment ends an initialization block, revert to fast case.
1967 if (expr->ends_initialization_block()) {
1968 __ push(eax); // Result of assignment, saved even if not needed.
1969 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
1970 __ CallRuntime(Runtime::kToFastProperties, 1);
1971 __ pop(eax);
Leon Clarke4515c472010-02-03 11:58:03 +00001972 DropAndApply(1, context_, eax);
1973 } else {
1974 Apply(context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00001975 }
Steve Blockd0582a62009-12-15 09:54:21 +00001976}
1977
1978
Leon Clarked91b9f72010-01-27 17:25:45 +00001979void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001980 // Assignment to a property, using a keyed store IC.
1981
1982 // If the assignment starts a block of assignments to the same object,
1983 // change to slow case to avoid the quadratic behavior of repeatedly
1984 // adding fast properties.
1985 if (expr->starts_initialization_block()) {
Leon Clarkee46be812010-01-19 14:06:41 +00001986 __ push(result_register());
1987 // Receiver is now under the key and value.
Steve Blockd0582a62009-12-15 09:54:21 +00001988 __ push(Operand(esp, 2 * kPointerSize));
1989 __ CallRuntime(Runtime::kToSlowProperties, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001990 __ pop(result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00001991 }
1992
Steve Block6ded16b2010-05-10 14:33:55 +01001993 __ pop(ecx);
1994 if (expr->ends_initialization_block()) {
1995 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
1996 } else {
1997 __ pop(edx);
1998 }
Leon Clarkee46be812010-01-19 14:06:41 +00001999 // Record source code position before IC call.
2000 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00002001 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
2002 __ call(ic, RelocInfo::CODE_TARGET);
2003 // This nop signals to the IC that there is no inlined code at the call
2004 // site for it to patch.
2005 __ nop();
2006
2007 // If the assignment ends an initialization block, revert to fast case.
2008 if (expr->ends_initialization_block()) {
Steve Block6ded16b2010-05-10 14:33:55 +01002009 __ pop(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00002010 __ push(eax); // Result of assignment, saved even if not needed.
Steve Block6ded16b2010-05-10 14:33:55 +01002011 __ push(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00002012 __ CallRuntime(Runtime::kToFastProperties, 1);
2013 __ pop(eax);
2014 }
2015
Steve Block6ded16b2010-05-10 14:33:55 +01002016 Apply(context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002017}
2018
2019
Leon Clarked91b9f72010-01-27 17:25:45 +00002020void FullCodeGenerator::VisitProperty(Property* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002021 Comment cmnt(masm_, "[ Property");
2022 Expression* key = expr->key();
Steve Blockd0582a62009-12-15 09:54:21 +00002023
Leon Clarkee46be812010-01-19 14:06:41 +00002024 if (key->IsPropertyName()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002025 VisitForValue(expr->obj(), kAccumulator);
Leon Clarkee46be812010-01-19 14:06:41 +00002026 EmitNamedPropertyLoad(expr);
Andrei Popescu402d9372010-02-26 13:31:12 +00002027 Apply(context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002028 } else {
Andrei Popescu402d9372010-02-26 13:31:12 +00002029 VisitForValue(expr->obj(), kStack);
2030 VisitForValue(expr->key(), kAccumulator);
2031 __ pop(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00002032 EmitKeyedPropertyLoad(expr);
Andrei Popescu402d9372010-02-26 13:31:12 +00002033 Apply(context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002034 }
Steve Blockd0582a62009-12-15 09:54:21 +00002035}
2036
2037
Leon Clarked91b9f72010-01-27 17:25:45 +00002038void FullCodeGenerator::EmitCallWithIC(Call* expr,
Leon Clarkee46be812010-01-19 14:06:41 +00002039 Handle<Object> name,
2040 RelocInfo::Mode mode) {
Steve Blockd0582a62009-12-15 09:54:21 +00002041 // Code common for calls using the IC.
2042 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00002043 int arg_count = args->length();
2044 for (int i = 0; i < arg_count; i++) {
Leon Clarkee46be812010-01-19 14:06:41 +00002045 VisitForValue(args->at(i), kStack);
Steve Block3ce2e202009-11-05 08:53:23 +00002046 }
Leon Clarkee46be812010-01-19 14:06:41 +00002047 __ Set(ecx, Immediate(name));
2048 // Record source position of the IC call.
Steve Block3ce2e202009-11-05 08:53:23 +00002049 SetSourcePosition(expr->position());
Leon Clarkee46be812010-01-19 14:06:41 +00002050 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2051 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
2052 __ call(ic, mode);
Steve Block3ce2e202009-11-05 08:53:23 +00002053 // Restore context register.
2054 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00002055 Apply(context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002056}
2057
2058
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002059void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
2060 Expression* key,
2061 RelocInfo::Mode mode) {
2062 // Code common for calls using the IC.
2063 ZoneList<Expression*>* args = expr->arguments();
2064 int arg_count = args->length();
2065 for (int i = 0; i < arg_count; i++) {
2066 VisitForValue(args->at(i), kStack);
2067 }
2068 VisitForValue(key, kAccumulator);
2069 __ mov(ecx, eax);
2070 // Record source position of the IC call.
2071 SetSourcePosition(expr->position());
2072 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2073 Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(
2074 arg_count, in_loop);
2075 __ call(ic, mode);
2076 // Restore context register.
2077 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2078 Apply(context_, eax);
2079}
2080
2081
Leon Clarked91b9f72010-01-27 17:25:45 +00002082void FullCodeGenerator::EmitCallWithStub(Call* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002083 // Code common for calls using the call stub.
2084 ZoneList<Expression*>* args = expr->arguments();
2085 int arg_count = args->length();
2086 for (int i = 0; i < arg_count; i++) {
Leon Clarkee46be812010-01-19 14:06:41 +00002087 VisitForValue(args->at(i), kStack);
Steve Block3ce2e202009-11-05 08:53:23 +00002088 }
Steve Blockd0582a62009-12-15 09:54:21 +00002089 // Record source position for debugger.
2090 SetSourcePosition(expr->position());
Leon Clarkef7060e22010-06-03 12:02:55 +01002091 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2092 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
Steve Blockd0582a62009-12-15 09:54:21 +00002093 __ CallStub(&stub);
2094 // Restore context register.
2095 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00002096 DropAndApply(1, context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002097}
2098
2099
Leon Clarked91b9f72010-01-27 17:25:45 +00002100void FullCodeGenerator::VisitCall(Call* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002101 Comment cmnt(masm_, "[ Call");
2102 Expression* fun = expr->expression();
2103 Variable* var = fun->AsVariableProxy()->AsVariable();
2104
2105 if (var != NULL && var->is_possibly_eval()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002106 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2107 // resolve the function we need to call and the receiver of the
2108 // call. Then we call the resolved function using the given
2109 // arguments.
2110 VisitForValue(fun, kStack);
2111 __ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
2112
2113 // Push the arguments.
2114 ZoneList<Expression*>* args = expr->arguments();
2115 int arg_count = args->length();
2116 for (int i = 0; i < arg_count; i++) {
2117 VisitForValue(args->at(i), kStack);
2118 }
2119
2120 // Push copy of the function - found below the arguments.
2121 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2122
2123 // Push copy of the first argument or undefined if it doesn't exist.
2124 if (arg_count > 0) {
2125 __ push(Operand(esp, arg_count * kPointerSize));
2126 } else {
2127 __ push(Immediate(Factory::undefined_value()));
2128 }
2129
2130 // Push the receiver of the enclosing function and do runtime call.
2131 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
2132 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
2133
2134 // The runtime call returns a pair of values in eax (function) and
2135 // edx (receiver). Touch up the stack with the right values.
2136 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2137 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
2138
2139 // Record source position for debugger.
2140 SetSourcePosition(expr->position());
2141 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2142 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
2143 __ CallStub(&stub);
2144 // Restore context register.
2145 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2146 DropAndApply(1, context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002147 } else if (var != NULL && !var->is_this() && var->is_global()) {
Leon Clarkee46be812010-01-19 14:06:41 +00002148 // Push global object as receiver for the call IC.
Steve Blockd0582a62009-12-15 09:54:21 +00002149 __ push(CodeGenerator::GlobalObject());
Leon Clarkee46be812010-01-19 14:06:41 +00002150 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
Steve Blockd0582a62009-12-15 09:54:21 +00002151 } else if (var != NULL && var->slot() != NULL &&
2152 var->slot()->type() == Slot::LOOKUP) {
Steve Block59151502010-09-22 15:07:15 +01002153 // Call to a lookup slot (dynamically introduced variable).
2154 Label slow, done;
2155
2156 // Generate code for loading from variables potentially shadowed
2157 // by eval-introduced variables.
2158 EmitDynamicLoadFromSlotFastCase(var->slot(),
2159 NOT_INSIDE_TYPEOF,
2160 &slow,
2161 &done);
2162
2163 __ bind(&slow);
2164 // Call the runtime to find the function to call (returned in eax)
2165 // and the object holding it (returned in edx).
Leon Clarkef7060e22010-06-03 12:02:55 +01002166 __ push(context_register());
2167 __ push(Immediate(var->name()));
2168 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2169 __ push(eax); // Function.
2170 __ push(edx); // Receiver.
Steve Block59151502010-09-22 15:07:15 +01002171
2172 // If fast case code has been generated, emit code to push the
2173 // function and receiver and have the slow path jump around this
2174 // code.
2175 if (done.is_linked()) {
2176 Label call;
2177 __ jmp(&call);
2178 __ bind(&done);
2179 // Push function.
2180 __ push(eax);
2181 // Push global receiver.
2182 __ mov(ebx, CodeGenerator::GlobalObject());
2183 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2184 __ bind(&call);
2185 }
2186
Leon Clarkef7060e22010-06-03 12:02:55 +01002187 EmitCallWithStub(expr);
Steve Blockd0582a62009-12-15 09:54:21 +00002188 } else if (fun->AsProperty() != NULL) {
2189 // Call to an object property.
2190 Property* prop = fun->AsProperty();
2191 Literal* key = prop->key()->AsLiteral();
2192 if (key != NULL && key->handle()->IsSymbol()) {
2193 // Call to a named property, use call IC.
Leon Clarkee46be812010-01-19 14:06:41 +00002194 VisitForValue(prop->obj(), kStack);
2195 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
Steve Blockd0582a62009-12-15 09:54:21 +00002196 } else {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002197 // Call to a keyed property.
2198 // For a synthetic property use keyed load IC followed by function call,
2199 // for a regular property use keyed CallIC.
Leon Clarkee46be812010-01-19 14:06:41 +00002200 VisitForValue(prop->obj(), kStack);
Andrei Popescu402d9372010-02-26 13:31:12 +00002201 if (prop->is_synthetic()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002202 VisitForValue(prop->key(), kAccumulator);
2203 // Record source code position for IC call.
2204 SetSourcePosition(prop->position());
Andrei Popescu402d9372010-02-26 13:31:12 +00002205 __ pop(edx); // We do not need to keep the receiver.
Andrei Popescu402d9372010-02-26 13:31:12 +00002206
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002207 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
2208 __ call(ic, RelocInfo::CODE_TARGET);
2209 // By emitting a nop we make sure that we do not have a "test eax,..."
2210 // instruction after the call as it is treated specially
2211 // by the LoadIC code.
2212 __ nop();
Andrei Popescu402d9372010-02-26 13:31:12 +00002213 // Push result (function).
2214 __ push(eax);
2215 // Push Global receiver.
Leon Clarkee46be812010-01-19 14:06:41 +00002216 __ mov(ecx, CodeGenerator::GlobalObject());
2217 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002218 EmitCallWithStub(expr);
Steve Blockd0582a62009-12-15 09:54:21 +00002219 } else {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002220 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
Steve Blockd0582a62009-12-15 09:54:21 +00002221 }
Steve Blockd0582a62009-12-15 09:54:21 +00002222 }
2223 } else {
2224 // Call to some other expression. If the expression is an anonymous
2225 // function literal not called in a loop, mark it as one that should
Leon Clarked91b9f72010-01-27 17:25:45 +00002226 // also use the full code generator.
Steve Blockd0582a62009-12-15 09:54:21 +00002227 FunctionLiteral* lit = fun->AsFunctionLiteral();
2228 if (lit != NULL &&
2229 lit->name()->Equals(Heap::empty_string()) &&
2230 loop_depth() == 0) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002231 lit->set_try_full_codegen(true);
Steve Blockd0582a62009-12-15 09:54:21 +00002232 }
Leon Clarkee46be812010-01-19 14:06:41 +00002233 VisitForValue(fun, kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00002234 // Load global receiver object.
2235 __ mov(ebx, CodeGenerator::GlobalObject());
2236 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
2237 // Emit function call.
2238 EmitCallWithStub(expr);
2239 }
2240}
2241
2242
Leon Clarked91b9f72010-01-27 17:25:45 +00002243void FullCodeGenerator::VisitCallNew(CallNew* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002244 Comment cmnt(masm_, "[ CallNew");
2245 // According to ECMA-262, section 11.2.2, page 44, the function
2246 // expression in new calls must be evaluated before the
2247 // arguments.
Steve Blockd0582a62009-12-15 09:54:21 +00002248
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002249 // Push constructor on the stack. If it's not a function it's used as
2250 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2251 // ignored.
2252 VisitForValue(expr->expression(), kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00002253
2254 // Push the arguments ("left-to-right") on the stack.
2255 ZoneList<Expression*>* args = expr->arguments();
2256 int arg_count = args->length();
2257 for (int i = 0; i < arg_count; i++) {
Leon Clarkee46be812010-01-19 14:06:41 +00002258 VisitForValue(args->at(i), kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00002259 }
2260
2261 // Call the construct call builtin that handles allocation and
2262 // constructor invocation.
2263 SetSourcePosition(expr->position());
2264
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002265 // Load function and argument count into edi and eax.
Steve Blockd0582a62009-12-15 09:54:21 +00002266 __ Set(eax, Immediate(arg_count));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002267 __ mov(edi, Operand(esp, arg_count * kPointerSize));
Steve Blockd0582a62009-12-15 09:54:21 +00002268
2269 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
2270 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002271 Apply(context_, eax);
Steve Block3ce2e202009-11-05 08:53:23 +00002272}
2273
2274
Leon Clarkef7060e22010-06-03 12:02:55 +01002275void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2276 ASSERT(args->length() == 1);
2277
2278 VisitForValue(args->at(0), kAccumulator);
2279
2280 Label materialize_true, materialize_false;
2281 Label* if_true = NULL;
2282 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002283 Label* fall_through = NULL;
2284 PrepareTest(&materialize_true, &materialize_false,
2285 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002286
2287 __ test(eax, Immediate(kSmiTagMask));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002288 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002289
2290 Apply(context_, if_true, if_false);
2291}
2292
2293
2294void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2295 ASSERT(args->length() == 1);
2296
2297 VisitForValue(args->at(0), kAccumulator);
2298
2299 Label materialize_true, materialize_false;
2300 Label* if_true = NULL;
2301 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002302 Label* fall_through = NULL;
2303 PrepareTest(&materialize_true, &materialize_false,
2304 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002305
2306 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002307 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002308
2309 Apply(context_, if_true, if_false);
2310}
2311
2312
2313void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2314 ASSERT(args->length() == 1);
2315
2316 VisitForValue(args->at(0), kAccumulator);
2317
2318 Label materialize_true, materialize_false;
2319 Label* if_true = NULL;
2320 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002321 Label* fall_through = NULL;
2322 PrepareTest(&materialize_true, &materialize_false,
2323 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002324
2325 __ test(eax, Immediate(kSmiTagMask));
2326 __ j(zero, if_false);
2327 __ cmp(eax, Factory::null_value());
2328 __ j(equal, if_true);
2329 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2330 // Undetectable objects behave like undefined when tested with typeof.
2331 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2332 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2333 __ j(not_zero, if_false);
2334 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2335 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
2336 __ j(below, if_false);
2337 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002338 Split(below_equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002339
2340 Apply(context_, if_true, if_false);
2341}
2342
2343
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002344void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2345 ASSERT(args->length() == 1);
2346
2347 VisitForValue(args->at(0), kAccumulator);
2348
2349 Label materialize_true, materialize_false;
2350 Label* if_true = NULL;
2351 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002352 Label* fall_through = NULL;
2353 PrepareTest(&materialize_true, &materialize_false,
2354 &if_true, &if_false, &fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002355
2356 __ test(eax, Immediate(kSmiTagMask));
2357 __ j(equal, if_false);
2358 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002359 Split(above_equal, if_true, if_false, fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002360
2361 Apply(context_, if_true, if_false);
2362}
2363
2364
Leon Clarkef7060e22010-06-03 12:02:55 +01002365void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2366 ASSERT(args->length() == 1);
2367
2368 VisitForValue(args->at(0), kAccumulator);
2369
2370 Label materialize_true, materialize_false;
2371 Label* if_true = NULL;
2372 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002373 Label* fall_through = NULL;
2374 PrepareTest(&materialize_true, &materialize_false,
2375 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002376
2377 __ test(eax, Immediate(kSmiTagMask));
2378 __ j(zero, if_false);
2379 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2380 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2381 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002382 Split(not_zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002383
2384 Apply(context_, if_true, if_false);
2385}
2386
2387
Iain Merrick75681382010-08-19 15:07:18 +01002388void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2389 ZoneList<Expression*>* args) {
2390 ASSERT(args->length() == 1);
2391
2392 VisitForValue(args->at(0), kAccumulator);
2393
2394 Label materialize_true, materialize_false;
2395 Label* if_true = NULL;
2396 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002397 Label* fall_through = NULL;
2398 PrepareTest(&materialize_true, &materialize_false,
2399 &if_true, &if_false, &fall_through);
Iain Merrick75681382010-08-19 15:07:18 +01002400
2401 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
2402 // used in a few functions in runtime.js which should not normally be hit by
2403 // this compiler.
2404 __ jmp(if_false);
2405 Apply(context_, if_true, if_false);
2406}
2407
2408
Leon Clarkef7060e22010-06-03 12:02:55 +01002409void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2410 ASSERT(args->length() == 1);
2411
2412 VisitForValue(args->at(0), kAccumulator);
2413
2414 Label materialize_true, materialize_false;
2415 Label* if_true = NULL;
2416 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002417 Label* fall_through = NULL;
2418 PrepareTest(&materialize_true, &materialize_false,
2419 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002420
2421 __ test(eax, Immediate(kSmiTagMask));
2422 __ j(zero, if_false);
2423 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002424 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002425
2426 Apply(context_, if_true, if_false);
2427}
2428
2429
2430void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2431 ASSERT(args->length() == 1);
2432
2433 VisitForValue(args->at(0), kAccumulator);
2434
2435 Label materialize_true, materialize_false;
2436 Label* if_true = NULL;
2437 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002438 Label* fall_through = NULL;
2439 PrepareTest(&materialize_true, &materialize_false,
2440 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002441
2442 __ test(eax, Immediate(kSmiTagMask));
2443 __ j(equal, if_false);
2444 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002445 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002446
2447 Apply(context_, if_true, if_false);
2448}
2449
2450
2451void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2452 ASSERT(args->length() == 1);
2453
2454 VisitForValue(args->at(0), kAccumulator);
2455
2456 Label materialize_true, materialize_false;
2457 Label* if_true = NULL;
2458 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002459 Label* fall_through = NULL;
2460 PrepareTest(&materialize_true, &materialize_false,
2461 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002462
2463 __ test(eax, Immediate(kSmiTagMask));
2464 __ j(equal, if_false);
2465 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002466 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002467
2468 Apply(context_, if_true, if_false);
2469}
2470
2471
2472
2473void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2474 ASSERT(args->length() == 0);
2475
2476 Label materialize_true, materialize_false;
2477 Label* if_true = NULL;
2478 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002479 Label* fall_through = NULL;
2480 PrepareTest(&materialize_true, &materialize_false,
2481 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002482
2483 // Get the frame pointer for the calling frame.
2484 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2485
2486 // Skip the arguments adaptor frame if it exists.
2487 Label check_frame_marker;
2488 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2489 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2490 __ j(not_equal, &check_frame_marker);
2491 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2492
2493 // Check the marker in the calling frame.
2494 __ bind(&check_frame_marker);
2495 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2496 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002497 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002498
2499 Apply(context_, if_true, if_false);
2500}
2501
2502
2503void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2504 ASSERT(args->length() == 2);
2505
2506 // Load the two objects into registers and perform the comparison.
2507 VisitForValue(args->at(0), kStack);
2508 VisitForValue(args->at(1), kAccumulator);
2509
2510 Label materialize_true, materialize_false;
2511 Label* if_true = NULL;
2512 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002513 Label* fall_through = NULL;
2514 PrepareTest(&materialize_true, &materialize_false,
2515 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002516
2517 __ pop(ebx);
2518 __ cmp(eax, Operand(ebx));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002519 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01002520
2521 Apply(context_, if_true, if_false);
2522}
2523
2524
2525void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2526 ASSERT(args->length() == 1);
2527
2528 // ArgumentsAccessStub expects the key in edx and the formal
2529 // parameter count in eax.
2530 VisitForValue(args->at(0), kAccumulator);
2531 __ mov(edx, eax);
2532 __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2533 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2534 __ CallStub(&stub);
2535 Apply(context_, eax);
2536}
2537
2538
2539void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2540 ASSERT(args->length() == 0);
2541
2542 Label exit;
2543 // Get the number of formal parameters.
2544 __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2545
2546 // Check if the calling frame is an arguments adaptor frame.
2547 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2548 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2549 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2550 __ j(not_equal, &exit);
2551
2552 // Arguments adaptor case: Read the arguments length from the
2553 // adaptor frame.
2554 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2555
2556 __ bind(&exit);
2557 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
2558 Apply(context_, eax);
2559}
2560
2561
2562void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2563 ASSERT(args->length() == 1);
2564 Label done, null, function, non_function_constructor;
2565
2566 VisitForValue(args->at(0), kAccumulator);
2567
2568 // If the object is a smi, we return null.
2569 __ test(eax, Immediate(kSmiTagMask));
2570 __ j(zero, &null);
2571
2572 // Check that the object is a JS object but take special care of JS
2573 // functions to make sure they have 'Function' as their class.
2574 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, eax); // Map is now in eax.
2575 __ j(below, &null);
2576
2577 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2578 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2579 // LAST_JS_OBJECT_TYPE.
2580 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2581 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
Steve Block8defd9f2010-07-08 12:39:36 +01002582 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
Leon Clarkef7060e22010-06-03 12:02:55 +01002583 __ j(equal, &function);
2584
2585 // Check if the constructor in the map is a function.
2586 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2587 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2588 __ j(not_equal, &non_function_constructor);
2589
2590 // eax now contains the constructor function. Grab the
2591 // instance class name from there.
2592 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2593 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2594 __ jmp(&done);
2595
2596 // Functions have class 'Function'.
2597 __ bind(&function);
2598 __ mov(eax, Factory::function_class_symbol());
2599 __ jmp(&done);
2600
2601 // Objects with a non-function constructor have class 'Object'.
2602 __ bind(&non_function_constructor);
2603 __ mov(eax, Factory::Object_symbol());
2604 __ jmp(&done);
2605
2606 // Non-JS objects have class null.
2607 __ bind(&null);
2608 __ mov(eax, Factory::null_value());
2609
2610 // All done.
2611 __ bind(&done);
2612
2613 Apply(context_, eax);
2614}
2615
2616
2617void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2618 // Conditionally generate a log call.
2619 // Args:
2620 // 0 (literal string): The type of logging (corresponds to the flags).
2621 // This is used to determine whether or not to generate the log call.
2622 // 1 (string): Format string. Access the string at argument index 2
2623 // with '%2s' (see Logger::LogRuntime for all the formats).
2624 // 2 (array): Arguments to the format string.
2625 ASSERT_EQ(args->length(), 3);
2626#ifdef ENABLE_LOGGING_AND_PROFILING
2627 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
2628 VisitForValue(args->at(1), kStack);
2629 VisitForValue(args->at(2), kStack);
2630 __ CallRuntime(Runtime::kLog, 2);
2631 }
2632#endif
2633 // Finally, we're expected to leave a value on the top of the stack.
2634 __ mov(eax, Factory::undefined_value());
2635 Apply(context_, eax);
2636}
2637
2638
2639void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2640 ASSERT(args->length() == 0);
2641
2642 Label slow_allocate_heapnumber;
2643 Label heapnumber_allocated;
2644
2645 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2646 __ jmp(&heapnumber_allocated);
2647
2648 __ bind(&slow_allocate_heapnumber);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002649 // Allocate a heap number.
2650 __ CallRuntime(Runtime::kNumberAlloc, 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01002651 __ mov(edi, eax);
2652
2653 __ bind(&heapnumber_allocated);
2654
2655 __ PrepareCallCFunction(0, ebx);
2656 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2657
2658 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2659 // by computing:
2660 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2661 // This is implemented on both SSE2 and FPU.
2662 if (CpuFeatures::IsSupported(SSE2)) {
2663 CpuFeatures::Scope fscope(SSE2);
2664 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2665 __ movd(xmm1, Operand(ebx));
2666 __ movd(xmm0, Operand(eax));
2667 __ cvtss2sd(xmm1, xmm1);
2668 __ pxor(xmm0, xmm1);
2669 __ subsd(xmm0, xmm1);
2670 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2671 } else {
2672 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2673 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2674 Immediate(0x41300000));
2675 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2676 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2677 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2678 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2679 __ fsubp(1);
2680 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2681 }
2682 __ mov(eax, edi);
2683 Apply(context_, eax);
2684}
2685
2686
2687void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2688 // Load the arguments on the stack and call the stub.
2689 SubStringStub stub;
2690 ASSERT(args->length() == 3);
2691 VisitForValue(args->at(0), kStack);
2692 VisitForValue(args->at(1), kStack);
2693 VisitForValue(args->at(2), kStack);
2694 __ CallStub(&stub);
2695 Apply(context_, eax);
2696}
2697
2698
2699void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2700 // Load the arguments on the stack and call the stub.
2701 RegExpExecStub stub;
2702 ASSERT(args->length() == 4);
2703 VisitForValue(args->at(0), kStack);
2704 VisitForValue(args->at(1), kStack);
2705 VisitForValue(args->at(2), kStack);
2706 VisitForValue(args->at(3), kStack);
2707 __ CallStub(&stub);
2708 Apply(context_, eax);
2709}
2710
2711
2712void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2713 ASSERT(args->length() == 1);
2714
2715 VisitForValue(args->at(0), kAccumulator); // Load the object.
2716
2717 Label done;
2718 // If the object is a smi return the object.
2719 __ test(eax, Immediate(kSmiTagMask));
2720 __ j(zero, &done);
2721 // If the object is not a value type, return the object.
2722 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
2723 __ j(not_equal, &done);
2724 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2725
2726 __ bind(&done);
2727 Apply(context_, eax);
2728}
2729
2730
2731void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2732 // Load the arguments on the stack and call the runtime function.
2733 ASSERT(args->length() == 2);
2734 VisitForValue(args->at(0), kStack);
2735 VisitForValue(args->at(1), kStack);
2736 __ CallRuntime(Runtime::kMath_pow, 2);
2737 Apply(context_, eax);
2738}
2739
2740
2741void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2742 ASSERT(args->length() == 2);
2743
2744 VisitForValue(args->at(0), kStack); // Load the object.
2745 VisitForValue(args->at(1), kAccumulator); // Load the value.
2746 __ pop(ebx); // eax = value. ebx = object.
2747
2748 Label done;
2749 // If the object is a smi, return the value.
2750 __ test(ebx, Immediate(kSmiTagMask));
2751 __ j(zero, &done);
2752
2753 // If the object is not a value type, return the value.
2754 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
2755 __ j(not_equal, &done);
2756
2757 // Store the value.
2758 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
2759 // Update the write barrier. Save the value as it will be
2760 // overwritten by the write barrier code and is needed afterward.
2761 __ mov(edx, eax);
2762 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
2763
2764 __ bind(&done);
2765 Apply(context_, eax);
2766}
2767
2768
2769void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2770 ASSERT_EQ(args->length(), 1);
2771
2772 // Load the argument on the stack and call the stub.
2773 VisitForValue(args->at(0), kStack);
2774
2775 NumberToStringStub stub;
2776 __ CallStub(&stub);
2777 Apply(context_, eax);
2778}
2779
2780
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002781void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
Leon Clarkef7060e22010-06-03 12:02:55 +01002782 ASSERT(args->length() == 1);
2783
2784 VisitForValue(args->at(0), kAccumulator);
2785
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002786 Label done;
2787 StringCharFromCodeGenerator generator(eax, ebx);
2788 generator.GenerateFast(masm_);
Leon Clarkef7060e22010-06-03 12:02:55 +01002789 __ jmp(&done);
2790
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002791 NopRuntimeCallHelper call_helper;
2792 generator.GenerateSlow(masm_, call_helper);
Leon Clarkef7060e22010-06-03 12:02:55 +01002793
2794 __ bind(&done);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002795 Apply(context_, ebx);
Leon Clarkef7060e22010-06-03 12:02:55 +01002796}
2797
2798
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002799void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2800 ASSERT(args->length() == 2);
2801
2802 VisitForValue(args->at(0), kStack);
2803 VisitForValue(args->at(1), kAccumulator);
2804
2805 Register object = ebx;
2806 Register index = eax;
2807 Register scratch = ecx;
2808 Register result = edx;
2809
2810 __ pop(object);
2811
2812 Label need_conversion;
2813 Label index_out_of_range;
2814 Label done;
2815 StringCharCodeAtGenerator generator(object,
2816 index,
2817 scratch,
2818 result,
2819 &need_conversion,
2820 &need_conversion,
2821 &index_out_of_range,
2822 STRING_INDEX_IS_NUMBER);
2823 generator.GenerateFast(masm_);
2824 __ jmp(&done);
2825
2826 __ bind(&index_out_of_range);
2827 // When the index is out of range, the spec requires us to return
2828 // NaN.
2829 __ Set(result, Immediate(Factory::nan_value()));
2830 __ jmp(&done);
2831
2832 __ bind(&need_conversion);
Leon Clarkef7060e22010-06-03 12:02:55 +01002833 // Move the undefined value into the result register, which will
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002834 // trigger conversion.
2835 __ Set(result, Immediate(Factory::undefined_value()));
2836 __ jmp(&done);
2837
2838 NopRuntimeCallHelper call_helper;
2839 generator.GenerateSlow(masm_, call_helper);
2840
2841 __ bind(&done);
2842 Apply(context_, result);
Leon Clarkef7060e22010-06-03 12:02:55 +01002843}
2844
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002845
2846void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2847 ASSERT(args->length() == 2);
2848
2849 VisitForValue(args->at(0), kStack);
2850 VisitForValue(args->at(1), kAccumulator);
2851
2852 Register object = ebx;
2853 Register index = eax;
2854 Register scratch1 = ecx;
2855 Register scratch2 = edx;
2856 Register result = eax;
2857
2858 __ pop(object);
2859
2860 Label need_conversion;
2861 Label index_out_of_range;
2862 Label done;
2863 StringCharAtGenerator generator(object,
2864 index,
2865 scratch1,
2866 scratch2,
2867 result,
2868 &need_conversion,
2869 &need_conversion,
2870 &index_out_of_range,
2871 STRING_INDEX_IS_NUMBER);
2872 generator.GenerateFast(masm_);
2873 __ jmp(&done);
2874
2875 __ bind(&index_out_of_range);
2876 // When the index is out of range, the spec requires us to return
2877 // the empty string.
2878 __ Set(result, Immediate(Factory::empty_string()));
2879 __ jmp(&done);
2880
2881 __ bind(&need_conversion);
2882 // Move smi zero into the result register, which will trigger
2883 // conversion.
2884 __ Set(result, Immediate(Smi::FromInt(0)));
2885 __ jmp(&done);
2886
2887 NopRuntimeCallHelper call_helper;
2888 generator.GenerateSlow(masm_, call_helper);
2889
2890 __ bind(&done);
2891 Apply(context_, result);
2892}
2893
2894
Leon Clarkef7060e22010-06-03 12:02:55 +01002895void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2896 ASSERT_EQ(2, args->length());
2897
2898 VisitForValue(args->at(0), kStack);
2899 VisitForValue(args->at(1), kStack);
2900
2901 StringAddStub stub(NO_STRING_ADD_FLAGS);
2902 __ CallStub(&stub);
2903 Apply(context_, eax);
2904}
2905
2906
2907void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2908 ASSERT_EQ(2, args->length());
2909
2910 VisitForValue(args->at(0), kStack);
2911 VisitForValue(args->at(1), kStack);
2912
2913 StringCompareStub stub;
2914 __ CallStub(&stub);
2915 Apply(context_, eax);
2916}
2917
2918
2919void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2920 // Load the argument on the stack and call the stub.
2921 TranscendentalCacheStub stub(TranscendentalCache::SIN);
2922 ASSERT(args->length() == 1);
2923 VisitForValue(args->at(0), kStack);
2924 __ CallStub(&stub);
2925 Apply(context_, eax);
2926}
2927
2928
2929void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2930 // Load the argument on the stack and call the stub.
2931 TranscendentalCacheStub stub(TranscendentalCache::COS);
2932 ASSERT(args->length() == 1);
2933 VisitForValue(args->at(0), kStack);
2934 __ CallStub(&stub);
2935 Apply(context_, eax);
2936}
2937
2938
2939void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2940 // Load the argument on the stack and call the runtime function.
2941 ASSERT(args->length() == 1);
2942 VisitForValue(args->at(0), kStack);
2943 __ CallRuntime(Runtime::kMath_sqrt, 1);
2944 Apply(context_, eax);
2945}
2946
2947
2948void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
2949 ASSERT(args->length() >= 2);
2950
2951 int arg_count = args->length() - 2; // For receiver and function.
2952 VisitForValue(args->at(0), kStack); // Receiver.
2953 for (int i = 0; i < arg_count; i++) {
2954 VisitForValue(args->at(i + 1), kStack);
2955 }
2956 VisitForValue(args->at(arg_count + 1), kAccumulator); // Function.
2957
2958 // InvokeFunction requires function in edi. Move it in there.
2959 if (!result_register().is(edi)) __ mov(edi, result_register());
2960 ParameterCount count(arg_count);
2961 __ InvokeFunction(edi, count, CALL_FUNCTION);
2962 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2963 Apply(context_, eax);
2964}
2965
2966
2967void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
2968 ASSERT(args->length() == 3);
2969 VisitForValue(args->at(0), kStack);
2970 VisitForValue(args->at(1), kStack);
2971 VisitForValue(args->at(2), kStack);
2972 __ CallRuntime(Runtime::kRegExpConstructResult, 3);
2973 Apply(context_, eax);
2974}
2975
2976
2977void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2978 ASSERT(args->length() == 3);
2979 VisitForValue(args->at(0), kStack);
2980 VisitForValue(args->at(1), kStack);
2981 VisitForValue(args->at(2), kStack);
2982 __ CallRuntime(Runtime::kSwapElements, 3);
2983 Apply(context_, eax);
2984}
2985
2986
2987void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2988 ASSERT_EQ(2, args->length());
2989
2990 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2991 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2992
2993 Handle<FixedArray> jsfunction_result_caches(
2994 Top::global_context()->jsfunction_result_caches());
2995 if (jsfunction_result_caches->length() <= cache_id) {
2996 __ Abort("Attempt to use undefined cache.");
2997 __ mov(eax, Factory::undefined_value());
2998 Apply(context_, eax);
2999 return;
3000 }
3001
3002 VisitForValue(args->at(1), kAccumulator);
3003
3004 Register key = eax;
3005 Register cache = ebx;
3006 Register tmp = ecx;
Steve Block59151502010-09-22 15:07:15 +01003007 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003008 __ mov(cache,
3009 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
Steve Block59151502010-09-22 15:07:15 +01003010 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003011 __ mov(cache,
3012 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3013
3014 Label done, not_found;
3015 // tmp now holds finger offset as a smi.
3016 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3017 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3018 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
3019 __ j(not_equal, &not_found);
3020
3021 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
3022 __ jmp(&done);
3023
3024 __ bind(&not_found);
3025 // Call runtime to perform the lookup.
3026 __ push(cache);
3027 __ push(key);
3028 __ CallRuntime(Runtime::kGetFromCache, 2);
3029
3030 __ bind(&done);
3031 Apply(context_, eax);
3032}
3033
3034
Ben Murdochbb769b22010-08-11 14:56:33 +01003035void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3036 ASSERT_EQ(2, args->length());
3037
3038 Register right = eax;
3039 Register left = ebx;
3040 Register tmp = ecx;
3041
3042 VisitForValue(args->at(0), kStack);
3043 VisitForValue(args->at(1), kAccumulator);
3044 __ pop(left);
3045
3046 Label done, fail, ok;
3047 __ cmp(left, Operand(right));
3048 __ j(equal, &ok);
3049 // Fail if either is a non-HeapObject.
3050 __ mov(tmp, left);
3051 __ and_(Operand(tmp), right);
3052 __ test(Operand(tmp), Immediate(kSmiTagMask));
3053 __ j(zero, &fail);
3054 __ CmpObjectType(left, JS_REGEXP_TYPE, tmp);
3055 __ j(not_equal, &fail);
3056 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
3057 __ j(not_equal, &fail);
3058 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
3059 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
3060 __ j(equal, &ok);
3061 __ bind(&fail);
3062 __ mov(eax, Immediate(Factory::false_value()));
3063 __ jmp(&done);
3064 __ bind(&ok);
3065 __ mov(eax, Immediate(Factory::true_value()));
3066 __ bind(&done);
3067
3068 Apply(context_, eax);
3069}
3070
3071
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003072void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
3073 ASSERT(args->length() == 1);
3074
3075 VisitForValue(args->at(0), kAccumulator);
3076
3077 if (FLAG_debug_code) {
3078 __ AbortIfNotString(eax);
3079 }
3080
3081 Label materialize_true, materialize_false;
3082 Label* if_true = NULL;
3083 Label* if_false = NULL;
3084 Label* fall_through = NULL;
3085 PrepareTest(&materialize_true, &materialize_false,
3086 &if_true, &if_false, &fall_through);
3087
3088 __ test(FieldOperand(eax, String::kHashFieldOffset),
3089 Immediate(String::kContainsCachedArrayIndexMask));
3090 Split(zero, if_true, if_false, fall_through);
3091
3092 Apply(context_, if_true, if_false);
3093}
3094
3095
3096void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3097 ASSERT(args->length() == 1);
3098
3099 VisitForValue(args->at(0), kAccumulator);
3100
3101 if (FLAG_debug_code) {
3102 __ AbortIfNotString(eax);
3103 }
3104
3105 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3106 __ IndexFromHash(eax, eax);
3107
3108 Apply(context_, eax);
3109}
3110
3111
Leon Clarked91b9f72010-01-27 17:25:45 +00003112void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003113 Handle<String> name = expr->name();
3114 if (name->length() > 0 && name->Get(0) == '_') {
3115 Comment cmnt(masm_, "[ InlineRuntimeCall");
3116 EmitInlineRuntimeCall(expr);
3117 return;
3118 }
3119
Steve Block3ce2e202009-11-05 08:53:23 +00003120 Comment cmnt(masm_, "[ CallRuntime");
3121 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00003122
Steve Blockd0582a62009-12-15 09:54:21 +00003123 if (expr->is_jsruntime()) {
3124 // Prepare for calling JS runtime function.
Steve Blockd0582a62009-12-15 09:54:21 +00003125 __ mov(eax, CodeGenerator::GlobalObject());
3126 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
3127 }
Steve Block3ce2e202009-11-05 08:53:23 +00003128
3129 // Push the arguments ("left-to-right").
3130 int arg_count = args->length();
3131 for (int i = 0; i < arg_count; i++) {
Leon Clarkee46be812010-01-19 14:06:41 +00003132 VisitForValue(args->at(i), kStack);
Steve Block3ce2e202009-11-05 08:53:23 +00003133 }
3134
Steve Blockd0582a62009-12-15 09:54:21 +00003135 if (expr->is_jsruntime()) {
Leon Clarkee46be812010-01-19 14:06:41 +00003136 // Call the JS runtime function via a call IC.
3137 __ Set(ecx, Immediate(expr->name()));
3138 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
3139 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
Steve Blockd0582a62009-12-15 09:54:21 +00003140 __ call(ic, RelocInfo::CODE_TARGET);
3141 // Restore context register.
3142 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00003143 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00003144 // Call the C runtime function.
3145 __ CallRuntime(expr->function(), arg_count);
Steve Blockd0582a62009-12-15 09:54:21 +00003146 }
Leon Clarkee46be812010-01-19 14:06:41 +00003147 Apply(context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003148}
3149
3150
Leon Clarked91b9f72010-01-27 17:25:45 +00003151void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003152 switch (expr->op()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003153 case Token::DELETE: {
3154 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3155 Property* prop = expr->expression()->AsProperty();
3156 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
3157 if (prop == NULL && var == NULL) {
3158 // Result of deleting non-property, non-variable reference is true.
3159 // The subexpression may have side effects.
3160 VisitForEffect(expr->expression());
3161 Apply(context_, true);
3162 } else if (var != NULL &&
3163 !var->is_global() &&
3164 var->slot() != NULL &&
3165 var->slot()->type() != Slot::LOOKUP) {
3166 // Result of deleting non-global, non-dynamic variables is false.
3167 // The subexpression does not have side effects.
3168 Apply(context_, false);
3169 } else {
3170 // Property or variable reference. Call the delete builtin with
3171 // object and property name as arguments.
3172 if (prop != NULL) {
3173 VisitForValue(prop->obj(), kStack);
3174 VisitForValue(prop->key(), kStack);
3175 } else if (var->is_global()) {
3176 __ push(CodeGenerator::GlobalObject());
3177 __ push(Immediate(var->name()));
3178 } else {
3179 // Non-global variable. Call the runtime to look up the context
3180 // where the variable was introduced.
3181 __ push(context_register());
3182 __ push(Immediate(var->name()));
3183 __ CallRuntime(Runtime::kLookupContext, 2);
3184 __ push(eax);
3185 __ push(Immediate(var->name()));
3186 }
3187 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3188 Apply(context_, eax);
3189 }
3190 break;
3191 }
3192
Steve Blockd0582a62009-12-15 09:54:21 +00003193 case Token::VOID: {
3194 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
Leon Clarkee46be812010-01-19 14:06:41 +00003195 VisitForEffect(expr->expression());
3196 switch (context_) {
Steve Blockd0582a62009-12-15 09:54:21 +00003197 case Expression::kUninitialized:
3198 UNREACHABLE();
3199 break;
3200 case Expression::kEffect:
3201 break;
3202 case Expression::kValue:
Leon Clarkee46be812010-01-19 14:06:41 +00003203 switch (location_) {
3204 case kAccumulator:
3205 __ mov(result_register(), Factory::undefined_value());
3206 break;
3207 case kStack:
3208 __ push(Immediate(Factory::undefined_value()));
3209 break;
3210 }
Steve Blockd0582a62009-12-15 09:54:21 +00003211 break;
Leon Clarkee46be812010-01-19 14:06:41 +00003212 case Expression::kTest:
Steve Blockd0582a62009-12-15 09:54:21 +00003213 __ jmp(false_label_);
3214 break;
3215 }
3216 break;
3217 }
3218
3219 case Token::NOT: {
3220 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003221
Leon Clarkef7060e22010-06-03 12:02:55 +01003222 Label materialize_true, materialize_false;
3223 Label* if_true = NULL;
3224 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003225 Label* fall_through = NULL;
Leon Clarkef7060e22010-06-03 12:02:55 +01003226 // Notice that the labels are swapped.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003227 PrepareTest(&materialize_true, &materialize_false,
3228 &if_false, &if_true, &fall_through);
3229 VisitForControl(expr->expression(), if_true, if_false, fall_through);
Leon Clarkee46be812010-01-19 14:06:41 +00003230 Apply(context_, if_false, if_true); // Labels swapped.
Steve Blockd0582a62009-12-15 09:54:21 +00003231 break;
3232 }
3233
3234 case Token::TYPEOF: {
3235 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003236 VisitForTypeofValue(expr->expression(), kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00003237 __ CallRuntime(Runtime::kTypeof, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00003238 Apply(context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003239 break;
3240 }
3241
Leon Clarked91b9f72010-01-27 17:25:45 +00003242 case Token::ADD: {
3243 Comment cmt(masm_, "[ UnaryOperation (ADD)");
3244 VisitForValue(expr->expression(), kAccumulator);
3245 Label no_conversion;
3246 __ test(result_register(), Immediate(kSmiTagMask));
3247 __ j(zero, &no_conversion);
3248 __ push(result_register());
3249 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
3250 __ bind(&no_conversion);
3251 Apply(context_, result_register());
3252 break;
3253 }
3254
Leon Clarke4515c472010-02-03 11:58:03 +00003255 case Token::SUB: {
3256 Comment cmt(masm_, "[ UnaryOperation (SUB)");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003257 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
Leon Clarkeac952652010-07-15 11:15:24 +01003258 UnaryOverwriteMode overwrite =
3259 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
Leon Clarke4515c472010-02-03 11:58:03 +00003260 GenericUnaryOpStub stub(Token::SUB, overwrite);
3261 // GenericUnaryOpStub expects the argument to be in the
3262 // accumulator register eax.
3263 VisitForValue(expr->expression(), kAccumulator);
3264 __ CallStub(&stub);
3265 Apply(context_, eax);
3266 break;
3267 }
3268
3269 case Token::BIT_NOT: {
3270 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003271 // The generic unary operation stub expects the argument to be
3272 // in the accumulator register eax.
Leon Clarke4515c472010-02-03 11:58:03 +00003273 VisitForValue(expr->expression(), kAccumulator);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003274 Label done;
3275 if (ShouldInlineSmiCase(expr->op())) {
3276 Label call_stub;
3277 __ test(eax, Immediate(kSmiTagMask));
3278 __ j(not_zero, &call_stub);
3279 __ lea(eax, Operand(eax, kSmiTagMask));
3280 __ not_(eax);
3281 __ jmp(&done);
3282 __ bind(&call_stub);
3283 }
3284 bool overwrite = expr->expression()->ResultOverwriteAllowed();
3285 UnaryOverwriteMode mode =
3286 overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
3287 GenericUnaryOpStub stub(Token::BIT_NOT, mode);
Leon Clarke4515c472010-02-03 11:58:03 +00003288 __ CallStub(&stub);
Leon Clarke4515c472010-02-03 11:58:03 +00003289 __ bind(&done);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003290 Apply(context_, eax);
Leon Clarke4515c472010-02-03 11:58:03 +00003291 break;
3292 }
3293
Steve Blockd0582a62009-12-15 09:54:21 +00003294 default:
3295 UNREACHABLE();
3296 }
3297}
3298
3299
Leon Clarked91b9f72010-01-27 17:25:45 +00003300void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003301 Comment cmnt(masm_, "[ CountOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003302 SetSourcePosition(expr->position());
3303
Leon Clarkef7060e22010-06-03 12:02:55 +01003304 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3305 // as the left-hand side.
3306 if (!expr->expression()->IsValidLeftHandSide()) {
3307 VisitForEffect(expr->expression());
3308 return;
3309 }
Steve Blockd0582a62009-12-15 09:54:21 +00003310
Leon Clarkee46be812010-01-19 14:06:41 +00003311 // Expression can only be a property, a global or a (parameter or local)
3312 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
3313 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3314 LhsKind assign_type = VARIABLE;
3315 Property* prop = expr->expression()->AsProperty();
3316 // In case of a property we use the uninitialized expression context
3317 // of the key to detect a named property.
3318 if (prop != NULL) {
3319 assign_type =
3320 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3321 }
3322
3323 // Evaluate expression and get value.
3324 if (assign_type == VARIABLE) {
3325 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
3326 Location saved_location = location_;
Leon Clarked91b9f72010-01-27 17:25:45 +00003327 location_ = kAccumulator;
Leon Clarkee46be812010-01-19 14:06:41 +00003328 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
3329 Expression::kValue);
3330 location_ = saved_location;
Leon Clarkef7060e22010-06-03 12:02:55 +01003331 } else {
Leon Clarkee46be812010-01-19 14:06:41 +00003332 // Reserve space for result of postfix operation.
3333 if (expr->is_postfix() && context_ != Expression::kEffect) {
3334 __ push(Immediate(Smi::FromInt(0)));
3335 }
Leon Clarkee46be812010-01-19 14:06:41 +00003336 if (assign_type == NAMED_PROPERTY) {
Andrei Popescu402d9372010-02-26 13:31:12 +00003337 // Put the object both on the stack and in the accumulator.
3338 VisitForValue(prop->obj(), kAccumulator);
3339 __ push(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003340 EmitNamedPropertyLoad(prop);
3341 } else {
Andrei Popescu402d9372010-02-26 13:31:12 +00003342 VisitForValue(prop->obj(), kStack);
3343 VisitForValue(prop->key(), kAccumulator);
3344 __ mov(edx, Operand(esp, 0));
3345 __ push(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003346 EmitKeyedPropertyLoad(prop);
3347 }
Leon Clarkee46be812010-01-19 14:06:41 +00003348 }
3349
Leon Clarked91b9f72010-01-27 17:25:45 +00003350 // Call ToNumber only if operand is not a smi.
3351 Label no_conversion;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003352 if (ShouldInlineSmiCase(expr->op())) {
3353 __ test(eax, Immediate(kSmiTagMask));
3354 __ j(zero, &no_conversion);
3355 }
Leon Clarked91b9f72010-01-27 17:25:45 +00003356 __ push(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003357 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
Leon Clarked91b9f72010-01-27 17:25:45 +00003358 __ bind(&no_conversion);
Steve Blockd0582a62009-12-15 09:54:21 +00003359
Leon Clarkee46be812010-01-19 14:06:41 +00003360 // Save result for postfix expressions.
3361 if (expr->is_postfix()) {
3362 switch (context_) {
3363 case Expression::kUninitialized:
3364 UNREACHABLE();
3365 case Expression::kEffect:
3366 // Do not save result.
3367 break;
3368 case Expression::kValue:
3369 case Expression::kTest:
Leon Clarkee46be812010-01-19 14:06:41 +00003370 // Save the result on the stack. If we have a named or keyed property
3371 // we store the result under the receiver that is currently on top
3372 // of the stack.
3373 switch (assign_type) {
3374 case VARIABLE:
3375 __ push(eax);
3376 break;
3377 case NAMED_PROPERTY:
3378 __ mov(Operand(esp, kPointerSize), eax);
3379 break;
3380 case KEYED_PROPERTY:
3381 __ mov(Operand(esp, 2 * kPointerSize), eax);
3382 break;
3383 }
3384 break;
3385 }
Steve Blockd0582a62009-12-15 09:54:21 +00003386 }
Leon Clarkee46be812010-01-19 14:06:41 +00003387
Leon Clarked91b9f72010-01-27 17:25:45 +00003388 // Inline smi case if we are in a loop.
3389 Label stub_call, done;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003390 if (ShouldInlineSmiCase(expr->op())) {
Leon Clarked91b9f72010-01-27 17:25:45 +00003391 if (expr->op() == Token::INC) {
3392 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3393 } else {
3394 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3395 }
3396 __ j(overflow, &stub_call);
3397 // We could eliminate this smi check if we split the code at
3398 // the first smi check before calling ToNumber.
3399 __ test(eax, Immediate(kSmiTagMask));
3400 __ j(zero, &done);
3401 __ bind(&stub_call);
3402 // Call stub. Undo operation first.
3403 if (expr->op() == Token::INC) {
3404 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3405 } else {
3406 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3407 }
3408 }
Leon Clarkee46be812010-01-19 14:06:41 +00003409 // Call stub for +1/-1.
Leon Clarkee46be812010-01-19 14:06:41 +00003410 GenericBinaryOpStub stub(expr->binary_op(),
3411 NO_OVERWRITE,
Steve Block6ded16b2010-05-10 14:33:55 +01003412 NO_GENERIC_BINARY_FLAGS,
3413 TypeInfo::Unknown());
Leon Clarked91b9f72010-01-27 17:25:45 +00003414 stub.GenerateCall(masm(), eax, Smi::FromInt(1));
3415 __ bind(&done);
Steve Blockd0582a62009-12-15 09:54:21 +00003416
Leon Clarkee46be812010-01-19 14:06:41 +00003417 // Store the value returned in eax.
3418 switch (assign_type) {
3419 case VARIABLE:
3420 if (expr->is_postfix()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003421 // Perform the assignment as if via '='.
Leon Clarkee46be812010-01-19 14:06:41 +00003422 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Leon Clarkef7060e22010-06-03 12:02:55 +01003423 Token::ASSIGN,
Leon Clarkee46be812010-01-19 14:06:41 +00003424 Expression::kEffect);
3425 // For all contexts except kEffect: We have the result on
3426 // top of the stack.
3427 if (context_ != Expression::kEffect) {
3428 ApplyTOS(context_);
3429 }
3430 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01003431 // Perform the assignment as if via '='.
Leon Clarkee46be812010-01-19 14:06:41 +00003432 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Leon Clarkef7060e22010-06-03 12:02:55 +01003433 Token::ASSIGN,
Leon Clarkee46be812010-01-19 14:06:41 +00003434 context_);
3435 }
Steve Blockd0582a62009-12-15 09:54:21 +00003436 break;
Leon Clarkee46be812010-01-19 14:06:41 +00003437 case NAMED_PROPERTY: {
3438 __ mov(ecx, prop->key()->AsLiteral()->handle());
Leon Clarke4515c472010-02-03 11:58:03 +00003439 __ pop(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00003440 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
3441 __ call(ic, RelocInfo::CODE_TARGET);
3442 // This nop signals to the IC that there is no inlined code at the call
3443 // site for it to patch.
3444 __ nop();
3445 if (expr->is_postfix()) {
Leon Clarkee46be812010-01-19 14:06:41 +00003446 if (context_ != Expression::kEffect) {
3447 ApplyTOS(context_);
3448 }
3449 } else {
Leon Clarke4515c472010-02-03 11:58:03 +00003450 Apply(context_, eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003451 }
Steve Blockd0582a62009-12-15 09:54:21 +00003452 break;
3453 }
Leon Clarkee46be812010-01-19 14:06:41 +00003454 case KEYED_PROPERTY: {
Steve Block6ded16b2010-05-10 14:33:55 +01003455 __ pop(ecx);
3456 __ pop(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00003457 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
3458 __ call(ic, RelocInfo::CODE_TARGET);
3459 // This nop signals to the IC that there is no inlined code at the call
3460 // site for it to patch.
3461 __ nop();
3462 if (expr->is_postfix()) {
Steve Block6ded16b2010-05-10 14:33:55 +01003463 // Result is on the stack
Leon Clarkee46be812010-01-19 14:06:41 +00003464 if (context_ != Expression::kEffect) {
3465 ApplyTOS(context_);
3466 }
3467 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01003468 Apply(context_, eax);
Leon Clarkee46be812010-01-19 14:06:41 +00003469 }
Steve Blockd0582a62009-12-15 09:54:21 +00003470 break;
3471 }
Steve Block3ce2e202009-11-05 08:53:23 +00003472 }
3473}
3474
3475
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003476void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) {
3477 VariableProxy* proxy = expr->AsVariableProxy();
3478 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3479 Comment cmnt(masm_, "Global variable");
3480 __ mov(eax, CodeGenerator::GlobalObject());
3481 __ mov(ecx, Immediate(proxy->name()));
3482 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
3483 // Use a regular load, not a contextual load, to avoid a reference
3484 // error.
3485 __ call(ic, RelocInfo::CODE_TARGET);
3486 if (where == kStack) __ push(eax);
3487 } else if (proxy != NULL &&
3488 proxy->var()->slot() != NULL &&
3489 proxy->var()->slot()->type() == Slot::LOOKUP) {
Steve Block59151502010-09-22 15:07:15 +01003490 Label done, slow;
3491
3492 // Generate code for loading from variables potentially shadowed
3493 // by eval-introduced variables.
3494 Slot* slot = proxy->var()->slot();
3495 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3496
3497 __ bind(&slow);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003498 __ push(esi);
3499 __ push(Immediate(proxy->name()));
3500 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
Steve Block59151502010-09-22 15:07:15 +01003501 __ bind(&done);
3502
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003503 if (where == kStack) __ push(eax);
3504 } else {
3505 // This expression cannot throw a reference error at the top level.
3506 VisitForValue(expr, where);
Steve Block3ce2e202009-11-05 08:53:23 +00003507 }
Steve Block3ce2e202009-11-05 08:53:23 +00003508}
3509
3510
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003511bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
3512 Expression* left,
3513 Expression* right,
3514 Label* if_true,
3515 Label* if_false,
3516 Label* fall_through) {
3517 if (op != Token::EQ && op != Token::EQ_STRICT) return false;
3518
3519 // Check for the pattern: typeof <expression> == <string literal>.
3520 Literal* right_literal = right->AsLiteral();
3521 if (right_literal == NULL) return false;
3522 Handle<Object> right_literal_value = right_literal->handle();
3523 if (!right_literal_value->IsString()) return false;
3524 UnaryOperation* left_unary = left->AsUnaryOperation();
3525 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
3526 Handle<String> check = Handle<String>::cast(right_literal_value);
3527
3528 VisitForTypeofValue(left_unary->expression(), kAccumulator);
3529 if (check->Equals(Heap::number_symbol())) {
3530 __ test(eax, Immediate(kSmiTagMask));
3531 __ j(zero, if_true);
3532 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3533 Factory::heap_number_map());
3534 Split(equal, if_true, if_false, fall_through);
3535 } else if (check->Equals(Heap::string_symbol())) {
3536 __ test(eax, Immediate(kSmiTagMask));
Leon Clarkef7060e22010-06-03 12:02:55 +01003537 __ j(zero, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003538 // Check for undetectable objects => false.
3539 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3540 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3541 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3542 __ j(not_zero, if_false);
3543 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE);
3544 Split(below, if_true, if_false, fall_through);
3545 } else if (check->Equals(Heap::boolean_symbol())) {
3546 __ cmp(eax, Factory::true_value());
3547 __ j(equal, if_true);
3548 __ cmp(eax, Factory::false_value());
3549 Split(equal, if_true, if_false, fall_through);
3550 } else if (check->Equals(Heap::undefined_symbol())) {
3551 __ cmp(eax, Factory::undefined_value());
3552 __ j(equal, if_true);
3553 __ test(eax, Immediate(kSmiTagMask));
3554 __ j(zero, if_false);
3555 // Check for undetectable objects => true.
3556 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3557 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3558 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3559 Split(not_zero, if_true, if_false, fall_through);
3560 } else if (check->Equals(Heap::function_symbol())) {
3561 __ test(eax, Immediate(kSmiTagMask));
3562 __ j(zero, if_false);
3563 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
3564 __ j(equal, if_true);
3565 // Regular expressions => 'function' (they are callable).
3566 __ CmpInstanceType(edx, JS_REGEXP_TYPE);
3567 Split(equal, if_true, if_false, fall_through);
3568 } else if (check->Equals(Heap::object_symbol())) {
3569 __ test(eax, Immediate(kSmiTagMask));
3570 __ j(zero, if_false);
3571 __ cmp(eax, Factory::null_value());
3572 __ j(equal, if_true);
3573 // Regular expressions => 'function', not 'object'.
3574 __ CmpObjectType(eax, JS_REGEXP_TYPE, edx);
3575 __ j(equal, if_false);
3576 // Check for undetectable objects => false.
3577 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3578 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3579 __ j(not_zero, if_false);
3580 // Check for JS objects => true.
3581 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
3582 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
3583 __ j(less, if_false);
3584 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
3585 Split(less_equal, if_true, if_false, fall_through);
3586 } else {
3587 if (if_false != fall_through) __ jmp(if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003588 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003589
3590 return true;
Leon Clarkef7060e22010-06-03 12:02:55 +01003591}
3592
3593
Leon Clarked91b9f72010-01-27 17:25:45 +00003594void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003595 Comment cmnt(masm_, "[ CompareOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003596 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00003597
Leon Clarkee46be812010-01-19 14:06:41 +00003598 // Always perform the comparison for its control flow. Pack the result
3599 // into the expression's context after the comparison is performed.
Leon Clarkef7060e22010-06-03 12:02:55 +01003600
3601 Label materialize_true, materialize_false;
3602 Label* if_true = NULL;
3603 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003604 Label* fall_through = NULL;
3605 PrepareTest(&materialize_true, &materialize_false,
3606 &if_true, &if_false, &fall_through);
3607
3608 // First we try a fast inlined version of the compare when one of
3609 // the operands is a literal.
3610 Token::Value op = expr->op();
3611 Expression* left = expr->left();
3612 Expression* right = expr->right();
3613 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
3614 Apply(context_, if_true, if_false);
3615 return;
3616 }
Steve Blockd0582a62009-12-15 09:54:21 +00003617
Leon Clarkee46be812010-01-19 14:06:41 +00003618 VisitForValue(expr->left(), kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00003619 switch (expr->op()) {
Leon Clarkee46be812010-01-19 14:06:41 +00003620 case Token::IN:
3621 VisitForValue(expr->right(), kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00003622 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
3623 __ cmp(eax, Factory::true_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003624 Split(equal, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00003625 break;
Steve Blockd0582a62009-12-15 09:54:21 +00003626
3627 case Token::INSTANCEOF: {
Leon Clarkee46be812010-01-19 14:06:41 +00003628 VisitForValue(expr->right(), kStack);
Steve Blockd0582a62009-12-15 09:54:21 +00003629 InstanceofStub stub;
3630 __ CallStub(&stub);
3631 __ test(eax, Operand(eax));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003632 // The stub returns 0 for true.
3633 Split(zero, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00003634 break;
3635 }
3636
3637 default: {
Leon Clarkee46be812010-01-19 14:06:41 +00003638 VisitForValue(expr->right(), kAccumulator);
Steve Blockd0582a62009-12-15 09:54:21 +00003639 Condition cc = no_condition;
3640 bool strict = false;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003641 switch (op) {
Steve Blockd0582a62009-12-15 09:54:21 +00003642 case Token::EQ_STRICT:
3643 strict = true;
3644 // Fall through
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003645 case Token::EQ:
Steve Blockd0582a62009-12-15 09:54:21 +00003646 cc = equal;
Steve Blockd0582a62009-12-15 09:54:21 +00003647 __ pop(edx);
3648 break;
3649 case Token::LT:
3650 cc = less;
Steve Blockd0582a62009-12-15 09:54:21 +00003651 __ pop(edx);
3652 break;
3653 case Token::GT:
3654 // Reverse left and right sizes to obtain ECMA-262 conversion order.
3655 cc = less;
Leon Clarkee46be812010-01-19 14:06:41 +00003656 __ mov(edx, result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00003657 __ pop(eax);
3658 break;
3659 case Token::LTE:
3660 // Reverse left and right sizes to obtain ECMA-262 conversion order.
3661 cc = greater_equal;
Leon Clarkee46be812010-01-19 14:06:41 +00003662 __ mov(edx, result_register());
Steve Blockd0582a62009-12-15 09:54:21 +00003663 __ pop(eax);
3664 break;
3665 case Token::GTE:
3666 cc = greater_equal;
Steve Blockd0582a62009-12-15 09:54:21 +00003667 __ pop(edx);
3668 break;
3669 case Token::IN:
3670 case Token::INSTANCEOF:
3671 default:
3672 UNREACHABLE();
3673 }
3674
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003675 if (ShouldInlineSmiCase(op)) {
3676 Label slow_case;
3677 __ mov(ecx, Operand(edx));
3678 __ or_(ecx, Operand(eax));
3679 __ test(ecx, Immediate(kSmiTagMask));
3680 __ j(not_zero, &slow_case, not_taken);
3681 __ cmp(edx, Operand(eax));
3682 Split(cc, if_true, if_false, NULL);
3683 __ bind(&slow_case);
3684 }
Steve Blockd0582a62009-12-15 09:54:21 +00003685
Steve Blockd0582a62009-12-15 09:54:21 +00003686 CompareStub stub(cc, strict);
3687 __ CallStub(&stub);
3688 __ test(eax, Operand(eax));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003689 Split(cc, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00003690 }
3691 }
3692
Leon Clarkee46be812010-01-19 14:06:41 +00003693 // Convert the result of the comparison into one expected for this
3694 // expression's context.
3695 Apply(context_, if_true, if_false);
Steve Blockd0582a62009-12-15 09:54:21 +00003696}
3697
3698
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003699void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
3700 Label materialize_true, materialize_false;
3701 Label* if_true = NULL;
3702 Label* if_false = NULL;
3703 Label* fall_through = NULL;
3704 PrepareTest(&materialize_true, &materialize_false,
3705 &if_true, &if_false, &fall_through);
3706
3707 VisitForValue(expr->expression(), kAccumulator);
3708 __ cmp(eax, Factory::null_value());
3709 if (expr->is_strict()) {
3710 Split(equal, if_true, if_false, fall_through);
3711 } else {
3712 __ j(equal, if_true);
3713 __ cmp(eax, Factory::undefined_value());
3714 __ j(equal, if_true);
3715 __ test(eax, Immediate(kSmiTagMask));
3716 __ j(zero, if_false);
3717 // It can be an undetectable object.
3718 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3719 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
3720 __ test(edx, Immediate(1 << Map::kIsUndetectable));
3721 Split(not_zero, if_true, if_false, fall_through);
3722 }
3723 Apply(context_, if_true, if_false);
3724}
3725
3726
Leon Clarked91b9f72010-01-27 17:25:45 +00003727void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003728 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Leon Clarkee46be812010-01-19 14:06:41 +00003729 Apply(context_, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00003730}
3731
Steve Blockd0582a62009-12-15 09:54:21 +00003732
Leon Clarked91b9f72010-01-27 17:25:45 +00003733Register FullCodeGenerator::result_register() { return eax; }
Leon Clarkee46be812010-01-19 14:06:41 +00003734
3735
Leon Clarked91b9f72010-01-27 17:25:45 +00003736Register FullCodeGenerator::context_register() { return esi; }
Leon Clarkee46be812010-01-19 14:06:41 +00003737
3738
Leon Clarked91b9f72010-01-27 17:25:45 +00003739void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
Leon Clarkee46be812010-01-19 14:06:41 +00003740 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3741 __ mov(Operand(ebp, frame_offset), value);
3742}
3743
3744
Leon Clarked91b9f72010-01-27 17:25:45 +00003745void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
Steve Block59151502010-09-22 15:07:15 +01003746 __ mov(dst, ContextOperand(esi, context_index));
Leon Clarkee46be812010-01-19 14:06:41 +00003747}
3748
3749
3750// ----------------------------------------------------------------------------
3751// Non-local control flow support.
3752
Leon Clarked91b9f72010-01-27 17:25:45 +00003753void FullCodeGenerator::EnterFinallyBlock() {
Leon Clarkee46be812010-01-19 14:06:41 +00003754 // Cook return address on top of stack (smi encoded Code* delta)
3755 ASSERT(!result_register().is(edx));
3756 __ mov(edx, Operand(esp, 0));
3757 __ sub(Operand(edx), Immediate(masm_->CodeObject()));
3758 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
3759 ASSERT_EQ(0, kSmiTag);
3760 __ add(edx, Operand(edx)); // Convert to smi.
3761 __ mov(Operand(esp, 0), edx);
3762 // Store result register while executing finally block.
3763 __ push(result_register());
3764}
3765
3766
Leon Clarked91b9f72010-01-27 17:25:45 +00003767void FullCodeGenerator::ExitFinallyBlock() {
Leon Clarkee46be812010-01-19 14:06:41 +00003768 ASSERT(!result_register().is(edx));
3769 // Restore result register from stack.
3770 __ pop(result_register());
3771 // Uncook return address.
3772 __ mov(edx, Operand(esp, 0));
3773 __ sar(edx, 1); // Convert smi to int.
3774 __ add(Operand(edx), Immediate(masm_->CodeObject()));
3775 __ mov(Operand(esp, 0), edx);
3776 // And return.
3777 __ ret(0);
3778}
3779
3780
3781#undef __
Steve Blockd0582a62009-12-15 09:54:21 +00003782
Steve Block3ce2e202009-11-05 08:53:23 +00003783} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01003784
3785#endif // V8_TARGET_ARCH_IA32