| Index: src/x64/full-codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/full-codegen-x64.cc (revision 6179)
|
| +++ src/x64/full-codegen-x64.cc (working copy)
|
| @@ -459,7 +459,7 @@
|
|
|
|
|
| void FullCodeGenerator::TestContext::Plug(bool flag) const {
|
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| + codegen()->PrepareForBailoutBeforeSplit(TOS_REG, true, NULL, NULL);
|
| if (flag) {
|
| if (true_label_ != fall_through_) __ jmp(true_label_);
|
| } else {
|
| @@ -555,6 +555,25 @@
|
| bool should_normalize,
|
| Label* if_true,
|
| Label* if_false) {
|
| + // Only prepare for bailouts before splits if we're in a test
|
| + // context. Otherwise, we let the Visit function deal with the
|
| + // preparation to avoid preparing with the same AST id twice.
|
| + if (!context()->IsTest() || !info_->IsOptimizable()) return;
|
| +
|
| + NearLabel skip;
|
| + if (should_normalize) __ jmp(&skip);
|
| +
|
| + ForwardBailoutStack* current = forward_bailout_stack_;
|
| + while (current != NULL) {
|
| + PrepareForBailout(current->expr(), state);
|
| + current = current->parent();
|
| + }
|
| +
|
| + if (should_normalize) {
|
| + __ CompareRoot(rax, Heap::kTrueValueRootIndex);
|
| + Split(equal, if_true, if_false, NULL);
|
| + __ bind(&skip);
|
| + }
|
| }
|
|
|
|
|
| @@ -669,8 +688,10 @@
|
| Comment cmnt(masm_, "[ SwitchStatement");
|
| Breakable nested_statement(this, stmt);
|
| SetStatementPosition(stmt);
|
| +
|
| // Keep the switch value on the stack until a case matches.
|
| VisitForStackValue(stmt->tag());
|
| + PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
|
|
|
| ZoneList<CaseClause*>* clauses = stmt->cases();
|
| CaseClause* default_clause = NULL; // Can occur anywhere in the list.
|
| @@ -735,6 +756,7 @@
|
| }
|
|
|
| __ bind(nested_statement.break_target());
|
| + PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| }
|
|
|
|
|
| @@ -1224,6 +1246,7 @@
|
| if (property->emit_store()) {
|
| Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| + PrepareForBailoutForId(key->id(), NO_REGISTERS);
|
| }
|
| break;
|
| }
|
| @@ -1311,6 +1334,8 @@
|
|
|
| // Update the write barrier for the array store.
|
| __ RecordWrite(rbx, offset, result_register(), rcx);
|
| +
|
| + PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
|
| }
|
|
|
| if (result_saved) {
|
| @@ -1383,6 +1408,12 @@
|
| }
|
| }
|
|
|
| + // For property compound assignments we need another deoptimization
|
| + // point after the property load.
|
| + if (property != NULL) {
|
| + PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
|
| + }
|
| +
|
| Token::Value op = expr->binary_op();
|
| ConstantOperand constant = ShouldInlineSmiCase(op)
|
| ? GetConstantOperand(op, expr->target(), expr->value())
|
| @@ -1408,6 +1439,8 @@
|
| } else {
|
| EmitBinaryOp(op, mode);
|
| }
|
| + // Deoptimization point in case the binary operation may have side effects.
|
| + PrepareForBailout(expr->binary_operation(), TOS_REG);
|
| } else {
|
| VisitForAccumulatorValue(expr->value());
|
| }
|
| @@ -1420,6 +1453,7 @@
|
| case VARIABLE:
|
| EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
|
| expr->op());
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context()->Plug(rax);
|
| break;
|
| case NAMED_PROPERTY:
|
| @@ -1529,7 +1563,7 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_id) {
|
| +void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
|
| // Invalid left-hand sides are rewritten to have a 'throw
|
| // ReferenceError' on the left-hand side.
|
| if (!expr->IsValidLeftHandSide()) {
|
| @@ -1577,6 +1611,7 @@
|
| break;
|
| }
|
| }
|
| + PrepareForBailoutForId(bailout_ast_id, TOS_REG);
|
| context()->Plug(rax);
|
| }
|
|
|
| @@ -1688,6 +1723,7 @@
|
| __ pop(rax);
|
| __ Drop(1);
|
| }
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context()->Plug(rax);
|
| }
|
|
|
| @@ -1726,6 +1762,7 @@
|
| __ pop(rax);
|
| }
|
|
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context()->Plug(rax);
|
| }
|
|
|
| @@ -2023,6 +2060,7 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ JumpIfSmi(rax, if_true);
|
| __ jmp(if_false);
|
|
|
| @@ -2042,6 +2080,7 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
|
| Split(non_negative_smi, if_true, if_false, fall_through);
|
|
|
| @@ -2073,6 +2112,7 @@
|
| __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE));
|
| __ j(below, if_false);
|
| __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE));
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(below_equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2093,6 +2133,7 @@
|
|
|
| __ JumpIfSmi(rax, if_false);
|
| __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(above_equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2115,6 +2156,7 @@
|
| __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
|
| __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
|
| Immediate(1 << Map::kIsUndetectable));
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(not_zero, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2137,6 +2179,7 @@
|
| // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
|
| // used in a few functions in runtime.js which should not normally be hit by
|
| // this compiler.
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ jmp(if_false);
|
| context()->Plug(if_true, if_false);
|
| }
|
| @@ -2156,6 +2199,7 @@
|
|
|
| __ JumpIfSmi(rax, if_false);
|
| __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2176,6 +2220,7 @@
|
|
|
| __ JumpIfSmi(rax, if_false);
|
| __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2196,6 +2241,7 @@
|
|
|
| __ JumpIfSmi(rax, if_false);
|
| __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2227,6 +2273,7 @@
|
| __ bind(&check_frame_marker);
|
| __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset),
|
| Smi::FromInt(StackFrame::CONSTRUCT));
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2249,6 +2296,7 @@
|
|
|
| __ pop(rbx);
|
| __ cmpq(rax, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2822,6 +2870,7 @@
|
|
|
| __ testl(FieldOperand(rax, String::kHashFieldOffset),
|
| Immediate(String::kContainsCachedArrayIndexMask));
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ j(zero, if_true);
|
| __ jmp(if_false);
|
|
|
| @@ -2943,6 +2992,7 @@
|
| // Notice that the labels are swapped.
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_false, &if_true, &fall_through);
|
| + if (context()->IsTest()) ForwardBailoutToChild(expr);
|
| VisitForControl(expr->expression(), if_true, if_false, fall_through);
|
| context()->Plug(if_false, if_true); // Labels swapped.
|
| break;
|
| @@ -3064,6 +3114,10 @@
|
| }
|
| }
|
|
|
| + // We need a second deoptimization point after loading the value
|
| + // in case evaluating the property load my have a side effect.
|
| + PrepareForBailout(expr->increment(), TOS_REG);
|
| +
|
| // Call ToNumber only if operand is not a smi.
|
| NearLabel no_conversion;
|
| Condition is_smi;
|
| @@ -3133,6 +3187,7 @@
|
| { EffectContext context(this);
|
| EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| Token::ASSIGN);
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context.Plug(rax);
|
| }
|
| // For all contexts except kEffect: We have the result on
|
| @@ -3144,6 +3199,7 @@
|
| // Perform the assignment as if via '='.
|
| EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| Token::ASSIGN);
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context()->Plug(rax);
|
| }
|
| break;
|
| @@ -3152,6 +3208,7 @@
|
| __ pop(rdx);
|
| Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| if (expr->is_postfix()) {
|
| if (!context()->IsEffect()) {
|
| context()->PlugTOS();
|
| @@ -3166,6 +3223,7 @@
|
| __ pop(rdx);
|
| Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| if (expr->is_postfix()) {
|
| if (!context()->IsEffect()) {
|
| context()->PlugTOS();
|
| @@ -3192,6 +3250,7 @@
|
| // Use a regular load, not a contextual load, to avoid a reference
|
| // error.
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| + PrepareForBailout(expr, TOS_REG);
|
| context()->Plug(rax);
|
| } else if (proxy != NULL &&
|
| proxy->var()->AsSlot() != NULL &&
|
| @@ -3207,6 +3266,7 @@
|
| __ push(rsi);
|
| __ Push(proxy->name());
|
| __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
| + PrepareForBailout(expr, TOS_REG);
|
| __ bind(&done);
|
|
|
| context()->Plug(rax);
|
| @@ -3237,6 +3297,7 @@
|
| { AccumulatorValueContext context(this);
|
| VisitForTypeofValue(left_unary->expression());
|
| }
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
|
|
| if (check->Equals(Heap::number_symbol())) {
|
| Condition is_smi = masm_->CheckSmi(rax);
|
| @@ -3330,6 +3391,7 @@
|
| case Token::IN:
|
| VisitForStackValue(expr->right());
|
| __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| __ CompareRoot(rax, Heap::kTrueValueRootIndex);
|
| Split(equal, if_true, if_false, fall_through);
|
| break;
|
| @@ -3338,6 +3400,7 @@
|
| VisitForStackValue(expr->right());
|
| InstanceofStub stub(InstanceofStub::kNoFlags);
|
| __ CallStub(&stub);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ testq(rax, rax);
|
| // The stub returns 0 for true.
|
| Split(zero, if_true, if_false, fall_through);
|
| @@ -3396,6 +3459,8 @@
|
| : NO_COMPARE_FLAGS;
|
| CompareStub stub(cc, strict, flags);
|
| __ CallStub(&stub);
|
| +
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ testq(rax, rax);
|
| Split(cc, if_true, if_false, fall_through);
|
| }
|
| @@ -3417,6 +3482,7 @@
|
| &if_true, &if_false, &fall_through);
|
|
|
| VisitForAccumulatorValue(expr->expression());
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ CompareRoot(rax, Heap::kNullValueRootIndex);
|
| if (expr->is_strict()) {
|
| Split(equal, if_true, if_false, fall_through);
|
|
|