Elide unnecessary context reload in generated stubs.
Review URL: https://codereview.chromium.org/11550005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13290 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e536abb777
commit
45a012ec2c
@ -999,7 +999,14 @@ LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
|
||||
return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext);
|
||||
// If there is a non-return use, the context must be allocated in a register.
|
||||
for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
|
||||
if (!it.value()->IsReturn()) {
|
||||
return DefineAsRegister(new(zone()) LContext);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2820,9 +2820,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
|
||||
__ ldm(ia_w, sp, fp.bit() | lr.bit());
|
||||
__ add(sp, sp, Operand(sp_delta));
|
||||
}
|
||||
if (info()->IsStub()) {
|
||||
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||
}
|
||||
__ Jump(lr);
|
||||
}
|
||||
|
||||
|
@ -51,17 +51,19 @@ Handle<Code> HydrogenCodeStub::CodeFromGraph(HGraph* graph) {
|
||||
class CodeStubGraphBuilderBase : public HGraphBuilder {
|
||||
public:
|
||||
CodeStubGraphBuilderBase(Isolate* isolate, HydrogenCodeStub* stub)
|
||||
: HGraphBuilder(&info_), info_(stub, isolate) {}
|
||||
: HGraphBuilder(&info_), info_(stub, isolate), context_(NULL) {}
|
||||
virtual bool BuildGraph();
|
||||
|
||||
protected:
|
||||
virtual void BuildCodeStub() = 0;
|
||||
HParameter* GetParameter(int parameter) { return parameters_[parameter]; }
|
||||
HydrogenCodeStub* stub() { return info_.code_stub(); }
|
||||
HContext* context() { return context_; }
|
||||
|
||||
private:
|
||||
SmartArrayPointer<HParameter*> parameters_;
|
||||
CompilationInfoWithZone info_;
|
||||
HContext* context_;
|
||||
};
|
||||
|
||||
|
||||
@ -77,6 +79,9 @@ bool CodeStubGraphBuilderBase::BuildGraph() {
|
||||
graph()->entry_block()->Finish(jump);
|
||||
set_current_block(next_block);
|
||||
|
||||
context_ = new(zone()) HContext();
|
||||
AddInstruction(context_);
|
||||
|
||||
int major_key = stub()->MajorKey();
|
||||
CodeStubInterfaceDescriptor* descriptor =
|
||||
info_.isolate()->code_stub_interface_descriptor(major_key);
|
||||
@ -121,7 +126,7 @@ void CodeStubGraphBuilder<KeyedLoadFastElementStub>::BuildCodeStub() {
|
||||
casted_stub()->is_js_array(), casted_stub()->elements_kind(), false);
|
||||
AddInstruction(load);
|
||||
|
||||
HReturn* ret = new(zone) HReturn(load);
|
||||
HReturn* ret = new(zone) HReturn(load, context());
|
||||
current_block()->Finish(ret);
|
||||
}
|
||||
|
||||
|
@ -1171,10 +1171,11 @@ class HCompareMap: public HUnaryControlInstruction {
|
||||
};
|
||||
|
||||
|
||||
class HReturn: public HTemplateControlInstruction<0, 1> {
|
||||
class HReturn: public HTemplateControlInstruction<0, 2> {
|
||||
public:
|
||||
explicit HReturn(HValue* value) {
|
||||
HReturn(HValue* value, HValue* context) {
|
||||
SetOperandAt(0, value);
|
||||
SetOperandAt(1, context);
|
||||
}
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
@ -1184,6 +1185,7 @@ class HReturn: public HTemplateControlInstruction<0, 1> {
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
HValue* value() { return OperandAt(0); }
|
||||
HValue* context() { return OperandAt(1); }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(Return)
|
||||
};
|
||||
|
@ -3399,7 +3399,8 @@ bool HOptimizedGraphBuilder::BuildGraph() {
|
||||
if (HasStackOverflow()) return false;
|
||||
|
||||
if (current_block() != NULL) {
|
||||
HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined());
|
||||
HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined(),
|
||||
context);
|
||||
current_block()->FinishExit(instr);
|
||||
set_current_block(NULL);
|
||||
}
|
||||
@ -4215,7 +4216,9 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
|
||||
// Not an inlined return, so an actual one.
|
||||
CHECK_ALIVE(VisitForValue(stmt->expression()));
|
||||
HValue* result = environment()->Pop();
|
||||
current_block()->FinishExit(new(zone()) HReturn(result));
|
||||
current_block()->FinishExit(new(zone()) HReturn(
|
||||
result,
|
||||
environment()->LookupContext()));
|
||||
} else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
|
||||
// Return from an inlined construct call. In a test context the return value
|
||||
// will always evaluate to true, in a value context the return value needs
|
||||
|
@ -804,9 +804,9 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
|
||||
ASSERT(environment->HasBeenRegistered());
|
||||
int id = environment->deoptimization_index();
|
||||
ASSERT(info()->IsOptimizing() || info()->IsStub());
|
||||
Deoptimizer::BailoutType bailout_type = frame_is_built_
|
||||
? Deoptimizer::EAGER
|
||||
: Deoptimizer::LAZY;
|
||||
Deoptimizer::BailoutType bailout_type = info()->IsStub()
|
||||
? Deoptimizer::LAZY
|
||||
: Deoptimizer::EAGER;
|
||||
Address entry = Deoptimizer::GetDeoptimizationEntry(id, bailout_type);
|
||||
if (entry == NULL) {
|
||||
Abort("bailout was not prepared");
|
||||
@ -2661,7 +2661,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
|
||||
__ bind(&no_padding);
|
||||
}
|
||||
if (info()->IsStub()) {
|
||||
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
||||
__ Ret();
|
||||
} else {
|
||||
__ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
|
||||
@ -3396,7 +3395,12 @@ void LCodeGen::DoThisFunction(LThisFunction* instr) {
|
||||
|
||||
void LCodeGen::DoContext(LContext* instr) {
|
||||
Register result = ToRegister(instr->result());
|
||||
__ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
|
||||
if (info()->IsOptimizing()) {
|
||||
__ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
|
||||
} else {
|
||||
// If there is no frame, the context must be in esi.
|
||||
ASSERT(result.is(esi));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1055,7 +1055,13 @@ LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
|
||||
return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext);
|
||||
if (instr->HasNoUses()) return NULL;
|
||||
|
||||
if (info()->IsStub()) {
|
||||
return DefineFixed(new(zone()) LContext, esi);
|
||||
}
|
||||
|
||||
return DefineAsRegister(new(zone()) LContext);
|
||||
}
|
||||
|
||||
|
||||
@ -1884,7 +1890,10 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
|
||||
return new(zone()) LReturn(UseFixed(instr->value(), eax));
|
||||
LOperand* context = info()->IsStub()
|
||||
? UseFixed(instr->context(), esi)
|
||||
: NULL;
|
||||
return new(zone()) LReturn(UseFixed(instr->value(), eax), context);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1344,10 +1344,11 @@ class LArithmeticT: public LTemplateInstruction<1, 3, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LReturn: public LTemplateInstruction<0, 1, 0> {
|
||||
class LReturn: public LTemplateInstruction<0, 2, 0> {
|
||||
public:
|
||||
explicit LReturn(LOperand* value) {
|
||||
explicit LReturn(LOperand* value, LOperand* context) {
|
||||
inputs_[0] = value;
|
||||
inputs_[1] = context;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(Return, "return")
|
||||
|
@ -99,6 +99,7 @@ bool InputIterator::Done() { return current_ >= limit_; }
|
||||
|
||||
LOperand* InputIterator::Current() {
|
||||
ASSERT(!Done());
|
||||
ASSERT(instr_->InputAt(current_) != NULL);
|
||||
return instr_->InputAt(current_);
|
||||
}
|
||||
|
||||
@ -110,7 +111,9 @@ void InputIterator::Advance() {
|
||||
|
||||
|
||||
void InputIterator::SkipUninteresting() {
|
||||
while (current_ < limit_ && instr_->InputAt(current_)->IsConstantOperand()) {
|
||||
while (current_ < limit_) {
|
||||
LOperand* current = instr_->InputAt(current_);
|
||||
if (current != NULL && !current->IsConstantOperand()) break;
|
||||
++current_;
|
||||
}
|
||||
}
|
||||
@ -127,9 +130,11 @@ bool UseIterator::Done() {
|
||||
|
||||
LOperand* UseIterator::Current() {
|
||||
ASSERT(!Done());
|
||||
return input_iterator_.Done()
|
||||
LOperand* result = input_iterator_.Done()
|
||||
? env_iterator_.Current()
|
||||
: input_iterator_.Current();
|
||||
ASSERT(result != NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -581,6 +581,7 @@ class ShallowIterator BASE_EMBEDDED {
|
||||
|
||||
LOperand* Current() {
|
||||
ASSERT(!Done());
|
||||
ASSERT(env_->values()->at(current_) != NULL);
|
||||
return env_->values()->at(current_);
|
||||
}
|
||||
|
||||
@ -622,6 +623,7 @@ class DeepIterator BASE_EMBEDDED {
|
||||
|
||||
LOperand* Current() {
|
||||
ASSERT(!current_iterator_.Done());
|
||||
ASSERT(current_iterator_.Current() != NULL);
|
||||
return current_iterator_.Current();
|
||||
}
|
||||
|
||||
|
@ -2463,7 +2463,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
|
||||
__ pop(rbp);
|
||||
}
|
||||
if (info()->IsStub()) {
|
||||
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
||||
__ Ret(0, r10);
|
||||
} else {
|
||||
__ Ret((GetParameterCount() + 1) * kPointerSize, rcx);
|
||||
|
@ -1006,7 +1006,14 @@ LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
|
||||
return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext);
|
||||
// If there is a non-return use, the context must be allocated in a register.
|
||||
for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
|
||||
if (!it.value()->IsReturn()) {
|
||||
return DefineAsRegister(new(zone()) LContext);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user