Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(661)

Side by Side Diff: src/ia32/fast-codegen-ia32.cc

Issue 541047: Introduce 'top-of-stack caching' to the toplevel code generator by... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/fast-codegen.cc ('k') | src/x64/fast-codegen-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 11 matching lines...) Expand all
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include "v8.h" 28 #include "v8.h"
29 29
30 #include "codegen-inl.h" 30 #include "codegen-inl.h"
31 #include "compiler.h" 31 #include "compiler.h"
32 #include "debug.h"
32 #include "fast-codegen.h" 33 #include "fast-codegen.h"
33 #include "parser.h" 34 #include "parser.h"
34 #include "debug.h"
35 35
36 namespace v8 { 36 namespace v8 {
37 namespace internal { 37 namespace internal {
38 38
39 #define __ ACCESS_MASM(masm_) 39 #define __ ACCESS_MASM(masm_)
40 40
41 // Generate code for a JS function. On entry to the function the receiver 41 // Generate code for a JS function. On entry to the function the receiver
42 // and arguments have been pushed on the stack left to right, with the 42 // and arguments have been pushed on the stack left to right, with the
43 // return address on top of them. The actual argument count matches the 43 // return address on top of them. The actual argument count matches the
44 // formal parameter count expected by the function. 44 // formal parameter count expected by the function.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 } else { 109 } else {
110 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 110 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
111 } 111 }
112 // Receiver is just before the parameters on the caller's stack. 112 // Receiver is just before the parameters on the caller's stack.
113 __ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset + 113 __ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
114 fun->num_parameters() * kPointerSize)); 114 fun->num_parameters() * kPointerSize));
115 __ push(edx); 115 __ push(edx);
116 __ push(Immediate(Smi::FromInt(fun->num_parameters()))); 116 __ push(Immediate(Smi::FromInt(fun->num_parameters())));
117 // Arguments to ArgumentsAccessStub: 117 // Arguments to ArgumentsAccessStub:
118 // function, receiver address, parameter count. 118 // function, receiver address, parameter count.
119 // The stub will rewrite receiever and parameter count if the previous 119 // The stub will rewrite receiver and parameter count if the previous
120 // stack frame was an arguments adapter frame. 120 // stack frame was an arguments adapter frame.
121 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); 121 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
122 __ CallStub(&stub); 122 __ CallStub(&stub);
123 __ mov(ecx, eax); // Duplicate result. 123 __ mov(ecx, eax); // Duplicate result.
124 Move(arguments->slot(), eax, ebx, edx); 124 Move(arguments->slot(), eax, ebx, edx);
125 Slot* dot_arguments_slot = 125 Slot* dot_arguments_slot =
126 fun->scope()->arguments_shadow()->AsVariable()->slot(); 126 fun->scope()->arguments_shadow()->AsVariable()->slot();
127 Move(dot_arguments_slot, ecx, ebx, edx); 127 Move(dot_arguments_slot, ecx, ebx, edx);
128 } 128 }
129 129
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 #ifdef ENABLE_DEBUGGER_SUPPORT 186 #ifdef ENABLE_DEBUGGER_SUPPORT
187 // Check that the size of the code used for returning matches what is 187 // Check that the size of the code used for returning matches what is
188 // expected by the debugger. 188 // expected by the debugger.
189 ASSERT_EQ(Assembler::kJSReturnSequenceLength, 189 ASSERT_EQ(Assembler::kJSReturnSequenceLength,
190 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); 190 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
191 #endif 191 #endif
192 } 192 }
193 } 193 }
194 194
195 195
196 void FastCodeGenerator::Apply(Expression::Context context, 196 void FastCodeGenerator::Apply(Expression::Context context, Register reg) {
197 Slot* slot, 197 switch (context) {
198 Register scratch) { 198 case Expression::kUninitialized:
199 UNREACHABLE();
200
201 case Expression::kEffect:
202 // Nothing to do.
203 break;
204
205 case Expression::kValue:
206 // Move value into place.
207 switch (location_) {
208 case kAccumulator:
209 if (!reg.is(result_register())) __ mov(result_register(), reg);
210 break;
211 case kStack:
212 __ push(reg);
213 break;
214 }
215 break;
216
217 case Expression::kValueTest:
218 case Expression::kTestValue:
219 // Push an extra copy of the value in case it's needed.
220 __ push(reg);
221 // Fall through.
222
223 case Expression::kTest:
224 // For simplicity we always test the accumulator register.
225 if (!reg.is(result_register())) __ mov(result_register(), reg);
226 DoTest(context);
227 break;
228 }
229 }
230
231
232 void FastCodeGenerator::Apply(Expression::Context context, Slot* slot) {
199 switch (context) { 233 switch (context) {
200 case Expression::kUninitialized: 234 case Expression::kUninitialized:
201 UNREACHABLE(); 235 UNREACHABLE();
202 case Expression::kEffect: 236 case Expression::kEffect:
237 // Nothing to do.
203 break; 238 break;
204 case Expression::kValue: { 239 case Expression::kValue: {
205 MemOperand location = EmitSlotSearch(slot, scratch); 240 MemOperand slot_operand = EmitSlotSearch(slot, result_register());
206 __ push(location); 241 switch (location_) {
242 case kAccumulator:
243 __ mov(result_register(), slot_operand);
244 break;
245 case kStack:
246 // Memory operands can be pushed directly.
247 __ push(slot_operand);
248 break;
249 }
207 break; 250 break;
208 } 251 }
252
209 case Expression::kTest: 253 case Expression::kTest:
254 Move(result_register(), slot);
255 DoTest(context);
256 break;
257
210 case Expression::kValueTest: 258 case Expression::kValueTest:
211 case Expression::kTestValue: 259 case Expression::kTestValue:
212 Move(scratch, slot); 260 Move(result_register(), slot);
213 Apply(context, scratch); 261 __ push(result_register());
262 DoTest(context);
214 break; 263 break;
215 } 264 }
216 } 265 }
217 266
218 267
219 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { 268 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) {
220 switch (context) { 269 switch (context) {
221 case Expression::kUninitialized: 270 case Expression::kUninitialized:
222 UNREACHABLE(); 271 UNREACHABLE();
223 case Expression::kEffect: 272 case Expression::kEffect:
273 // Nothing to do.
224 break; 274 break;
225 case Expression::kValue: 275 case Expression::kValue:
226 __ push(Immediate(lit->handle())); 276 switch (location_) {
277 case kAccumulator:
278 __ mov(result_register(), lit->handle());
279 break;
280 case kStack:
281 // Immediates can be pushed directly.
282 __ push(Immediate(lit->handle()));
283 break;
284 }
227 break; 285 break;
286
228 case Expression::kTest: 287 case Expression::kTest:
288 __ mov(result_register(), lit->handle());
289 DoTest(context);
290 break;
291
229 case Expression::kValueTest: 292 case Expression::kValueTest:
230 case Expression::kTestValue: 293 case Expression::kTestValue:
231 __ mov(eax, lit->handle()); 294 __ mov(result_register(), lit->handle());
232 Apply(context, eax); 295 __ push(result_register());
296 DoTest(context);
233 break; 297 break;
234 } 298 }
235 } 299 }
236 300
237 301
238 void FastCodeGenerator::ApplyTOS(Expression::Context context) { 302 void FastCodeGenerator::ApplyTOS(Expression::Context context) {
239 switch (context) { 303 switch (context) {
240 case Expression::kUninitialized: 304 case Expression::kUninitialized:
241 UNREACHABLE(); 305 UNREACHABLE();
306
242 case Expression::kEffect: 307 case Expression::kEffect:
243 __ Drop(1); 308 __ Drop(1);
244 break; 309 break;
310
245 case Expression::kValue: 311 case Expression::kValue:
312 switch (location_) {
313 case kAccumulator:
314 __ pop(result_register());
315 break;
316 case kStack:
317 break;
318 }
246 break; 319 break;
320
247 case Expression::kTest: 321 case Expression::kTest:
248 __ pop(eax); 322 __ pop(result_register());
249 TestAndBranch(eax, true_label_, false_label_); 323 DoTest(context);
250 break; 324 break;
251 case Expression::kValueTest: { 325
252 Label discard; 326 case Expression::kValueTest:
253 __ mov(eax, Operand(esp, 0)); 327 case Expression::kTestValue:
254 TestAndBranch(eax, true_label_, &discard); 328 __ mov(result_register(), Operand(esp, 0));
255 __ bind(&discard); 329 DoTest(context);
256 __ Drop(1);
257 __ jmp(false_label_);
258 break; 330 break;
259 }
260 case Expression::kTestValue: {
261 Label discard;
262 __ mov(eax, Operand(esp, 0));
263 TestAndBranch(eax, &discard, false_label_);
264 __ bind(&discard);
265 __ Drop(1);
266 __ jmp(true_label_);
267 }
268 } 331 }
269 } 332 }
270 333
271 334
272 void FastCodeGenerator::DropAndApply(int count, 335 void FastCodeGenerator::DropAndApply(int count,
273 Expression::Context context, 336 Expression::Context context,
274 Register reg) { 337 Register reg) {
275 ASSERT(count > 0); 338 ASSERT(count > 0);
276 ASSERT(!reg.is(esp)); 339 ASSERT(!reg.is(esp));
277 switch (context) { 340 switch (context) {
278 case Expression::kUninitialized: 341 case Expression::kUninitialized:
279 UNREACHABLE(); 342 UNREACHABLE();
343
280 case Expression::kEffect: 344 case Expression::kEffect:
281 __ Drop(count); 345 __ Drop(count);
282 break; 346 break;
347
283 case Expression::kValue: 348 case Expression::kValue:
284 if (count > 1) __ Drop(count - 1); 349 switch (location_) {
285 __ mov(Operand(esp, 0), reg); 350 case kAccumulator:
351 __ Drop(count);
352 if (!reg.is(result_register())) __ mov(result_register(), reg);
353 break;
354 case kStack:
355 if (count > 1) __ Drop(count - 1);
356 __ mov(Operand(esp, 0), reg);
357 break;
358 }
286 break; 359 break;
360
287 case Expression::kTest: 361 case Expression::kTest:
288 __ Drop(count); 362 __ Drop(count);
289 TestAndBranch(reg, true_label_, false_label_); 363 if (!reg.is(result_register())) __ mov(result_register(), reg);
364 DoTest(context);
290 break; 365 break;
291 case Expression::kValueTest: { 366
292 Label discard; 367 case Expression::kValueTest:
368 case Expression::kTestValue:
293 if (count > 1) __ Drop(count - 1); 369 if (count > 1) __ Drop(count - 1);
294 __ mov(Operand(esp, 0), reg); 370 if (!reg.is(result_register())) __ mov(result_register(), reg);
295 TestAndBranch(reg, true_label_, &discard); 371 __ mov(Operand(esp, 0), result_register());
372 DoTest(context);
373 break;
374 }
375 }
376
377
378 void FastCodeGenerator::Apply(Expression::Context context,
379 Label* materialize_true,
380 Label* materialize_false) {
381 switch (context) {
382 case Expression::kUninitialized:
383
384 case Expression::kEffect:
385 ASSERT_EQ(materialize_true, materialize_false);
386 __ bind(materialize_true);
387
388 case Expression::kValue: {
389 Label done;
390 switch (location_) {
391 case kAccumulator:
392 __ bind(materialize_true);
393 __ mov(result_register(), Factory::true_value());
394 __ jmp(&done);
395 __ bind(materialize_false);
396 __ mov(result_register(), Factory::false_value());
397 break;
398 case kStack:
399 __ bind(materialize_true);
400 __ push(Immediate(Factory::true_value()));
401 __ jmp(&done);
402 __ bind(materialize_false);
403 __ push(Immediate(Factory::false_value()));
404 break;
405 }
406 __ bind(&done);
407 break;
408 }
409
410 case Expression::kTest:
411 break;
412
413 case Expression::kValueTest:
414 __ bind(materialize_true);
415 switch (location_) {
416 case kAccumulator:
417 __ mov(result_register(), Factory::true_value());
418 break;
419 case kStack:
420 __ push(Immediate(Factory::true_value()));
421 break;
422 }
423 __ jmp(true_label_);
424 break;
425
426 case Expression::kTestValue:
427 __ bind(materialize_false);
428 switch (location_) {
429 case kAccumulator:
430 __ mov(result_register(), Factory::false_value());
431 break;
432 case kStack:
433 __ push(Immediate(Factory::false_value()));
434 break;
435 }
436 __ jmp(false_label_);
437 break;
438 }
439 }
440
441
442 void FastCodeGenerator::DoTest(Expression::Context context) {
443 // The value to test is in the accumulator, and duplicated on the stack if
444 // necessary (for value/test and test/value contexts).
445 ASSERT_NE(NULL, true_label_);
446 ASSERT_NE(NULL, false_label_);
447
448 // If there is a value on the stack, use a discard label for the
449 // value-is-unneeded branch in the inlined part of the test.
450 Label discard;
451 Label* if_true =
452 (context == Expression::kTestValue) ? &discard : true_label_;
453 Label* if_false =
454 (context == Expression::kValueTest) ? &discard : false_label_;
455
456 // Emit the inlined tests assumed by the stub.
457 __ cmp(result_register(), Factory::undefined_value());
458 __ j(equal, if_false);
459 __ cmp(result_register(), Factory::true_value());
460 __ j(equal, if_true);
461 __ cmp(result_register(), Factory::false_value());
462 __ j(equal, if_false);
463 ASSERT_EQ(0, kSmiTag);
464 __ test(result_register(), Operand(result_register()));
465 __ j(zero, if_false);
466 __ test(result_register(), Immediate(kSmiTagMask));
467 __ j(zero, if_true);
468
469 // Call the ToBoolean stub for all other cases.
470 ToBooleanStub stub;
471 __ push(result_register());
472 __ CallStub(&stub);
473 __ test(eax, Operand(eax));
474
475 // The stub returns nonzero for true. Complete based on the context.
476 switch (context) {
477 case Expression::kUninitialized:
478 case Expression::kEffect:
479 case Expression::kValue:
480 UNREACHABLE();
481
482 case Expression::kTest:
483 __ j(not_zero, true_label_);
484 __ jmp(false_label_);
485 break;
486
487 case Expression::kValueTest:
488 switch (location_) {
489 case kAccumulator:
490 __ j(zero, &discard);
491 __ pop(result_register());
492 __ jmp(true_label_);
493 break;
494 case kStack:
495 __ j(not_zero, true_label_);
496 break;
497 }
296 __ bind(&discard); 498 __ bind(&discard);
297 __ Drop(1); 499 __ Drop(1);
298 __ jmp(false_label_); 500 __ jmp(false_label_);
299 break; 501 break;
300 } 502
301 case Expression::kTestValue: { 503 case Expression::kTestValue:
302 Label discard; 504 switch (location_) {
303 if (count > 1) __ Drop(count - 1); 505 case kAccumulator:
304 __ mov(Operand(esp, 0), reg); 506 __ j(not_zero, &discard);
305 TestAndBranch(reg, &discard, false_label_); 507 __ pop(result_register());
508 __ jmp(false_label_);
509 break;
510 case kStack:
511 __ j(zero, false_label_);
512 break;
513 }
306 __ bind(&discard); 514 __ bind(&discard);
307 __ Drop(1); 515 __ Drop(1);
308 __ jmp(true_label_); 516 __ jmp(true_label_);
309 break; 517 break;
310 }
311 } 518 }
312 } 519 }
313 520
314 521
315 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { 522 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
316 switch (slot->type()) { 523 switch (slot->type()) {
317 case Slot::PARAMETER: 524 case Slot::PARAMETER:
318 case Slot::LOCAL: 525 case Slot::LOCAL:
319 return Operand(ebp, SlotOffset(slot)); 526 return Operand(ebp, SlotOffset(slot));
320 case Slot::CONTEXT: { 527 case Slot::CONTEXT: {
(...skipping 25 matching lines...) Expand all
346 MemOperand location = EmitSlotSearch(dst, scratch1); 553 MemOperand location = EmitSlotSearch(dst, scratch1);
347 __ mov(location, src); 554 __ mov(location, src);
348 // Emit the write barrier code if the location is in the heap. 555 // Emit the write barrier code if the location is in the heap.
349 if (dst->type() == Slot::CONTEXT) { 556 if (dst->type() == Slot::CONTEXT) {
350 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; 557 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
351 __ RecordWrite(scratch1, offset, src, scratch2); 558 __ RecordWrite(scratch1, offset, src, scratch2);
352 } 559 }
353 } 560 }
354 561
355 562
356 void FastCodeGenerator::TestAndBranch(Register source,
357 Label* true_label,
358 Label* false_label) {
359 ASSERT_NE(NULL, true_label);
360 ASSERT_NE(NULL, false_label);
361 // Use the shared ToBoolean stub to compile the value in the register into
362 // control flow to the code generator's true and false labels. Perform
363 // the fast checks assumed by the stub.
364 __ cmp(source, Factory::undefined_value()); // The undefined value is false.
365 __ j(equal, false_label);
366 __ cmp(source, Factory::true_value()); // True is true.
367 __ j(equal, true_label);
368 __ cmp(source, Factory::false_value()); // False is false.
369 __ j(equal, false_label);
370 ASSERT_EQ(0, kSmiTag);
371 __ test(source, Operand(source)); // The smi zero is false.
372 __ j(zero, false_label);
373 __ test(source, Immediate(kSmiTagMask)); // All other smis are true.
374 __ j(zero, true_label);
375
376 // Call the stub for all other cases.
377 __ push(source);
378 ToBooleanStub stub;
379 __ CallStub(&stub);
380 __ test(eax, Operand(eax)); // The stub returns nonzero for true.
381 __ j(not_zero, true_label);
382 __ jmp(false_label);
383 }
384
385
386 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { 563 void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
387 Comment cmnt(masm_, "[ Declaration"); 564 Comment cmnt(masm_, "[ Declaration");
388 Variable* var = decl->proxy()->var(); 565 Variable* var = decl->proxy()->var();
389 ASSERT(var != NULL); // Must have been resolved. 566 ASSERT(var != NULL); // Must have been resolved.
390 Slot* slot = var->slot(); 567 Slot* slot = var->slot();
391 Property* prop = var->AsProperty(); 568 Property* prop = var->AsProperty();
392 569
393 if (slot != NULL) { 570 if (slot != NULL) {
394 switch (slot->type()) { 571 switch (slot->type()) {
395 case Slot::PARAMETER: 572 case Slot::PARAMETER:
396 case Slot::LOCAL: 573 case Slot::LOCAL:
397 if (decl->mode() == Variable::CONST) { 574 if (decl->mode() == Variable::CONST) {
398 __ mov(Operand(ebp, SlotOffset(slot)), 575 __ mov(Operand(ebp, SlotOffset(slot)),
399 Immediate(Factory::the_hole_value())); 576 Immediate(Factory::the_hole_value()));
400 } else if (decl->fun() != NULL) { 577 } else if (decl->fun() != NULL) {
401 Visit(decl->fun()); 578 VisitForValue(decl->fun(), kAccumulator);
402 __ pop(Operand(ebp, SlotOffset(slot))); 579 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
403 } 580 }
404 break; 581 break;
405 582
406 case Slot::CONTEXT: 583 case Slot::CONTEXT:
407 // We bypass the general EmitSlotSearch because we know more about 584 // We bypass the general EmitSlotSearch because we know more about
408 // this specific context. 585 // this specific context.
409 586
410 // The variable in the decl always resides in the current context. 587 // The variable in the decl always resides in the current context.
411 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); 588 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope()));
412 if (FLAG_debug_code) { 589 if (FLAG_debug_code) {
413 // Check if we have the correct context pointer. 590 // Check if we have the correct context pointer.
414 __ mov(ebx, 591 __ mov(ebx,
415 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX)); 592 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX));
416 __ cmp(ebx, Operand(esi)); 593 __ cmp(ebx, Operand(esi));
417 __ Check(equal, "Unexpected declaration in current context."); 594 __ Check(equal, "Unexpected declaration in current context.");
418 } 595 }
419 if (decl->mode() == Variable::CONST) { 596 if (decl->mode() == Variable::CONST) {
420 __ mov(eax, Immediate(Factory::the_hole_value())); 597 __ mov(eax, Immediate(Factory::the_hole_value()));
421 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); 598 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
422 // No write barrier since the hole value is in old space. 599 // No write barrier since the hole value is in old space.
423 } else if (decl->fun() != NULL) { 600 } else if (decl->fun() != NULL) {
424 Visit(decl->fun()); 601 VisitForValue(decl->fun(), kAccumulator);
425 __ pop(eax); 602 __ mov(CodeGenerator::ContextOperand(esi, slot->index()),
426 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); 603 result_register());
427 int offset = Context::SlotOffset(slot->index()); 604 int offset = Context::SlotOffset(slot->index());
428 __ RecordWrite(esi, offset, eax, ecx); 605 __ RecordWrite(esi, offset, result_register(), ecx);
429 } 606 }
430 break; 607 break;
431 608
432 case Slot::LOOKUP: { 609 case Slot::LOOKUP: {
433 __ push(esi); 610 __ push(esi);
434 __ push(Immediate(var->name())); 611 __ push(Immediate(var->name()));
435 // Declaration nodes are always introduced in one of two modes. 612 // Declaration nodes are always introduced in one of two modes.
436 ASSERT(decl->mode() == Variable::VAR || 613 ASSERT(decl->mode() == Variable::VAR ||
437 decl->mode() == Variable::CONST); 614 decl->mode() == Variable::CONST);
438 PropertyAttributes attr = 615 PropertyAttributes attr =
439 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; 616 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
440 __ push(Immediate(Smi::FromInt(attr))); 617 __ push(Immediate(Smi::FromInt(attr)));
441 // Push initial value, if any. 618 // Push initial value, if any.
442 // Note: For variables we must not push an initial value (such as 619 // Note: For variables we must not push an initial value (such as
443 // 'undefined') because we may have a (legal) redeclaration and we 620 // 'undefined') because we may have a (legal) redeclaration and we
444 // must not destroy the current value. 621 // must not destroy the current value.
445 if (decl->mode() == Variable::CONST) { 622 if (decl->mode() == Variable::CONST) {
446 __ push(Immediate(Factory::the_hole_value())); 623 __ push(Immediate(Factory::the_hole_value()));
447 } else if (decl->fun() != NULL) { 624 } else if (decl->fun() != NULL) {
448 Visit(decl->fun()); 625 VisitForValue(decl->fun(), kStack);
449 } else { 626 } else {
450 __ push(Immediate(Smi::FromInt(0))); // No initial value! 627 __ push(Immediate(Smi::FromInt(0))); // No initial value!
451 } 628 }
452 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 629 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
453 break; 630 break;
454 } 631 }
455 } 632 }
456 633
457 } else if (prop != NULL) { 634 } else if (prop != NULL) {
458 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { 635 if (decl->fun() != NULL || decl->mode() == Variable::CONST) {
459 // We are declaring a function or constant that rewrites to a 636 // We are declaring a function or constant that rewrites to a
460 // property. Use (keyed) IC to set the initial value. 637 // property. Use (keyed) IC to set the initial value.
461 ASSERT_EQ(Expression::kValue, prop->obj()->context()); 638 VisitForValue(prop->obj(), kStack);
462 Visit(prop->obj()); 639 VisitForValue(prop->key(), kStack);
463 ASSERT_EQ(Expression::kValue, prop->key()->context());
464 Visit(prop->key());
465 640
466 if (decl->fun() != NULL) { 641 if (decl->fun() != NULL) {
467 ASSERT_EQ(Expression::kValue, decl->fun()->context()); 642 VisitForValue(decl->fun(), kAccumulator);
468 Visit(decl->fun());
469 __ pop(eax);
470 } else { 643 } else {
471 __ Set(eax, Immediate(Factory::the_hole_value())); 644 __ mov(result_register(), Factory::the_hole_value());
472 } 645 }
473 646
474 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 647 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
475 __ call(ic, RelocInfo::CODE_TARGET); 648 __ call(ic, RelocInfo::CODE_TARGET);
476 // Absence of a test eax instruction following the call 649 // Absence of a test eax instruction following the call
477 // indicates that none of the load was inlined. 650 // indicates that none of the load was inlined.
651 __ nop();
478 652
479 // Value in eax is ignored (declarations are statements). Receiver 653 // Value in eax is ignored (declarations are statements). Receiver
480 // and key on stack are discarded. 654 // and key on stack are discarded.
481 __ Drop(2); 655 __ Drop(2);
482 } 656 }
483 } 657 }
484 } 658 }
485 659
486 660
487 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 661 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 } 721 }
548 case Slot::CONTEXT: { 722 case Slot::CONTEXT: {
549 Comment cmnt(masm_, "Context slot"); 723 Comment cmnt(masm_, "Context slot");
550 break; 724 break;
551 } 725 }
552 case Slot::LOOKUP: 726 case Slot::LOOKUP:
553 UNIMPLEMENTED(); 727 UNIMPLEMENTED();
554 break; 728 break;
555 } 729 }
556 } 730 }
557 Apply(context, slot, eax); 731 Apply(context, slot);
558 } else { 732 } else {
559 Comment cmnt(masm_, "Variable rewritten to property"); 733 Comment cmnt(masm_, "Variable rewritten to property");
560 // A variable has been rewritten into an explicit access to an object 734 // A variable has been rewritten into an explicit access to an object
561 // property. 735 // property.
562 Property* property = rewrite->AsProperty(); 736 Property* property = rewrite->AsProperty();
563 ASSERT_NOT_NULL(property); 737 ASSERT_NOT_NULL(property);
564 738
565 // The only property expressions that can occur are of the form 739 // The only property expressions that can occur are of the form
566 // "slot[literal]". 740 // "slot[literal]".
567 741
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 801 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
628 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset)); 802 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
629 __ push(Immediate(Smi::FromInt(expr->literal_index()))); 803 __ push(Immediate(Smi::FromInt(expr->literal_index())));
630 __ push(Immediate(expr->constant_properties())); 804 __ push(Immediate(expr->constant_properties()));
631 if (expr->depth() > 1) { 805 if (expr->depth() > 1) {
632 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); 806 __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
633 } else { 807 } else {
634 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); 808 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
635 } 809 }
636 810
637 // If result_saved == true: The result is saved on top of the 811 // If result_saved is true the result is on top of the stack. If
638 // stack and in eax. 812 // result_saved is false the result is in eax.
639 // If result_saved == false: The result not on the stack, just in eax.
640 bool result_saved = false; 813 bool result_saved = false;
641 814
642 for (int i = 0; i < expr->properties()->length(); i++) { 815 for (int i = 0; i < expr->properties()->length(); i++) {
643 ObjectLiteral::Property* property = expr->properties()->at(i); 816 ObjectLiteral::Property* property = expr->properties()->at(i);
644 if (property->IsCompileTimeValue()) continue; 817 if (property->IsCompileTimeValue()) continue;
645 818
646 Literal* key = property->key(); 819 Literal* key = property->key();
647 Expression* value = property->value(); 820 Expression* value = property->value();
648 if (!result_saved) { 821 if (!result_saved) {
649 __ push(eax); // Save result on the stack 822 __ push(eax); // Save result on the stack
650 result_saved = true; 823 result_saved = true;
651 } 824 }
652 switch (property->kind()) { 825 switch (property->kind()) {
653 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // Fall through. 826 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
654 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); 827 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
828 // Fall through.
655 case ObjectLiteral::Property::COMPUTED: 829 case ObjectLiteral::Property::COMPUTED:
656 if (key->handle()->IsSymbol()) { 830 if (key->handle()->IsSymbol()) {
657 Visit(value); 831 VisitForValue(value, kAccumulator);
658 ASSERT_EQ(Expression::kValue, value->context());
659 __ pop(eax);
660 __ mov(ecx, Immediate(key->handle())); 832 __ mov(ecx, Immediate(key->handle()));
661 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 833 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
662 __ call(ic, RelocInfo::CODE_TARGET); 834 __ call(ic, RelocInfo::CODE_TARGET);
835 __ nop();
663 // StoreIC leaves the receiver on the stack. 836 // StoreIC leaves the receiver on the stack.
664 __ mov(eax, Operand(esp, 0)); // Restore result into eax.
665 break; 837 break;
666 } 838 }
667 // Fall through. 839 // Fall through.
668 case ObjectLiteral::Property::PROTOTYPE: 840 case ObjectLiteral::Property::PROTOTYPE:
669 __ push(eax); 841 __ push(Operand(esp, 0)); // Duplicate receiver.
670 Visit(key); 842 VisitForValue(key, kStack);
671 ASSERT_EQ(Expression::kValue, key->context()); 843 VisitForValue(value, kStack);
672 Visit(value);
673 ASSERT_EQ(Expression::kValue, value->context());
674 __ CallRuntime(Runtime::kSetProperty, 3); 844 __ CallRuntime(Runtime::kSetProperty, 3);
675 __ mov(eax, Operand(esp, 0)); // Restore result into eax.
676 break; 845 break;
677 case ObjectLiteral::Property::SETTER: 846 case ObjectLiteral::Property::SETTER:
678 case ObjectLiteral::Property::GETTER: 847 case ObjectLiteral::Property::GETTER:
679 __ push(eax); 848 __ push(Operand(esp, 0)); // Duplicate receiver.
680 Visit(key); 849 VisitForValue(key, kStack);
681 ASSERT_EQ(Expression::kValue, key->context());
682 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? 850 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
683 Smi::FromInt(1) : 851 Smi::FromInt(1) :
684 Smi::FromInt(0))); 852 Smi::FromInt(0)));
685 Visit(value); 853 VisitForValue(value, kStack);
686 ASSERT_EQ(Expression::kValue, value->context());
687 __ CallRuntime(Runtime::kDefineAccessor, 4); 854 __ CallRuntime(Runtime::kDefineAccessor, 4);
688 __ mov(eax, Operand(esp, 0)); // Restore result into eax.
689 break; 855 break;
690 default: UNREACHABLE(); 856 default: UNREACHABLE();
691 } 857 }
692 } 858 }
693 switch (expr->context()) { 859
694 case Expression::kUninitialized: 860 if (result_saved) {
695 UNREACHABLE(); 861 ApplyTOS(expr->context());
696 case Expression::kEffect: 862 } else {
697 if (result_saved) __ Drop(1); 863 Apply(expr->context(), eax);
698 break;
699 case Expression::kValue:
700 if (!result_saved) __ push(eax);
701 break;
702 case Expression::kTest:
703 if (result_saved) __ pop(eax);
704 TestAndBranch(eax, true_label_, false_label_);
705 break;
706 case Expression::kValueTest: {
707 Label discard;
708 if (!result_saved) __ push(eax);
709 TestAndBranch(eax, true_label_, &discard);
710 __ bind(&discard);
711 __ Drop(1);
712 __ jmp(false_label_);
713 break;
714 }
715 case Expression::kTestValue: {
716 Label discard;
717 if (!result_saved) __ push(eax);
718 TestAndBranch(eax, &discard, false_label_);
719 __ bind(&discard);
720 __ Drop(1);
721 __ jmp(true_label_);
722 break;
723 }
724 } 864 }
725 } 865 }
726 866
727 867
728 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 868 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
729 Comment cmnt(masm_, "[ ArrayLiteral"); 869 Comment cmnt(masm_, "[ ArrayLiteral");
730 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 870 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
731 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); 871 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
732 __ push(Immediate(Smi::FromInt(expr->literal_index()))); 872 __ push(Immediate(Smi::FromInt(expr->literal_index())));
733 __ push(Immediate(expr->constant_elements())); 873 __ push(Immediate(expr->constant_elements()));
(...skipping 14 matching lines...) Expand all
748 // is already set in the cloned array. 888 // is already set in the cloned array.
749 if (subexpr->AsLiteral() != NULL || 889 if (subexpr->AsLiteral() != NULL ||
750 CompileTimeValue::IsCompileTimeValue(subexpr)) { 890 CompileTimeValue::IsCompileTimeValue(subexpr)) {
751 continue; 891 continue;
752 } 892 }
753 893
754 if (!result_saved) { 894 if (!result_saved) {
755 __ push(eax); 895 __ push(eax);
756 result_saved = true; 896 result_saved = true;
757 } 897 }
758 Visit(subexpr); 898 VisitForValue(subexpr, kAccumulator);
759 ASSERT_EQ(Expression::kValue, subexpr->context());
760 899
761 // Store the subexpression value in the array's elements. 900 // Store the subexpression value in the array's elements.
762 __ pop(eax); // Subexpression value.
763 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. 901 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
764 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); 902 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
765 int offset = FixedArray::kHeaderSize + (i * kPointerSize); 903 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
766 __ mov(FieldOperand(ebx, offset), eax); 904 __ mov(FieldOperand(ebx, offset), result_register());
767 905
768 // Update the write barrier for the array store. 906 // Update the write barrier for the array store.
769 __ RecordWrite(ebx, offset, eax, ecx); 907 __ RecordWrite(ebx, offset, result_register(), ecx);
770 } 908 }
771 909
772 switch (expr->context()) { 910 if (result_saved) {
773 case Expression::kUninitialized: 911 ApplyTOS(expr->context());
774 UNREACHABLE(); 912 } else {
775 case Expression::kEffect: 913 Apply(expr->context(), eax);
776 if (result_saved) __ Drop(1);
777 break;
778 case Expression::kValue:
779 if (!result_saved) __ push(eax);
780 break;
781 case Expression::kTest:
782 if (result_saved) __ pop(eax);
783 TestAndBranch(eax, true_label_, false_label_);
784 break;
785 case Expression::kValueTest: {
786 Label discard;
787 if (!result_saved) __ push(eax);
788 TestAndBranch(eax, true_label_, &discard);
789 __ bind(&discard);
790 __ Drop(1);
791 __ jmp(false_label_);
792 break;
793 }
794 case Expression::kTestValue: {
795 Label discard;
796 if (!result_saved) __ push(eax);
797 TestAndBranch(eax, &discard, false_label_);
798 __ bind(&discard);
799 __ Drop(1);
800 __ jmp(true_label_);
801 break;
802 }
803 } 914 }
804 } 915 }
805 916
806 917
807 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop) { 918 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
808 SetSourcePosition(prop->position()); 919 SetSourcePosition(prop->position());
809 Literal* key = prop->key()->AsLiteral(); 920 Literal* key = prop->key()->AsLiteral();
810 __ mov(ecx, Immediate(key->handle())); 921 __ mov(ecx, Immediate(key->handle()));
811 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 922 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
812 __ call(ic, RelocInfo::CODE_TARGET); 923 __ call(ic, RelocInfo::CODE_TARGET);
813 __ nop(); 924 __ nop();
814 } 925 }
815 926
816 927
817 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { 928 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
818 SetSourcePosition(prop->position()); 929 SetSourcePosition(prop->position());
819 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 930 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
820 __ call(ic, RelocInfo::CODE_TARGET); 931 __ call(ic, RelocInfo::CODE_TARGET);
821 __ nop(); 932 __ nop();
822 } 933 }
823 934
824 935
825 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, 936 void FastCodeGenerator::EmitBinaryOp(Token::Value op,
826 Expression::Context context) { 937 Expression::Context context) {
938 __ push(result_register());
827 GenericBinaryOpStub stub(op, 939 GenericBinaryOpStub stub(op,
828 NO_OVERWRITE, 940 NO_OVERWRITE,
829 NO_GENERIC_BINARY_FLAGS); 941 NO_GENERIC_BINARY_FLAGS);
830 __ CallStub(&stub); 942 __ CallStub(&stub);
831 Apply(context, eax); 943 Apply(context, eax);
832 } 944 }
833 945
834 946
835 void FastCodeGenerator::EmitVariableAssignment(Variable* var, 947 void FastCodeGenerator::EmitVariableAssignment(Variable* var,
836 Expression::Context context) { 948 Expression::Context context) {
837 ASSERT(var != NULL); 949 ASSERT(var != NULL);
838 ASSERT(var->is_global() || var->slot() != NULL); 950 ASSERT(var->is_global() || var->slot() != NULL);
839 if (var->is_global()) { 951 if (var->is_global()) {
840 // Assignment to a global variable. Use inline caching for the 952 // Assignment to a global variable. Use inline caching for the
841 // assignment. Right-hand-side value is passed in eax, variable name in 953 // assignment. Right-hand-side value is passed in eax, variable name in
842 // ecx, and the global object on the stack. 954 // ecx, and the global object on the stack.
843 __ pop(eax);
844 __ mov(ecx, var->name()); 955 __ mov(ecx, var->name());
845 __ push(CodeGenerator::GlobalObject()); 956 __ push(CodeGenerator::GlobalObject());
846 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 957 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
847 __ call(ic, RelocInfo::CODE_TARGET); 958 __ call(ic, RelocInfo::CODE_TARGET);
848 __ nop(); 959 __ nop();
849 // Overwrite the receiver on the stack with the result if needed. 960 // Overwrite the receiver on the stack with the result if needed.
850 DropAndApply(1, context, eax); 961 DropAndApply(1, context, eax);
851 962
852 } else if (var->slot() != NULL) { 963 } else if (var->slot() != NULL) {
853 Slot* slot = var->slot(); 964 Slot* slot = var->slot();
854 switch (slot->type()) { 965 switch (slot->type()) {
855 case Slot::LOCAL: 966 case Slot::LOCAL:
856 case Slot::PARAMETER: { 967 case Slot::PARAMETER:
857 Operand target = Operand(ebp, SlotOffset(slot)); 968 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
858 switch (context) { 969 break;
859 case Expression::kUninitialized: 970
860 UNREACHABLE(); 971 case Slot::CONTEXT: {
861 case Expression::kEffect: 972 MemOperand target = EmitSlotSearch(slot, ecx);
862 // Perform assignment and discard value. 973 __ mov(target, result_register());
863 __ pop(target); 974
864 break; 975 // RecordWrite may destroy all its register arguments.
865 case Expression::kValue: 976 __ mov(edx, result_register());
866 // Perform assignment and preserve value. 977 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
867 __ mov(eax, Operand(esp, 0)); 978 __ RecordWrite(ecx, offset, edx, ebx);
868 __ mov(target, eax);
869 break;
870 case Expression::kTest:
871 // Perform assignment and test (and discard) value.
872 __ pop(eax);
873 __ mov(target, eax);
874 TestAndBranch(eax, true_label_, false_label_);
875 break;
876 case Expression::kValueTest: {
877 Label discard;
878 __ mov(eax, Operand(esp, 0));
879 __ mov(target, eax);
880 TestAndBranch(eax, true_label_, &discard);
881 __ bind(&discard);
882 __ Drop(1);
883 __ jmp(false_label_);
884 break;
885 }
886 case Expression::kTestValue: {
887 Label discard;
888 __ mov(eax, Operand(esp, 0));
889 __ mov(target, eax);
890 TestAndBranch(eax, &discard, false_label_);
891 __ bind(&discard);
892 __ Drop(1);
893 __ jmp(true_label_);
894 break;
895 }
896 }
897 break; 979 break;
898 } 980 }
899 981
900 case Slot::CONTEXT: {
901 MemOperand target = EmitSlotSearch(slot, ecx);
902 __ pop(eax);
903 __ mov(target, eax);
904
905 // RecordWrite may destroy all its register arguments.
906 if (context == Expression::kValue) {
907 __ push(eax);
908 } else if (context != Expression::kEffect) {
909 __ mov(edx, eax);
910 }
911 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
912 __ RecordWrite(ecx, offset, eax, ebx);
913 if (context != Expression::kEffect && context != Expression::kValue) {
914 Apply(context, edx);
915 }
916 break;
917 }
918
919 case Slot::LOOKUP: 982 case Slot::LOOKUP:
920 UNREACHABLE(); 983 UNREACHABLE();
921 break; 984 break;
922 } 985 }
986 Apply(context, result_register());
987
923 } else { 988 } else {
924 // Variables rewritten as properties are not treated as variables in 989 // Variables rewritten as properties are not treated as variables in
925 // assignments. 990 // assignments.
926 UNREACHABLE(); 991 UNREACHABLE();
927 } 992 }
928 } 993 }
929 994
930 995
931 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 996 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
932 // Assignment to a property, using a named store IC. 997 // Assignment to a property, using a named store IC.
933 Property* prop = expr->target()->AsProperty(); 998 Property* prop = expr->target()->AsProperty();
934 ASSERT(prop != NULL); 999 ASSERT(prop != NULL);
935 ASSERT(prop->key()->AsLiteral() != NULL); 1000 ASSERT(prop->key()->AsLiteral() != NULL);
936 1001
937 // If the assignment starts a block of assignments to the same object, 1002 // If the assignment starts a block of assignments to the same object,
938 // change to slow case to avoid the quadratic behavior of repeatedly 1003 // change to slow case to avoid the quadratic behavior of repeatedly
939 // adding fast properties. 1004 // adding fast properties.
940 if (expr->starts_initialization_block()) { 1005 if (expr->starts_initialization_block()) {
941 __ push(Operand(esp, kPointerSize)); // Receiver is under value. 1006 __ push(result_register());
1007 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
942 __ CallRuntime(Runtime::kToSlowProperties, 1); 1008 __ CallRuntime(Runtime::kToSlowProperties, 1);
1009 __ pop(result_register());
943 } 1010 }
944 1011
945 // Record source code position before IC call. 1012 // Record source code position before IC call.
946 SetSourcePosition(expr->position()); 1013 SetSourcePosition(expr->position());
947
948 __ pop(eax);
949 __ mov(ecx, prop->key()->AsLiteral()->handle()); 1014 __ mov(ecx, prop->key()->AsLiteral()->handle());
950 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 1015 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
951 __ call(ic, RelocInfo::CODE_TARGET); 1016 __ call(ic, RelocInfo::CODE_TARGET);
1017 __ nop();
952 1018
953 // If the assignment ends an initialization block, revert to fast case. 1019 // If the assignment ends an initialization block, revert to fast case.
954 if (expr->ends_initialization_block()) { 1020 if (expr->ends_initialization_block()) {
955 __ push(eax); // Result of assignment, saved even if not needed. 1021 __ push(eax); // Result of assignment, saved even if not needed.
956 __ push(Operand(esp, kPointerSize)); // Receiver is under value. 1022 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
957 __ CallRuntime(Runtime::kToFastProperties, 1); 1023 __ CallRuntime(Runtime::kToFastProperties, 1);
958 __ pop(eax); 1024 __ pop(eax);
959 } 1025 }
960 1026
961 DropAndApply(1, expr->context(), eax); 1027 DropAndApply(1, expr->context(), eax);
962 } 1028 }
963 1029
964 1030
965 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { 1031 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
966 // Assignment to a property, using a keyed store IC. 1032 // Assignment to a property, using a keyed store IC.
967 1033
968 // If the assignment starts a block of assignments to the same object, 1034 // If the assignment starts a block of assignments to the same object,
969 // change to slow case to avoid the quadratic behavior of repeatedly 1035 // change to slow case to avoid the quadratic behavior of repeatedly
970 // adding fast properties. 1036 // adding fast properties.
971 if (expr->starts_initialization_block()) { 1037 if (expr->starts_initialization_block()) {
972 // Reciever is under the key and value. 1038 __ push(result_register());
1039 // Receiver is now under the key and value.
973 __ push(Operand(esp, 2 * kPointerSize)); 1040 __ push(Operand(esp, 2 * kPointerSize));
974 __ CallRuntime(Runtime::kToSlowProperties, 1); 1041 __ CallRuntime(Runtime::kToSlowProperties, 1);
1042 __ pop(result_register());
975 } 1043 }
976 1044
977 // Record source code position before IC call. 1045 // Record source code position before IC call.
978 SetSourcePosition(expr->position()); 1046 SetSourcePosition(expr->position());
979
980 __ pop(eax);
981 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 1047 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
982 __ call(ic, RelocInfo::CODE_TARGET); 1048 __ call(ic, RelocInfo::CODE_TARGET);
983 // This nop signals to the IC that there is no inlined code at the call 1049 // This nop signals to the IC that there is no inlined code at the call
984 // site for it to patch. 1050 // site for it to patch.
985 __ nop(); 1051 __ nop();
986 1052
987 // If the assignment ends an initialization block, revert to fast case. 1053 // If the assignment ends an initialization block, revert to fast case.
988 if (expr->ends_initialization_block()) { 1054 if (expr->ends_initialization_block()) {
989 __ push(eax); // Result of assignment, saved even if not needed. 1055 __ push(eax); // Result of assignment, saved even if not needed.
990 // Reciever is under the key and value. 1056 // Receiver is under the key and value.
991 __ push(Operand(esp, 2 * kPointerSize)); 1057 __ push(Operand(esp, 2 * kPointerSize));
992 __ CallRuntime(Runtime::kToFastProperties, 1); 1058 __ CallRuntime(Runtime::kToFastProperties, 1);
993 __ pop(eax); 1059 __ pop(eax);
994 } 1060 }
995 1061
996 // Receiver and key are still on stack. 1062 // Receiver and key are still on stack.
997 DropAndApply(2, expr->context(), eax); 1063 DropAndApply(2, expr->context(), eax);
998 } 1064 }
999 1065
1000 1066
1001 void FastCodeGenerator::VisitProperty(Property* expr) { 1067 void FastCodeGenerator::VisitProperty(Property* expr) {
1002 Comment cmnt(masm_, "[ Property"); 1068 Comment cmnt(masm_, "[ Property");
1003 Expression* key = expr->key(); 1069 Expression* key = expr->key();
1004 1070
1005 // Evaluate the receiver. 1071 // Evaluate the receiver.
1006 Visit(expr->obj()); 1072 VisitForValue(expr->obj(), kStack);
1007 1073
1008 if (key->IsPropertyName()) { 1074 if (key->IsPropertyName()) {
1009 EmitNamedPropertyLoad(expr); 1075 EmitNamedPropertyLoad(expr);
1010 // Drop receiver left on the stack by IC. 1076 // Drop receiver left on the stack by IC.
1011 DropAndApply(1, expr->context(), eax); 1077 DropAndApply(1, expr->context(), eax);
1012 } else { 1078 } else {
1013 Visit(expr->key()); 1079 VisitForValue(expr->key(), kStack);
1014 EmitKeyedPropertyLoad(expr); 1080 EmitKeyedPropertyLoad(expr);
1015 // Drop key and receiver left on the stack by IC. 1081 // Drop key and receiver left on the stack by IC.
1016 DropAndApply(2, expr->context(), eax); 1082 DropAndApply(2, expr->context(), eax);
1017 } 1083 }
1018 } 1084 }
1019 1085
1020 1086
1021 void FastCodeGenerator::EmitCallWithIC(Call* expr, 1087 void FastCodeGenerator::EmitCallWithIC(Call* expr,
1022 Handle<Object> name, 1088 Handle<Object> name,
1023 RelocInfo::Mode mode) { 1089 RelocInfo::Mode mode) {
1024 // Code common for calls using the IC. 1090 // Code common for calls using the IC.
1025 ZoneList<Expression*>* args = expr->arguments(); 1091 ZoneList<Expression*>* args = expr->arguments();
1026 int arg_count = args->length(); 1092 int arg_count = args->length();
1027 for (int i = 0; i < arg_count; i++) { 1093 for (int i = 0; i < arg_count; i++) {
1028 Visit(args->at(i)); 1094 VisitForValue(args->at(i), kStack);
1029 ASSERT_EQ(Expression::kValue, args->at(i)->context());
1030 } 1095 }
1031 __ Set(ecx, Immediate(name)); 1096 __ Set(ecx, Immediate(name));
1032 // Record source position of the IC call. 1097 // Record source position of the IC call.
1033 SetSourcePosition(expr->position()); 1098 SetSourcePosition(expr->position());
1034 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 1099 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1035 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); 1100 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
1036 __ call(ic, mode); 1101 __ call(ic, mode);
1037 // Restore context register. 1102 // Restore context register.
1038 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 1103 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1039 Apply(expr->context(), eax); 1104 Apply(expr->context(), eax);
1040 } 1105 }
1041 1106
1042 1107
1043 void FastCodeGenerator::EmitCallWithStub(Call* expr) { 1108 void FastCodeGenerator::EmitCallWithStub(Call* expr) {
1044 // Code common for calls using the call stub. 1109 // Code common for calls using the call stub.
1045 ZoneList<Expression*>* args = expr->arguments(); 1110 ZoneList<Expression*>* args = expr->arguments();
1046 int arg_count = args->length(); 1111 int arg_count = args->length();
1047 for (int i = 0; i < arg_count; i++) { 1112 for (int i = 0; i < arg_count; i++) {
1048 Visit(args->at(i)); 1113 VisitForValue(args->at(i), kStack);
1049 } 1114 }
1050 // Record source position for debugger. 1115 // Record source position for debugger.
1051 SetSourcePosition(expr->position()); 1116 SetSourcePosition(expr->position());
1052 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); 1117 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
1053 __ CallStub(&stub); 1118 __ CallStub(&stub);
1054 // Restore context register. 1119 // Restore context register.
1055 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 1120 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1056 DropAndApply(1, expr->context(), eax); 1121 DropAndApply(1, expr->context(), eax);
1057 } 1122 }
1058 1123
(...skipping 13 matching lines...) Expand all
1072 } else if (var != NULL && var->slot() != NULL && 1137 } else if (var != NULL && var->slot() != NULL &&
1073 var->slot()->type() == Slot::LOOKUP) { 1138 var->slot()->type() == Slot::LOOKUP) {
1074 // Call to a lookup slot. 1139 // Call to a lookup slot.
1075 UNREACHABLE(); 1140 UNREACHABLE();
1076 } else if (fun->AsProperty() != NULL) { 1141 } else if (fun->AsProperty() != NULL) {
1077 // Call to an object property. 1142 // Call to an object property.
1078 Property* prop = fun->AsProperty(); 1143 Property* prop = fun->AsProperty();
1079 Literal* key = prop->key()->AsLiteral(); 1144 Literal* key = prop->key()->AsLiteral();
1080 if (key != NULL && key->handle()->IsSymbol()) { 1145 if (key != NULL && key->handle()->IsSymbol()) {
1081 // Call to a named property, use call IC. 1146 // Call to a named property, use call IC.
1082 Visit(prop->obj()); 1147 VisitForValue(prop->obj(), kStack);
1083 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); 1148 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1084 } else { 1149 } else {
1085 // Call to a keyed property, use keyed load IC followed by function 1150 // Call to a keyed property, use keyed load IC followed by function
1086 // call. 1151 // call.
1087 Visit(prop->obj()); 1152 VisitForValue(prop->obj(), kStack);
1088 Visit(prop->key()); 1153 VisitForValue(prop->key(), kStack);
1089 // Record source code position for IC call. 1154 // Record source code position for IC call.
1090 SetSourcePosition(prop->position()); 1155 SetSourcePosition(prop->position());
1091 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 1156 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1092 __ call(ic, RelocInfo::CODE_TARGET); 1157 __ call(ic, RelocInfo::CODE_TARGET);
1093 // By emitting a nop we make sure that we do not have a "test eax,..." 1158 // By emitting a nop we make sure that we do not have a "test eax,..."
1094 // instruction after the call it is treated specially by the LoadIC code. 1159 // instruction after the call it is treated specially by the LoadIC code.
1095 __ nop(); 1160 __ nop();
1096 // Drop key left on the stack by IC. 1161 // Drop key left on the stack by IC.
1097 __ Drop(1); 1162 __ Drop(1);
1098 // Pop receiver. 1163 // Pop receiver.
(...skipping 12 matching lines...) Expand all
1111 } else { 1176 } else {
1112 // Call to some other expression. If the expression is an anonymous 1177 // Call to some other expression. If the expression is an anonymous
1113 // function literal not called in a loop, mark it as one that should 1178 // function literal not called in a loop, mark it as one that should
1114 // also use the fast code generator. 1179 // also use the fast code generator.
1115 FunctionLiteral* lit = fun->AsFunctionLiteral(); 1180 FunctionLiteral* lit = fun->AsFunctionLiteral();
1116 if (lit != NULL && 1181 if (lit != NULL &&
1117 lit->name()->Equals(Heap::empty_string()) && 1182 lit->name()->Equals(Heap::empty_string()) &&
1118 loop_depth() == 0) { 1183 loop_depth() == 0) {
1119 lit->set_try_fast_codegen(true); 1184 lit->set_try_fast_codegen(true);
1120 } 1185 }
1121 Visit(fun); 1186 VisitForValue(fun, kStack);
1122 // Load global receiver object. 1187 // Load global receiver object.
1123 __ mov(ebx, CodeGenerator::GlobalObject()); 1188 __ mov(ebx, CodeGenerator::GlobalObject());
1124 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); 1189 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
1125 // Emit function call. 1190 // Emit function call.
1126 EmitCallWithStub(expr); 1191 EmitCallWithStub(expr);
1127 } 1192 }
1128 } 1193 }
1129 1194
1130 1195
1131 void FastCodeGenerator::VisitCallNew(CallNew* expr) { 1196 void FastCodeGenerator::VisitCallNew(CallNew* expr) {
1132 Comment cmnt(masm_, "[ CallNew"); 1197 Comment cmnt(masm_, "[ CallNew");
1133 // According to ECMA-262, section 11.2.2, page 44, the function 1198 // According to ECMA-262, section 11.2.2, page 44, the function
1134 // expression in new calls must be evaluated before the 1199 // expression in new calls must be evaluated before the
1135 // arguments. 1200 // arguments.
1136 // Push function on the stack. 1201 // Push function on the stack.
1137 Visit(expr->expression()); 1202 VisitForValue(expr->expression(), kStack);
1138 ASSERT_EQ(Expression::kValue, expr->expression()->context());
1139 1203
1140 // Push global object (receiver). 1204 // Push global object (receiver).
1141 __ push(CodeGenerator::GlobalObject()); 1205 __ push(CodeGenerator::GlobalObject());
1142 1206
1143 // Push the arguments ("left-to-right") on the stack. 1207 // Push the arguments ("left-to-right") on the stack.
1144 ZoneList<Expression*>* args = expr->arguments(); 1208 ZoneList<Expression*>* args = expr->arguments();
1145 int arg_count = args->length(); 1209 int arg_count = args->length();
1146 for (int i = 0; i < arg_count; i++) { 1210 for (int i = 0; i < arg_count; i++) {
1147 Visit(args->at(i)); 1211 VisitForValue(args->at(i), kStack);
1148 ASSERT_EQ(Expression::kValue, args->at(i)->context());
1149 // If location is value, it is already on the stack,
1150 // so nothing to do here.
1151 } 1212 }
1152 1213
1153 // Call the construct call builtin that handles allocation and 1214 // Call the construct call builtin that handles allocation and
1154 // constructor invocation. 1215 // constructor invocation.
1155 SetSourcePosition(expr->position()); 1216 SetSourcePosition(expr->position());
1156 1217
1157 // Load function, arg_count into edi and eax. 1218 // Load function, arg_count into edi and eax.
1158 __ Set(eax, Immediate(arg_count)); 1219 __ Set(eax, Immediate(arg_count));
1159 // Function is in esp[arg_count + 1]. 1220 // Function is in esp[arg_count + 1].
1160 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); 1221 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
(...skipping 12 matching lines...) Expand all
1173 1234
1174 if (expr->is_jsruntime()) { 1235 if (expr->is_jsruntime()) {
1175 // Prepare for calling JS runtime function. 1236 // Prepare for calling JS runtime function.
1176 __ mov(eax, CodeGenerator::GlobalObject()); 1237 __ mov(eax, CodeGenerator::GlobalObject());
1177 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); 1238 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
1178 } 1239 }
1179 1240
1180 // Push the arguments ("left-to-right"). 1241 // Push the arguments ("left-to-right").
1181 int arg_count = args->length(); 1242 int arg_count = args->length();
1182 for (int i = 0; i < arg_count; i++) { 1243 for (int i = 0; i < arg_count; i++) {
1183 Visit(args->at(i)); 1244 VisitForValue(args->at(i), kStack);
1184 ASSERT_EQ(Expression::kValue, args->at(i)->context());
1185 } 1245 }
1186 1246
1187 if (expr->is_jsruntime()) { 1247 if (expr->is_jsruntime()) {
1188 // Call the JS runtime function via a call IC. 1248 // Call the JS runtime function via a call IC.
1189 __ Set(ecx, Immediate(expr->name())); 1249 __ Set(ecx, Immediate(expr->name()));
1190 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 1250 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1191 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); 1251 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
1192 __ call(ic, RelocInfo::CODE_TARGET); 1252 __ call(ic, RelocInfo::CODE_TARGET);
1193 // Restore context register. 1253 // Restore context register.
1194 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 1254 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1195 } else { 1255 } else {
1196 // Call the C runtime function. 1256 // Call the C runtime function.
1197 __ CallRuntime(expr->function(), arg_count); 1257 __ CallRuntime(expr->function(), arg_count);
1198 } 1258 }
1199 Apply(expr->context(), eax); 1259 Apply(expr->context(), eax);
1200 } 1260 }
1201 1261
1202 1262
1203 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 1263 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
1204 switch (expr->op()) { 1264 switch (expr->op()) {
1205 case Token::VOID: { 1265 case Token::VOID: {
1206 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 1266 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
1267 ASSERT_EQ(Expression::kEffect, expr->expression()->context());
1207 Visit(expr->expression()); 1268 Visit(expr->expression());
1208 ASSERT_EQ(Expression::kEffect, expr->expression()->context());
1209 switch (expr->context()) { 1269 switch (expr->context()) {
1210 case Expression::kUninitialized: 1270 case Expression::kUninitialized:
1211 UNREACHABLE(); 1271 UNREACHABLE();
1212 break; 1272 break;
1213 case Expression::kEffect: 1273 case Expression::kEffect:
1214 break; 1274 break;
1215 case Expression::kValue: 1275 case Expression::kValue:
1216 __ push(Immediate(Factory::undefined_value())); 1276 switch (location_) {
1277 case kAccumulator:
1278 __ mov(result_register(), Factory::undefined_value());
1279 break;
1280 case kStack:
1281 __ push(Immediate(Factory::undefined_value()));
1282 break;
1283 }
1217 break; 1284 break;
1218 case Expression::kTestValue: 1285 case Expression::kTestValue:
1219 // Value is false so it's needed. 1286 // Value is false so it's needed.
1220 __ push(Immediate(Factory::undefined_value())); 1287 switch (location_) {
1288 case kAccumulator:
1289 __ mov(result_register(), Factory::undefined_value());
1290 break;
1291 case kStack:
1292 __ push(Immediate(Factory::undefined_value()));
1293 break;
1294 }
1221 // Fall through. 1295 // Fall through.
1222 case Expression::kTest: 1296 case Expression::kTest:
1223 case Expression::kValueTest: 1297 case Expression::kValueTest:
1224 __ jmp(false_label_); 1298 __ jmp(false_label_);
1225 break; 1299 break;
1226 } 1300 }
1227 break; 1301 break;
1228 } 1302 }
1229 1303
1230 case Token::NOT: { 1304 case Token::NOT: {
1231 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 1305 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
1232 ASSERT_EQ(Expression::kTest, expr->expression()->context()); 1306 ASSERT_EQ(Expression::kTest, expr->expression()->context());
1233 1307
1234 Label push_true, push_false, done; 1308 Label materialize_true, materialize_false, done;
1309 // Initially assume a pure test context. Notice that the labels are
1310 // swapped.
1311 Label* if_true = false_label_;
1312 Label* if_false = true_label_;
1235 switch (expr->context()) { 1313 switch (expr->context()) {
1236 case Expression::kUninitialized: 1314 case Expression::kUninitialized:
1237 UNREACHABLE(); 1315 UNREACHABLE();
1238 break; 1316 break;
1239
1240 case Expression::kEffect: 1317 case Expression::kEffect:
1241 VisitForControl(expr->expression(), &done, &done); 1318 if_true = &done;
1242 __ bind(&done); 1319 if_false = &done;
1243 break; 1320 break;
1244
1245 case Expression::kValue: 1321 case Expression::kValue:
1246 VisitForControl(expr->expression(), &push_false, &push_true); 1322 if_true = &materialize_false;
1247 __ bind(&push_true); 1323 if_false = &materialize_true;
1248 __ push(Immediate(Factory::true_value()));
1249 __ jmp(&done);
1250 __ bind(&push_false);
1251 __ push(Immediate(Factory::false_value()));
1252 __ bind(&done);
1253 break; 1324 break;
1254
1255 case Expression::kTest: 1325 case Expression::kTest:
1256 VisitForControl(expr->expression(), false_label_, true_label_);
1257 break; 1326 break;
1258
1259 case Expression::kValueTest: 1327 case Expression::kValueTest:
1260 VisitForControl(expr->expression(), false_label_, &push_true); 1328 if_false = &materialize_true;
1261 __ bind(&push_true);
1262 __ push(Immediate(Factory::true_value()));
1263 __ jmp(true_label_);
1264 break; 1329 break;
1265
1266 case Expression::kTestValue: 1330 case Expression::kTestValue:
1267 VisitForControl(expr->expression(), &push_false, true_label_); 1331 if_true = &materialize_false;
1268 __ bind(&push_false);
1269 __ push(Immediate(Factory::false_value()));
1270 __ jmp(false_label_);
1271 break; 1332 break;
1272 } 1333 }
1334 VisitForControl(expr->expression(), if_true, if_false);
1335 Apply(expr->context(), if_false, if_true); // Labels swapped.
1273 break; 1336 break;
1274 } 1337 }
1275 1338
1276 case Token::TYPEOF: { 1339 case Token::TYPEOF: {
1277 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 1340 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
1278 ASSERT_EQ(Expression::kValue, expr->expression()->context()); 1341 ASSERT_EQ(Expression::kValue, expr->expression()->context());
1279 1342
1280 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 1343 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1281 if (proxy != NULL && 1344 if (proxy != NULL &&
1282 !proxy->var()->is_this() && 1345 !proxy->var()->is_this() &&
1283 proxy->var()->is_global()) { 1346 proxy->var()->is_global()) {
1284 Comment cmnt(masm_, "Global variable"); 1347 Comment cmnt(masm_, "Global variable");
1285 __ push(CodeGenerator::GlobalObject()); 1348 __ push(CodeGenerator::GlobalObject());
1286 __ mov(ecx, Immediate(proxy->name())); 1349 __ mov(ecx, Immediate(proxy->name()));
1287 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 1350 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1288 // Use a regular load, not a contextual load, to avoid a reference 1351 // Use a regular load, not a contextual load, to avoid a reference
1289 // error. 1352 // error.
1290 __ call(ic, RelocInfo::CODE_TARGET); 1353 __ call(ic, RelocInfo::CODE_TARGET);
1291 __ mov(Operand(esp, 0), eax); 1354 __ mov(Operand(esp, 0), eax);
1292 } else if (proxy != NULL && 1355 } else if (proxy != NULL &&
1293 proxy->var()->slot() != NULL && 1356 proxy->var()->slot() != NULL &&
1294 proxy->var()->slot()->type() == Slot::LOOKUP) { 1357 proxy->var()->slot()->type() == Slot::LOOKUP) {
1295 __ push(esi); 1358 __ push(esi);
1296 __ push(Immediate(proxy->name())); 1359 __ push(Immediate(proxy->name()));
1297 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); 1360 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
1298 __ push(eax); 1361 __ push(eax);
1299 } else { 1362 } else {
1300 // This expression cannot throw a reference error at the top level. 1363 // This expression cannot throw a reference error at the top level.
1301 Visit(expr->expression()); 1364 VisitForValue(expr->expression(), kStack);
1302 } 1365 }
1303 1366
1304 __ CallRuntime(Runtime::kTypeof, 1); 1367 __ CallRuntime(Runtime::kTypeof, 1);
1305 Apply(expr->context(), eax); 1368 Apply(expr->context(), eax);
1306 break; 1369 break;
1307 } 1370 }
1308 1371
1309 default: 1372 default:
1310 UNREACHABLE(); 1373 UNREACHABLE();
1311 } 1374 }
(...skipping 12 matching lines...) Expand all
1324 // of the key to detect a named property. 1387 // of the key to detect a named property.
1325 if (prop != NULL) { 1388 if (prop != NULL) {
1326 assign_type = (prop->key()->context() == Expression::kUninitialized) 1389 assign_type = (prop->key()->context() == Expression::kUninitialized)
1327 ? NAMED_PROPERTY 1390 ? NAMED_PROPERTY
1328 : KEYED_PROPERTY; 1391 : KEYED_PROPERTY;
1329 } 1392 }
1330 1393
1331 // Evaluate expression and get value. 1394 // Evaluate expression and get value.
1332 if (assign_type == VARIABLE) { 1395 if (assign_type == VARIABLE) {
1333 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); 1396 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
1397 Location saved_location = location_;
1398 location_ = kStack;
1334 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), 1399 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
1335 Expression::kValue); 1400 Expression::kValue);
1401 location_ = saved_location;
1336 } else { 1402 } else {
1337 // Reserve space for result of postfix operation. 1403 // Reserve space for result of postfix operation.
1338 if (expr->is_postfix() && expr->context() != Expression::kEffect) { 1404 if (expr->is_postfix() && expr->context() != Expression::kEffect) {
1339 ASSERT(expr->context() != Expression::kUninitialized); 1405 ASSERT(expr->context() != Expression::kUninitialized);
1340 __ push(Immediate(Smi::FromInt(0))); 1406 __ push(Immediate(Smi::FromInt(0)));
1341 } 1407 }
1342 Visit(prop->obj()); 1408 VisitForValue(prop->obj(), kStack);
1343 ASSERT_EQ(Expression::kValue, prop->obj()->context());
1344 if (assign_type == NAMED_PROPERTY) { 1409 if (assign_type == NAMED_PROPERTY) {
1345 EmitNamedPropertyLoad(prop); 1410 EmitNamedPropertyLoad(prop);
1346 } else { 1411 } else {
1347 Visit(prop->key()); 1412 VisitForValue(prop->key(), kStack);
1348 ASSERT_EQ(Expression::kValue, prop->key()->context());
1349 EmitKeyedPropertyLoad(prop); 1413 EmitKeyedPropertyLoad(prop);
1350 } 1414 }
1351 __ push(eax); 1415 __ push(eax);
1352 } 1416 }
1353 1417
1354 // Convert to number. 1418 // Convert to number.
1355 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); 1419 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
1356 1420
1357 // Save result for postfix expressions. 1421 // Save result for postfix expressions.
1358 if (expr->is_postfix()) { 1422 if (expr->is_postfix()) {
1359 switch (expr->context()) { 1423 switch (expr->context()) {
1360 case Expression::kUninitialized: 1424 case Expression::kUninitialized:
1361 UNREACHABLE(); 1425 UNREACHABLE();
1362 case Expression::kEffect: 1426 case Expression::kEffect:
1363 // Do not save result. 1427 // Do not save result.
1364 break; 1428 break;
1365 case Expression::kValue: 1429 case Expression::kValue:
1366 case Expression::kTest: 1430 case Expression::kTest:
1431 case Expression::kValueTest:
1367 case Expression::kTestValue: 1432 case Expression::kTestValue:
1368 case Expression::kValueTest:
1369 // Save the result on the stack. If we have a named or keyed property 1433 // Save the result on the stack. If we have a named or keyed property
1370 // we store the result under the receiver that is currently on top 1434 // we store the result under the receiver that is currently on top
1371 // of the stack. 1435 // of the stack.
1372 switch (assign_type) { 1436 switch (assign_type) {
1373 case VARIABLE: 1437 case VARIABLE:
1374 __ push(eax); 1438 __ push(eax);
1375 break; 1439 break;
1376 case NAMED_PROPERTY: 1440 case NAMED_PROPERTY:
1377 __ mov(Operand(esp, kPointerSize), eax); 1441 __ mov(Operand(esp, kPointerSize), eax);
1378 break; 1442 break;
1379 case KEYED_PROPERTY: 1443 case KEYED_PROPERTY:
1380 __ mov(Operand(esp, 2 * kPointerSize), eax); 1444 __ mov(Operand(esp, 2 * kPointerSize), eax);
1381 break; 1445 break;
1382 } 1446 }
1383 break; 1447 break;
1384 } 1448 }
1385 } 1449 }
1386 1450
1387 // Call stub for +1/-1. 1451 // Call stub for +1/-1.
1388 __ push(eax); 1452 __ push(eax);
1389 __ push(Immediate(Smi::FromInt(1))); 1453 __ push(Immediate(Smi::FromInt(1)));
1390 GenericBinaryOpStub stub(expr->binary_op(), 1454 GenericBinaryOpStub stub(expr->binary_op(),
1391 NO_OVERWRITE, 1455 NO_OVERWRITE,
1392 NO_GENERIC_BINARY_FLAGS); 1456 NO_GENERIC_BINARY_FLAGS);
1393 __ CallStub(&stub); 1457 __ CallStub(&stub);
1394 1458
1395 // Store the value returned in eax. 1459 // Store the value returned in eax.
1396 switch (assign_type) { 1460 switch (assign_type) {
1397 case VARIABLE: 1461 case VARIABLE:
1398 __ push(eax);
1399 if (expr->is_postfix()) { 1462 if (expr->is_postfix()) {
1400 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 1463 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
1401 Expression::kEffect); 1464 Expression::kEffect);
1402 // For all contexts except kEffect: We have the result on 1465 // For all contexts except kEffect: We have the result on
1403 // top of the stack. 1466 // top of the stack.
1404 if (expr->context() != Expression::kEffect) { 1467 if (expr->context() != Expression::kEffect) {
1405 ApplyTOS(expr->context()); 1468 ApplyTOS(expr->context());
1406 } 1469 }
1407 } else { 1470 } else {
1408 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 1471 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1464 case Token::ADD: 1527 case Token::ADD:
1465 case Token::SUB: 1528 case Token::SUB:
1466 case Token::DIV: 1529 case Token::DIV:
1467 case Token::MOD: 1530 case Token::MOD:
1468 case Token::MUL: 1531 case Token::MUL:
1469 case Token::BIT_OR: 1532 case Token::BIT_OR:
1470 case Token::BIT_AND: 1533 case Token::BIT_AND:
1471 case Token::BIT_XOR: 1534 case Token::BIT_XOR:
1472 case Token::SHL: 1535 case Token::SHL:
1473 case Token::SHR: 1536 case Token::SHR:
1474 case Token::SAR: { 1537 case Token::SAR:
1475 ASSERT_EQ(Expression::kValue, expr->left()->context()); 1538 VisitForValue(expr->left(), kStack);
1476 ASSERT_EQ(Expression::kValue, expr->right()->context()); 1539 VisitForValue(expr->right(), kAccumulator);
1540 EmitBinaryOp(expr->op(), expr->context());
1541 break;
1477 1542
1478 Visit(expr->left());
1479 Visit(expr->right());
1480 GenericBinaryOpStub stub(expr->op(),
1481 NO_OVERWRITE,
1482 NO_GENERIC_BINARY_FLAGS);
1483 __ CallStub(&stub);
1484 Apply(expr->context(), eax);
1485
1486 break;
1487 }
1488 default: 1543 default:
1489 UNREACHABLE(); 1544 UNREACHABLE();
1490 } 1545 }
1491 } 1546 }
1492 1547
1493 1548
1494 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 1549 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
1495 Comment cmnt(masm_, "[ CompareOperation"); 1550 Comment cmnt(masm_, "[ CompareOperation");
1496 ASSERT_EQ(Expression::kValue, expr->left()->context());
1497 ASSERT_EQ(Expression::kValue, expr->right()->context());
1498 Visit(expr->left());
1499 Visit(expr->right());
1500 1551
1501 // Always perform the comparison for its control flow. Pack the result 1552 // Always perform the comparison for its control flow. Pack the result
1502 // into the expression's context after the comparison is performed. 1553 // into the expression's context after the comparison is performed.
1503 Label push_true, push_false, done; 1554 Label materialize_true, materialize_false, done;
1504 // Initially assume we are in a test context. 1555 // Initially assume we are in a test context.
1505 Label* if_true = true_label_; 1556 Label* if_true = true_label_;
1506 Label* if_false = false_label_; 1557 Label* if_false = false_label_;
1507 switch (expr->context()) { 1558 switch (expr->context()) {
1508 case Expression::kUninitialized: 1559 case Expression::kUninitialized:
1509 UNREACHABLE(); 1560 UNREACHABLE();
1510 break; 1561 break;
1511 case Expression::kEffect: 1562 case Expression::kEffect:
1512 if_true = &done; 1563 if_true = &done;
1513 if_false = &done; 1564 if_false = &done;
1514 break; 1565 break;
1515 case Expression::kValue: 1566 case Expression::kValue:
1516 if_true = &push_true; 1567 if_true = &materialize_true;
1517 if_false = &push_false; 1568 if_false = &materialize_false;
1518 break; 1569 break;
1519 case Expression::kTest: 1570 case Expression::kTest:
1520 break; 1571 break;
1521 case Expression::kValueTest: 1572 case Expression::kValueTest:
1522 if_true = &push_true; 1573 if_true = &materialize_true;
1523 break; 1574 break;
1524 case Expression::kTestValue: 1575 case Expression::kTestValue:
1525 if_false = &push_false; 1576 if_false = &materialize_false;
1526 break; 1577 break;
1527 } 1578 }
1528 1579
1580 VisitForValue(expr->left(), kStack);
1529 switch (expr->op()) { 1581 switch (expr->op()) {
1530 case Token::IN: { 1582 case Token::IN:
1583 VisitForValue(expr->right(), kStack);
1531 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); 1584 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
1532 __ cmp(eax, Factory::true_value()); 1585 __ cmp(eax, Factory::true_value());
1533 __ j(equal, if_true); 1586 __ j(equal, if_true);
1534 __ jmp(if_false); 1587 __ jmp(if_false);
1535 break; 1588 break;
1536 }
1537 1589
1538 case Token::INSTANCEOF: { 1590 case Token::INSTANCEOF: {
1591 VisitForValue(expr->right(), kStack);
1539 InstanceofStub stub; 1592 InstanceofStub stub;
1540 __ CallStub(&stub); 1593 __ CallStub(&stub);
1541 __ test(eax, Operand(eax)); 1594 __ test(eax, Operand(eax));
1542 __ j(zero, if_true); // The stub returns 0 for true. 1595 __ j(zero, if_true); // The stub returns 0 for true.
1543 __ jmp(if_false); 1596 __ jmp(if_false);
1544 break; 1597 break;
1545 } 1598 }
1546 1599
1547 default: { 1600 default: {
1601 VisitForValue(expr->right(), kAccumulator);
1548 Condition cc = no_condition; 1602 Condition cc = no_condition;
1549 bool strict = false; 1603 bool strict = false;
1550 switch (expr->op()) { 1604 switch (expr->op()) {
1551 case Token::EQ_STRICT: 1605 case Token::EQ_STRICT:
1552 strict = true; 1606 strict = true;
1553 // Fall through 1607 // Fall through
1554 case Token::EQ: 1608 case Token::EQ:
1555 cc = equal; 1609 cc = equal;
1556 __ pop(eax);
1557 __ pop(edx); 1610 __ pop(edx);
1558 break; 1611 break;
1559 case Token::LT: 1612 case Token::LT:
1560 cc = less; 1613 cc = less;
1561 __ pop(eax);
1562 __ pop(edx); 1614 __ pop(edx);
1563 break; 1615 break;
1564 case Token::GT: 1616 case Token::GT:
1565 // Reverse left and right sizes to obtain ECMA-262 conversion order. 1617 // Reverse left and right sizes to obtain ECMA-262 conversion order.
1566 cc = less; 1618 cc = less;
1567 __ pop(edx); 1619 __ mov(edx, result_register());
1568 __ pop(eax); 1620 __ pop(eax);
1569 break; 1621 break;
1570 case Token::LTE: 1622 case Token::LTE:
1571 // Reverse left and right sizes to obtain ECMA-262 conversion order. 1623 // Reverse left and right sizes to obtain ECMA-262 conversion order.
1572 cc = greater_equal; 1624 cc = greater_equal;
1573 __ pop(edx); 1625 __ mov(edx, result_register());
1574 __ pop(eax); 1626 __ pop(eax);
1575 break; 1627 break;
1576 case Token::GTE: 1628 case Token::GTE:
1577 cc = greater_equal; 1629 cc = greater_equal;
1578 __ pop(eax);
1579 __ pop(edx); 1630 __ pop(edx);
1580 break; 1631 break;
1581 case Token::IN: 1632 case Token::IN:
1582 case Token::INSTANCEOF: 1633 case Token::INSTANCEOF:
1583 default: 1634 default:
1584 UNREACHABLE(); 1635 UNREACHABLE();
1585 } 1636 }
1586 1637
1587 // The comparison stub expects the smi vs. smi case to be handled 1638 // The comparison stub expects the smi vs. smi case to be handled
1588 // before it is called. 1639 // before it is called.
(...skipping 10 matching lines...) Expand all
1599 CompareStub stub(cc, strict); 1650 CompareStub stub(cc, strict);
1600 __ CallStub(&stub); 1651 __ CallStub(&stub);
1601 __ test(eax, Operand(eax)); 1652 __ test(eax, Operand(eax));
1602 __ j(cc, if_true); 1653 __ j(cc, if_true);
1603 __ jmp(if_false); 1654 __ jmp(if_false);
1604 } 1655 }
1605 } 1656 }
1606 1657
1607 // Convert the result of the comparison into one expected for this 1658 // Convert the result of the comparison into one expected for this
1608 // expression's context. 1659 // expression's context.
1609 switch (expr->context()) { 1660 Apply(expr->context(), if_true, if_false);
1610 case Expression::kUninitialized:
1611 UNREACHABLE();
1612 break;
1613
1614 case Expression::kEffect:
1615 __ bind(&done);
1616 break;
1617
1618 case Expression::kValue:
1619 __ bind(&push_true);
1620 __ push(Immediate(Factory::true_value()));
1621 __ jmp(&done);
1622 __ bind(&push_false);
1623 __ push(Immediate(Factory::false_value()));
1624 __ bind(&done);
1625 break;
1626
1627 case Expression::kTest:
1628 break;
1629
1630 case Expression::kValueTest:
1631 __ bind(&push_true);
1632 __ push(Immediate(Factory::true_value()));
1633 __ jmp(true_label_);
1634 break;
1635
1636 case Expression::kTestValue:
1637 __ bind(&push_false);
1638 __ push(Immediate(Factory::false_value()));
1639 __ jmp(false_label_);
1640 break;
1641 }
1642 } 1661 }
1643 1662
1644 1663
1645 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { 1664 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
1646 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1665 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1647 Apply(expr->context(), eax); 1666 Apply(expr->context(), eax);
1648 } 1667 }
1649 1668
1650 1669
1651 Register FastCodeGenerator::result_register() { return eax; } 1670 Register FastCodeGenerator::result_register() { return eax; }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1692 __ add(Operand(edx), Immediate(masm_->CodeObject())); 1711 __ add(Operand(edx), Immediate(masm_->CodeObject()));
1693 __ mov(Operand(esp, 0), edx); 1712 __ mov(Operand(esp, 0), edx);
1694 // And return. 1713 // And return.
1695 __ ret(0); 1714 __ ret(0);
1696 } 1715 }
1697 1716
1698 1717
1699 #undef __ 1718 #undef __
1700 1719
1701 } } // namespace v8::internal 1720 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/fast-codegen.cc ('k') | src/x64/fast-codegen-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698