Author: [email protected]
Date: Tue Feb 10 02:34:41 2009
New Revision: 1246
Modified:
branches/experimental/toiger/src/codegen-arm.cc
branches/experimental/toiger/src/codegen-arm.h
branches/experimental/toiger/src/jump-target-arm.cc
branches/experimental/toiger/src/register-allocator-ia32.h
branches/experimental/toiger/src/register-allocator.h
branches/experimental/toiger/src/virtual-frame-arm.h
branches/experimental/toiger/src/virtual-frame.h
Log:
A bunch of changes to get the ARM port compiling again.
Review URL: http://codereview.chromium.org/20218
Modified: branches/experimental/toiger/src/codegen-arm.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-arm.cc (original)
+++ branches/experimental/toiger/src/codegen-arm.cc Tue Feb 10 02:34:41 2009
@@ -87,6 +87,17 @@
}
+void CodeGenerator::SetFrame(VirtualFrame* new_frame) {
+ frame_ = new_frame;
+}
+
+
+void CodeGenerator::DeleteFrame() {
+ delete frame_;
+ frame_ = NULL;
+}
+
+
// Calling conventions:
// r0: the number of arguments
// fp: frame pointer
@@ -101,9 +112,9 @@
ASSERT(scope_ == NULL);
scope_ = fun->scope();
ASSERT(frame_ == NULL);
- set_frame(new VirtualFrame(this));
+ frame_ = new VirtualFrame(this);
cc_reg_ = al;
- function_return_.set_code_generator(this);
+ function_return_.Initialize(this, JumpTarget::BIDIRECTIONAL);
function_return_is_shadowed_ = false;
{
CodeGenState state(this);
@@ -771,10 +782,10 @@
new DeferredInlinedSmiOperation(this, op, int_value, reversed);
__ add(r0, r0, Operand(value), SetCC);
- __ b(vs, deferred->enter());
+ deferred->enter()->Branch(vs);
__ tst(r0, Operand(kSmiTagMask));
- __ b(ne, deferred->enter());
- __ bind(deferred->exit());
+ deferred->enter()->Branch(ne);
+ deferred->exit()->Bind();
break;
}
@@ -787,10 +798,10 @@
} else {
__ rsb(r0, r0, Operand(value), SetCC);
}
- __ b(vs, deferred->enter());
+ deferred->enter()->Branch(vs);
__ tst(r0, Operand(kSmiTagMask));
- __ b(ne, deferred->enter());
- __ bind(deferred->exit());
+ deferred->enter()->Branch(ne);
+ deferred->exit()->Bind();
break;
}
@@ -800,14 +811,14 @@
DeferredCode* deferred =
new DeferredInlinedSmiOperation(this, op, int_value, reversed);
__ tst(r0, Operand(kSmiTagMask));
- __ b(ne, deferred->enter());
+ deferred->enter()->Branch(ne);
switch (op) {
case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break;
case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break;
case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break;
default: UNREACHABLE();
}
- __ bind(deferred->exit());
+ deferred->exit()->Bind();
break;
}
@@ -825,14 +836,14 @@
DeferredCode* deferred =
new DeferredInlinedSmiOperation(this, op, shift_value, false);
__ tst(r0, Operand(kSmiTagMask));
- __ b(ne, deferred->enter());
+ deferred->enter()->Branch(ne);
__ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags
switch (op) {
case Token::SHL: {
__ mov(r2, Operand(r2, LSL, shift_value));
// check that the *unsigned* result fits in a smi
__ add(r3, r2, Operand(0x40000000), SetCC);
- __ b(mi, deferred->enter());
+ deferred->enter()->Branch(mi);
break;
}
case Token::SHR: {
@@ -847,7 +858,7 @@
// smi tagging these two cases can only happen with shifts
// by 0 or 1 when handed a valid smi
__ and_(r3, r2, Operand(0xc0000000), SetCC);
- __ b(ne, deferred->enter());
+ deferred->enter()->Branch(ne);
break;
}
case Token::SAR: {
@@ -860,7 +871,7 @@
default: UNREACHABLE();
}
__ mov(r0, Operand(r2, LSL, kSmiTagSize));
- __ bind(deferred->exit());
+ deferred->exit()->Bind();
}
break;
}
@@ -1011,13 +1022,11 @@
void CodeGenerator::VisitBlock(Block* node) {
Comment cmnt(masm_, "[ Block");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
- node->break_target()->set_code_generator(this);
+ node->break_target()->Initialize(this);
VisitStatements(node->statements());
- if (node->break_target()->is_linked()) {
- node->break_target()->Bind();
- }
+ node->break_target()->Bind();
}
@@ -1034,7 +1043,7 @@
void CodeGenerator::VisitDeclaration(Declaration* node) {
Comment cmnt(masm_, "[ Declaration");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
Variable* var = node->proxy()->var();
ASSERT(var != NULL); // must have been resolved
Slot* slot = var->slot();
@@ -1100,7 +1109,7 @@
void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
Comment cmnt(masm_, "[ ExpressionStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
Expression* expression = node->expression();
expression->MarkAsStatement();
Load(expression);
@@ -1110,7 +1119,7 @@
void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
Comment cmnt(masm_, "// EmptyStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
// nothing to do
}
@@ -1122,7 +1131,7 @@
bool has_then_stm = node->HasThenStatement();
bool has_else_stm = node->HasElseStatement();
- CodeForStatement(node);
+ CodeForStatementPosition(node);
JumpTarget exit(this);
if (has_then_stm && has_else_stm) {
@@ -1207,7 +1216,7 @@
void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
Comment cmnt(masm_, "[ ContinueStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
CleanStack(break_stack_height_ - node->target()->break_stack_height());
node->target()->continue_target()->Jump();
}
@@ -1215,7 +1224,7 @@
void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
Comment cmnt(masm_, "[ BreakStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
CleanStack(break_stack_height_ - node->target()->break_stack_height());
node->target()->break_target()->Jump();
}
@@ -1223,7 +1232,7 @@
void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
Comment cmnt(masm_, "[ ReturnStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
Load(node->expression());
// Move the function result into r0.
frame_->Pop(r0);
@@ -1234,7 +1243,7 @@
void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
Comment cmnt(masm_, "[ WithEnterStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
Load(node->expression());
if (node->is_catch_block()) {
frame_->CallRuntime(Runtime::kPushCatchContext, 1);
@@ -1255,7 +1264,7 @@
void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
Comment cmnt(masm_, "[ WithExitStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
// Pop context.
__ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
// Update context local.
@@ -1276,9 +1285,9 @@
SwitchStatement* node,
int min_index,
int range,
- JumpTarget* fail_label,
- Vector<JumpTarget*> case_targets,
- Vector<JumpTarget> case_labels) {
+ Label* default_label,
+ Vector<Label*> case_targets,
+ Vector<Label> case_labels) {
ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
@@ -1291,7 +1300,7 @@
__ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag));
__ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag));
__ cmp(r1, Operand(HEAP_NUMBER_TYPE));
- fail_label->Branch(ne);
+ __ b(ne, default_label);
frame_->EmitPush(r0);
frame_->CallRuntime(Runtime::kNumberToSmi, 1);
is_smi.Bind();
@@ -1311,32 +1320,31 @@
}
}
__ tst(r0, Operand(0x80000000 | kSmiTagMask));
- fail_label->Branch(ne);
+ __ b(ne, default_label);
__ cmp(r0, Operand(Smi::FromInt(range)));
- fail_label->Branch(ge);
+ __ b(ge, default_label);
__ SmiJumpTable(r0, case_targets);
- JumpTarget table_start(this);
- table_start.Bind();
+ frame_->MakeMergable();
+ VirtualFrame* start_frame = new VirtualFrame(frame_);
// Table containing branch operations.
for (int i = 0; i < range; i++) {
- case_targets[i]->Jump();
- frame_ = new VirtualFrame(table_start.expected_frame());
+ __ jmp(case_targets[i]);
}
- GenerateFastCaseSwitchCases(node, case_labels, &table_start);
+ GenerateFastCaseSwitchCases(node, case_labels, start_frame);
+ delete start_frame;
}
void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
Comment cmnt(masm_, "[ SwitchStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
- node->break_target()->set_code_generator(this);
+ node->break_target()->Initialize(this);
Load(node->tag());
-
if (TryGenerateFastCaseSwitchStatement(node)) {
- return;
+ return;
}
JumpTarget next_test(this);
@@ -1418,10 +1426,10 @@
void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
Comment cmnt(masm_, "[ LoopStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
- node->break_target()->set_code_generator(this);
- node->continue_target()->set_code_generator(this);
+ node->break_target()->Initialize(this);
+ node->continue_target()->Initialize(this);
// Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
// known result for the test expression, with no side effects.
@@ -1572,10 +1580,8 @@
// Record source position of the statement as this code which
is
// after the code for the body actually belongs to the loop
// statement and not the body.
- CodeForStatement(node);
-
+ CodeForStatementPosition(node);
- ASSERT(node->type() == LoopStatement::FOR_LOOP);
Visit(node->next());
loop.Jump();
}
@@ -1593,7 +1599,7 @@
void CodeGenerator::VisitForInStatement(ForInStatement* node) {
Comment cmnt(masm_, "[ ForInStatement");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
// We keep stuff on the stack while the body is executing.
// Record it, so that a break/continue crossing this statement
@@ -1601,8 +1607,8 @@
const int kForInStackSize = 5 * kPointerSize;
break_stack_height_ += kForInStackSize;
node->set_break_stack_height(break_stack_height_);
- node->break_target()->set_code_generator(this);
- node->continue_target()->set_code_generator(this);
+ node->break_target()->Initialize(this);
+ node->continue_target()->Initialize(this);
JumpTarget primitive(this);
JumpTarget jsobject(this);
@@ -1782,7 +1788,7 @@
void CodeGenerator::VisitTryCatch(TryCatch* node) {
Comment cmnt(masm_, "[ TryCatch");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
JumpTarget try_block(this);
JumpTarget exit(this);
@@ -1882,7 +1888,7 @@
frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// Code slot popped.
frame_->Forget(1);
- shadows[i]->original_target()->Jump();
+ shadows[i]->other_target()->Jump();
}
}
@@ -1892,7 +1898,7 @@
void CodeGenerator::VisitTryFinally(TryFinally* node) {
Comment cmnt(masm_, "[ TryFinally");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
// State: Used to keep track of reason for entering the finally
// block. Should probably be extended to hold information for
@@ -1961,7 +1967,7 @@
for (int i = 0; i <= nof_escapes; i++) {
if (shadows[i]->is_linked()) {
shadows[i]->Bind();
- if (shadows[i]->original_target() == &function_return_) {
+ if (shadows[i]->other_target() == &function_return_) {
// If this label shadowed the function return, materialize the
// return value on the stack.
frame_->EmitPush(r0);
@@ -2023,13 +2029,13 @@
for (int i = 0; i <= nof_escapes; i++) {
if (shadows[i]->is_bound()) {
__ cmp(r2, Operand(Smi::FromInt(JUMPING + i)));
- if (shadows[i]->original_target() != &function_return_) {
+ if (shadows[i]->other_target() != &function_return_) {
JumpTarget next(this);
next.Branch(ne);
- shadows[i]->original_target()->Jump();
+ shadows[i]->other_target()->Jump();
next.Bind();
} else {
- shadows[i]->original_target()->Branch(eq);
+ shadows[i]->other_target()->Branch(eq);
}
}
}
@@ -2050,7 +2056,7 @@
void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
Comment cmnt(masm_, "[ DebuggerStatament");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
frame_->CallRuntime(Runtime::kDebugBreak, 0);
// Ignore the return value.
}
@@ -2262,8 +2268,8 @@
// Check whether we need to materialize the object literal boilerplate.
// If so, jump to the deferred code.
__ cmp(r2, Operand(Factory::undefined_value()));
- __ b(eq, deferred->enter());
- __ bind(deferred->exit());
+ deferred->enter()->Branch(eq);
+ deferred->exit()->Bind();
// Push the object literal boilerplate.
frame_->EmitPush(r2);
@@ -2365,13 +2371,13 @@
Load(node->key());
Load(node->value());
__ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
- frame_->Push(r0);
+ frame_->EmitPush(r0);
}
void CodeGenerator::VisitAssignment(Assignment* node) {
Comment cmnt(masm_, "[ Assignment");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
Reference target(this, node->target());
if (target.is_illegal()) {
@@ -2444,7 +2450,7 @@
ZoneList<Expression*>* args = node->arguments();
- CodeForStatement(node);
+ CodeForStatementPosition(node);
// Standard function call.
// Check if the function is a variable or a property.
@@ -2588,7 +2594,7 @@
ZoneList<Expression*>* args = node->arguments();
Expression* function = node->expression();
- CodeForStatement(node);
+ CodeForStatementPosition(node);
// Prepare stack for call to resolved function.
Load(function);
@@ -2625,14 +2631,14 @@
__ ldr(cp, frame_->Context());
// Remove the function from the stack.
- frame_->Pop();
- frame_->Push(r0);
+ frame_->Drop();
+ frame_->EmitPush(r0);
}
void CodeGenerator::VisitCallNew(CallNew* node) {
Comment cmnt(masm_, "[ CallNew");
- CodeForStatement(node);
+ CodeForStatementPosition(node);
// According to ECMA-262, section 11.2.2, page 44, the function
// expression in new calls must be evaluated before the
@@ -2738,7 +2744,7 @@
}
#endif
__ mov(r0, Operand(Factory::undefined_value()));
- frame_->Push(r0);
+ frame_->EmitPush(r0);
}
@@ -3399,6 +3405,11 @@
UNREACHABLE();
}
}
+
+
+#ifdef DEBUG
+bool CodeGenerator::HasValidEntryRegisters() { return true; }
+#endif
bool CodeGenerator::IsActualFunctionReturn(JumpTarget* target) {
Modified: branches/experimental/toiger/src/codegen-arm.h
==============================================================================
--- branches/experimental/toiger/src/codegen-arm.h (original)
+++ branches/experimental/toiger/src/codegen-arm.h Tue Feb 10 02:34:41 2009
@@ -162,12 +162,11 @@
VirtualFrame* frame() const { return frame_; }
- void set_frame(VirtualFrame* frame) { frame_ = frame; }
+ bool has_valid_frame() const { return frame_ != NULL; }
- void delete_frame() {
- delete frame_;
- frame_ = NULL;
- }
+ void SetFrame(VirtualFrame* frame);
+
+ void DeleteFrame();
CodeGenState* state() { return state_; }
void set_state(CodeGenState* state) { state_ = state; }
@@ -319,15 +318,15 @@
void GenerateFastCaseSwitchJumpTable(SwitchStatement* node,
int min_index,
int range,
- JumpTarget* fail_label,
- Vector<JumpTarget*> case_targets,
- Vector<JumpTarget> case_labels);
+ Label* default_label,
+ Vector<Label*> case_targets,
+ Vector<Label> case_labels);
// Generate the code for cases for the fast case switch.
// Called by GenerateFastCaseSwitchJumpTable.
void GenerateFastCaseSwitchCases(SwitchStatement* node,
- Vector<JumpTarget> case_labels,
- JumpTarget* table_start);
+ Vector<Label> case_labels,
+ VirtualFrame* start_frame);
// Fast support for constant-Smi switches.
void GenerateFastCaseSwitchStatement(SwitchStatement* node,
@@ -344,7 +343,8 @@
// Methods used to indicate which source code is generated for. Source
// positions are collected by the assembler and emitted with the
relocation
// information.
- void CodeForStatement(Node* node);
+ void CodeForFunctionPosition(FunctionLiteral* fun);
+ void CodeForStatementPosition(Node* node);
void CodeForSourcePosition(int pos);
// Is the given jump target the actual (ie, non-shadowed) function return
@@ -352,6 +352,12 @@
bool IsActualFunctionReturn(JumpTarget* target);
bool is_eval_; // Tells whether code is generated for eval.
+
+#ifdef DEBUG
+ // True if the registers are valid for entry to a block.
+ bool HasValidEntryRegisters();
+#endif
+
Handle<Script> script_;
List<DeferredCode*> deferred_;
Modified: branches/experimental/toiger/src/jump-target-arm.cc
==============================================================================
--- branches/experimental/toiger/src/jump-target-arm.cc (original)
+++ branches/experimental/toiger/src/jump-target-arm.cc Tue Feb 10 02:34:41
2009
@@ -37,171 +37,358 @@
#define __ masm_->
-JumpTarget::JumpTarget(CodeGenerator* cgen)
- : expected_frame_(NULL),
- code_generator_(cgen),
- masm_(cgen->masm()) {
+JumpTarget::JumpTarget(CodeGenerator* cgen, Directionality direction)
+ : cgen_(cgen),
+ direction_(direction),
+ reaching_frames_(0),
+ merge_labels_(0),
+ expected_frame_(NULL),
+ is_bound_(false),
+ is_linked_(false) {
+ ASSERT(cgen_ != NULL);
+ masm_ = cgen_->masm();
}
JumpTarget::JumpTarget()
- : expected_frame_(NULL),
- code_generator_(NULL),
- masm_(NULL) {
+ : cgen_(NULL),
+ masm_(NULL),
+ direction_(FORWARD_ONLY),
+ reaching_frames_(0),
+ merge_labels_(0),
+ expected_frame_(NULL),
+ is_bound_(false),
+ is_linked_(false) {
}
-void JumpTarget::set_code_generator(CodeGenerator* cgen) {
+void JumpTarget::Initialize(CodeGenerator* cgen, Directionality direction)
{
ASSERT(cgen != NULL);
- ASSERT(code_generator_ == NULL);
- code_generator_ = cgen;
+ ASSERT(cgen_ == NULL);
+ cgen_ = cgen;
masm_ = cgen->masm();
+ direction_ = direction;
+}
+
+
+void JumpTarget::Unuse() {
+ ASSERT(!is_linked());
+ entry_label_.Unuse();
+ delete expected_frame_;
+ expected_frame_ = NULL;
+ is_bound_ = false;
+ is_linked_ = false;
+}
+
+
+void JumpTarget::Reset() {
+ reaching_frames_.Clear();
+ merge_labels_.Clear();
+ expected_frame_ = NULL;
+ entry_label_.Unuse();
+ is_bound_ = false;
+ is_linked_ = false;
}
void JumpTarget::Jump() {
- // Precondition: there is a current frame. There may or may not be an
- // expected frame at the label.
- ASSERT(code_generator_ != NULL);
-
- VirtualFrame* current_frame = code_generator_->frame();
- ASSERT(current_frame != NULL);
-
- if (expected_frame_ == NULL) {
- expected_frame_ = current_frame;
- code_generator_->set_frame(NULL);
- // The frame at the actual function return will always have height
zero.
- if (code_generator_->IsActualFunctionReturn(this)) {
- expected_frame_->Forget(expected_frame_->height());
- }
+ ASSERT(cgen_ != NULL);
+ ASSERT(cgen_->has_valid_frame());
+ // Live non-frame registers are not allowed at unconditional jumps
+ // because we have no way of invalidating the corresponding results
+ // which are still live in the C++ code.
+ ASSERT(cgen_->HasValidEntryRegisters());
+
+ if (is_bound()) {
+ // Backward jump. There is an expected frame to merge to.
+ ASSERT(direction_ == BIDIRECTIONAL);
+ cgen_->frame()->MergeTo(expected_frame_);
+ cgen_->DeleteFrame();
+ __ jmp(&entry_label_);
} else {
- // No code needs to be emitted to merge to the expected frame at the
- // actual function return.
- if (!code_generator_->IsActualFunctionReturn(this)) {
- current_frame->MergeTo(expected_frame_);
- }
- code_generator_->delete_frame();
+ // Forward jump. The current frame is added to the end of the list
+ // of frames reaching the target block and a jump to the merge code
+ // is emitted.
+ AddReachingFrame(cgen_->frame());
+ cgen_->SetFrame(NULL);
+ __ jmp(&merge_labels_.last());
}
- __ b(&label_);
- // Postcondition: there is no current frame but there is an expected
frame
- // at the label.
+ is_linked_ = !is_bound_;
+}
+
+
+void JumpTarget::Jump(Result* arg) {
+ UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Jump(Result* arg0, Result* arg1) {
+ UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Jump(Result* arg0, Result* arg1, Result* arg2) {
+ UNIMPLEMENTED();
}
void JumpTarget::Branch(Condition cc, Hint ignored) {
- // Precondition: there is a current frame. There may or may not be an
- // expected frame at the label.
- ASSERT(code_generator_ != NULL);
- ASSERT(masm_ != NULL);
-
- VirtualFrame* current_frame = code_generator_->frame();
- ASSERT(current_frame != NULL);
-
- if (expected_frame_ == NULL) {
- expected_frame_ = new VirtualFrame(current_frame);
- // The frame at the actual function return will always have height
zero.
- if (code_generator_->IsActualFunctionReturn(this)) {
- expected_frame_->Forget(expected_frame_->height());
- }
+ ASSERT(cgen_ != NULL);
+ ASSERT(cgen_->has_valid_frame());
+
+ if (is_bound()) {
+ // Backward branch. We have an expected frame to merge to on the
+ // backward edge. We negate the condition and emit the merge code
+ // here.
+ //
+ // TODO(210): we should try to avoid negating the condition in the
+ // case where there is no merge code to emit. Otherwise, we emit
+ // a branch around an unconditional jump.
+ ASSERT(direction_ == BIDIRECTIONAL);
+ Label original_fall_through;
+ __ b(NegateCondition(cc), &original_fall_through);
+ // Swap the current frame for a copy of it, saving non-frame
+ // register reference counts and invalidating all non-frame register
+ // references except the reserved ones on the backward edge.
+ VirtualFrame* original_frame = cgen_->frame();
+ VirtualFrame* working_frame = new VirtualFrame(original_frame);
+ cgen_->SetFrame(working_frame);
+
+ working_frame->MergeTo(expected_frame_);
+ cgen_->DeleteFrame();
+ __ jmp(&entry_label_);
+
+ // Restore the frame and its associated non-frame registers.
+ cgen_->SetFrame(original_frame);
+ __ bind(&original_fall_through);
} else {
- // No code needs to be emitted to merge to the expected frame at the
- // actual function return.
- if (!code_generator_->IsActualFunctionReturn(this)) {
- current_frame->MergeTo(expected_frame_);
- }
+ // Forward branch. A copy of the current frame is added to the end
+ // of the list of frames reaching the target block and a branch to
+ // the merge code is emitted.
+ AddReachingFrame(new VirtualFrame(cgen_->frame()));
+ __ b(cc, &merge_labels_.last());
}
- __ b(cc, &label_);
- // Postcondition: there is both a current frame and an expected frame at
- // the label and they match.
+ is_linked_ = !is_bound_;
+}
+
+
+void JumpTarget::Branch(Condition cc, Result* arg, Hint ignored) {
+ UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Branch(Condition cc,
+ Result* arg0,
+ Result* arg1,
+ Hint ignored) {
+ UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Branch(Condition cc,
+ Result* arg0,
+ Result* arg1,
+ Result* arg2,
+ Hint ignored) {
+ UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Branch(Condition cc,
+ Result* arg0,
+ Result* arg1,
+ Result* arg2,
+ Result* arg3,
+ Hint ignored) {
+ UNIMPLEMENTED();
}
void JumpTarget::Call() {
- // Precondition: there is a current frame, and there is no expected frame
- // at the label.
- ASSERT(code_generator_ != NULL);
- ASSERT(masm_ != NULL);
- ASSERT(!code_generator_->IsActualFunctionReturn(this));
-
- VirtualFrame* current_frame = code_generator_->frame();
- ASSERT(current_frame != NULL);
- ASSERT(expected_frame_ == NULL);
-
- expected_frame_ = new VirtualFrame(current_frame);
- // Adjust the expected frame's height to account for the return address
- // pushed by the call instruction.
- expected_frame_->Adjust(1);
-
- __ bl(&label_);
- // Postcondition: there is both a current frame and an expected frame at
- // the label. The current frame is one shorter than the one at the label
- // (which contains the return address in memory).
+ // Call is used to push the address of the catch block on the stack as
+ // a return address when compiling try/catch and try/finally. We
+ // fully spill the frame before making the call. The expected frame
+ // at the label (which should be the only one) is the spilled current
+ // frame plus an in-memory return address. The "fall-through" frame
+ // at the return site is the spilled current frame.
+ ASSERT(cgen_ != NULL);
+ ASSERT(cgen_->has_valid_frame());
+ // There are no non-frame references across the call.
+ ASSERT(cgen_->HasValidEntryRegisters());
+ ASSERT(!is_linked());
+
+ VirtualFrame* target_frame = new VirtualFrame(cgen_->frame());
+ target_frame->Adjust(1);
+ AddReachingFrame(target_frame);
+ __ bl(&merge_labels_.last());
+
+ is_linked_ = !is_bound_;
}
void JumpTarget::Bind() {
- // Precondition: there is either a current frame or an expected frame at
- // the label (and possibly both). The label is unbound.
- ASSERT(code_generator_ != NULL);
- ASSERT(masm_ != NULL);
-
- VirtualFrame* current_frame = code_generator_->frame();
- ASSERT(current_frame != NULL || expected_frame_ != NULL);
- ASSERT(!label_.is_bound());
-
- if (expected_frame_ == NULL) {
- expected_frame_ = new VirtualFrame(current_frame);
- // The frame at the actual function return will always have height
zero.
- if (code_generator_->IsActualFunctionReturn(this)) {
- expected_frame_->Forget(expected_frame_->height());
+ ASSERT(cgen_ != NULL);
+ ASSERT(!is_bound());
+
+ if (is_linked()) {
+ // There were forward jumps. A mergable frame is created and all
+ // the frames reaching the block via forward jumps are merged to it.
+ ASSERT(reaching_frames_.length() == merge_labels_.length());
+
+ // A special case is that there was only one jump to the block so
+ // far, no fall-through, and there cannot be another entry because
+ // the block is forward only. In that case, simply use the single
+ // frame.
+ bool single_entry = (direction_ == FORWARD_ONLY) &&
+ !cgen_->has_valid_frame() &&
+ (reaching_frames_.length() == 1);
+ if (single_entry) {
+ // Pick up the only forward reaching frame and bind its merge
+ // label. No merge code is emitted.
+ cgen_->SetFrame(reaching_frames_[0]);
+ __ bind(&merge_labels_[0]);
+ } else {
+ // Otherwise, choose a frame as the basis of the expected frame,
+ // and make it mergable. If there is a current frame use it,
+ // otherwise use the first in the list (there will be at least
+ // one).
+ int start_index = 0;
+ if (cgen_->has_valid_frame()) {
+ // Live non-frame registers are not allowed at the start of a
+ // labeled basic block.
+ ASSERT(cgen_->HasValidEntryRegisters());
+ } else {
+ cgen_->SetFrame(reaching_frames_[start_index]);
+ __ bind(&merge_labels_[start_index++]);
+ }
+ cgen_->frame()->MakeMergable();
+ expected_frame_ = new VirtualFrame(cgen_->frame());
+
+ for (int i = start_index; i < reaching_frames_.length(); i++) {
+ cgen_->DeleteFrame();
+ __ jmp(&entry_label_);
+
+ cgen_->SetFrame(reaching_frames_[i]);
+ __ bind(&merge_labels_[i]);
+
+ cgen_->frame()->MergeTo(expected_frame_);
+ }
+
+ __ bind(&entry_label_);
}
- } else if (current_frame == NULL) {
- code_generator_->set_frame(new VirtualFrame(expected_frame_));
+
+ // All but the last reaching virtual frame have been deleted, and
+ // the last one is the current frame.
+ reaching_frames_.Clear();
+ merge_labels_.Clear();
+
} else {
- // No code needs to be emitted to merge to the expected frame at the
- // actual function return.
- if (!code_generator_->IsActualFunctionReturn(this)) {
- current_frame->MergeTo(expected_frame_);
+ // There were no forward jumps. If this jump target is not
+ // bidirectional, there is no need to do anything. For
+ // bidirectional jump targets, the current frame is made mergable
+ // and used for the expected frame.
+ if (direction_ == BIDIRECTIONAL) {
+ ASSERT(cgen_->HasValidEntryRegisters());
+ cgen_->frame()->MakeMergable();
+ expected_frame_ = new VirtualFrame(cgen_->frame());
+ __ bind(&entry_label_);
}
}
- __ bind(&label_);
- // Postcondition: there is both a current frame and an expected frame at
- // the label and they match. The label is bound.
+ is_linked_ = false;
+ is_bound_ = true;
+}
+
+
+void JumpTarget::Bind(Result* arg) {
+ UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Bind(Result* arg0, Result* arg1) {
+ UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Bind(Result* arg0, Result* arg1, Result* arg2) {
+ UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Bind(Result* arg0, Result* arg1, Result* arg2, Result*
arg3) {
+ UNIMPLEMENTED();
+}
+
+
+void JumpTarget::CopyTo(JumpTarget* destination) {
+ ASSERT(destination != NULL);
+ destination->cgen_ = cgen_;
+ destination->masm_ = masm_;
+ destination->direction_ = direction_;
+ destination->reaching_frames_.Clear();
+ destination->merge_labels_.Clear();
+ ASSERT(reaching_frames_.length() == merge_labels_.length());
+ for (int i = 0; i < reaching_frames_.length(); i++) {
+ destination->reaching_frames_.Add(reaching_frames_[i]);
+ destination->merge_labels_.Add(merge_labels_[i]);
+ }
+ destination->expected_frame_ = expected_frame_;
+ destination->entry_label_ = entry_label_;
+ destination->is_bound_ = is_bound_;
+ destination->is_linked_ = is_linked_;
+}
+
+
+void JumpTarget::AddReachingFrame(VirtualFrame* frame) {
+ ASSERT(reaching_frames_.length() == merge_labels_.length());
+ Label fresh;
+ merge_labels_.Add(fresh);
+ reaching_frames_.Add(frame);
}
//
-------------------------------------------------------------------------
// ShadowTarget implementation.
-ShadowTarget::ShadowTarget(JumpTarget* original) {
- ASSERT(original != NULL);
- original_target_ = original;
- original_pos_ = original->label()->pos_;
- original_expected_frame_ = original->expected_frame();
-
- // We do not call Unuse() on the orginal jump target, because we do not
- // want to delete the expected frame.
- original->label()->pos_ = 0;
- original->set_expected_frame(NULL);
+ShadowTarget::ShadowTarget(JumpTarget* shadowed) {
+ ASSERT(shadowed != NULL);
+ other_target_ = shadowed;
+
#ifdef DEBUG
is_shadowing_ = true;
#endif
+ // While shadowing this shadow target saves the state of the original.
+ shadowed->CopyTo(this);
+
+ // Setting the code generator to null prevents the shadow target from
+ // being used until shadowing stops.
+ cgen_ = NULL;
+ masm_ = NULL;
+
+ // The original's state is reset. We do not Unuse it because that
+ // would delete the expected frame and assert that the target is not
+ // linked.
+ shadowed->Reset();
}
void ShadowTarget::StopShadowing() {
ASSERT(is_shadowing_);
- ASSERT(is_unused());
-
- set_code_generator(original_target_->code_generator());
- label_.pos_ = original_target_->label()->pos_;
- expected_frame_ = original_target_->expected_frame();
- original_target_->label()->pos_ = original_pos_;
- original_target_->set_expected_frame(original_expected_frame_);
+ // This target does not have a valid code generator yet.
+ cgen_ = other_target_->code_generator();
+ ASSERT(cgen_ != NULL);
+ masm_ = cgen_->masm();
+
+ // The states of this target, which was shadowed, and the original
+ // target, which was shadowing, are swapped.
+ JumpTarget temp;
+ other_target_->CopyTo(&temp);
+ CopyTo(other_target_);
+ temp.CopyTo(this);
+ temp.Reset(); // So the destructor does not deallocate virtual frames.
#ifdef DEBUG
is_shadowing_ = false;
Modified: branches/experimental/toiger/src/register-allocator-ia32.h
==============================================================================
--- branches/experimental/toiger/src/register-allocator-ia32.h (original)
+++ branches/experimental/toiger/src/register-allocator-ia32.h Tue Feb 10
02:34:41 2009
@@ -28,94 +28,7 @@
#ifndef V8_REGISTER_ALLOCATOR_IA32_H_
#define V8_REGISTER_ALLOCATOR_IA32_H_
-#include "macro-assembler.h"
-
namespace v8 { namespace internal {
-
-
-//
-------------------------------------------------------------------------
-// Results
-//
-// Results encapsulate the compile-time values manipulated by the code
-// generator. They can represent registers or constants.
-
-class Result BASE_EMBEDDED {
- public:
- enum Type {
- INVALID,
- REGISTER,
- CONSTANT
- };
-
- // Construct an invalid result.
- explicit Result(CodeGenerator* cgen) : type_(INVALID), cgen_(cgen) {}
-
- // Construct a register Result.
- Result(Register reg, CodeGenerator* cgen);
-
- // Construct a Result whose value is a compile-time constant.
- Result(Handle<Object> value, CodeGenerator * cgen)
- : type_(CONSTANT),
- cgen_(cgen) {
- data_.handle_ = value.location();
- }
-
- // The copy constructor and assignment operators could each create a new
- // register reference.
- Result(const Result& other) {
- other.CopyTo(this);
- }
-
- Result& operator=(const Result& other) {
- if (this != &other) {
- Unuse();
- other.CopyTo(this);
- }
- return *this;
- }
-
- ~Result() { Unuse(); }
-
- void Unuse();
-
- Type type() const { return type_; }
-
- 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_;
- }
-
- Handle<Object> handle() const {
- ASSERT(type() == CONSTANT);
- return Handle<Object>(data_.handle_);
- }
-
- // Move this result to an arbitrary register. The register is not
- // necessarily spilled from the frame or even singly-referenced outside
- // it.
- void ToRegister();
-
- // Move this result to a specified register. The register is spilled
from
- // the frame, and the register is singly-referenced (by this result)
- // outside the frame.
- void ToRegister(Register reg);
-
- private:
- Type type_;
-
- union {
- Register reg_;
- Object** handle_;
- } data_;
-
- CodeGenerator* cgen_;
-
- void CopyTo(Result* destination) const;
-};
//
-------------------------------------------------------------------------
Modified: branches/experimental/toiger/src/register-allocator.h
==============================================================================
--- branches/experimental/toiger/src/register-allocator.h (original)
+++ branches/experimental/toiger/src/register-allocator.h Tue Feb 10
02:34:41 2009
@@ -28,7 +28,98 @@
#ifndef V8_REGISTER_ALLOCATOR_H_
#define V8_REGISTER_ALLOCATOR_H_
-#if defined(ARM) || defined(__arm__) || defined(__thumb__)
+#include "macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+//
-------------------------------------------------------------------------
+// Results
+//
+// Results encapsulate the compile-time values manipulated by the code
+// generator. They can represent registers or constants.
+
+class Result BASE_EMBEDDED {
+ public:
+ enum Type {
+ INVALID,
+ REGISTER,
+ CONSTANT
+ };
+
+ // Construct an invalid result.
+ explicit Result(CodeGenerator* cgen) : type_(INVALID), cgen_(cgen) {}
+
+ // Construct a register Result.
+ Result(Register reg, CodeGenerator* cgen);
+
+ // Construct a Result whose value is a compile-time constant.
+ Result(Handle<Object> value, CodeGenerator * cgen)
+ : type_(CONSTANT),
+ cgen_(cgen) {
+ data_.handle_ = value.location();
+ }
+
+ // The copy constructor and assignment operators could each create a new
+ // register reference.
+ Result(const Result& other) {
+ other.CopyTo(this);
+ }
+
+ Result& operator=(const Result& other) {
+ if (this != &other) {
+ Unuse();
+ other.CopyTo(this);
+ }
+ return *this;
+ }
+
+ ~Result() { Unuse(); }
+
+ void Unuse();
+
+ Type type() const { return type_; }
+
+ 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_;
+ }
+
+ Handle<Object> handle() const {
+ ASSERT(type() == CONSTANT);
+ return Handle<Object>(data_.handle_);
+ }
+
+ // Move this result to an arbitrary register. The register is not
+ // necessarily spilled from the frame or even singly-referenced outside
+ // it.
+ void ToRegister();
+
+ // Move this result to a specified register. The register is spilled
from
+ // the frame, and the register is singly-referenced (by this result)
+ // outside the frame.
+ void ToRegister(Register reg);
+
+ private:
+ Type type_;
+
+ union {
+ Register reg_;
+ Object** handle_;
+ } data_;
+
+ CodeGenerator* cgen_;
+
+ void CopyTo(Result* destination) const;
+};
+
+} } // namespace v8::internal
+
+
+#ifdef ARM
#else // ia32
#include "register-allocator-ia32.h"
#endif
Modified: branches/experimental/toiger/src/virtual-frame-arm.h
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-arm.h (original)
+++ branches/experimental/toiger/src/virtual-frame-arm.h Tue Feb 10
02:34:41 2009
@@ -29,6 +29,7 @@
#define V8_VIRTUAL_FRAME_ARM_H_
#include "macro-assembler.h"
+#include "register-allocator.h"
namespace v8 { namespace internal {
@@ -76,6 +77,10 @@
// Forget frame elements without generating code.
void Forget(int count);
+
+ // Ensure that this frame is in a state where an arbitrary frame of the
+ // right size could be merged to it. May emit code.
+ void MakeMergable() { }
// Make this virtual frame have a state identical to an expected virtual
// frame. As a side effect, code may be emitted to make this frame match
Modified: branches/experimental/toiger/src/virtual-frame.h
==============================================================================
--- branches/experimental/toiger/src/virtual-frame.h (original)
+++ branches/experimental/toiger/src/virtual-frame.h Tue Feb 10 02:34:41
2009
@@ -28,7 +28,7 @@
#ifndef V8_VIRTUAL_FRAME_H_
#define V8_VIRTUAL_FRAME_H_
-#if defined(ARM) || defined (__arm__) || defined(__thumb__)
+#ifdef ARM
#include "virtual-frame-arm.h"
#else // ia32
#include "virtual-frame-ia32.h"
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---