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

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

Powered by Google App Engine
This is Rietveld 408576698