Clean up the Result class. Reduce the size of Result from four words
to one by keeping a stack of active code generators and by using indirection to handles. Mainly a cleanup. No visible performance impact. Review URL: http://codereview.chromium.org/113455 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1965 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
ed72ecb02e
commit
a3f30f5a3a
@ -40,6 +40,10 @@
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
|
||||
|
||||
CodeGenerator* CodeGeneratorScope::top_ = NULL;
|
||||
|
||||
|
||||
DeferredCode::DeferredCode(CodeGenerator* generator)
|
||||
: generator_(generator),
|
||||
masm_(generator->masm()),
|
||||
@ -154,6 +158,7 @@ Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* flit,
|
||||
// Generate code.
|
||||
const int initial_buffer_size = 4 * KB;
|
||||
CodeGenerator cgen(initial_buffer_size, script, is_eval);
|
||||
CodeGeneratorScope scope(&cgen);
|
||||
cgen.GenCode(flit);
|
||||
if (cgen.HasStackOverflow()) {
|
||||
ASSERT(!Top::has_pending_exception());
|
||||
|
@ -86,9 +86,35 @@ enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
|
||||
#include "arm/codegen-arm.h"
|
||||
#endif
|
||||
|
||||
#include "register-allocator.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
|
||||
|
||||
// Code generation can be nested. Code generation scopes form a stack
|
||||
// of active code generators.
|
||||
class CodeGeneratorScope BASE_EMBEDDED {
|
||||
public:
|
||||
explicit CodeGeneratorScope(CodeGenerator* cgen) {
|
||||
previous_ = top_;
|
||||
top_ = cgen;
|
||||
}
|
||||
|
||||
~CodeGeneratorScope() {
|
||||
top_ = previous_;
|
||||
}
|
||||
|
||||
static CodeGenerator* Current() {
|
||||
ASSERT(top_ != NULL);
|
||||
return top_;
|
||||
}
|
||||
|
||||
private:
|
||||
static CodeGenerator* top_;
|
||||
CodeGenerator* previous_;
|
||||
};
|
||||
|
||||
|
||||
// Use lazy compilation; defaults to true.
|
||||
// NOTE: Do not remove non-lazy compilation until we can properly
|
||||
// install extensions with lazy compilation enabled. At the
|
||||
|
@ -79,7 +79,10 @@ class CompilationZoneScope : public ZoneScope {
|
||||
public:
|
||||
explicit CompilationZoneScope(ZoneScopeMode mode) : ZoneScope(mode) { }
|
||||
virtual ~CompilationZoneScope() {
|
||||
if (ShouldDeleteOnExit()) FrameElement::ClearConstantList();
|
||||
if (ShouldDeleteOnExit()) {
|
||||
FrameElement::ClearConstantList();
|
||||
Result::ClearConstantList();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -281,7 +281,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
|
||||
ASSERT(!function_return_is_shadowed_);
|
||||
CodeForReturnPosition(fun);
|
||||
frame_->PrepareForReturn();
|
||||
Result undefined(Factory::undefined_value(), this);
|
||||
Result undefined(Factory::undefined_value());
|
||||
if (function_return_.is_bound()) {
|
||||
function_return_.Jump(&undefined);
|
||||
} else {
|
||||
@ -296,7 +296,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
|
||||
// control does not flow off the end of the body so we did not
|
||||
// compile an artificial return statement just above, and (b) there
|
||||
// are return statements in the body but (c) they are all shadowed.
|
||||
Result return_value(this);
|
||||
Result return_value;
|
||||
// Though this is a (possibly) backward block, the frames can
|
||||
// only differ on their top element.
|
||||
function_return_.Bind(&return_value, 1);
|
||||
@ -388,7 +388,7 @@ Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot,
|
||||
JumpTarget* slow) {
|
||||
ASSERT(slot->type() == Slot::CONTEXT);
|
||||
ASSERT(tmp.is_register());
|
||||
Result context(esi, this);
|
||||
Result context(esi);
|
||||
|
||||
for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
|
||||
if (s->num_heap_slots() > 0) {
|
||||
@ -803,8 +803,8 @@ class DeferredInlineBinaryOperation: public DeferredCode {
|
||||
|
||||
|
||||
void DeferredInlineBinaryOperation::Generate() {
|
||||
Result left(generator());
|
||||
Result right(generator());
|
||||
Result left;
|
||||
Result right;
|
||||
enter()->Bind(&left, &right);
|
||||
generator()->frame()->Push(&left);
|
||||
generator()->frame()->Push(&right);
|
||||
@ -859,7 +859,7 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
|
||||
if (left_is_string || right_is_string) {
|
||||
frame_->Push(&left);
|
||||
frame_->Push(&right);
|
||||
Result answer(this);
|
||||
Result answer;
|
||||
if (left_is_string) {
|
||||
if (right_is_string) {
|
||||
// TODO(lrn): if (left.is_constant() && right.is_constant())
|
||||
@ -1045,7 +1045,7 @@ class DeferredInlineSmiOperation: public DeferredCode {
|
||||
|
||||
|
||||
void DeferredInlineSmiOperation::Generate() {
|
||||
Result left(generator());
|
||||
Result left;
|
||||
enter()->Bind(&left);
|
||||
generator()->frame()->Push(&left);
|
||||
generator()->frame()->Push(value_);
|
||||
@ -1078,7 +1078,7 @@ class DeferredInlineSmiOperationReversed: public DeferredCode {
|
||||
|
||||
|
||||
void DeferredInlineSmiOperationReversed::Generate() {
|
||||
Result right(generator());
|
||||
Result right;
|
||||
enter()->Bind(&right);
|
||||
generator()->frame()->Push(value_);
|
||||
generator()->frame()->Push(&right);
|
||||
@ -1109,7 +1109,7 @@ class DeferredInlineSmiAdd: public DeferredCode {
|
||||
|
||||
void DeferredInlineSmiAdd::Generate() {
|
||||
// Undo the optimistic add operation and call the shared stub.
|
||||
Result left(generator()); // Initially left + value_.
|
||||
Result left; // Initially left + value_.
|
||||
enter()->Bind(&left);
|
||||
left.ToRegister();
|
||||
generator()->frame()->Spill(left.reg());
|
||||
@ -1143,7 +1143,7 @@ class DeferredInlineSmiAddReversed: public DeferredCode {
|
||||
|
||||
void DeferredInlineSmiAddReversed::Generate() {
|
||||
// Undo the optimistic add operation and call the shared stub.
|
||||
Result right(generator()); // Initially value_ + right.
|
||||
Result right; // Initially value_ + right.
|
||||
enter()->Bind(&right);
|
||||
right.ToRegister();
|
||||
generator()->frame()->Spill(right.reg());
|
||||
@ -1177,7 +1177,7 @@ class DeferredInlineSmiSub: public DeferredCode {
|
||||
|
||||
void DeferredInlineSmiSub::Generate() {
|
||||
// Undo the optimistic sub operation and call the shared stub.
|
||||
Result left(generator()); // Initially left - value_.
|
||||
Result left; // Initially left - value_.
|
||||
enter()->Bind(&left);
|
||||
left.ToRegister();
|
||||
generator()->frame()->Spill(left.reg());
|
||||
@ -1211,7 +1211,7 @@ class DeferredInlineSmiSubReversed: public DeferredCode {
|
||||
|
||||
void DeferredInlineSmiSubReversed::Generate() {
|
||||
// Call the shared stub.
|
||||
Result right(generator());
|
||||
Result right;
|
||||
enter()->Bind(&right);
|
||||
generator()->frame()->Push(value_);
|
||||
generator()->frame()->Push(&right);
|
||||
@ -1235,7 +1235,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
|
||||
// TODO(199): Optimize some special cases of operations involving a
|
||||
// smi literal (multiply by 2, shift by 0, etc.).
|
||||
if (IsUnsafeSmi(value)) {
|
||||
Result unsafe_operand(value, this);
|
||||
Result unsafe_operand(value);
|
||||
if (reversed) {
|
||||
LikelySmiBinaryOperation(op, &unsafe_operand, operand,
|
||||
overwrite_mode);
|
||||
@ -1275,7 +1275,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
|
||||
|
||||
case Token::SUB: {
|
||||
DeferredCode* deferred = NULL;
|
||||
Result answer(this); // Only allocate a new register if reversed.
|
||||
Result answer; // Only allocate a new register if reversed.
|
||||
if (reversed) {
|
||||
answer = allocator()->Allocate();
|
||||
ASSERT(answer.is_valid());
|
||||
@ -1304,7 +1304,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
|
||||
|
||||
case Token::SAR: {
|
||||
if (reversed) {
|
||||
Result constant_operand(value, this);
|
||||
Result constant_operand(value);
|
||||
LikelySmiBinaryOperation(op, &constant_operand, operand,
|
||||
overwrite_mode);
|
||||
} else {
|
||||
@ -1330,7 +1330,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
|
||||
|
||||
case Token::SHR: {
|
||||
if (reversed) {
|
||||
Result constant_operand(value, this);
|
||||
Result constant_operand(value);
|
||||
LikelySmiBinaryOperation(op, &constant_operand, operand,
|
||||
overwrite_mode);
|
||||
} else {
|
||||
@ -1365,7 +1365,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
|
||||
|
||||
case Token::SHL: {
|
||||
if (reversed) {
|
||||
Result constant_operand(value, this);
|
||||
Result constant_operand(value);
|
||||
LikelySmiBinaryOperation(op, &constant_operand, operand,
|
||||
overwrite_mode);
|
||||
} else {
|
||||
@ -1435,7 +1435,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
|
||||
}
|
||||
|
||||
default: {
|
||||
Result constant_operand(value, this);
|
||||
Result constant_operand(value);
|
||||
if (reversed) {
|
||||
LikelySmiBinaryOperation(op, &constant_operand, operand,
|
||||
overwrite_mode);
|
||||
@ -1484,8 +1484,8 @@ void CodeGenerator::Comparison(Condition cc,
|
||||
// Strict only makes sense for equality comparisons.
|
||||
ASSERT(!strict || cc == equal);
|
||||
|
||||
Result left_side(this);
|
||||
Result right_side(this);
|
||||
Result left_side;
|
||||
Result right_side;
|
||||
// Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
|
||||
if (cc == greater || cc == less_equal) {
|
||||
cc = ReverseCondition(cc);
|
||||
@ -1769,7 +1769,7 @@ void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
|
||||
frame_->Push(pairs);
|
||||
|
||||
// Duplicate the context register.
|
||||
Result context(esi, this);
|
||||
Result context(esi);
|
||||
frame_->Push(&context);
|
||||
|
||||
frame_->Push(Smi::FromInt(is_eval() ? 1 : 0));
|
||||
@ -1793,7 +1793,7 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
|
||||
// during variable resolution and must have mode DYNAMIC.
|
||||
ASSERT(var->is_dynamic());
|
||||
// For now, just do a runtime call. Duplicate the context register.
|
||||
Result context(esi, this);
|
||||
Result context(esi);
|
||||
frame_->Push(&context);
|
||||
frame_->Push(var->name());
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
@ -2032,7 +2032,7 @@ void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
|
||||
Comment cmnt(masm_, "[ WithEnterStatement");
|
||||
CodeForStatementPosition(node);
|
||||
Load(node->expression());
|
||||
Result context(this);
|
||||
Result context;
|
||||
if (node->is_catch_block()) {
|
||||
context = frame_->CallRuntime(Runtime::kPushCatchContext, 1);
|
||||
} else {
|
||||
@ -2941,7 +2941,7 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
|
||||
|
||||
// Generate unlink code for the (formerly) shadowing targets that
|
||||
// have been jumped to. Deallocate each shadow target.
|
||||
Result return_value(this);
|
||||
Result return_value;
|
||||
for (int i = 0; i < shadows.length(); i++) {
|
||||
if (shadows[i]->is_linked()) {
|
||||
// Unlink from try chain; be careful not to destroy the TOS if
|
||||
@ -3073,7 +3073,7 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
|
||||
// on the virtual frame. We must preserve it until it is
|
||||
// pushed.
|
||||
if (i == kReturnShadowIndex) {
|
||||
Result return_value(this);
|
||||
Result return_value;
|
||||
shadows[i]->Bind(&return_value);
|
||||
return_value.ToRegister(eax);
|
||||
} else {
|
||||
@ -3256,7 +3256,7 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
|
||||
|
||||
JumpTarget slow(this);
|
||||
JumpTarget done(this);
|
||||
Result value(this);
|
||||
Result value;
|
||||
|
||||
// Generate fast-case code for variables that might be shadowed by
|
||||
// eval-introduced variables. Eval is used a lot without
|
||||
@ -3356,7 +3356,7 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
|
||||
JumpTarget* slow) {
|
||||
// Check that no extension objects have been created by calls to
|
||||
// eval from the current scope to the global scope.
|
||||
Result context(esi, this);
|
||||
Result context(esi);
|
||||
Result tmp = allocator_->Allocate();
|
||||
ASSERT(tmp.is_valid()); // All non-reserved registers were available.
|
||||
|
||||
@ -3431,7 +3431,7 @@ void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
|
||||
frame_->Push(esi);
|
||||
frame_->Push(slot->var()->name());
|
||||
|
||||
Result value(this);
|
||||
Result value;
|
||||
if (init_state == CONST_INIT) {
|
||||
// Same as the case for a normal store, but ignores attribute
|
||||
// (e.g. READ_ONLY) of context slot so that we can initialize const
|
||||
@ -3574,7 +3574,7 @@ class DeferredRegExpLiteral: public DeferredCode {
|
||||
|
||||
|
||||
void DeferredRegExpLiteral::Generate() {
|
||||
Result literals(generator());
|
||||
Result literals;
|
||||
enter()->Bind(&literals);
|
||||
// Since the entry is undefined we call the runtime system to
|
||||
// compute the literal.
|
||||
@ -3651,7 +3651,7 @@ class DeferredObjectLiteral: public DeferredCode {
|
||||
|
||||
|
||||
void DeferredObjectLiteral::Generate() {
|
||||
Result literals(generator());
|
||||
Result literals;
|
||||
enter()->Bind(&literals);
|
||||
// Since the entry is undefined we call the runtime system to
|
||||
// compute the literal.
|
||||
@ -3789,7 +3789,7 @@ class DeferredArrayLiteral: public DeferredCode {
|
||||
|
||||
|
||||
void DeferredArrayLiteral::Generate() {
|
||||
Result literals(generator());
|
||||
Result literals;
|
||||
enter()->Bind(&literals);
|
||||
// Since the entry is undefined we call the runtime system to
|
||||
// compute the literal.
|
||||
@ -4438,7 +4438,7 @@ void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 0);
|
||||
// ArgumentsAccessStub takes the parameter count as an input argument
|
||||
// in register eax. Create a constant result for it.
|
||||
Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())), this);
|
||||
Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())));
|
||||
// Call the shared stub to get to the arguments.length.
|
||||
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
|
||||
Result result = frame_->CallStub(&stub, &count);
|
||||
@ -4521,7 +4521,7 @@ void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
|
||||
Load(args->at(0));
|
||||
Result key = frame_->Pop();
|
||||
// Explicitly create a constant result.
|
||||
Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())), this);
|
||||
Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())));
|
||||
// Call the shared stub to get to arguments[key].
|
||||
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
|
||||
Result result = frame_->CallStub(&stub, &key, &count);
|
||||
@ -4771,7 +4771,7 @@ class DeferredCountOperation: public DeferredCode {
|
||||
|
||||
void DeferredCountOperation::Generate() {
|
||||
CodeGenerator* cgen = generator();
|
||||
Result value(cgen);
|
||||
Result value;
|
||||
enter()->Bind(&value);
|
||||
VirtualFrame* frame = cgen->frame();
|
||||
// Undo the optimistic smi operation.
|
||||
@ -5269,7 +5269,7 @@ class DeferredReferenceGetNamedValue: public DeferredCode {
|
||||
|
||||
void DeferredReferenceGetNamedValue::Generate() {
|
||||
CodeGenerator* cgen = generator();
|
||||
Result receiver(cgen);
|
||||
Result receiver;
|
||||
enter()->Bind(&receiver);
|
||||
|
||||
cgen->frame()->Push(&receiver);
|
||||
@ -5311,8 +5311,8 @@ class DeferredReferenceGetKeyedValue: public DeferredCode {
|
||||
|
||||
void DeferredReferenceGetKeyedValue::Generate() {
|
||||
CodeGenerator* cgen = generator();
|
||||
Result receiver(cgen);
|
||||
Result key(cgen);
|
||||
Result receiver;
|
||||
Result key;
|
||||
enter()->Bind(&receiver, &key);
|
||||
cgen->frame()->Push(&receiver); // First IC argument.
|
||||
cgen->frame()->Push(&key); // Second IC argument.
|
||||
|
@ -38,12 +38,13 @@ namespace v8 { namespace internal {
|
||||
void Result::ToRegister() {
|
||||
ASSERT(is_valid());
|
||||
if (is_constant()) {
|
||||
Result fresh = cgen_->allocator()->Allocate();
|
||||
Result fresh = CodeGeneratorScope::Current()->allocator()->Allocate();
|
||||
ASSERT(fresh.is_valid());
|
||||
if (cgen_->IsUnsafeSmi(handle())) {
|
||||
cgen_->LoadUnsafeSmi(fresh.reg(), handle());
|
||||
if (CodeGeneratorScope::Current()->IsUnsafeSmi(handle())) {
|
||||
CodeGeneratorScope::Current()->LoadUnsafeSmi(fresh.reg(), handle());
|
||||
} else {
|
||||
cgen_->masm()->Set(fresh.reg(), Immediate(handle()));
|
||||
CodeGeneratorScope::Current()->masm()->Set(fresh.reg(),
|
||||
Immediate(handle()));
|
||||
}
|
||||
// This result becomes a copy of the fresh one.
|
||||
*this = fresh;
|
||||
@ -55,23 +56,24 @@ void Result::ToRegister() {
|
||||
void Result::ToRegister(Register target) {
|
||||
ASSERT(is_valid());
|
||||
if (!is_register() || !reg().is(target)) {
|
||||
Result fresh = cgen_->allocator()->Allocate(target);
|
||||
Result fresh = CodeGeneratorScope::Current()->allocator()->Allocate(target);
|
||||
ASSERT(fresh.is_valid());
|
||||
if (is_register()) {
|
||||
cgen_->masm()->mov(fresh.reg(), reg());
|
||||
CodeGeneratorScope::Current()->masm()->mov(fresh.reg(), reg());
|
||||
} else {
|
||||
ASSERT(is_constant());
|
||||
if (cgen_->IsUnsafeSmi(handle())) {
|
||||
cgen_->LoadUnsafeSmi(fresh.reg(), handle());
|
||||
if (CodeGeneratorScope::Current()->IsUnsafeSmi(handle())) {
|
||||
CodeGeneratorScope::Current()->LoadUnsafeSmi(fresh.reg(), handle());
|
||||
} else {
|
||||
cgen_->masm()->Set(fresh.reg(), Immediate(handle()));
|
||||
CodeGeneratorScope::Current()->masm()->Set(fresh.reg(),
|
||||
Immediate(handle()));
|
||||
}
|
||||
}
|
||||
*this = fresh;
|
||||
} else if (is_register() && reg().is(target)) {
|
||||
ASSERT(cgen_->has_valid_frame());
|
||||
cgen_->frame()->Spill(target);
|
||||
ASSERT(cgen_->allocator()->count(target) == 1);
|
||||
ASSERT(CodeGeneratorScope::Current()->has_valid_frame());
|
||||
CodeGeneratorScope::Current()->frame()->Spill(target);
|
||||
ASSERT(CodeGeneratorScope::Current()->allocator()->count(target) == 1);
|
||||
}
|
||||
ASSERT(is_register());
|
||||
ASSERT(reg().is(target));
|
||||
@ -127,7 +129,7 @@ Result RegisterAllocator::AllocateByteRegisterWithoutSpilling() {
|
||||
// register if valid and return an invalid result.
|
||||
if (result.is_valid() && !result.reg().is_byte_register()) {
|
||||
result.Unuse();
|
||||
return Result(cgen_);
|
||||
return Result();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1075,12 +1075,12 @@ Result VirtualFrame::Pop() {
|
||||
new_element.set_static_type(element.static_type());
|
||||
elements_[index] = new_element;
|
||||
__ mov(temp.reg(), Operand(ebp, fp_relative(index)));
|
||||
return Result(temp.reg(), cgen_, element.static_type());
|
||||
return Result(temp.reg(), element.static_type());
|
||||
} else if (element.is_register()) {
|
||||
return Result(element.reg(), cgen_, element.static_type());
|
||||
return Result(element.reg(), element.static_type());
|
||||
} else {
|
||||
ASSERT(element.is_constant());
|
||||
return Result(element.handle(), cgen_);
|
||||
return Result(element.handle());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ class VirtualFrame : public ZoneObject {
|
||||
|
||||
// Set a frame element to a constant. The index is frame-top relative.
|
||||
void SetElementAt(int index, Handle<Object> value) {
|
||||
Result temp(value, cgen_);
|
||||
Result temp(value);
|
||||
SetElementAt(index, &temp);
|
||||
}
|
||||
|
||||
|
@ -35,13 +35,25 @@
|
||||
namespace v8 { namespace internal {
|
||||
|
||||
Result::~Result() {
|
||||
if (is_register()) cgen_->allocator()->Unuse(reg());
|
||||
if (is_register()) {
|
||||
CodeGeneratorScope::Current()->allocator()->Unuse(reg());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Result::Unuse() {
|
||||
if (is_register()) cgen_->allocator()->Unuse(reg());
|
||||
type_ = INVALID;
|
||||
if (is_register()) {
|
||||
CodeGeneratorScope::Current()->allocator()->Unuse(reg());
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
|
||||
void Result::CopyTo(Result* destination) const {
|
||||
destination->value_ = value_;
|
||||
if (is_register()) {
|
||||
CodeGeneratorScope::Current()->allocator()->Use(reg());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,39 +35,22 @@ namespace v8 { namespace internal {
|
||||
// -------------------------------------------------------------------------
|
||||
// Result implementation.
|
||||
|
||||
Result::Result(Register reg, CodeGenerator* cgen)
|
||||
: static_type_(),
|
||||
type_(REGISTER),
|
||||
cgen_(cgen) {
|
||||
data_.reg_ = reg;
|
||||
|
||||
Result::Result(Register reg) {
|
||||
ASSERT(reg.is_valid());
|
||||
cgen_->allocator()->Use(reg);
|
||||
CodeGeneratorScope::Current()->allocator()->Use(reg);
|
||||
value_ = StaticTypeField::encode(StaticType::UNKNOWN_TYPE)
|
||||
| TypeField::encode(REGISTER)
|
||||
| DataField::encode(reg.code_);
|
||||
}
|
||||
|
||||
|
||||
Result::Result(Register reg, CodeGenerator* cgen, StaticType static_type)
|
||||
: static_type_(static_type),
|
||||
type_(REGISTER),
|
||||
cgen_(cgen) {
|
||||
data_.reg_ = reg;
|
||||
Result::Result(Register reg, StaticType type) {
|
||||
ASSERT(reg.is_valid());
|
||||
cgen_->allocator()->Use(reg);
|
||||
}
|
||||
|
||||
|
||||
void Result::CopyTo(Result* destination) const {
|
||||
destination->static_type_ = static_type_;
|
||||
destination->type_ = type();
|
||||
destination->cgen_ = cgen_;
|
||||
|
||||
if (is_register()) {
|
||||
destination->data_.reg_ = reg();
|
||||
cgen_->allocator()->Use(reg());
|
||||
} else if (is_constant()) {
|
||||
destination->data_.handle_ = data_.handle_;
|
||||
} else {
|
||||
ASSERT(!is_valid());
|
||||
}
|
||||
CodeGeneratorScope::Current()->allocator()->Use(reg);
|
||||
value_ = StaticTypeField::encode(type.static_type_)
|
||||
| TypeField::encode(REGISTER)
|
||||
| DataField::encode(reg.code_);
|
||||
}
|
||||
|
||||
|
||||
@ -80,9 +63,9 @@ Result RegisterAllocator::AllocateWithoutSpilling() {
|
||||
int free_reg = registers_.ScanForFreeRegister();
|
||||
if (free_reg < kNumRegisters) {
|
||||
Register free_result = { free_reg };
|
||||
return Result(free_result, cgen_);
|
||||
return Result(free_result);
|
||||
}
|
||||
return Result(cgen_);
|
||||
return Result();
|
||||
}
|
||||
|
||||
|
||||
@ -94,7 +77,7 @@ Result RegisterAllocator::Allocate() {
|
||||
Register free_reg = cgen_->frame()->SpillAnyRegister();
|
||||
if (free_reg.is_valid()) {
|
||||
ASSERT(!is_used(free_reg));
|
||||
return Result(free_reg, cgen_);
|
||||
return Result(free_reg);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -104,7 +87,7 @@ Result RegisterAllocator::Allocate() {
|
||||
Result RegisterAllocator::Allocate(Register target) {
|
||||
// If the target is not referenced, it can simply be allocated.
|
||||
if (!is_used(target)) {
|
||||
return Result(target, cgen_);
|
||||
return Result(target);
|
||||
}
|
||||
// If the target is only referenced in the frame, it can be spilled and
|
||||
// then allocated.
|
||||
@ -112,10 +95,10 @@ Result RegisterAllocator::Allocate(Register target) {
|
||||
if (cgen_->frame()->is_used(target) && count(target) == 1) {
|
||||
cgen_->frame()->Spill(target);
|
||||
ASSERT(!is_used(target));
|
||||
return Result(target, cgen_);
|
||||
return Result(target);
|
||||
}
|
||||
// Otherwise (if it's referenced outside the frame) we cannot allocate it.
|
||||
return Result(cgen_);
|
||||
return Result();
|
||||
}
|
||||
|
||||
|
||||
|
@ -103,6 +103,7 @@ class StaticType BASE_EMBEDDED {
|
||||
StaticTypeEnum static_type_;
|
||||
|
||||
friend class FrameElement;
|
||||
friend class Result;
|
||||
};
|
||||
|
||||
|
||||
@ -121,26 +122,20 @@ class Result BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
// Construct an invalid result.
|
||||
explicit Result(CodeGenerator* cgen)
|
||||
: static_type_(),
|
||||
type_(INVALID),
|
||||
cgen_(cgen) {}
|
||||
Result() { invalidate(); }
|
||||
|
||||
// Construct a register Result.
|
||||
Result(Register reg,
|
||||
CodeGenerator* cgen);
|
||||
explicit Result(Register reg);
|
||||
|
||||
// Construct a register Result with a known static type.
|
||||
Result(Register reg,
|
||||
CodeGenerator* cgen,
|
||||
StaticType static_type);
|
||||
Result(Register reg, StaticType static_type);
|
||||
|
||||
// Construct a Result whose value is a compile-time constant.
|
||||
Result(Handle<Object> value, CodeGenerator * cgen)
|
||||
: static_type_(StaticType::TypeOf(*value)),
|
||||
type_(CONSTANT),
|
||||
cgen_(cgen) {
|
||||
data_.handle_ = value.location();
|
||||
explicit Result(Handle<Object> value) {
|
||||
value_ = StaticTypeField::encode(StaticType::TypeOf(*value).static_type_)
|
||||
| TypeField::encode(CONSTANT)
|
||||
| DataField::encode(ConstantList()->length());
|
||||
ConstantList()->Add(value);
|
||||
}
|
||||
|
||||
// The copy constructor and assignment operators could each create a new
|
||||
@ -159,25 +154,51 @@ class Result BASE_EMBEDDED {
|
||||
|
||||
inline ~Result();
|
||||
|
||||
// Static indirection table for handles to constants. If a Result
|
||||
// represents a constant, the data contains an index into this table
|
||||
// of handles to the actual constants.
|
||||
typedef ZoneList<Handle<Object> > ZoneObjectList;
|
||||
|
||||
static ZoneObjectList* ConstantList() {
|
||||
static ZoneObjectList list(10);
|
||||
return &list;
|
||||
}
|
||||
|
||||
// Clear the constants indirection table.
|
||||
static void ClearConstantList() {
|
||||
ConstantList()->Clear();
|
||||
}
|
||||
|
||||
inline void Unuse();
|
||||
|
||||
StaticType static_type() const { return static_type_; }
|
||||
void set_static_type(StaticType static_type) { static_type_ = static_type; }
|
||||
StaticType static_type() const {
|
||||
return StaticType(StaticTypeField::decode(value_));
|
||||
}
|
||||
|
||||
Type type() const { return static_cast<Type>(type_); }
|
||||
void set_static_type(StaticType type) {
|
||||
value_ = value_ & ~StaticTypeField::mask();
|
||||
value_ = value_ | StaticTypeField::encode(type.static_type_);
|
||||
}
|
||||
|
||||
Type type() const { return TypeField::decode(value_); }
|
||||
|
||||
void invalidate() { value_ = TypeField::encode(INVALID); }
|
||||
|
||||
bool is_valid() const { return type() != INVALID; }
|
||||
bool is_register() const { return type() == REGISTER; }
|
||||
bool is_constant() const { return type() == CONSTANT; }
|
||||
|
||||
Register reg() const {
|
||||
ASSERT(type() == REGISTER);
|
||||
return data_.reg_;
|
||||
ASSERT(is_register());
|
||||
uint32_t reg = DataField::decode(value_);
|
||||
Register result;
|
||||
result.code_ = reg;
|
||||
return result;
|
||||
}
|
||||
|
||||
Handle<Object> handle() const {
|
||||
ASSERT(type() == CONSTANT);
|
||||
return Handle<Object>(data_.handle_);
|
||||
return ConstantList()->at(DataField::decode(value_));
|
||||
}
|
||||
|
||||
// Move this result to an arbitrary register. The register is not
|
||||
@ -191,17 +212,15 @@ class Result BASE_EMBEDDED {
|
||||
void ToRegister(Register reg);
|
||||
|
||||
private:
|
||||
StaticType static_type_;
|
||||
byte type_;
|
||||
uint32_t value_;
|
||||
|
||||
union {
|
||||
Register reg_;
|
||||
Object** handle_;
|
||||
} data_;
|
||||
class StaticTypeField: public BitField<StaticType::StaticTypeEnum, 0, 3> {};
|
||||
class TypeField: public BitField<Type, 3, 2> {};
|
||||
class DataField: public BitField<uint32_t, 5, 32 - 6> {};
|
||||
|
||||
CodeGenerator* cgen_;
|
||||
inline void CopyTo(Result* destination) const;
|
||||
|
||||
void CopyTo(Result* destination) const;
|
||||
friend class CodeGeneratorScope;
|
||||
};
|
||||
|
||||
|
||||
|
@ -324,11 +324,11 @@ void VirtualFrame::SetElementAt(int index, Result* value) {
|
||||
|
||||
// Early exit if the element is the same as the one being set.
|
||||
bool same_register = original.is_register()
|
||||
&& value->is_register()
|
||||
&& original.reg().is(value->reg());
|
||||
&& value->is_register()
|
||||
&& original.reg().is(value->reg());
|
||||
bool same_constant = original.is_constant()
|
||||
&& value->is_constant()
|
||||
&& original.handle().is_identical_to(value->handle());
|
||||
&& value->is_constant()
|
||||
&& original.handle().is_identical_to(value->handle());
|
||||
if (same_register || same_constant) {
|
||||
value->Unuse();
|
||||
return;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "top.h"
|
||||
#include "cctest.h"
|
||||
#include "disassembler.h"
|
||||
#include "register-allocator-inl.h"
|
||||
|
||||
using v8::Function;
|
||||
using v8::Local;
|
||||
|
Loading…
Reference in New Issue
Block a user