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:
danno@chromium.org 2012-12-28 16:25:38 +00:00
parent e536abb777
commit 45a012ec2c
12 changed files with 64 additions and 23 deletions

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)
};

View File

@ -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

View File

@ -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));
}
}

View File

@ -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);
}

View File

@ -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")

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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;
}