Lazy deoptimization for comparisons in Turbofan.
BUG= R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/526953004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23594 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
9bd36b8d13
commit
bb6cfbc416
@ -42,10 +42,9 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
|
||||
CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
|
||||
int parameter_count,
|
||||
Operator::Property properties,
|
||||
CallDescriptor::Flags flags,
|
||||
Zone* zone) {
|
||||
return LinkageHelper::GetRuntimeCallDescriptor<LinkageHelperTraits>(
|
||||
zone, function, parameter_count, properties, flags);
|
||||
zone, function, parameter_count, properties);
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,10 +42,9 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
|
||||
CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
|
||||
int parameter_count,
|
||||
Operator::Property properties,
|
||||
CallDescriptor::Flags flags,
|
||||
Zone* zone) {
|
||||
return LinkageHelper::GetRuntimeCallDescriptor<LinkageHelperTraits>(
|
||||
zone, function, parameter_count, properties, flags);
|
||||
zone, function, parameter_count, properties);
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,10 +38,9 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
|
||||
CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
|
||||
int parameter_count,
|
||||
Operator::Property properties,
|
||||
CallDescriptor::Flags flags,
|
||||
Zone* zone) {
|
||||
return LinkageHelper::GetRuntimeCallDescriptor<LinkageHelperTraits>(
|
||||
zone, function, parameter_count, properties, flags);
|
||||
zone, function, parameter_count, properties);
|
||||
}
|
||||
|
||||
|
||||
|
@ -299,28 +299,48 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token,
|
||||
bool pure) {
|
||||
BinaryOpICStub stub(isolate(), Token::ADD); // TODO(mstarzinger): Hack.
|
||||
CodeStubInterfaceDescriptor* d = stub.GetInterfaceDescriptor();
|
||||
bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op());
|
||||
CallDescriptor* desc_compare = linkage()->GetStubCallDescriptor(
|
||||
d, 0, CallDescriptor::kPatchableCallSiteWithNop);
|
||||
d, 0, CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node));
|
||||
Handle<Code> ic = CompareIC::GetUninitialized(isolate(), token);
|
||||
Node* compare;
|
||||
NodeVector inputs(zone());
|
||||
inputs.reserve(node->InputCount() + 1);
|
||||
inputs.push_back(CodeConstant(ic));
|
||||
inputs.push_back(NodeProperties::GetValueInput(node, 0));
|
||||
inputs.push_back(NodeProperties::GetValueInput(node, 1));
|
||||
inputs.push_back(NodeProperties::GetContextInput(node));
|
||||
if (pure) {
|
||||
// A pure (strict) comparison doesn't have an effect or control.
|
||||
// But for the graph, we need to add these inputs.
|
||||
compare = graph()->NewNode(common()->Call(desc_compare), CodeConstant(ic),
|
||||
NodeProperties::GetValueInput(node, 0),
|
||||
NodeProperties::GetValueInput(node, 1),
|
||||
NodeProperties::GetContextInput(node),
|
||||
graph()->start(), graph()->start());
|
||||
// A pure (strict) comparison doesn't have an effect, control or frame
|
||||
// state. But for the graph, we need to add control and effect inputs.
|
||||
DCHECK(!has_frame_state);
|
||||
inputs.push_back(graph()->start());
|
||||
inputs.push_back(graph()->start());
|
||||
} else {
|
||||
compare = graph()->NewNode(common()->Call(desc_compare), CodeConstant(ic),
|
||||
NodeProperties::GetValueInput(node, 0),
|
||||
NodeProperties::GetValueInput(node, 1),
|
||||
NodeProperties::GetContextInput(node),
|
||||
NodeProperties::GetEffectInput(node),
|
||||
NodeProperties::GetControlInput(node));
|
||||
DCHECK(has_frame_state == FLAG_turbo_deoptimization);
|
||||
if (FLAG_turbo_deoptimization) {
|
||||
inputs.push_back(NodeProperties::GetFrameStateInput(node));
|
||||
}
|
||||
inputs.push_back(NodeProperties::GetEffectInput(node));
|
||||
inputs.push_back(NodeProperties::GetControlInput(node));
|
||||
}
|
||||
Node* compare = graph()->NewNode(common()->Call(desc_compare), inputs.size(),
|
||||
&inputs.front());
|
||||
|
||||
node->ReplaceInput(0, compare);
|
||||
node->ReplaceInput(1, SmiConstant(token));
|
||||
|
||||
if (has_frame_state) {
|
||||
// Remove the frame state from inputs.
|
||||
// TODO(jarin) This should use Node::RemoveInput (which does not exist yet).
|
||||
int dest = NodeProperties::FirstFrameStateIndex(node);
|
||||
for (int i = NodeProperties::PastFrameStateIndex(node);
|
||||
i < node->InputCount(); i++) {
|
||||
node->ReplaceInput(dest, node->InputAt(i));
|
||||
dest++;
|
||||
}
|
||||
node->TrimInputCount(dest);
|
||||
}
|
||||
|
||||
ReplaceWithRuntimeCall(node, Runtime::kBooleanize);
|
||||
}
|
||||
|
||||
@ -360,8 +380,7 @@ void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
|
||||
Operator::Property props = node->op()->properties();
|
||||
const Runtime::Function* fun = Runtime::FunctionForId(f);
|
||||
int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
|
||||
CallDescriptor* desc =
|
||||
linkage()->GetRuntimeCallDescriptor(f, nargs, props, FlagsForNode(node));
|
||||
CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(f, nargs, props);
|
||||
Node* ref = ExternalConstant(ExternalReference(f, isolate()));
|
||||
Node* arity = Int32Constant(nargs);
|
||||
if (!centrystub_constant_.is_set()) {
|
||||
|
@ -71,7 +71,7 @@ class LinkageHelper {
|
||||
template <typename LinkageTraits>
|
||||
static CallDescriptor* GetRuntimeCallDescriptor(
|
||||
Zone* zone, Runtime::FunctionId function_id, int parameter_count,
|
||||
Operator::Property properties, CallDescriptor::Flags flags) {
|
||||
Operator::Property properties) {
|
||||
const int code_count = 1;
|
||||
const int function_count = 1;
|
||||
const int num_args_count = 1;
|
||||
@ -109,6 +109,10 @@ class LinkageHelper {
|
||||
WordRegisterLocation(LinkageTraits::RuntimeCallArgCountReg());
|
||||
locations[index++] = TaggedRegisterLocation(LinkageTraits::ContextReg());
|
||||
|
||||
CallDescriptor::Flags flags = Linkage::NeedsFrameState(function_id)
|
||||
? CallDescriptor::kNeedsFrameState
|
||||
: CallDescriptor::kNoFlags;
|
||||
|
||||
// TODO(titzer): refactor TurboFan graph to consider context a value input.
|
||||
return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject, // kind
|
||||
return_count, // return_count
|
||||
@ -196,6 +200,25 @@ class LinkageHelper {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool Linkage::NeedsFrameState(Runtime::FunctionId function) {
|
||||
if (!FLAG_turbo_deoptimization) {
|
||||
return false;
|
||||
}
|
||||
// TODO(jarin) At the moment, we only add frame state for
|
||||
// few chosen runtime functions.
|
||||
switch (function) {
|
||||
case Runtime::kDebugBreak:
|
||||
case Runtime::kDeoptimizeFunction:
|
||||
case Runtime::kSetScriptBreakPoint:
|
||||
case Runtime::kDebugGetLoadedScripts:
|
||||
case Runtime::kStackGuard:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -93,11 +93,10 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count) {
|
||||
}
|
||||
|
||||
|
||||
CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
|
||||
int parameter_count,
|
||||
Operator::Property properties,
|
||||
CallDescriptor::Flags flags) {
|
||||
return GetRuntimeCallDescriptor(function, parameter_count, properties, flags,
|
||||
CallDescriptor* Linkage::GetRuntimeCallDescriptor(
|
||||
Runtime::FunctionId function, int parameter_count,
|
||||
Operator::Property properties) {
|
||||
return GetRuntimeCallDescriptor(function, parameter_count, properties,
|
||||
this->info_->zone());
|
||||
}
|
||||
|
||||
@ -123,7 +122,6 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
|
||||
CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
|
||||
int parameter_count,
|
||||
Operator::Property properties,
|
||||
CallDescriptor::Flags flags,
|
||||
Zone* zone) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
|
@ -147,14 +147,12 @@ class Linkage : public ZoneObject {
|
||||
CallDescriptor* GetIncomingDescriptor() { return incoming_; }
|
||||
CallDescriptor* GetJSCallDescriptor(int parameter_count);
|
||||
static CallDescriptor* GetJSCallDescriptor(int parameter_count, Zone* zone);
|
||||
CallDescriptor* GetRuntimeCallDescriptor(
|
||||
Runtime::FunctionId function, int parameter_count,
|
||||
Operator::Property properties,
|
||||
CallDescriptor::Flags flags = CallDescriptor::kNoFlags);
|
||||
CallDescriptor* GetRuntimeCallDescriptor(Runtime::FunctionId function,
|
||||
int parameter_count,
|
||||
Operator::Property properties);
|
||||
static CallDescriptor* GetRuntimeCallDescriptor(Runtime::FunctionId function,
|
||||
int parameter_count,
|
||||
Operator::Property properties,
|
||||
CallDescriptor::Flags flags,
|
||||
Zone* zone);
|
||||
|
||||
CallDescriptor* GetStubCallDescriptor(
|
||||
@ -191,6 +189,8 @@ class Linkage : public ZoneObject {
|
||||
|
||||
CompilationInfo* info() const { return info_; }
|
||||
|
||||
static bool NeedsFrameState(Runtime::FunctionId function);
|
||||
|
||||
private:
|
||||
CompilationInfo* info_;
|
||||
CallDescriptor* incoming_;
|
||||
|
@ -37,27 +37,29 @@ inline bool OperatorProperties::HasFrameStateInput(Operator* op) {
|
||||
}
|
||||
|
||||
switch (op->opcode()) {
|
||||
case IrOpcode::kJSCallFunction:
|
||||
case IrOpcode::kJSCallConstruct:
|
||||
return true;
|
||||
case IrOpcode::kJSCallRuntime: {
|
||||
Runtime::FunctionId function =
|
||||
reinterpret_cast<Operator1<Runtime::FunctionId>*>(op)->parameter();
|
||||
// TODO(jarin) At the moment, we only add frame state for
|
||||
// few chosen runtime functions.
|
||||
switch (function) {
|
||||
case Runtime::kDebugBreak:
|
||||
case Runtime::kDeoptimizeFunction:
|
||||
case Runtime::kSetScriptBreakPoint:
|
||||
case Runtime::kDebugGetLoadedScripts:
|
||||
case Runtime::kStackGuard:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return Linkage::NeedsFrameState(function);
|
||||
}
|
||||
|
||||
// Strict equality cannot lazily deoptimize.
|
||||
case IrOpcode::kJSStrictEqual:
|
||||
case IrOpcode::kJSStrictNotEqual:
|
||||
return false;
|
||||
|
||||
// Calls
|
||||
case IrOpcode::kJSCallFunction:
|
||||
case IrOpcode::kJSCallConstruct:
|
||||
|
||||
// Compare operations
|
||||
case IrOpcode::kJSEqual:
|
||||
case IrOpcode::kJSNotEqual:
|
||||
case IrOpcode::kJSLessThan:
|
||||
case IrOpcode::kJSGreaterThan:
|
||||
case IrOpcode::kJSLessThanOrEqual:
|
||||
case IrOpcode::kJSGreaterThanOrEqual:
|
||||
|
||||
// Binary operations
|
||||
case IrOpcode::kJSBitwiseOr:
|
||||
case IrOpcode::kJSBitwiseXor:
|
||||
|
@ -107,8 +107,7 @@ Node* RawMachineAssembler::CallJS0(Node* function, Node* receiver,
|
||||
Node* RawMachineAssembler::CallRuntime1(Runtime::FunctionId function,
|
||||
Node* arg0, Node* frame_state) {
|
||||
CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor(
|
||||
function, 1, Operator::kNoProperties, CallDescriptor::kNeedsFrameState,
|
||||
zone());
|
||||
function, 1, Operator::kNoProperties, zone());
|
||||
|
||||
Node* centry = HeapConstant(CEntryStub(isolate(), 1).GetCode());
|
||||
Node* ref = NewNode(
|
||||
|
@ -73,6 +73,14 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
||||
effect_count + control_count;
|
||||
CHECK_EQ(input_count, node->InputCount());
|
||||
|
||||
// Verify that frame state has been inserted for the nodes that need it.
|
||||
if (OperatorProperties::HasFrameStateInput(node->op())) {
|
||||
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
||||
CHECK(frame_state->opcode() == IrOpcode::kFrameState);
|
||||
CHECK(IsDefUseChainLinkPresent(frame_state, node));
|
||||
CHECK(IsUseDefChainLinkPresent(frame_state, node));
|
||||
}
|
||||
|
||||
// Verify all value inputs actually produce a value.
|
||||
for (int i = 0; i < value_count; ++i) {
|
||||
Node* value = NodeProperties::GetValueInput(node, i);
|
||||
|
@ -57,10 +57,9 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
|
||||
CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
|
||||
int parameter_count,
|
||||
Operator::Property properties,
|
||||
CallDescriptor::Flags flags,
|
||||
Zone* zone) {
|
||||
return LinkageHelper::GetRuntimeCallDescriptor<LinkageHelperTraits>(
|
||||
zone, function, parameter_count, properties, flags);
|
||||
zone, function, parameter_count, properties);
|
||||
}
|
||||
|
||||
|
||||
|
@ -101,9 +101,6 @@
|
||||
'test-debug/ThreadedDebugging': [PASS, NO_VARIANTS],
|
||||
'test-debug/DebugBreakLoop': [PASS, NO_VARIANTS],
|
||||
|
||||
# Support for lazy deoptimization is missing.
|
||||
'test-deoptimization/DeoptimizeCompare': [PASS, NO_VARIANTS],
|
||||
|
||||
# Support for breakpoints requires using LoadICs and StoreICs.
|
||||
'test-debug/BreakPointICStore': [PASS, NO_VARIANTS],
|
||||
'test-debug/BreakPointICLoad': [PASS, NO_VARIANTS],
|
||||
|
Loading…
Reference in New Issue
Block a user