Commit 5b742b35 authored by jarin@chromium.org's avatar jarin@chromium.org

Adding more missing deoptimization points in Turbofan.

BUG=
R=bmeurer@chromium.org

Review URL: https://codereview.chromium.org/595863002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24289 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d5e33ac3
...@@ -2892,6 +2892,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2892,6 +2892,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// r1 (receiver). Touch up the stack with the right values. // r1 (receiver). Touch up the stack with the right values.
__ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ str(r1, MemOperand(sp, arg_count * kPointerSize)); __ str(r1, MemOperand(sp, arg_count * kPointerSize));
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
} }
// Record source position for debugger. // Record source position for debugger.
...@@ -2925,6 +2927,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2925,6 +2927,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ Push(context_register(), r2); __ Push(context_register(), r2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2); __ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(r0, r1); // Function, receiver. __ Push(r0, r1); // Function, receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the // If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this // function and receiver and have the slow path jump around this
......
...@@ -2557,6 +2557,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2557,6 +2557,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// The runtime call returns a pair of values in x0 (function) and // The runtime call returns a pair of values in x0 (function) and
// x1 (receiver). Touch up the stack with the right values. // x1 (receiver). Touch up the stack with the right values.
__ PokePair(x1, x0, arg_count * kPointerSize); __ PokePair(x1, x0, arg_count * kPointerSize);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
} }
// Record source position for debugger. // Record source position for debugger.
...@@ -2592,6 +2594,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2592,6 +2594,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ Push(context_register(), x10); __ Push(context_register(), x10);
__ CallRuntime(Runtime::kLoadLookupSlot, 2); __ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(x0, x1); // Receiver, function. __ Push(x0, x1); // Receiver, function.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the // If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this // function and receiver and have the slow path jump around this
......
...@@ -1796,6 +1796,7 @@ class Call FINAL : public Expression, public FeedbackSlotInterface { ...@@ -1796,6 +1796,7 @@ class Call FINAL : public Expression, public FeedbackSlotInterface {
bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupIterator* it); bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupIterator* it);
BailoutId ReturnId() const { return return_id_; } BailoutId ReturnId() const { return return_id_; }
BailoutId EvalOrLookupId() const { return eval_or_lookup_id_; }
enum CallType { enum CallType {
POSSIBLY_EVAL_CALL, POSSIBLY_EVAL_CALL,
...@@ -1821,7 +1822,8 @@ class Call FINAL : public Expression, public FeedbackSlotInterface { ...@@ -1821,7 +1822,8 @@ class Call FINAL : public Expression, public FeedbackSlotInterface {
expression_(expression), expression_(expression),
arguments_(arguments), arguments_(arguments),
call_feedback_slot_(kInvalidFeedbackSlot), call_feedback_slot_(kInvalidFeedbackSlot),
return_id_(id_gen->GetNextId()) { return_id_(id_gen->GetNextId()),
eval_or_lookup_id_(id_gen->GetNextId()) {
if (expression->IsProperty()) { if (expression->IsProperty()) {
expression->AsProperty()->mark_for_call(); expression->AsProperty()->mark_for_call();
} }
...@@ -1837,6 +1839,9 @@ class Call FINAL : public Expression, public FeedbackSlotInterface { ...@@ -1837,6 +1839,9 @@ class Call FINAL : public Expression, public FeedbackSlotInterface {
int call_feedback_slot_; int call_feedback_slot_;
const BailoutId return_id_; const BailoutId return_id_;
// TODO(jarin) Only allocate the bailout id for the POSSIBLY_EVAL_CALL and
// LOOKUP_SLOT_CALL types.
const BailoutId eval_or_lookup_id_;
}; };
......
...@@ -861,6 +861,7 @@ void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { ...@@ -861,6 +861,7 @@ void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
const Operator* op = const Operator* op =
javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4); javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, pattern, flags); Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(literal); ast_context()->ProduceValue(literal);
} }
...@@ -1095,14 +1096,16 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { ...@@ -1095,14 +1096,16 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
Unique<Name> name = Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName()); MakeUnique(property->key()->AsLiteral()->AsPropertyName());
old_value = NewNode(javascript()->LoadNamed(name), object); old_value = NewNode(javascript()->LoadNamed(name), object);
PrepareFrameState(old_value, property->LoadId(), kPushOutput); PrepareFrameState(old_value, property->LoadId(),
OutputFrameStateCombine::Push());
break; break;
} }
case KEYED_PROPERTY: { case KEYED_PROPERTY: {
Node* key = environment()->Top(); Node* key = environment()->Top();
Node* object = environment()->Peek(1); Node* object = environment()->Peek(1);
old_value = NewNode(javascript()->LoadProperty(), object, key); old_value = NewNode(javascript()->LoadProperty(), object, key);
PrepareFrameState(old_value, property->LoadId(), kPushOutput); PrepareFrameState(old_value, property->LoadId(),
OutputFrameStateCombine::Push());
break; break;
} }
} }
...@@ -1111,7 +1114,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { ...@@ -1111,7 +1114,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
Node* right = environment()->Pop(); Node* right = environment()->Pop();
Node* left = environment()->Pop(); Node* left = environment()->Pop();
Node* value = BuildBinaryOp(left, right, expr->binary_op()); Node* value = BuildBinaryOp(left, right, expr->binary_op());
PrepareFrameState(value, expr->binary_operation()->id(), kPushOutput); PrepareFrameState(value, expr->binary_operation()->id(),
OutputFrameStateCombine::Push());
environment()->Push(value); environment()->Push(value);
} else { } else {
VisitForValue(expr->value()); VisitForValue(expr->value());
...@@ -1164,6 +1168,7 @@ void AstGraphBuilder::VisitThrow(Throw* expr) { ...@@ -1164,6 +1168,7 @@ void AstGraphBuilder::VisitThrow(Throw* expr) {
Node* exception = environment()->Pop(); Node* exception = environment()->Pop();
const Operator* op = javascript()->Runtime(Runtime::kThrow, 1); const Operator* op = javascript()->Runtime(Runtime::kThrow, 1);
Node* value = NewNode(op, exception); Node* value = NewNode(op, exception);
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value); ast_context()->ProduceValue(value);
} }
...@@ -1212,6 +1217,9 @@ void AstGraphBuilder::VisitCall(Call* expr) { ...@@ -1212,6 +1217,9 @@ void AstGraphBuilder::VisitCall(Call* expr) {
Node* pair = NewNode(op, current_context(), name); Node* pair = NewNode(op, current_context(), name);
callee_value = NewNode(common()->Projection(0), pair); callee_value = NewNode(common()->Projection(0), pair);
receiver_value = NewNode(common()->Projection(1), pair); receiver_value = NewNode(common()->Projection(1), pair);
PrepareFrameState(pair, expr->EvalOrLookupId(),
OutputFrameStateCombine::Push());
break; break;
} }
case Call::PROPERTY_CALL: { case Call::PROPERTY_CALL: {
...@@ -1227,7 +1235,8 @@ void AstGraphBuilder::VisitCall(Call* expr) { ...@@ -1227,7 +1235,8 @@ void AstGraphBuilder::VisitCall(Call* expr) {
Node* key = environment()->Pop(); Node* key = environment()->Pop();
callee_value = NewNode(javascript()->LoadProperty(), object, key); callee_value = NewNode(javascript()->LoadProperty(), object, key);
} }
PrepareFrameState(callee_value, property->LoadId(), kPushOutput); PrepareFrameState(callee_value, property->LoadId(),
OutputFrameStateCombine::Push());
receiver_value = environment()->Pop(); receiver_value = environment()->Pop();
// Note that a PROPERTY_CALL requires the receiver to be wrapped into an // Note that a PROPERTY_CALL requires the receiver to be wrapped into an
// object for sloppy callees. This could also be modeled explicitly here, // object for sloppy callees. This could also be modeled explicitly here,
...@@ -1271,6 +1280,8 @@ void AstGraphBuilder::VisitCall(Call* expr) { ...@@ -1271,6 +1280,8 @@ void AstGraphBuilder::VisitCall(Call* expr) {
const Operator* op = const Operator* op =
javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 5); javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 5);
Node* pair = NewNode(op, callee, source, receiver, strict, position); Node* pair = NewNode(op, callee, source, receiver, strict, position);
PrepareFrameState(pair, expr->EvalOrLookupId(),
OutputFrameStateCombine::PokeAt(arg_count + 1));
Node* new_callee = NewNode(common()->Projection(0), pair); Node* new_callee = NewNode(common()->Projection(0), pair);
Node* new_receiver = NewNode(common()->Projection(1), pair); Node* new_receiver = NewNode(common()->Projection(1), pair);
...@@ -1313,7 +1324,8 @@ void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) { ...@@ -1313,7 +1324,8 @@ void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
Node* callee_value = NewNode(javascript()->LoadNamed(unique), receiver_value); Node* callee_value = NewNode(javascript()->LoadNamed(unique), receiver_value);
// TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft // TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
// refuses to optimize functions with jsruntime calls). // refuses to optimize functions with jsruntime calls).
PrepareFrameState(callee_value, BailoutId::None(), kPushOutput); PrepareFrameState(callee_value, BailoutId::None(),
OutputFrameStateCombine::Push());
environment()->Push(callee_value); environment()->Push(callee_value);
environment()->Push(receiver_value); environment()->Push(receiver_value);
...@@ -1395,7 +1407,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -1395,7 +1407,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
Unique<Name> name = Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName()); MakeUnique(property->key()->AsLiteral()->AsPropertyName());
old_value = NewNode(javascript()->LoadNamed(name), object); old_value = NewNode(javascript()->LoadNamed(name), object);
PrepareFrameState(old_value, property->LoadId(), kPushOutput); PrepareFrameState(old_value, property->LoadId(),
OutputFrameStateCombine::Push());
stack_depth = 1; stack_depth = 1;
break; break;
} }
...@@ -1405,7 +1418,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -1405,7 +1418,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
Node* key = environment()->Top(); Node* key = environment()->Top();
Node* object = environment()->Peek(1); Node* object = environment()->Peek(1);
old_value = NewNode(javascript()->LoadProperty(), object, key); old_value = NewNode(javascript()->LoadProperty(), object, key);
PrepareFrameState(old_value, property->LoadId(), kPushOutput); PrepareFrameState(old_value, property->LoadId(),
OutputFrameStateCombine::Push());
stack_depth = 2; stack_depth = 2;
break; break;
} }
...@@ -1583,7 +1597,8 @@ void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { ...@@ -1583,7 +1597,8 @@ void AstGraphBuilder::VisitDelete(UnaryOperation* expr) {
// deleting "this" is allowed in all language modes. // deleting "this" is allowed in all language modes.
Variable* variable = expr->expression()->AsVariableProxy()->var(); Variable* variable = expr->expression()->AsVariableProxy()->var();
DCHECK(strict_mode() == SLOPPY || variable->is_this()); DCHECK(strict_mode() == SLOPPY || variable->is_this());
value = BuildVariableDelete(variable); value = BuildVariableDelete(variable, expr->id(),
ast_context()->GetStateCombine());
} else if (expr->expression()->IsProperty()) { } else if (expr->expression()->IsProperty()) {
Property* property = expr->expression()->AsProperty(); Property* property = expr->expression()->AsProperty();
VisitForValue(property->obj()); VisitForValue(property->obj());
...@@ -1591,6 +1606,7 @@ void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { ...@@ -1591,6 +1606,7 @@ void AstGraphBuilder::VisitDelete(UnaryOperation* expr) {
Node* key = environment()->Pop(); Node* key = environment()->Pop();
Node* object = environment()->Pop(); Node* object = environment()->Pop();
value = NewNode(javascript()->DeleteProperty(strict_mode()), object, key); value = NewNode(javascript()->DeleteProperty(strict_mode()), object, key);
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
} else { } else {
VisitForEffect(expr->expression()); VisitForEffect(expr->expression());
value = jsgraph()->TrueConstant(); value = jsgraph()->TrueConstant();
...@@ -1736,13 +1752,14 @@ Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole, ...@@ -1736,13 +1752,14 @@ Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole,
Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable, Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
Node* not_hole) { Node* not_hole,
BailoutId bailout_id) {
IfBuilder hole_check(this); IfBuilder hole_check(this);
Node* the_hole = jsgraph()->TheHoleConstant(); Node* the_hole = jsgraph()->TheHoleConstant();
Node* check = NewNode(javascript()->StrictEqual(), value, the_hole); Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
hole_check.If(check); hole_check.If(check);
hole_check.Then(); hole_check.Then();
environment()->Push(BuildThrowReferenceError(variable)); environment()->Push(BuildThrowReferenceError(variable, bailout_id));
hole_check.Else(); hole_check.Else();
environment()->Push(not_hole); environment()->Push(not_hole);
hole_check.End(); hole_check.End();
...@@ -1762,7 +1779,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, ...@@ -1762,7 +1779,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
Unique<Name> name = MakeUnique(variable->name()); Unique<Name> name = MakeUnique(variable->name());
const Operator* op = javascript()->LoadNamed(name, contextual_mode); const Operator* op = javascript()->LoadNamed(name, contextual_mode);
Node* node = NewNode(op, global); Node* node = NewNode(op, global);
PrepareFrameState(node, bailout_id, kPushOutput); PrepareFrameState(node, bailout_id, OutputFrameStateCombine::Push());
return node; return node;
} }
case Variable::PARAMETER: case Variable::PARAMETER:
...@@ -1780,9 +1797,9 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, ...@@ -1780,9 +1797,9 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
} else if (mode == LET || mode == CONST) { } else if (mode == LET || mode == CONST) {
// Perform check for uninitialized let/const variables. // Perform check for uninitialized let/const variables.
if (value->op() == the_hole->op()) { if (value->op() == the_hole->op()) {
value = BuildThrowReferenceError(variable); value = BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi) { } else if (value->opcode() == IrOpcode::kPhi) {
value = BuildHoleCheckThrow(value, variable, value); value = BuildHoleCheckThrow(value, variable, value, bailout_id);
} }
} }
return value; return value;
...@@ -1803,7 +1820,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, ...@@ -1803,7 +1820,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
value = BuildHoleCheckSilent(value, undefined, value); value = BuildHoleCheckSilent(value, undefined, value);
} else if (mode == LET || mode == CONST) { } else if (mode == LET || mode == CONST) {
// Perform check for uninitialized let/const variables. // Perform check for uninitialized let/const variables.
value = BuildHoleCheckThrow(value, variable, value); value = BuildHoleCheckThrow(value, variable, value, bailout_id);
} }
return value; return value;
} }
...@@ -1816,6 +1833,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, ...@@ -1816,6 +1833,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
: Runtime::kLoadLookupSlotNoReferenceError; : Runtime::kLoadLookupSlotNoReferenceError;
const Operator* op = javascript()->Runtime(function_id, 2); const Operator* op = javascript()->Runtime(function_id, 2);
Node* pair = NewNode(op, current_context(), name); Node* pair = NewNode(op, current_context(), name);
PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1));
return NewNode(common()->Projection(0), pair); return NewNode(common()->Projection(0), pair);
} }
} }
...@@ -1824,14 +1842,18 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, ...@@ -1824,14 +1842,18 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
} }
Node* AstGraphBuilder::BuildVariableDelete(Variable* variable) { Node* AstGraphBuilder::BuildVariableDelete(
Variable* variable, BailoutId bailout_id,
OutputFrameStateCombine state_combine) {
switch (variable->location()) { switch (variable->location()) {
case Variable::UNALLOCATED: { case Variable::UNALLOCATED: {
// Global var, const, or let variable. // Global var, const, or let variable.
Node* global = BuildLoadGlobalObject(); Node* global = BuildLoadGlobalObject();
Node* name = jsgraph()->Constant(variable->name()); Node* name = jsgraph()->Constant(variable->name());
const Operator* op = javascript()->DeleteProperty(strict_mode()); const Operator* op = javascript()->DeleteProperty(strict_mode());
return NewNode(op, global, name); Node* result = NewNode(op, global, name);
PrepareFrameState(result, bailout_id, state_combine);
return result;
} }
case Variable::PARAMETER: case Variable::PARAMETER:
case Variable::LOCAL: case Variable::LOCAL:
...@@ -1843,7 +1865,9 @@ Node* AstGraphBuilder::BuildVariableDelete(Variable* variable) { ...@@ -1843,7 +1865,9 @@ Node* AstGraphBuilder::BuildVariableDelete(Variable* variable) {
// Dynamic lookup of context variable (anywhere in the chain). // Dynamic lookup of context variable (anywhere in the chain).
Node* name = jsgraph()->Constant(variable->name()); Node* name = jsgraph()->Constant(variable->name());
const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2); const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2);
return NewNode(op, current_context(), name); Node* result = NewNode(op, current_context(), name);
PrepareFrameState(result, bailout_id, state_combine);
return result;
} }
} }
UNREACHABLE(); UNREACHABLE();
...@@ -1885,9 +1909,9 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value, ...@@ -1885,9 +1909,9 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
// temporal dead zone of a let declared variable. // temporal dead zone of a let declared variable.
Node* current = environment()->Lookup(variable); Node* current = environment()->Lookup(variable);
if (current->op() == the_hole->op()) { if (current->op() == the_hole->op()) {
value = BuildThrowReferenceError(variable); value = BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi) { } else if (value->opcode() == IrOpcode::kPhi) {
value = BuildHoleCheckThrow(current, variable, value); value = BuildHoleCheckThrow(current, variable, value, bailout_id);
} }
} else if (mode == CONST && op != Token::INIT_CONST) { } else if (mode == CONST && op != Token::INIT_CONST) {
// All assignments to const variables are early errors. // All assignments to const variables are early errors.
...@@ -1912,7 +1936,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value, ...@@ -1912,7 +1936,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
const Operator* op = const Operator* op =
javascript()->LoadContext(depth, variable->index(), false); javascript()->LoadContext(depth, variable->index(), false);
Node* current = NewNode(op, current_context()); Node* current = NewNode(op, current_context());
value = BuildHoleCheckThrow(current, variable, value); value = BuildHoleCheckThrow(current, variable, value, bailout_id);
} else if (mode == CONST && op != Token::INIT_CONST) { } else if (mode == CONST && op != Token::INIT_CONST) {
// All assignments to const variables are early errors. // All assignments to const variables are early errors.
UNREACHABLE(); UNREACHABLE();
...@@ -1927,7 +1951,9 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value, ...@@ -1927,7 +1951,9 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
// TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
// initializations of const declarations. // initializations of const declarations.
const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4); const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4);
return NewNode(op, value, current_context(), name, strict); Node* store = NewNode(op, value, current_context(), name, strict);
PrepareFrameState(store, bailout_id);
return store;
} }
} }
UNREACHABLE(); UNREACHABLE();
...@@ -1965,11 +1991,14 @@ Node* AstGraphBuilder::BuildToBoolean(Node* value) { ...@@ -1965,11 +1991,14 @@ Node* AstGraphBuilder::BuildToBoolean(Node* value) {
} }
Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable) { Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
BailoutId bailout_id) {
// TODO(mstarzinger): Should be unified with the VisitThrow implementation. // TODO(mstarzinger): Should be unified with the VisitThrow implementation.
Node* variable_name = jsgraph()->Constant(variable->name()); Node* variable_name = jsgraph()->Constant(variable->name());
const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1); const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1);
return NewNode(op, variable_name); Node* call = NewNode(op, variable_name);
PrepareFrameState(call, bailout_id);
return call;
} }
......
...@@ -80,7 +80,8 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { ...@@ -80,7 +80,8 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
// Builders for variable load and assignment. // Builders for variable load and assignment.
Node* BuildVariableAssignment(Variable* var, Node* value, Token::Value op, Node* BuildVariableAssignment(Variable* var, Node* value, Token::Value op,
BailoutId bailout_id); BailoutId bailout_id);
Node* BuildVariableDelete(Variable* var); Node* BuildVariableDelete(Variable* var, BailoutId bailout_id,
OutputFrameStateCombine state_combine);
Node* BuildVariableLoad(Variable* var, BailoutId bailout_id, Node* BuildVariableLoad(Variable* var, BailoutId bailout_id,
ContextualMode mode = CONTEXTUAL); ContextualMode mode = CONTEXTUAL);
...@@ -94,11 +95,12 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { ...@@ -94,11 +95,12 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
Node* BuildToBoolean(Node* value); Node* BuildToBoolean(Node* value);
// Builders for error reporting at runtime. // Builders for error reporting at runtime.
Node* BuildThrowReferenceError(Variable* var); Node* BuildThrowReferenceError(Variable* var, BailoutId bailout_id);
// Builders for dynamic hole-checks at runtime. // Builders for dynamic hole-checks at runtime.
Node* BuildHoleCheckSilent(Node* value, Node* for_hole, Node* not_hole); Node* BuildHoleCheckSilent(Node* value, Node* for_hole, Node* not_hole);
Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole); Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole,
BailoutId bailout_id);
// Builders for binary operations. // Builders for binary operations.
Node* BuildBinaryOp(Node* left, Node* right, Token::Value op); Node* BuildBinaryOp(Node* left, Node* right, Token::Value op);
...@@ -173,8 +175,9 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { ...@@ -173,8 +175,9 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
void VisitForInAssignment(Expression* expr, Node* value); void VisitForInAssignment(Expression* expr, Node* value);
// Builds deoptimization for a given node. // Builds deoptimization for a given node.
void PrepareFrameState(Node* node, BailoutId ast_id, void PrepareFrameState(
OutputFrameStateCombine combine = kIgnoreOutput); Node* node, BailoutId ast_id,
OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
OutputFrameStateCombine StateCombineFromAstContext(); OutputFrameStateCombine StateCombineFromAstContext();
...@@ -288,7 +291,8 @@ class AstGraphBuilder::AstContext BASE_EMBEDDED { ...@@ -288,7 +291,8 @@ class AstGraphBuilder::AstContext BASE_EMBEDDED {
// Determines how to combine the frame state with the value // Determines how to combine the frame state with the value
// that is about to be plugged into this AstContext. // that is about to be plugged into this AstContext.
OutputFrameStateCombine GetStateCombine() { OutputFrameStateCombine GetStateCombine() {
return IsEffect() ? kIgnoreOutput : kPushOutput; return IsEffect() ? OutputFrameStateCombine::Ignore()
: OutputFrameStateCombine::Push();
} }
// Plug a node into this expression context. Call this function in tail // Plug a node into this expression context. Call this function in tail
......
...@@ -260,15 +260,15 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { ...@@ -260,15 +260,15 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) {
// because it is only used to get locals and arguments (by the debugger and // because it is only used to get locals and arguments (by the debugger and
// f.arguments), and those are the same in the pre-call and post-call // f.arguments), and those are the same in the pre-call and post-call
// states. // states.
if (descriptor->state_combine() != kIgnoreOutput) { if (!descriptor->state_combine().IsOutputIgnored()) {
deopt_state_id = deopt_state_id = BuildTranslation(instr, -1, frame_state_offset,
BuildTranslation(instr, -1, frame_state_offset, kIgnoreOutput); OutputFrameStateCombine::Ignore());
} }
#if DEBUG #if DEBUG
// Make sure all the values live in stack slots or they are immediates. // Make sure all the values live in stack slots or they are immediates.
// (The values should not live in register because registers are clobbered // (The values should not live in register because registers are clobbered
// by calls.) // by calls.)
for (size_t i = 0; i < descriptor->size(); i++) { for (size_t i = 0; i < descriptor->GetSize(); i++) {
InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i); InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i);
CHECK(op->IsStackSlot() || op->IsImmediate()); CHECK(op->IsStackSlot() || op->IsImmediate());
} }
...@@ -296,6 +296,33 @@ FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor( ...@@ -296,6 +296,33 @@ FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor(
return code()->GetFrameStateDescriptor(state_id); return code()->GetFrameStateDescriptor(state_id);
} }
static InstructionOperand* OperandForFrameState(
FrameStateDescriptor* descriptor, Instruction* instr,
size_t frame_state_offset, size_t index, OutputFrameStateCombine combine) {
DCHECK(index < descriptor->GetSize(combine));
switch (combine.kind()) {
case OutputFrameStateCombine::kPushOutput: {
DCHECK(combine.GetPushCount() <= instr->OutputCount());
size_t size_without_output =
descriptor->GetSize(OutputFrameStateCombine::Ignore());
// If the index is past the existing stack items, return the output.
if (index >= size_without_output) {
return instr->OutputAt(index - size_without_output);
}
break;
}
case OutputFrameStateCombine::kPokeAt:
size_t index_from_top =
descriptor->GetSize(combine) - 1 - combine.GetOffsetToPokeAt();
if (index >= index_from_top &&
index < index_from_top + instr->OutputCount()) {
return instr->OutputAt(index - index_from_top);
}
break;
}
return instr->InputAt(frame_state_offset + index);
}
void CodeGenerator::BuildTranslationForFrameStateDescriptor( void CodeGenerator::BuildTranslationForFrameStateDescriptor(
FrameStateDescriptor* descriptor, Instruction* instr, FrameStateDescriptor* descriptor, Instruction* instr,
...@@ -305,7 +332,7 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor( ...@@ -305,7 +332,7 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
if (descriptor->outer_state() != NULL) { if (descriptor->outer_state() != NULL) {
BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), instr, BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), instr,
translation, frame_state_offset, translation, frame_state_offset,
kIgnoreOutput); OutputFrameStateCombine::Ignore());
} }
int id = Translation::kSelfLiteralId; int id = Translation::kSelfLiteralId;
...@@ -318,7 +345,8 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor( ...@@ -318,7 +345,8 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
case JS_FRAME: case JS_FRAME:
translation->BeginJSFrame( translation->BeginJSFrame(
descriptor->bailout_id(), id, descriptor->bailout_id(), id,
static_cast<unsigned int>(descriptor->GetHeight(state_combine))); static_cast<unsigned int>(descriptor->GetSize(state_combine) -
descriptor->parameters_count()));
break; break;
case ARGUMENTS_ADAPTOR: case ARGUMENTS_ADAPTOR:
translation->BeginArgumentsAdaptorFrame( translation->BeginArgumentsAdaptorFrame(
...@@ -327,19 +355,10 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor( ...@@ -327,19 +355,10 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
} }
frame_state_offset += descriptor->outer_state()->GetTotalSize(); frame_state_offset += descriptor->outer_state()->GetTotalSize();
for (size_t i = 0; i < descriptor->size(); i++) { for (size_t i = 0; i < descriptor->GetSize(state_combine); i++) {
AddTranslationForOperand( InstructionOperand* op = OperandForFrameState(
translation, instr, descriptor, instr, frame_state_offset, i, state_combine);
instr->InputAt(static_cast<int>(frame_state_offset + i))); AddTranslationForOperand(translation, instr, op);
}
switch (state_combine) {
case kPushOutput:
DCHECK(instr->OutputCount() == 1);
AddTranslationForOperand(translation, instr, instr->OutputAt(0));
break;
case kIgnoreOutput:
break;
} }
} }
......
...@@ -247,6 +247,50 @@ const Operator* CommonOperatorBuilder::Projection(size_t index) { ...@@ -247,6 +247,50 @@ const Operator* CommonOperatorBuilder::Projection(size_t index) {
1, 1, "Projection", index); 1, 1, "Projection", index);
} }
OutputFrameStateCombine::OutputFrameStateCombine(CombineKind kind,
size_t parameter)
: kind_(kind), parameter_(parameter) {}
// static
OutputFrameStateCombine OutputFrameStateCombine::Ignore() {
return OutputFrameStateCombine(kPushOutput, 0);
}
// static
OutputFrameStateCombine OutputFrameStateCombine::Push(size_t count) {
return OutputFrameStateCombine(kPushOutput, count);
}
// static
OutputFrameStateCombine OutputFrameStateCombine::PokeAt(size_t index) {
return OutputFrameStateCombine(kPokeAt, index);
}
OutputFrameStateCombine::CombineKind OutputFrameStateCombine::kind() {
return kind_;
}
size_t OutputFrameStateCombine::GetPushCount() {
DCHECK(kind() == kPushOutput);
return parameter_;
}
size_t OutputFrameStateCombine::GetOffsetToPokeAt() {
DCHECK(kind() == kPokeAt);
return parameter_;
}
bool OutputFrameStateCombine::IsOutputIgnored() {
return kind() == kPushOutput && GetPushCount() == 0;
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -26,9 +26,29 @@ class Operator; ...@@ -26,9 +26,29 @@ class Operator;
// Flag that describes how to combine the current environment with // Flag that describes how to combine the current environment with
// the output of a node to obtain a framestate for lazy bailout. // the output of a node to obtain a framestate for lazy bailout.
enum OutputFrameStateCombine { class OutputFrameStateCombine {
kPushOutput, // Push the output on the expression stack. public:
kIgnoreOutput // Use the frame state as-is. enum CombineKind {
kPushOutput, // Push the output on the expression stack.
kPokeAt // Poke at the given environment location,
// counting from the top of the stack.
};
static OutputFrameStateCombine Ignore();
static OutputFrameStateCombine Push(size_t count = 1);
static OutputFrameStateCombine PokeAt(size_t index);
CombineKind kind();
size_t GetPushCount();
size_t GetOffsetToPokeAt();
bool IsOutputIgnored();
private:
OutputFrameStateCombine(CombineKind kind, size_t parameter);
CombineKind kind_;
size_t parameter_;
}; };
......
...@@ -320,8 +320,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { ...@@ -320,8 +320,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
Node* context_dummy = m.Int32Constant(0); Node* context_dummy = m.Int32Constant(0);
Node* state_node = m.NewNode( Node* state_node = m.NewNode(
m.common()->FrameState(JS_FRAME, bailout_id, kPushOutput), parameters, m.common()->FrameState(JS_FRAME, bailout_id,
locals, stack, context_dummy, m.UndefinedConstant()); OutputFrameStateCombine::Push()),
parameters, locals, stack, context_dummy, m.UndefinedConstant());
Node* call = m.CallJS0(function_node, receiver, context, state_node); Node* call = m.CallJS0(function_node, receiver, context, state_node);
m.Return(call); m.Return(call);
...@@ -360,7 +361,8 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { ...@@ -360,7 +361,8 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
Node* context_sentinel = m.Int32Constant(0); Node* context_sentinel = m.Int32Constant(0);
Node* frame_state_before = m.NewNode( Node* frame_state_before = m.NewNode(
m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput), m.common()->FrameState(JS_FRAME, bailout_id_before,
OutputFrameStateCombine::Push()),
parameters, locals, stack, context_sentinel, m.UndefinedConstant()); parameters, locals, stack, context_sentinel, m.UndefinedConstant());
// Build the call. // Build the call.
...@@ -398,7 +400,8 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { ...@@ -398,7 +400,8 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
FrameStateDescriptor* desc_before = FrameStateDescriptor* desc_before =
s.GetFrameStateDescriptor(deopt_id_before); s.GetFrameStateDescriptor(deopt_id_before);
EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
EXPECT_EQ(kPushOutput, desc_before->state_combine()); EXPECT_EQ(OutputFrameStateCombine::kPushOutput,
desc_before->state_combine().kind());
EXPECT_EQ(1u, desc_before->parameters_count()); EXPECT_EQ(1u, desc_before->parameters_count());
EXPECT_EQ(1u, desc_before->locals_count()); EXPECT_EQ(1u, desc_before->locals_count());
EXPECT_EQ(1u, desc_before->stack_count()); EXPECT_EQ(1u, desc_before->stack_count());
...@@ -435,18 +438,20 @@ TARGET_TEST_F(InstructionSelectorTest, ...@@ -435,18 +438,20 @@ TARGET_TEST_F(InstructionSelectorTest,
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63)); Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64)); Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65)); Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
Node* frame_state_parent = m.NewNode( Node* frame_state_parent =
m.common()->FrameState(JS_FRAME, bailout_id_parent, kIgnoreOutput), m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent,
parameters, locals, stack, context, m.UndefinedConstant()); OutputFrameStateCombine::Ignore()),
parameters, locals, stack, context, m.UndefinedConstant());
Node* context2 = m.Int32Constant(46); Node* context2 = m.Int32Constant(46);
Node* parameters2 = Node* parameters2 =
m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
Node* frame_state_before = m.NewNode( Node* frame_state_before =
m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput), m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
parameters2, locals2, stack2, context2, frame_state_parent); OutputFrameStateCombine::Push()),
parameters2, locals2, stack2, context2, frame_state_parent);
// Build the call. // Build the call.
Node* call = m.CallFunctionStub0(function_node, receiver, context2, Node* call = m.CallFunctionStub0(function_node, receiver, context2,
......
...@@ -736,32 +736,29 @@ class FrameStateDescriptor : public ZoneObject { ...@@ -736,32 +736,29 @@ class FrameStateDescriptor : public ZoneObject {
FrameStateDescriptor* outer_state() const { return outer_state_; } FrameStateDescriptor* outer_state() const { return outer_state_; }
MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; } MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
size_t size() const { size_t GetSize(OutputFrameStateCombine combine =
return parameters_count_ + locals_count_ + stack_count_ + OutputFrameStateCombine::Ignore()) const {
(HasContext() ? 1 : 0); size_t size = parameters_count_ + locals_count_ + stack_count_ +
(HasContext() ? 1 : 0);
switch (combine.kind()) {
case OutputFrameStateCombine::kPushOutput:
size += combine.GetPushCount();
break;
case OutputFrameStateCombine::kPokeAt:
break;
}
return size;
} }
size_t GetTotalSize() const { size_t GetTotalSize() const {
size_t total_size = 0; size_t total_size = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL; for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) { iter = iter->outer_state_) {
total_size += iter->size(); total_size += iter->GetSize();
} }
return total_size; return total_size;
} }
size_t GetHeight(OutputFrameStateCombine override) const {
size_t height = size() - parameters_count();
switch (override) {
case kPushOutput:
++height;
break;
case kIgnoreOutput:
break;
}
return height;
}
size_t GetFrameCount() const { size_t GetFrameCount() const {
size_t count = 0; size_t count = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL; for (const FrameStateDescriptor* iter = this; iter != NULL;
......
...@@ -198,8 +198,8 @@ void JSGenericLowering::ReplaceWithBuiltinCall(Node* node, ...@@ -198,8 +198,8 @@ void JSGenericLowering::ReplaceWithBuiltinCall(Node* node,
int nargs) { int nargs) {
Callable callable = Callable callable =
CodeFactory::CallFunction(isolate(), nargs - 1, NO_CALL_FUNCTION_FLAGS); CodeFactory::CallFunction(isolate(), nargs - 1, NO_CALL_FUNCTION_FLAGS);
CallDescriptor* desc = CallDescriptor* desc = linkage()->GetStubCallDescriptor(
linkage()->GetStubCallDescriptor(callable.descriptor(), nargs); callable.descriptor(), nargs, FlagsForNode(node));
// TODO(mstarzinger): Accessing the builtins object this way prevents sharing // TODO(mstarzinger): Accessing the builtins object this way prevents sharing
// of code across native contexts. Fix this by loading from given context. // of code across native contexts. Fix this by loading from given context.
Handle<JSFunction> function( Handle<JSFunction> function(
...@@ -260,7 +260,7 @@ void JSGenericLowering::LowerJSToBoolean(Node* node) { ...@@ -260,7 +260,7 @@ void JSGenericLowering::LowerJSToBoolean(Node* node) {
void JSGenericLowering::LowerJSToNumber(Node* node) { void JSGenericLowering::LowerJSToNumber(Node* node) {
Callable callable = CodeFactory::ToNumber(isolate()); Callable callable = CodeFactory::ToNumber(isolate());
ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags); ReplaceWithStubCall(node, callable, FlagsForNode(node));
} }
...@@ -321,7 +321,8 @@ void JSGenericLowering::LowerJSInstanceOf(Node* node) { ...@@ -321,7 +321,8 @@ void JSGenericLowering::LowerJSInstanceOf(Node* node) {
InstanceofStub::kArgsInRegisters); InstanceofStub::kArgsInRegisters);
InstanceofStub stub(isolate(), flags); InstanceofStub stub(isolate(), flags);
CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor(); CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
CallDescriptor* desc = linkage()->GetStubCallDescriptor(d, 0); CallDescriptor* desc =
linkage()->GetStubCallDescriptor(d, 0, FlagsForNode(node));
Node* stub_code = CodeConstant(stub.GetCode()); Node* stub_code = CodeConstant(stub.GetCode());
PatchInsertInput(node, 0, stub_code); PatchInsertInput(node, 0, stub_code);
PatchOperator(node, common()->Call(desc)); PatchOperator(node, common()->Call(desc));
......
...@@ -348,9 +348,9 @@ void JSInliner::AddClosureToFrameState(Node* frame_state, ...@@ -348,9 +348,9 @@ void JSInliner::AddClosureToFrameState(Node* frame_state,
Node* JSInliner::CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call, Node* JSInliner::CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
Handle<JSFunction> jsfunction, Handle<JSFunction> jsfunction,
Zone* temp_zone) { Zone* temp_zone) {
const Operator* op = const Operator* op = jsgraph_->common()->FrameState(
jsgraph_->common()->FrameState(FrameStateType::ARGUMENTS_ADAPTOR, FrameStateType::ARGUMENTS_ADAPTOR, BailoutId(-1),
BailoutId(-1), kIgnoreOutput, jsfunction); OutputFrameStateCombine::Ignore(), jsfunction);
const Operator* op0 = jsgraph_->common()->StateValues(0); const Operator* op0 = jsgraph_->common()->StateValues(0);
Node* node0 = jsgraph_->graph()->NewNode(op0); Node* node0 = jsgraph_->graph()->NewNode(op0);
NodeVector params(temp_zone); NodeVector params(temp_zone);
......
...@@ -116,16 +116,67 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) { ...@@ -116,16 +116,67 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) {
// TODO(jarin) At the moment, we only add frame state for // TODO(jarin) At the moment, we only add frame state for
// few chosen runtime functions. // few chosen runtime functions.
switch (function) { switch (function) {
case Runtime::kApply:
case Runtime::kArrayBufferNeuter:
case Runtime::kArrayConcat:
case Runtime::kBasicJSONStringify:
case Runtime::kCheckExecutionState:
case Runtime::kCollectStackTrace:
case Runtime::kCompileLazy:
case Runtime::kCompileOptimized:
case Runtime::kCompileString:
case Runtime::kDebugBreak: case Runtime::kDebugBreak:
case Runtime::kDataViewSetInt8:
case Runtime::kDataViewSetUint8:
case Runtime::kDataViewSetInt16:
case Runtime::kDataViewSetUint16:
case Runtime::kDataViewSetInt32:
case Runtime::kDataViewSetUint32:
case Runtime::kDataViewSetFloat32:
case Runtime::kDataViewSetFloat64:
case Runtime::kDataViewGetInt8:
case Runtime::kDataViewGetUint8:
case Runtime::kDataViewGetInt16:
case Runtime::kDataViewGetUint16:
case Runtime::kDataViewGetInt32:
case Runtime::kDataViewGetUint32:
case Runtime::kDataViewGetFloat32:
case Runtime::kDataViewGetFloat64:
case Runtime::kDebugEvaluate:
case Runtime::kDebugGetLoadedScripts: case Runtime::kDebugGetLoadedScripts:
case Runtime::kDebugGetPropertyDetails:
case Runtime::kDebugPromiseRejectEvent:
case Runtime::kDebugPromiseEvent:
case Runtime::kDeleteProperty:
case Runtime::kDeoptimizeFunction: case Runtime::kDeoptimizeFunction:
case Runtime::kFunctionBindArguments:
case Runtime::kGetFrameCount:
case Runtime::kGetOwnProperty:
case Runtime::kInlineCallFunction: case Runtime::kInlineCallFunction:
case Runtime::kInlineDateField:
case Runtime::kInlineRegExpExec:
case Runtime::kLiveEditGatherCompileInfo:
case Runtime::kLoadLookupSlot:
case Runtime::kLoadLookupSlotNoReferenceError:
case Runtime::kMaterializeRegExpLiteral:
case Runtime::kNewObjectFromBound:
case Runtime::kObjectFreeze:
case Runtime::kParseJson:
case Runtime::kPrepareStep: case Runtime::kPrepareStep:
case Runtime::kPreventExtensions:
case Runtime::kRegExpCompile:
case Runtime::kRegExpExecMultiple:
case Runtime::kResolvePossiblyDirectEval:
// case Runtime::kSetPrototype:
case Runtime::kSetScriptBreakPoint: case Runtime::kSetScriptBreakPoint:
case Runtime::kStackGuard: case Runtime::kStackGuard:
case Runtime::kCheckExecutionState: case Runtime::kStoreLookupSlot:
case Runtime::kDebugEvaluate: case Runtime::kStringBuilderConcat:
case Runtime::kCollectStackTrace: case Runtime::kStringReplaceGlobalRegExpWithString:
case Runtime::kThrowReferenceError:
case Runtime::kThrow:
case Runtime::kTypedArraySetFastCases:
case Runtime::kTypedArrayInitializeFromArrayLike:
return true; return true;
default: default:
return false; return false;
......
...@@ -55,28 +55,33 @@ inline bool OperatorProperties::HasFrameStateInput(const Operator* op) { ...@@ -55,28 +55,33 @@ inline bool OperatorProperties::HasFrameStateInput(const Operator* op) {
// Compare operations // Compare operations
case IrOpcode::kJSEqual: case IrOpcode::kJSEqual:
case IrOpcode::kJSNotEqual:
case IrOpcode::kJSLessThan:
case IrOpcode::kJSGreaterThan: case IrOpcode::kJSGreaterThan:
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSGreaterThanOrEqual: case IrOpcode::kJSGreaterThanOrEqual:
case IrOpcode::kJSHasProperty:
case IrOpcode::kJSInstanceOf:
case IrOpcode::kJSLessThan:
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSNotEqual:
// Binary operations // Binary operations
case IrOpcode::kJSAdd:
case IrOpcode::kJSBitwiseAnd:
case IrOpcode::kJSBitwiseOr: case IrOpcode::kJSBitwiseOr:
case IrOpcode::kJSBitwiseXor: case IrOpcode::kJSBitwiseXor:
case IrOpcode::kJSBitwiseAnd: case IrOpcode::kJSDivide:
case IrOpcode::kJSLoadNamed:
case IrOpcode::kJSLoadProperty:
case IrOpcode::kJSModulus:
case IrOpcode::kJSMultiply:
case IrOpcode::kJSShiftLeft: case IrOpcode::kJSShiftLeft:
case IrOpcode::kJSShiftRight: case IrOpcode::kJSShiftRight:
case IrOpcode::kJSShiftRightLogical: case IrOpcode::kJSShiftRightLogical:
case IrOpcode::kJSAdd:
case IrOpcode::kJSSubtract:
case IrOpcode::kJSMultiply:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus:
case IrOpcode::kJSLoadProperty:
case IrOpcode::kJSStoreProperty:
case IrOpcode::kJSLoadNamed:
case IrOpcode::kJSStoreNamed: case IrOpcode::kJSStoreNamed:
case IrOpcode::kJSStoreProperty:
case IrOpcode::kJSSubtract:
// Other
case IrOpcode::kJSDeleteProperty:
return true; return true;
default: default:
......
...@@ -2798,6 +2798,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2798,6 +2798,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// edx (receiver). Touch up the stack with the right values. // edx (receiver). Touch up the stack with the right values.
__ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
} }
// Record source position for debugger. // Record source position for debugger.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
...@@ -2829,6 +2831,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2829,6 +2831,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ CallRuntime(Runtime::kLoadLookupSlot, 2); __ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ push(eax); // Function. __ push(eax); // Function.
__ push(edx); // Receiver. __ push(edx); // Receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function // If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code. // and receiver and have the slow path jump around this code.
......
...@@ -2871,6 +2871,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2871,6 +2871,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// v1 (receiver). Touch up the stack with the right values. // v1 (receiver). Touch up the stack with the right values.
__ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ sw(v1, MemOperand(sp, arg_count * kPointerSize)); __ sw(v1, MemOperand(sp, arg_count * kPointerSize));
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
} }
// Record source position for debugger. // Record source position for debugger.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
...@@ -2902,6 +2904,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2902,6 +2904,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ Push(context_register(), a2); __ Push(context_register(), a2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2); __ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(v0, v1); // Function, receiver. __ Push(v0, v1); // Function, receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the // If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this // function and receiver and have the slow path jump around this
......
...@@ -2870,6 +2870,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2870,6 +2870,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// v1 (receiver). Touch up the stack with the right values. // v1 (receiver). Touch up the stack with the right values.
__ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ sd(v1, MemOperand(sp, arg_count * kPointerSize)); __ sd(v1, MemOperand(sp, arg_count * kPointerSize));
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
} }
// Record source position for debugger. // Record source position for debugger.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
...@@ -2901,6 +2903,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2901,6 +2903,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ Push(context_register(), a2); __ Push(context_register(), a2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2); __ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(v0, v1); // Function, receiver. __ Push(v0, v1); // Function, receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the // If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this // function and receiver and have the slow path jump around this
......
...@@ -2795,6 +2795,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2795,6 +2795,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// rdx (receiver). Touch up the stack with the right values. // rdx (receiver). Touch up the stack with the right values.
__ movp(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); __ movp(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
__ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax); __ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
} }
// Record source position for debugger. // Record source position for debugger.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
...@@ -2826,6 +2828,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2826,6 +2828,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ CallRuntime(Runtime::kLoadLookupSlot, 2); __ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(rax); // Function. __ Push(rax); // Function.
__ Push(rdx); // Receiver. __ Push(rdx); // Receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function // If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code. // and receiver and have the slow path jump around this code.
......
...@@ -2785,6 +2785,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2785,6 +2785,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// edx (receiver). Touch up the stack with the right values. // edx (receiver). Touch up the stack with the right values.
__ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
} }
// Record source position for debugger. // Record source position for debugger.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
...@@ -2816,6 +2818,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2816,6 +2818,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ CallRuntime(Runtime::kLoadLookupSlot, 2); __ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ push(eax); // Function. __ push(eax); // Function.
__ push(edx); // Receiver. __ push(edx); // Receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function // If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code. // and receiver and have the slow path jump around this code.
......
...@@ -145,8 +145,9 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester { ...@@ -145,8 +145,9 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
Node* stack = m.NewNode(common.StateValues(0)); Node* stack = m.NewNode(common.StateValues(0));
Node* state_node = m.NewNode( Node* state_node = m.NewNode(
common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters, common.FrameState(JS_FRAME, bailout_id,
locals, stack, caller_context_node, m.UndefinedConstant()); OutputFrameStateCombine::Ignore()),
parameters, locals, stack, caller_context_node, m.UndefinedConstant());
Handle<Context> context(deopt_function->context(), CcTest::i_isolate()); Handle<Context> context(deopt_function->context(), CcTest::i_isolate());
Unique<Object> context_constant = Unique<Object> context_constant =
...@@ -259,8 +260,9 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester { ...@@ -259,8 +260,9 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
Node* stack = m.NewNode(common.StateValues(0)); Node* stack = m.NewNode(common.StateValues(0));
Node* state_node = m.NewNode( Node* state_node = m.NewNode(
common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters, common.FrameState(JS_FRAME, bailout_id,
locals, stack, context_node, m.UndefinedConstant()); OutputFrameStateCombine::Ignore()),
parameters, locals, stack, context_node, m.UndefinedConstant());
m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node, m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node,
state_node); state_node);
......
...@@ -65,7 +65,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope { ...@@ -65,7 +65,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
Node* stack = graph.NewNode(common.StateValues(0)); Node* stack = graph.NewNode(common.StateValues(0));
Node* state_node = Node* state_node =
graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0), kIgnoreOutput), graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0),
OutputFrameStateCombine::Ignore()),
parameters, locals, stack, context, UndefinedConstant()); parameters, locals, stack, context, UndefinedConstant());
return state_node; return state_node;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
// On MacOS X 10.7.5, this test needs a stack size of at least 788 kBytes. // On MacOS X 10.7.5, this test needs a stack size of at least 788 kBytes.
// Flags: --stack-size=800 // Flags: --stack-size=800
// Flags: --turbo-deoptimization
// Test that we can make large object literals that work. // Test that we can make large object literals that work.
// Also test that we can attempt to make even larger object literals without // Also test that we can attempt to make even larger object literals without
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-debug-as debug // Flags: --expose-debug-as debug --turbo-deoptimization
// Get the Debug object exposed from the debug context global object. // Get the Debug object exposed from the debug context global object.
Debug = debug.Debug Debug = debug.Debug
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --turbo-deoptimization
for (var i = 0; i < 10000; i++) { for (var i = 0; i < 10000; i++) {
try { try {
var object = { }; var object = { };
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --turbo-deoptimization
function CheckStrictMode(code, exception) { function CheckStrictMode(code, exception) {
assertDoesNotThrow(code); assertDoesNotThrow(code);
assertThrows("'use strict';\n" + code, exception); assertThrows("'use strict';\n" + code, exception);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment