namespace v8 { namespace internal {
+
+CodeGenerator* CodeGeneratorScope::top_ = NULL;
+
+
DeferredCode::DeferredCode(CodeGenerator* generator)
: generator_(generator),
masm_(generator->masm()),
// 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());
#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
public:
explicit CompilationZoneScope(ZoneScopeMode mode) : ZoneScope(mode) { }
virtual ~CompilationZoneScope() {
- if (ShouldDeleteOnExit()) FrameElement::ClearConstantList();
+ if (ShouldDeleteOnExit()) {
+ FrameElement::ClearConstantList();
+ Result::ClearConstantList();
+ }
}
};
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 {
// 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);
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) {
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);
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())
void DeferredInlineSmiOperation::Generate() {
- Result left(generator());
+ Result left;
enter()->Bind(&left);
generator()->frame()->Push(&left);
generator()->frame()->Push(value_);
void DeferredInlineSmiOperationReversed::Generate() {
- Result right(generator());
+ Result right;
enter()->Bind(&right);
generator()->frame()->Push(value_);
generator()->frame()->Push(&right);
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());
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());
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());
void DeferredInlineSmiSubReversed::Generate() {
// Call the shared stub.
- Result right(generator());
+ Result right;
enter()->Bind(&right);
generator()->frame()->Push(value_);
generator()->frame()->Push(&right);
// 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);
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());
case Token::SAR: {
if (reversed) {
- Result constant_operand(value, this);
+ Result constant_operand(value);
LikelySmiBinaryOperation(op, &constant_operand, operand,
overwrite_mode);
} else {
case Token::SHR: {
if (reversed) {
- Result constant_operand(value, this);
+ Result constant_operand(value);
LikelySmiBinaryOperation(op, &constant_operand, operand,
overwrite_mode);
} else {
case Token::SHL: {
if (reversed) {
- Result constant_operand(value, this);
+ Result constant_operand(value);
LikelySmiBinaryOperation(op, &constant_operand, operand,
overwrite_mode);
} else {
}
default: {
- Result constant_operand(value, this);
+ Result constant_operand(value);
if (reversed) {
LikelySmiBinaryOperation(op, &constant_operand, operand,
overwrite_mode);
// 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);
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));
// 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.
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 {
// 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
// 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 {
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
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.
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
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.
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.
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.
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);
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);
void DeferredCountOperation::Generate() {
CodeGenerator* cgen = generator();
- Result value(cgen);
+ Result value;
enter()->Bind(&value);
VirtualFrame* frame = cgen->frame();
// Undo the optimistic smi operation.
void DeferredReferenceGetNamedValue::Generate() {
CodeGenerator* cgen = generator();
- Result receiver(cgen);
+ Result receiver;
enter()->Bind(&receiver);
cgen->frame()->Push(&receiver);
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.
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;
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));
// 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;
}
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());
}
}
// 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);
}
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());
+ }
}
// -------------------------------------------------------------------------
// Result implementation.
-Result::Result(Register reg, CodeGenerator* cgen)
- : static_type_(),
- type_(REGISTER),
- cgen_(cgen) {
- data_.reg_ = reg;
- ASSERT(reg.is_valid());
- cgen_->allocator()->Use(reg);
-}
-
-Result::Result(Register reg, CodeGenerator* cgen, StaticType static_type)
- : static_type_(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_);
}
-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());
- }
+Result::Result(Register reg, StaticType type) {
+ ASSERT(reg.is_valid());
+ CodeGeneratorScope::Current()->allocator()->Use(reg);
+ value_ = StaticTypeField::encode(type.static_type_)
+ | TypeField::encode(REGISTER)
+ | DataField::encode(reg.code_);
}
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();
}
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;
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.
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();
}
StaticTypeEnum static_type_;
friend class FrameElement;
+ friend class Result;
};
};
// 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
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_));
+ }
+
+ void set_static_type(StaticType type) {
+ value_ = value_ & ~StaticTypeField::mask();
+ value_ = value_ | StaticTypeField::encode(type.static_type_);
+ }
- Type type() const { return static_cast<Type>(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
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;
};
// 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;
#include "top.h"
#include "cctest.h"
#include "disassembler.h"
+#include "register-allocator-inl.h"
using v8::Function;
using v8::Local;