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

Powered by Google App Engine
This is Rietveld 408576698