OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 } | 68 } |
69 } | 69 } |
70 } | 70 } |
71 | 71 |
72 | 72 |
73 // ------------------------------------------------------------------------- | 73 // ------------------------------------------------------------------------- |
74 // CodeGenState implementation. | 74 // CodeGenState implementation. |
75 | 75 |
76 CodeGenState::CodeGenState(CodeGenerator* owner) | 76 CodeGenState::CodeGenState(CodeGenerator* owner) |
77 : owner_(owner), | 77 : owner_(owner), |
78 typeof_state_(NOT_INSIDE_TYPEOF), | |
79 destination_(NULL), | 78 destination_(NULL), |
80 previous_(NULL) { | 79 previous_(NULL) { |
81 owner_->set_state(this); | 80 owner_->set_state(this); |
82 } | 81 } |
83 | 82 |
84 | 83 |
85 CodeGenState::CodeGenState(CodeGenerator* owner, | 84 CodeGenState::CodeGenState(CodeGenerator* owner, |
86 TypeofState typeof_state, | |
87 ControlDestination* destination) | 85 ControlDestination* destination) |
88 : owner_(owner), | 86 : owner_(owner), |
89 typeof_state_(typeof_state), | |
90 destination_(destination), | 87 destination_(destination), |
91 previous_(owner->state()) { | 88 previous_(owner->state()) { |
92 owner_->set_state(this); | 89 owner_->set_state(this); |
93 } | 90 } |
94 | 91 |
95 | 92 |
96 CodeGenState::~CodeGenState() { | 93 CodeGenState::~CodeGenState() { |
97 ASSERT(owner_->state() == this); | 94 ASSERT(owner_->state() == this); |
98 owner_->set_state(previous_); | 95 owner_->set_state(previous_); |
99 } | 96 } |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 __ mov(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); | 405 __ mov(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); |
409 return ContextOperand(tmp.reg(), slot->index()); | 406 return ContextOperand(tmp.reg(), slot->index()); |
410 } | 407 } |
411 | 408 |
412 | 409 |
413 // Emit code to load the value of an expression to the top of the | 410 // Emit code to load the value of an expression to the top of the |
414 // frame. If the expression is boolean-valued it may be compiled (or | 411 // frame. If the expression is boolean-valued it may be compiled (or |
415 // partially compiled) into control flow to the control destination. | 412 // partially compiled) into control flow to the control destination. |
416 // If force_control is true, control flow is forced. | 413 // If force_control is true, control flow is forced. |
417 void CodeGenerator::LoadCondition(Expression* x, | 414 void CodeGenerator::LoadCondition(Expression* x, |
418 TypeofState typeof_state, | |
419 ControlDestination* dest, | 415 ControlDestination* dest, |
420 bool force_control) { | 416 bool force_control) { |
421 ASSERT(!in_spilled_code()); | 417 ASSERT(!in_spilled_code()); |
422 int original_height = frame_->height(); | 418 int original_height = frame_->height(); |
423 | 419 |
424 { CodeGenState new_state(this, typeof_state, dest); | 420 { CodeGenState new_state(this, dest); |
425 Visit(x); | 421 Visit(x); |
426 | 422 |
427 // If we hit a stack overflow, we may not have actually visited | 423 // If we hit a stack overflow, we may not have actually visited |
428 // the expression. In that case, we ensure that we have a | 424 // the expression. In that case, we ensure that we have a |
429 // valid-looking frame state because we will continue to generate | 425 // valid-looking frame state because we will continue to generate |
430 // code as we unwind the C++ stack. | 426 // code as we unwind the C++ stack. |
431 // | 427 // |
432 // It's possible to have both a stack overflow and a valid frame | 428 // It's possible to have both a stack overflow and a valid frame |
433 // state (eg, a subexpression overflowed, visiting it returned | 429 // state (eg, a subexpression overflowed, visiting it returned |
434 // with a dummied frame state, and visiting this expression | 430 // with a dummied frame state, and visiting this expression |
435 // returned with a normal-looking state). | 431 // returned with a normal-looking state). |
436 if (HasStackOverflow() && | 432 if (HasStackOverflow() && |
437 !dest->is_used() && | 433 !dest->is_used() && |
438 frame_->height() == original_height) { | 434 frame_->height() == original_height) { |
439 dest->Goto(true); | 435 dest->Goto(true); |
440 } | 436 } |
441 } | 437 } |
442 | 438 |
443 if (force_control && !dest->is_used()) { | 439 if (force_control && !dest->is_used()) { |
444 // Convert the TOS value into flow to the control destination. | 440 // Convert the TOS value into flow to the control destination. |
445 ToBoolean(dest); | 441 ToBoolean(dest); |
446 } | 442 } |
447 | 443 |
448 ASSERT(!(force_control && !dest->is_used())); | 444 ASSERT(!(force_control && !dest->is_used())); |
449 ASSERT(dest->is_used() || frame_->height() == original_height + 1); | 445 ASSERT(dest->is_used() || frame_->height() == original_height + 1); |
450 } | 446 } |
451 | 447 |
452 | 448 |
453 void CodeGenerator::LoadAndSpill(Expression* expression, | 449 void CodeGenerator::LoadAndSpill(Expression* expression) { |
454 TypeofState typeof_state) { | |
455 ASSERT(in_spilled_code()); | 450 ASSERT(in_spilled_code()); |
456 set_in_spilled_code(false); | 451 set_in_spilled_code(false); |
457 Load(expression, typeof_state); | 452 Load(expression); |
458 frame_->SpillAll(); | 453 frame_->SpillAll(); |
459 set_in_spilled_code(true); | 454 set_in_spilled_code(true); |
460 } | 455 } |
461 | 456 |
462 | 457 |
463 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 458 void CodeGenerator::Load(Expression* expr) { |
464 #ifdef DEBUG | 459 #ifdef DEBUG |
465 int original_height = frame_->height(); | 460 int original_height = frame_->height(); |
466 #endif | 461 #endif |
467 ASSERT(!in_spilled_code()); | 462 ASSERT(!in_spilled_code()); |
468 JumpTarget true_target; | 463 JumpTarget true_target; |
469 JumpTarget false_target; | 464 JumpTarget false_target; |
470 ControlDestination dest(&true_target, &false_target, true); | 465 ControlDestination dest(&true_target, &false_target, true); |
471 LoadCondition(x, typeof_state, &dest, false); | 466 LoadCondition(expr, &dest, false); |
472 | 467 |
473 if (dest.false_was_fall_through()) { | 468 if (dest.false_was_fall_through()) { |
474 // The false target was just bound. | 469 // The false target was just bound. |
475 JumpTarget loaded; | 470 JumpTarget loaded; |
476 frame_->Push(Factory::false_value()); | 471 frame_->Push(Factory::false_value()); |
477 // There may be dangling jumps to the true target. | 472 // There may be dangling jumps to the true target. |
478 if (true_target.is_linked()) { | 473 if (true_target.is_linked()) { |
479 loaded.Jump(); | 474 loaded.Jump(); |
480 true_target.Bind(); | 475 true_target.Bind(); |
481 frame_->Push(Factory::true_value()); | 476 frame_->Push(Factory::true_value()); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 | 531 |
537 void CodeGenerator::LoadGlobalReceiver() { | 532 void CodeGenerator::LoadGlobalReceiver() { |
538 Result temp = allocator_->Allocate(); | 533 Result temp = allocator_->Allocate(); |
539 Register reg = temp.reg(); | 534 Register reg = temp.reg(); |
540 __ mov(reg, GlobalObject()); | 535 __ mov(reg, GlobalObject()); |
541 __ mov(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset)); | 536 __ mov(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset)); |
542 frame_->Push(&temp); | 537 frame_->Push(&temp); |
543 } | 538 } |
544 | 539 |
545 | 540 |
546 // TODO(1241834): Get rid of this function in favor of just using Load, now | 541 void CodeGenerator::LoadTypeofExpression(Expression* expr) { |
547 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global | 542 // Special handling of identifiers as subexpressions of typeof. |
548 // variables w/o reference errors elsewhere. | 543 Variable* variable = expr->AsVariableProxy()->AsVariable(); |
549 void CodeGenerator::LoadTypeofExpression(Expression* x) { | |
550 Variable* variable = x->AsVariableProxy()->AsVariable(); | |
551 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 544 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
552 // NOTE: This is somewhat nasty. We force the compiler to load | 545 // For a global variable we build the property reference |
553 // the variable as if through '<global>.<variable>' to make sure we | 546 // <global>.<variable> and perform a (regular non-contextual) property |
554 // do not get reference errors. | 547 // load to make sure we do not get reference errors. |
555 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 548 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
556 Literal key(variable->name()); | 549 Literal key(variable->name()); |
557 // TODO(1241834): Fetch the position from the variable instead of using | 550 // TODO(1241834): Fetch the position from the variable instead of using |
558 // no position. | 551 // no position. |
559 Property property(&global, &key, RelocInfo::kNoPosition); | 552 Property property(&global, &key, RelocInfo::kNoPosition); |
560 Load(&property); | 553 Reference ref(this, &property); |
| 554 ref.GetValue(); |
| 555 } else if (variable != NULL && variable->slot() != NULL) { |
| 556 // For a variable that rewrites to a slot, we signal it is the immediate |
| 557 // subexpression of a typeof. |
| 558 LoadFromSlotCheckForArguments(variable->slot(), INSIDE_TYPEOF); |
561 } else { | 559 } else { |
562 Load(x, INSIDE_TYPEOF); | 560 // Anything else can be handled normally. |
| 561 Load(expr); |
563 } | 562 } |
564 } | 563 } |
565 | 564 |
566 | 565 |
567 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() const { | 566 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() const { |
568 if (scope_->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; | 567 if (scope_->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; |
569 ASSERT(scope_->arguments_shadow() != NULL); | 568 ASSERT(scope_->arguments_shadow() != NULL); |
570 // We don't want to do lazy arguments allocation for functions that | 569 // We don't want to do lazy arguments allocation for functions that |
571 // have heap-allocated contexts, because it interfers with the | 570 // have heap-allocated contexts, because it interfers with the |
572 // uninitialized const tracking in the context objects. | 571 // uninitialized const tracking in the context objects. |
(...skipping 1426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1999 VariableProxy* arguments, | 1998 VariableProxy* arguments, |
2000 int position) { | 1999 int position) { |
2001 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); | 2000 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); |
2002 ASSERT(arguments->IsArguments()); | 2001 ASSERT(arguments->IsArguments()); |
2003 | 2002 |
2004 JumpTarget slow, done; | 2003 JumpTarget slow, done; |
2005 | 2004 |
2006 // Load the apply function onto the stack. This will usually | 2005 // Load the apply function onto the stack. This will usually |
2007 // give us a megamorphic load site. Not super, but it works. | 2006 // give us a megamorphic load site. Not super, but it works. |
2008 Reference ref(this, apply); | 2007 Reference ref(this, apply); |
2009 ref.GetValue(NOT_INSIDE_TYPEOF); | 2008 ref.GetValue(); |
2010 ASSERT(ref.type() == Reference::NAMED); | 2009 ASSERT(ref.type() == Reference::NAMED); |
2011 | 2010 |
2012 // Load the receiver and the existing arguments object onto the | 2011 // Load the receiver and the existing arguments object onto the |
2013 // expression stack. Avoid allocating the arguments object here. | 2012 // expression stack. Avoid allocating the arguments object here. |
2014 Load(receiver); | 2013 Load(receiver); |
2015 LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | 2014 LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); |
2016 | 2015 |
2017 // Emit the source position information after having loaded the | 2016 // Emit the source position information after having loaded the |
2018 // receiver and the arguments. | 2017 // receiver and the arguments. |
2019 CodeForSourcePosition(position); | 2018 CodeForSourcePosition(position); |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2338 // are present or not. | 2337 // are present or not. |
2339 bool has_then_stm = node->HasThenStatement(); | 2338 bool has_then_stm = node->HasThenStatement(); |
2340 bool has_else_stm = node->HasElseStatement(); | 2339 bool has_else_stm = node->HasElseStatement(); |
2341 | 2340 |
2342 CodeForStatementPosition(node); | 2341 CodeForStatementPosition(node); |
2343 JumpTarget exit; | 2342 JumpTarget exit; |
2344 if (has_then_stm && has_else_stm) { | 2343 if (has_then_stm && has_else_stm) { |
2345 JumpTarget then; | 2344 JumpTarget then; |
2346 JumpTarget else_; | 2345 JumpTarget else_; |
2347 ControlDestination dest(&then, &else_, true); | 2346 ControlDestination dest(&then, &else_, true); |
2348 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 2347 LoadCondition(node->condition(), &dest, true); |
2349 | 2348 |
2350 if (dest.false_was_fall_through()) { | 2349 if (dest.false_was_fall_through()) { |
2351 // The else target was bound, so we compile the else part first. | 2350 // The else target was bound, so we compile the else part first. |
2352 Visit(node->else_statement()); | 2351 Visit(node->else_statement()); |
2353 | 2352 |
2354 // We may have dangling jumps to the then part. | 2353 // We may have dangling jumps to the then part. |
2355 if (then.is_linked()) { | 2354 if (then.is_linked()) { |
2356 if (has_valid_frame()) exit.Jump(); | 2355 if (has_valid_frame()) exit.Jump(); |
2357 then.Bind(); | 2356 then.Bind(); |
2358 Visit(node->then_statement()); | 2357 Visit(node->then_statement()); |
2359 } | 2358 } |
2360 } else { | 2359 } else { |
2361 // The then target was bound, so we compile the then part first. | 2360 // The then target was bound, so we compile the then part first. |
2362 Visit(node->then_statement()); | 2361 Visit(node->then_statement()); |
2363 | 2362 |
2364 if (else_.is_linked()) { | 2363 if (else_.is_linked()) { |
2365 if (has_valid_frame()) exit.Jump(); | 2364 if (has_valid_frame()) exit.Jump(); |
2366 else_.Bind(); | 2365 else_.Bind(); |
2367 Visit(node->else_statement()); | 2366 Visit(node->else_statement()); |
2368 } | 2367 } |
2369 } | 2368 } |
2370 | 2369 |
2371 } else if (has_then_stm) { | 2370 } else if (has_then_stm) { |
2372 ASSERT(!has_else_stm); | 2371 ASSERT(!has_else_stm); |
2373 JumpTarget then; | 2372 JumpTarget then; |
2374 ControlDestination dest(&then, &exit, true); | 2373 ControlDestination dest(&then, &exit, true); |
2375 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 2374 LoadCondition(node->condition(), &dest, true); |
2376 | 2375 |
2377 if (dest.false_was_fall_through()) { | 2376 if (dest.false_was_fall_through()) { |
2378 // The exit label was bound. We may have dangling jumps to the | 2377 // The exit label was bound. We may have dangling jumps to the |
2379 // then part. | 2378 // then part. |
2380 if (then.is_linked()) { | 2379 if (then.is_linked()) { |
2381 exit.Unuse(); | 2380 exit.Unuse(); |
2382 exit.Jump(); | 2381 exit.Jump(); |
2383 then.Bind(); | 2382 then.Bind(); |
2384 Visit(node->then_statement()); | 2383 Visit(node->then_statement()); |
2385 } | 2384 } |
2386 } else { | 2385 } else { |
2387 // The then label was bound. | 2386 // The then label was bound. |
2388 Visit(node->then_statement()); | 2387 Visit(node->then_statement()); |
2389 } | 2388 } |
2390 | 2389 |
2391 } else if (has_else_stm) { | 2390 } else if (has_else_stm) { |
2392 ASSERT(!has_then_stm); | 2391 ASSERT(!has_then_stm); |
2393 JumpTarget else_; | 2392 JumpTarget else_; |
2394 ControlDestination dest(&exit, &else_, false); | 2393 ControlDestination dest(&exit, &else_, false); |
2395 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 2394 LoadCondition(node->condition(), &dest, true); |
2396 | 2395 |
2397 if (dest.true_was_fall_through()) { | 2396 if (dest.true_was_fall_through()) { |
2398 // The exit label was bound. We may have dangling jumps to the | 2397 // The exit label was bound. We may have dangling jumps to the |
2399 // else part. | 2398 // else part. |
2400 if (else_.is_linked()) { | 2399 if (else_.is_linked()) { |
2401 exit.Unuse(); | 2400 exit.Unuse(); |
2402 exit.Jump(); | 2401 exit.Jump(); |
2403 else_.Bind(); | 2402 else_.Bind(); |
2404 Visit(node->else_statement()); | 2403 Visit(node->else_statement()); |
2405 } | 2404 } |
2406 } else { | 2405 } else { |
2407 // The else label was bound. | 2406 // The else label was bound. |
2408 Visit(node->else_statement()); | 2407 Visit(node->else_statement()); |
2409 } | 2408 } |
2410 | 2409 |
2411 } else { | 2410 } else { |
2412 ASSERT(!has_then_stm && !has_else_stm); | 2411 ASSERT(!has_then_stm && !has_else_stm); |
2413 // We only care about the condition's side effects (not its value | 2412 // We only care about the condition's side effects (not its value |
2414 // or control flow effect). LoadCondition is called without | 2413 // or control flow effect). LoadCondition is called without |
2415 // forcing control flow. | 2414 // forcing control flow. |
2416 ControlDestination dest(&exit, &exit, true); | 2415 ControlDestination dest(&exit, &exit, true); |
2417 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, false); | 2416 LoadCondition(node->condition(), &dest, false); |
2418 if (!dest.is_used()) { | 2417 if (!dest.is_used()) { |
2419 // We got a value on the frame rather than (or in addition to) | 2418 // We got a value on the frame rather than (or in addition to) |
2420 // control flow. | 2419 // control flow. |
2421 frame_->Drop(); | 2420 frame_->Drop(); |
2422 } | 2421 } |
2423 } | 2422 } |
2424 | 2423 |
2425 if (exit.is_linked()) { | 2424 if (exit.is_linked()) { |
2426 exit.Bind(); | 2425 exit.Bind(); |
2427 } | 2426 } |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2708 } | 2707 } |
2709 break; | 2708 break; |
2710 case DONT_KNOW: | 2709 case DONT_KNOW: |
2711 // We have to compile the test expression if it can be reached by | 2710 // We have to compile the test expression if it can be reached by |
2712 // control flow falling out of the body or via continue. | 2711 // control flow falling out of the body or via continue. |
2713 if (node->continue_target()->is_linked()) { | 2712 if (node->continue_target()->is_linked()) { |
2714 node->continue_target()->Bind(); | 2713 node->continue_target()->Bind(); |
2715 } | 2714 } |
2716 if (has_valid_frame()) { | 2715 if (has_valid_frame()) { |
2717 ControlDestination dest(&body, node->break_target(), false); | 2716 ControlDestination dest(&body, node->break_target(), false); |
2718 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2717 LoadCondition(node->cond(), &dest, true); |
2719 } | 2718 } |
2720 if (node->break_target()->is_linked()) { | 2719 if (node->break_target()->is_linked()) { |
2721 node->break_target()->Bind(); | 2720 node->break_target()->Bind(); |
2722 } | 2721 } |
2723 break; | 2722 break; |
2724 } | 2723 } |
2725 | 2724 |
2726 DecrementLoopNesting(); | 2725 DecrementLoopNesting(); |
2727 } | 2726 } |
2728 | 2727 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2763 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); | 2762 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2764 } else { | 2763 } else { |
2765 // Label the test at the top as the continue target. The body | 2764 // Label the test at the top as the continue target. The body |
2766 // is a forward-only target. | 2765 // is a forward-only target. |
2767 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); | 2766 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
2768 node->continue_target()->Bind(); | 2767 node->continue_target()->Bind(); |
2769 } | 2768 } |
2770 // Compile the test with the body as the true target and preferred | 2769 // Compile the test with the body as the true target and preferred |
2771 // fall-through and with the break target as the false target. | 2770 // fall-through and with the break target as the false target. |
2772 ControlDestination dest(&body, node->break_target(), true); | 2771 ControlDestination dest(&body, node->break_target(), true); |
2773 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2772 LoadCondition(node->cond(), &dest, true); |
2774 | 2773 |
2775 if (dest.false_was_fall_through()) { | 2774 if (dest.false_was_fall_through()) { |
2776 // If we got the break target as fall-through, the test may have | 2775 // If we got the break target as fall-through, the test may have |
2777 // been unconditionally false (if there are no jumps to the | 2776 // been unconditionally false (if there are no jumps to the |
2778 // body). | 2777 // body). |
2779 if (!body.is_linked()) { | 2778 if (!body.is_linked()) { |
2780 DecrementLoopNesting(); | 2779 DecrementLoopNesting(); |
2781 return; | 2780 return; |
2782 } | 2781 } |
2783 | 2782 |
(...skipping 26 matching lines...) Expand all Loading... |
2810 if (test_at_bottom) { | 2809 if (test_at_bottom) { |
2811 // If we have chosen to recompile the test at the bottom, then | 2810 // If we have chosen to recompile the test at the bottom, then |
2812 // it is the continue target. | 2811 // it is the continue target. |
2813 if (node->continue_target()->is_linked()) { | 2812 if (node->continue_target()->is_linked()) { |
2814 node->continue_target()->Bind(); | 2813 node->continue_target()->Bind(); |
2815 } | 2814 } |
2816 if (has_valid_frame()) { | 2815 if (has_valid_frame()) { |
2817 // The break target is the fall-through (body is a backward | 2816 // The break target is the fall-through (body is a backward |
2818 // jump from here and thus an invalid fall-through). | 2817 // jump from here and thus an invalid fall-through). |
2819 ControlDestination dest(&body, node->break_target(), false); | 2818 ControlDestination dest(&body, node->break_target(), false); |
2820 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2819 LoadCondition(node->cond(), &dest, true); |
2821 } | 2820 } |
2822 } else { | 2821 } else { |
2823 // If we have chosen not to recompile the test at the bottom, | 2822 // If we have chosen not to recompile the test at the bottom, |
2824 // jump back to the one at the top. | 2823 // jump back to the one at the top. |
2825 if (has_valid_frame()) { | 2824 if (has_valid_frame()) { |
2826 node->continue_target()->Jump(); | 2825 node->continue_target()->Jump(); |
2827 } | 2826 } |
2828 } | 2827 } |
2829 break; | 2828 break; |
2830 case ALWAYS_FALSE: | 2829 case ALWAYS_FALSE: |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2901 node->continue_target()->Bind(); | 2900 node->continue_target()->Bind(); |
2902 } else { | 2901 } else { |
2903 // We are not recompiling the test at the bottom and there is an | 2902 // We are not recompiling the test at the bottom and there is an |
2904 // update expression. | 2903 // update expression. |
2905 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); | 2904 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2906 loop.Bind(); | 2905 loop.Bind(); |
2907 } | 2906 } |
2908 // Compile the test with the body as the true target and preferred | 2907 // Compile the test with the body as the true target and preferred |
2909 // fall-through and with the break target as the false target. | 2908 // fall-through and with the break target as the false target. |
2910 ControlDestination dest(&body, node->break_target(), true); | 2909 ControlDestination dest(&body, node->break_target(), true); |
2911 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2910 LoadCondition(node->cond(), &dest, true); |
2912 | 2911 |
2913 if (dest.false_was_fall_through()) { | 2912 if (dest.false_was_fall_through()) { |
2914 // If we got the break target as fall-through, the test may have | 2913 // If we got the break target as fall-through, the test may have |
2915 // been unconditionally false (if there are no jumps to the | 2914 // been unconditionally false (if there are no jumps to the |
2916 // body). | 2915 // body). |
2917 if (!body.is_linked()) { | 2916 if (!body.is_linked()) { |
2918 DecrementLoopNesting(); | 2917 DecrementLoopNesting(); |
2919 return; | 2918 return; |
2920 } | 2919 } |
2921 | 2920 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2971 // was no update expression. | 2970 // was no update expression. |
2972 node->continue_target()->Bind(); | 2971 node->continue_target()->Bind(); |
2973 } | 2972 } |
2974 // Control can reach the test at the bottom by falling out of | 2973 // Control can reach the test at the bottom by falling out of |
2975 // the body, by a continue in the body, or from the update | 2974 // the body, by a continue in the body, or from the update |
2976 // expression. | 2975 // expression. |
2977 if (has_valid_frame()) { | 2976 if (has_valid_frame()) { |
2978 // The break target is the fall-through (body is a backward | 2977 // The break target is the fall-through (body is a backward |
2979 // jump from here). | 2978 // jump from here). |
2980 ControlDestination dest(&body, node->break_target(), false); | 2979 ControlDestination dest(&body, node->break_target(), false); |
2981 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2980 LoadCondition(node->cond(), &dest, true); |
2982 } | 2981 } |
2983 } else { | 2982 } else { |
2984 // Otherwise, jump back to the test at the top. | 2983 // Otherwise, jump back to the test at the top. |
2985 if (has_valid_frame()) { | 2984 if (has_valid_frame()) { |
2986 if (node->next() == NULL) { | 2985 if (node->next() == NULL) { |
2987 node->continue_target()->Jump(); | 2986 node->continue_target()->Jump(); |
2988 } else { | 2987 } else { |
2989 loop.Jump(); | 2988 loop.Jump(); |
2990 } | 2989 } |
2991 } | 2990 } |
(...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3566 InstantiateBoilerplate(node->boilerplate()); | 3565 InstantiateBoilerplate(node->boilerplate()); |
3567 } | 3566 } |
3568 | 3567 |
3569 | 3568 |
3570 void CodeGenerator::VisitConditional(Conditional* node) { | 3569 void CodeGenerator::VisitConditional(Conditional* node) { |
3571 Comment cmnt(masm_, "[ Conditional"); | 3570 Comment cmnt(masm_, "[ Conditional"); |
3572 JumpTarget then; | 3571 JumpTarget then; |
3573 JumpTarget else_; | 3572 JumpTarget else_; |
3574 JumpTarget exit; | 3573 JumpTarget exit; |
3575 ControlDestination dest(&then, &else_, true); | 3574 ControlDestination dest(&then, &else_, true); |
3576 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 3575 LoadCondition(node->condition(), &dest, true); |
3577 | 3576 |
3578 if (dest.false_was_fall_through()) { | 3577 if (dest.false_was_fall_through()) { |
3579 // The else target was bound, so we compile the else part first. | 3578 // The else target was bound, so we compile the else part first. |
3580 Load(node->else_expression(), typeof_state()); | 3579 Load(node->else_expression()); |
3581 | 3580 |
3582 if (then.is_linked()) { | 3581 if (then.is_linked()) { |
3583 exit.Jump(); | 3582 exit.Jump(); |
3584 then.Bind(); | 3583 then.Bind(); |
3585 Load(node->then_expression(), typeof_state()); | 3584 Load(node->then_expression()); |
3586 } | 3585 } |
3587 } else { | 3586 } else { |
3588 // The then target was bound, so we compile the then part first. | 3587 // The then target was bound, so we compile the then part first. |
3589 Load(node->then_expression(), typeof_state()); | 3588 Load(node->then_expression()); |
3590 | 3589 |
3591 if (else_.is_linked()) { | 3590 if (else_.is_linked()) { |
3592 exit.Jump(); | 3591 exit.Jump(); |
3593 else_.Bind(); | 3592 else_.Bind(); |
3594 Load(node->else_expression(), typeof_state()); | 3593 Load(node->else_expression()); |
3595 } | 3594 } |
3596 } | 3595 } |
3597 | 3596 |
3598 exit.Bind(); | 3597 exit.Bind(); |
3599 } | 3598 } |
3600 | 3599 |
3601 | 3600 |
3602 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 3601 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
3603 if (slot->type() == Slot::LOOKUP) { | 3602 if (slot->type() == Slot::LOOKUP) { |
3604 ASSERT(slot->var()->is_dynamic()); | 3603 ASSERT(slot->var()->is_dynamic()); |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3906 // scope. | 3905 // scope. |
3907 } | 3906 } |
3908 | 3907 |
3909 exit.Bind(); | 3908 exit.Bind(); |
3910 } | 3909 } |
3911 } | 3910 } |
3912 | 3911 |
3913 | 3912 |
3914 void CodeGenerator::VisitSlot(Slot* node) { | 3913 void CodeGenerator::VisitSlot(Slot* node) { |
3915 Comment cmnt(masm_, "[ Slot"); | 3914 Comment cmnt(masm_, "[ Slot"); |
3916 LoadFromSlotCheckForArguments(node, typeof_state()); | 3915 LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF); |
3917 } | 3916 } |
3918 | 3917 |
3919 | 3918 |
3920 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 3919 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
3921 Comment cmnt(masm_, "[ VariableProxy"); | 3920 Comment cmnt(masm_, "[ VariableProxy"); |
3922 Variable* var = node->var(); | 3921 Variable* var = node->var(); |
3923 Expression* expr = var->rewrite(); | 3922 Expression* expr = var->rewrite(); |
3924 if (expr != NULL) { | 3923 if (expr != NULL) { |
3925 Visit(expr); | 3924 Visit(expr); |
3926 } else { | 3925 } else { |
3927 ASSERT(var->is_global()); | 3926 ASSERT(var->is_global()); |
3928 Reference ref(this, node); | 3927 Reference ref(this, node); |
3929 ref.GetValue(typeof_state()); | 3928 ref.GetValue(); |
3930 } | 3929 } |
3931 } | 3930 } |
3932 | 3931 |
3933 | 3932 |
3934 void CodeGenerator::VisitLiteral(Literal* node) { | 3933 void CodeGenerator::VisitLiteral(Literal* node) { |
3935 Comment cmnt(masm_, "[ Literal"); | 3934 Comment cmnt(masm_, "[ Literal"); |
3936 frame_->Push(node->handle()); | 3935 frame_->Push(node->handle()); |
3937 } | 3936 } |
3938 | 3937 |
3939 | 3938 |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4326 bool overwrite_value = | 4325 bool overwrite_value = |
4327 (node->value()->AsBinaryOperation() != NULL && | 4326 (node->value()->AsBinaryOperation() != NULL && |
4328 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 4327 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
4329 Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); | 4328 Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); |
4330 // There are two cases where the target is not read in the right hand | 4329 // There are two cases where the target is not read in the right hand |
4331 // side, that are easy to test for: the right hand side is a literal, | 4330 // side, that are easy to test for: the right hand side is a literal, |
4332 // or the right hand side is a different variable. TakeValue invalidates | 4331 // or the right hand side is a different variable. TakeValue invalidates |
4333 // the target, with an implicit promise that it will be written to again | 4332 // the target, with an implicit promise that it will be written to again |
4334 // before it is read. | 4333 // before it is read. |
4335 if (literal != NULL || (right_var != NULL && right_var != var)) { | 4334 if (literal != NULL || (right_var != NULL && right_var != var)) { |
4336 target.TakeValue(NOT_INSIDE_TYPEOF); | 4335 target.TakeValue(); |
4337 } else { | 4336 } else { |
4338 target.GetValue(NOT_INSIDE_TYPEOF); | 4337 target.GetValue(); |
4339 } | 4338 } |
4340 Load(node->value()); | 4339 Load(node->value()); |
4341 GenericBinaryOperation(node->binary_op(), | 4340 GenericBinaryOperation(node->binary_op(), |
4342 node->type(), | 4341 node->type(), |
4343 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 4342 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
4344 } | 4343 } |
4345 | 4344 |
4346 if (var != NULL && | 4345 if (var != NULL && |
4347 var->mode() == Variable::CONST && | 4346 var->mode() == Variable::CONST && |
4348 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 4347 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
(...skipping 27 matching lines...) Expand all Loading... |
4376 Comment cmnt(masm_, "[ Throw"); | 4375 Comment cmnt(masm_, "[ Throw"); |
4377 Load(node->exception()); | 4376 Load(node->exception()); |
4378 Result result = frame_->CallRuntime(Runtime::kThrow, 1); | 4377 Result result = frame_->CallRuntime(Runtime::kThrow, 1); |
4379 frame_->Push(&result); | 4378 frame_->Push(&result); |
4380 } | 4379 } |
4381 | 4380 |
4382 | 4381 |
4383 void CodeGenerator::VisitProperty(Property* node) { | 4382 void CodeGenerator::VisitProperty(Property* node) { |
4384 Comment cmnt(masm_, "[ Property"); | 4383 Comment cmnt(masm_, "[ Property"); |
4385 Reference property(this, node); | 4384 Reference property(this, node); |
4386 property.GetValue(typeof_state()); | 4385 property.GetValue(); |
4387 } | 4386 } |
4388 | 4387 |
4389 | 4388 |
4390 void CodeGenerator::VisitCall(Call* node) { | 4389 void CodeGenerator::VisitCall(Call* node) { |
4391 Comment cmnt(masm_, "[ Call"); | 4390 Comment cmnt(masm_, "[ Call"); |
4392 | 4391 |
4393 Expression* function = node->expression(); | 4392 Expression* function = node->expression(); |
4394 ZoneList<Expression*>* args = node->arguments(); | 4393 ZoneList<Expression*>* args = node->arguments(); |
4395 | 4394 |
4396 // Check if the function is a variable or a property. | 4395 // Check if the function is a variable or a property. |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4561 frame_->SetElementAt(0, &result); | 4560 frame_->SetElementAt(0, &result); |
4562 } | 4561 } |
4563 | 4562 |
4564 } else { | 4563 } else { |
4565 // ------------------------------------------- | 4564 // ------------------------------------------- |
4566 // JavaScript example: 'array[index](1, 2, 3)' | 4565 // JavaScript example: 'array[index](1, 2, 3)' |
4567 // ------------------------------------------- | 4566 // ------------------------------------------- |
4568 | 4567 |
4569 // Load the function to call from the property through a reference. | 4568 // Load the function to call from the property through a reference. |
4570 Reference ref(this, property); | 4569 Reference ref(this, property); |
4571 ref.GetValue(NOT_INSIDE_TYPEOF); | 4570 ref.GetValue(); |
4572 | 4571 |
4573 // Pass receiver to called function. | 4572 // Pass receiver to called function. |
4574 if (property->is_synthetic()) { | 4573 if (property->is_synthetic()) { |
4575 // Use global object as receiver. | 4574 // Use global object as receiver. |
4576 LoadGlobalReceiver(); | 4575 LoadGlobalReceiver(); |
4577 } else { | 4576 } else { |
4578 // The reference's size is non-negative. | 4577 // The reference's size is non-negative. |
4579 frame_->PushElementAt(ref.size()); | 4578 frame_->PushElementAt(ref.size()); |
4580 } | 4579 } |
4581 | 4580 |
(...skipping 614 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5196 frame_->SetElementAt(0, &answer); | 5195 frame_->SetElementAt(0, &answer); |
5197 } else { | 5196 } else { |
5198 // Call the C runtime function. | 5197 // Call the C runtime function. |
5199 Result answer = frame_->CallRuntime(function, arg_count); | 5198 Result answer = frame_->CallRuntime(function, arg_count); |
5200 frame_->Push(&answer); | 5199 frame_->Push(&answer); |
5201 } | 5200 } |
5202 } | 5201 } |
5203 | 5202 |
5204 | 5203 |
5205 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 5204 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
5206 // Note that because of NOT and an optimization in comparison of a typeof | |
5207 // expression to a literal string, this function can fail to leave a value | |
5208 // on top of the frame or in the cc register. | |
5209 Comment cmnt(masm_, "[ UnaryOperation"); | 5205 Comment cmnt(masm_, "[ UnaryOperation"); |
5210 | 5206 |
5211 Token::Value op = node->op(); | 5207 Token::Value op = node->op(); |
5212 | 5208 |
5213 if (op == Token::NOT) { | 5209 if (op == Token::NOT) { |
5214 // Swap the true and false targets but keep the same actual label | 5210 // Swap the true and false targets but keep the same actual label |
5215 // as the fall through. | 5211 // as the fall through. |
5216 destination()->Invert(); | 5212 destination()->Invert(); |
5217 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, destination(), true); | 5213 LoadCondition(node->expression(), destination(), true); |
5218 // Swap the labels back. | 5214 // Swap the labels back. |
5219 destination()->Invert(); | 5215 destination()->Invert(); |
5220 | 5216 |
5221 } else if (op == Token::DELETE) { | 5217 } else if (op == Token::DELETE) { |
5222 Property* property = node->expression()->AsProperty(); | 5218 Property* property = node->expression()->AsProperty(); |
5223 if (property != NULL) { | 5219 if (property != NULL) { |
5224 Load(property->obj()); | 5220 Load(property->obj()); |
5225 Load(property->key()); | 5221 Load(property->key()); |
5226 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 5222 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
5227 frame_->Push(&answer); | 5223 frame_->Push(&answer); |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5457 // value will be in the frame to be spilled. | 5453 // value will be in the frame to be spilled. |
5458 if (is_postfix) frame_->Push(Smi::FromInt(0)); | 5454 if (is_postfix) frame_->Push(Smi::FromInt(0)); |
5459 | 5455 |
5460 { Reference target(this, node->expression()); | 5456 { Reference target(this, node->expression()); |
5461 if (target.is_illegal()) { | 5457 if (target.is_illegal()) { |
5462 // Spoof the virtual frame to have the expected height (one higher | 5458 // Spoof the virtual frame to have the expected height (one higher |
5463 // than on entry). | 5459 // than on entry). |
5464 if (!is_postfix) frame_->Push(Smi::FromInt(0)); | 5460 if (!is_postfix) frame_->Push(Smi::FromInt(0)); |
5465 return; | 5461 return; |
5466 } | 5462 } |
5467 target.TakeValue(NOT_INSIDE_TYPEOF); | 5463 target.TakeValue(); |
5468 | 5464 |
5469 Result new_value = frame_->Pop(); | 5465 Result new_value = frame_->Pop(); |
5470 new_value.ToRegister(); | 5466 new_value.ToRegister(); |
5471 | 5467 |
5472 Result old_value; // Only allocated in the postfix case. | 5468 Result old_value; // Only allocated in the postfix case. |
5473 if (is_postfix) { | 5469 if (is_postfix) { |
5474 // Allocate a temporary to preserve the old value. | 5470 // Allocate a temporary to preserve the old value. |
5475 old_value = allocator_->Allocate(); | 5471 old_value = allocator_->Allocate(); |
5476 ASSERT(old_value.is_valid()); | 5472 ASSERT(old_value.is_valid()); |
5477 __ mov(old_value.reg(), new_value.reg()); | 5473 __ mov(old_value.reg(), new_value.reg()); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5535 // Non-constant: update the reference. | 5531 // Non-constant: update the reference. |
5536 if (!is_const) target.SetValue(NOT_CONST_INIT); | 5532 if (!is_const) target.SetValue(NOT_CONST_INIT); |
5537 } | 5533 } |
5538 | 5534 |
5539 // Postfix: drop the new value and use the old. | 5535 // Postfix: drop the new value and use the old. |
5540 if (is_postfix) frame_->Drop(); | 5536 if (is_postfix) frame_->Drop(); |
5541 } | 5537 } |
5542 | 5538 |
5543 | 5539 |
5544 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 5540 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
5545 // Note that due to an optimization in comparison operations (typeof | |
5546 // compared to a string literal), we can evaluate a binary expression such | |
5547 // as AND or OR and not leave a value on the frame or in the cc register. | |
5548 Comment cmnt(masm_, "[ BinaryOperation"); | 5541 Comment cmnt(masm_, "[ BinaryOperation"); |
5549 Token::Value op = node->op(); | 5542 Token::Value op = node->op(); |
5550 | 5543 |
5551 // According to ECMA-262 section 11.11, page 58, the binary logical | 5544 // According to ECMA-262 section 11.11, page 58, the binary logical |
5552 // operators must yield the result of one of the two expressions | 5545 // operators must yield the result of one of the two expressions |
5553 // before any ToBoolean() conversions. This means that the value | 5546 // before any ToBoolean() conversions. This means that the value |
5554 // produced by a && or || operator is not necessarily a boolean. | 5547 // produced by a && or || operator is not necessarily a boolean. |
5555 | 5548 |
5556 // NOTE: If the left hand side produces a materialized value (not | 5549 // NOTE: If the left hand side produces a materialized value (not |
5557 // control flow), we force the right hand side to do the same. This | 5550 // control flow), we force the right hand side to do the same. This |
5558 // is necessary because we assume that if we get control flow on the | 5551 // is necessary because we assume that if we get control flow on the |
5559 // last path out of an expression we got it on all paths. | 5552 // last path out of an expression we got it on all paths. |
5560 if (op == Token::AND) { | 5553 if (op == Token::AND) { |
5561 JumpTarget is_true; | 5554 JumpTarget is_true; |
5562 ControlDestination dest(&is_true, destination()->false_target(), true); | 5555 ControlDestination dest(&is_true, destination()->false_target(), true); |
5563 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false); | 5556 LoadCondition(node->left(), &dest, false); |
5564 | 5557 |
5565 if (dest.false_was_fall_through()) { | 5558 if (dest.false_was_fall_through()) { |
5566 // The current false target was used as the fall-through. If | 5559 // The current false target was used as the fall-through. If |
5567 // there are no dangling jumps to is_true then the left | 5560 // there are no dangling jumps to is_true then the left |
5568 // subexpression was unconditionally false. Otherwise we have | 5561 // subexpression was unconditionally false. Otherwise we have |
5569 // paths where we do have to evaluate the right subexpression. | 5562 // paths where we do have to evaluate the right subexpression. |
5570 if (is_true.is_linked()) { | 5563 if (is_true.is_linked()) { |
5571 // We need to compile the right subexpression. If the jump to | 5564 // We need to compile the right subexpression. If the jump to |
5572 // the current false target was a forward jump then we have a | 5565 // the current false target was a forward jump then we have a |
5573 // valid frame, we have just bound the false target, and we | 5566 // valid frame, we have just bound the false target, and we |
5574 // have to jump around the code for the right subexpression. | 5567 // have to jump around the code for the right subexpression. |
5575 if (has_valid_frame()) { | 5568 if (has_valid_frame()) { |
5576 destination()->false_target()->Unuse(); | 5569 destination()->false_target()->Unuse(); |
5577 destination()->false_target()->Jump(); | 5570 destination()->false_target()->Jump(); |
5578 } | 5571 } |
5579 is_true.Bind(); | 5572 is_true.Bind(); |
5580 // The left subexpression compiled to control flow, so the | 5573 // The left subexpression compiled to control flow, so the |
5581 // right one is free to do so as well. | 5574 // right one is free to do so as well. |
5582 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 5575 LoadCondition(node->right(), destination(), false); |
5583 } else { | 5576 } else { |
5584 // We have actually just jumped to or bound the current false | 5577 // We have actually just jumped to or bound the current false |
5585 // target but the current control destination is not marked as | 5578 // target but the current control destination is not marked as |
5586 // used. | 5579 // used. |
5587 destination()->Use(false); | 5580 destination()->Use(false); |
5588 } | 5581 } |
5589 | 5582 |
5590 } else if (dest.is_used()) { | 5583 } else if (dest.is_used()) { |
5591 // The left subexpression compiled to control flow (and is_true | 5584 // The left subexpression compiled to control flow (and is_true |
5592 // was just bound), so the right is free to do so as well. | 5585 // was just bound), so the right is free to do so as well. |
5593 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 5586 LoadCondition(node->right(), destination(), false); |
5594 | 5587 |
5595 } else { | 5588 } else { |
5596 // We have a materialized value on the frame, so we exit with | 5589 // We have a materialized value on the frame, so we exit with |
5597 // one on all paths. There are possibly also jumps to is_true | 5590 // one on all paths. There are possibly also jumps to is_true |
5598 // from nested subexpressions. | 5591 // from nested subexpressions. |
5599 JumpTarget pop_and_continue; | 5592 JumpTarget pop_and_continue; |
5600 JumpTarget exit; | 5593 JumpTarget exit; |
5601 | 5594 |
5602 // Avoid popping the result if it converts to 'false' using the | 5595 // Avoid popping the result if it converts to 'false' using the |
5603 // standard ToBoolean() conversion as described in ECMA-262, | 5596 // standard ToBoolean() conversion as described in ECMA-262, |
(...skipping 12 matching lines...) Expand all Loading... |
5616 is_true.Bind(); | 5609 is_true.Bind(); |
5617 Load(node->right()); | 5610 Load(node->right()); |
5618 | 5611 |
5619 // Exit (always with a materialized value). | 5612 // Exit (always with a materialized value). |
5620 exit.Bind(); | 5613 exit.Bind(); |
5621 } | 5614 } |
5622 | 5615 |
5623 } else if (op == Token::OR) { | 5616 } else if (op == Token::OR) { |
5624 JumpTarget is_false; | 5617 JumpTarget is_false; |
5625 ControlDestination dest(destination()->true_target(), &is_false, false); | 5618 ControlDestination dest(destination()->true_target(), &is_false, false); |
5626 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false); | 5619 LoadCondition(node->left(), &dest, false); |
5627 | 5620 |
5628 if (dest.true_was_fall_through()) { | 5621 if (dest.true_was_fall_through()) { |
5629 // The current true target was used as the fall-through. If | 5622 // The current true target was used as the fall-through. If |
5630 // there are no dangling jumps to is_false then the left | 5623 // there are no dangling jumps to is_false then the left |
5631 // subexpression was unconditionally true. Otherwise we have | 5624 // subexpression was unconditionally true. Otherwise we have |
5632 // paths where we do have to evaluate the right subexpression. | 5625 // paths where we do have to evaluate the right subexpression. |
5633 if (is_false.is_linked()) { | 5626 if (is_false.is_linked()) { |
5634 // We need to compile the right subexpression. If the jump to | 5627 // We need to compile the right subexpression. If the jump to |
5635 // the current true target was a forward jump then we have a | 5628 // the current true target was a forward jump then we have a |
5636 // valid frame, we have just bound the true target, and we | 5629 // valid frame, we have just bound the true target, and we |
5637 // have to jump around the code for the right subexpression. | 5630 // have to jump around the code for the right subexpression. |
5638 if (has_valid_frame()) { | 5631 if (has_valid_frame()) { |
5639 destination()->true_target()->Unuse(); | 5632 destination()->true_target()->Unuse(); |
5640 destination()->true_target()->Jump(); | 5633 destination()->true_target()->Jump(); |
5641 } | 5634 } |
5642 is_false.Bind(); | 5635 is_false.Bind(); |
5643 // The left subexpression compiled to control flow, so the | 5636 // The left subexpression compiled to control flow, so the |
5644 // right one is free to do so as well. | 5637 // right one is free to do so as well. |
5645 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 5638 LoadCondition(node->right(), destination(), false); |
5646 } else { | 5639 } else { |
5647 // We have just jumped to or bound the current true target but | 5640 // We have just jumped to or bound the current true target but |
5648 // the current control destination is not marked as used. | 5641 // the current control destination is not marked as used. |
5649 destination()->Use(true); | 5642 destination()->Use(true); |
5650 } | 5643 } |
5651 | 5644 |
5652 } else if (dest.is_used()) { | 5645 } else if (dest.is_used()) { |
5653 // The left subexpression compiled to control flow (and is_false | 5646 // The left subexpression compiled to control flow (and is_false |
5654 // was just bound), so the right is free to do so as well. | 5647 // was just bound), so the right is free to do so as well. |
5655 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 5648 LoadCondition(node->right(), destination(), false); |
5656 | 5649 |
5657 } else { | 5650 } else { |
5658 // We have a materialized value on the frame, so we exit with | 5651 // We have a materialized value on the frame, so we exit with |
5659 // one on all paths. There are possibly also jumps to is_false | 5652 // one on all paths. There are possibly also jumps to is_false |
5660 // from nested subexpressions. | 5653 // from nested subexpressions. |
5661 JumpTarget pop_and_continue; | 5654 JumpTarget pop_and_continue; |
5662 JumpTarget exit; | 5655 JumpTarget exit; |
5663 | 5656 |
5664 // Avoid popping the result if it converts to 'true' using the | 5657 // Avoid popping the result if it converts to 'true' using the |
5665 // standard ToBoolean() conversion as described in ECMA-262, | 5658 // standard ToBoolean() conversion as described in ECMA-262, |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6038 ASSERT(proxy->AsVariable()->is_global()); | 6031 ASSERT(proxy->AsVariable()->is_global()); |
6039 return proxy->name(); | 6032 return proxy->name(); |
6040 } else { | 6033 } else { |
6041 Literal* raw_name = property->key()->AsLiteral(); | 6034 Literal* raw_name = property->key()->AsLiteral(); |
6042 ASSERT(raw_name != NULL); | 6035 ASSERT(raw_name != NULL); |
6043 return Handle<String>(String::cast(*raw_name->handle())); | 6036 return Handle<String>(String::cast(*raw_name->handle())); |
6044 } | 6037 } |
6045 } | 6038 } |
6046 | 6039 |
6047 | 6040 |
6048 void Reference::GetValue(TypeofState typeof_state) { | 6041 void Reference::GetValue() { |
6049 ASSERT(!cgen_->in_spilled_code()); | 6042 ASSERT(!cgen_->in_spilled_code()); |
6050 ASSERT(cgen_->HasValidEntryRegisters()); | 6043 ASSERT(cgen_->HasValidEntryRegisters()); |
6051 ASSERT(!is_illegal()); | 6044 ASSERT(!is_illegal()); |
6052 MacroAssembler* masm = cgen_->masm(); | 6045 MacroAssembler* masm = cgen_->masm(); |
6053 | 6046 |
6054 // Record the source position for the property load. | 6047 // Record the source position for the property load. |
6055 Property* property = expression_->AsProperty(); | 6048 Property* property = expression_->AsProperty(); |
6056 if (property != NULL) { | 6049 if (property != NULL) { |
6057 cgen_->CodeForSourcePosition(property->position()); | 6050 cgen_->CodeForSourcePosition(property->position()); |
6058 } | 6051 } |
6059 | 6052 |
6060 switch (type_) { | 6053 switch (type_) { |
6061 case SLOT: { | 6054 case SLOT: { |
6062 Comment cmnt(masm, "[ Load from Slot"); | 6055 Comment cmnt(masm, "[ Load from Slot"); |
6063 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 6056 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
6064 ASSERT(slot != NULL); | 6057 ASSERT(slot != NULL); |
6065 cgen_->LoadFromSlotCheckForArguments(slot, typeof_state); | 6058 cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); |
6066 break; | 6059 break; |
6067 } | 6060 } |
6068 | 6061 |
6069 case NAMED: { | 6062 case NAMED: { |
6070 // TODO(1241834): Make sure that it is safe to ignore the | |
6071 // distinction between expressions in a typeof and not in a | |
6072 // typeof. If there is a chance that reference errors can be | |
6073 // thrown below, we must distinguish between the two kinds of | |
6074 // loads (typeof expression loads must not throw a reference | |
6075 // error). | |
6076 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 6063 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
6077 bool is_global = var != NULL; | 6064 bool is_global = var != NULL; |
6078 ASSERT(!is_global || var->is_global()); | 6065 ASSERT(!is_global || var->is_global()); |
6079 | 6066 |
6080 // Do not inline the inobject property case for loads from the global | 6067 // Do not inline the inobject property case for loads from the global |
6081 // object. Also do not inline for unoptimized code. This saves time | 6068 // object. Also do not inline for unoptimized code. This saves time |
6082 // in the code generator. Unoptimized code is toplevel code or code | 6069 // in the code generator. Unoptimized code is toplevel code or code |
6083 // that is not in a loop. | 6070 // that is not in a loop. |
6084 if (is_global || | 6071 if (is_global || |
6085 cgen_->scope()->is_global_scope() || | 6072 cgen_->scope()->is_global_scope() || |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6135 | 6122 |
6136 __ IncrementCounter(&Counters::named_load_inline, 1); | 6123 __ IncrementCounter(&Counters::named_load_inline, 1); |
6137 deferred->BindExit(); | 6124 deferred->BindExit(); |
6138 cgen_->frame()->Push(&receiver); | 6125 cgen_->frame()->Push(&receiver); |
6139 cgen_->frame()->Push(&value); | 6126 cgen_->frame()->Push(&value); |
6140 } | 6127 } |
6141 break; | 6128 break; |
6142 } | 6129 } |
6143 | 6130 |
6144 case KEYED: { | 6131 case KEYED: { |
6145 // TODO(1241834): Make sure that this it is safe to ignore the | |
6146 // distinction between expressions in a typeof and not in a typeof. | |
6147 Comment cmnt(masm, "[ Load from keyed Property"); | 6132 Comment cmnt(masm, "[ Load from keyed Property"); |
6148 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 6133 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
6149 bool is_global = var != NULL; | 6134 bool is_global = var != NULL; |
6150 ASSERT(!is_global || var->is_global()); | 6135 ASSERT(!is_global || var->is_global()); |
6151 | 6136 |
6152 // Inline array load code if inside of a loop. We do not know | 6137 // Inline array load code if inside of a loop. We do not know |
6153 // the receiver map yet, so we initially generate the code with | 6138 // the receiver map yet, so we initially generate the code with |
6154 // a check against an invalid map. In the inline cache code, we | 6139 // a check against an invalid map. In the inline cache code, we |
6155 // patch the map check if appropriate. | 6140 // patch the map check if appropriate. |
6156 if (cgen_->loop_nesting() > 0) { | 6141 if (cgen_->loop_nesting() > 0) { |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6255 } | 6240 } |
6256 break; | 6241 break; |
6257 } | 6242 } |
6258 | 6243 |
6259 default: | 6244 default: |
6260 UNREACHABLE(); | 6245 UNREACHABLE(); |
6261 } | 6246 } |
6262 } | 6247 } |
6263 | 6248 |
6264 | 6249 |
6265 void Reference::TakeValue(TypeofState typeof_state) { | 6250 void Reference::TakeValue() { |
6266 // For non-constant frame-allocated slots, we invalidate the value in the | 6251 // For non-constant frame-allocated slots, we invalidate the value in the |
6267 // slot. For all others, we fall back on GetValue. | 6252 // slot. For all others, we fall back on GetValue. |
6268 ASSERT(!cgen_->in_spilled_code()); | 6253 ASSERT(!cgen_->in_spilled_code()); |
6269 ASSERT(!is_illegal()); | 6254 ASSERT(!is_illegal()); |
6270 if (type_ != SLOT) { | 6255 if (type_ != SLOT) { |
6271 GetValue(typeof_state); | 6256 GetValue(); |
6272 return; | 6257 return; |
6273 } | 6258 } |
6274 | 6259 |
6275 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 6260 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
6276 ASSERT(slot != NULL); | 6261 ASSERT(slot != NULL); |
6277 if (slot->type() == Slot::LOOKUP || | 6262 if (slot->type() == Slot::LOOKUP || |
6278 slot->type() == Slot::CONTEXT || | 6263 slot->type() == Slot::CONTEXT || |
6279 slot->var()->mode() == Variable::CONST || | 6264 slot->var()->mode() == Variable::CONST || |
6280 slot->is_arguments()) { | 6265 slot->is_arguments()) { |
6281 GetValue(typeof_state); | 6266 GetValue(); |
6282 return; | 6267 return; |
6283 } | 6268 } |
6284 | 6269 |
6285 // Only non-constant, frame-allocated parameters and locals can | 6270 // Only non-constant, frame-allocated parameters and locals can |
6286 // reach here. Be careful not to use the optimizations for arguments | 6271 // reach here. Be careful not to use the optimizations for arguments |
6287 // object access since it may not have been initialized yet. | 6272 // object access since it may not have been initialized yet. |
6288 ASSERT(!slot->is_arguments()); | 6273 ASSERT(!slot->is_arguments()); |
6289 if (slot->type() == Slot::PARAMETER) { | 6274 if (slot->type() == Slot::PARAMETER) { |
6290 cgen_->frame()->TakeParameterAt(slot->index()); | 6275 cgen_->frame()->TakeParameterAt(slot->index()); |
6291 } else { | 6276 } else { |
(...skipping 1763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8055 | 8040 |
8056 int CompareStub::MinorKey() { | 8041 int CompareStub::MinorKey() { |
8057 // Encode the two parameters in a unique 16 bit value. | 8042 // Encode the two parameters in a unique 16 bit value. |
8058 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); | 8043 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); |
8059 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); | 8044 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); |
8060 } | 8045 } |
8061 | 8046 |
8062 #undef __ | 8047 #undef __ |
8063 | 8048 |
8064 } } // namespace v8::internal | 8049 } } // namespace v8::internal |
OLD | NEW |