Remove the unused support for jump-table switch statements.

Review URL: http://codereview.chromium.org/126193

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2183 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 824140bd
......@@ -1471,85 +1471,6 @@ void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
}
int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
return kFastSwitchMaxOverheadFactor;
}
int CodeGenerator::FastCaseSwitchMinCaseCount() {
return kFastSwitchMinCaseCount;
}
void CodeGenerator::GenerateFastCaseSwitchJumpTable(
SwitchStatement* node,
int min_index,
int range,
Label* default_label,
Vector<Label*> case_targets,
Vector<Label> case_labels) {
VirtualFrame::SpilledScope spilled_scope;
JumpTarget setup_default;
JumpTarget is_smi;
// A non-null default label pointer indicates a default case among
// the case labels. Otherwise we use the break target as a
// "default" for failure to hit the jump table.
JumpTarget* default_target =
(default_label == NULL) ? node->break_target() : &setup_default;
ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
frame_->EmitPop(r0);
// Test for a Smi value in a HeapNumber.
__ tst(r0, Operand(kSmiTagMask));
is_smi.Branch(eq);
__ CompareObjectType(r0, r1, r1, HEAP_NUMBER_TYPE);
default_target->Branch(ne);
frame_->EmitPush(r0);
frame_->CallRuntime(Runtime::kNumberToSmi, 1);
is_smi.Bind();
if (min_index != 0) {
// Small positive numbers can be immediate operands.
if (min_index < 0) {
// If min_index is Smi::kMinValue, -min_index is not a Smi.
if (Smi::IsValid(-min_index)) {
__ add(r0, r0, Operand(Smi::FromInt(-min_index)));
} else {
__ add(r0, r0, Operand(Smi::FromInt(-min_index - 1)));
__ add(r0, r0, Operand(Smi::FromInt(1)));
}
} else {
__ sub(r0, r0, Operand(Smi::FromInt(min_index)));
}
}
__ tst(r0, Operand(0x80000000 | kSmiTagMask));
default_target->Branch(ne);
__ cmp(r0, Operand(Smi::FromInt(range)));
default_target->Branch(ge);
VirtualFrame* start_frame = new VirtualFrame(frame_);
__ SmiJumpTable(r0, case_targets);
GenerateFastCaseSwitchCases(node, case_labels, start_frame);
// If there was a default case among the case labels, we need to
// emit code to jump to it from the default target used for failure
// to hit the jump table.
if (default_label != NULL) {
if (has_valid_frame()) {
node->break_target()->Jump();
}
setup_default.Bind();
frame_->MergeTo(start_frame);
__ b(default_label);
DeleteFrame();
}
if (node->break_target()->is_linked()) {
node->break_target()->Bind();
}
}
void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
#ifdef DEBUG
int original_height = frame_->height();
......@@ -1560,10 +1481,6 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
LoadAndSpill(node->tag());
if (TryGenerateFastCaseSwitchStatement(node)) {
ASSERT(!has_valid_frame() || frame_->height() == original_height);
return;
}
JumpTarget next_test;
JumpTarget fall_through;
......
......@@ -358,59 +358,6 @@ class CodeGenerator: public AstVisitor {
inline void GenerateMathSin(ZoneList<Expression*>* args);
inline void GenerateMathCos(ZoneList<Expression*>* args);
// Methods and constants for fast case switch statement support.
//
// Only allow fast-case switch if the range of labels is at most
// this factor times the number of case labels.
// Value is derived from comparing the size of code generated by the normal
// switch code for Smi-labels to the size of a single pointer. If code
// quality increases this number should be decreased to match.
static const int kFastSwitchMaxOverheadFactor = 10;
// Minimal number of switch cases required before we allow jump-table
// optimization.
static const int kFastSwitchMinCaseCount = 5;
// The limit of the range of a fast-case switch, as a factor of the number
// of cases of the switch. Each platform should return a value that
// is optimal compared to the default code generated for a switch statement
// on that platform.
int FastCaseSwitchMaxOverheadFactor();
// The minimal number of cases in a switch before the fast-case switch
// optimization is enabled. Each platform should return a value that
// is optimal compared to the default code generated for a switch statement
// on that platform.
int FastCaseSwitchMinCaseCount();
// Allocate a jump table and create code to jump through it.
// Should call GenerateFastCaseSwitchCases to generate the code for
// all the cases at the appropriate point.
void GenerateFastCaseSwitchJumpTable(SwitchStatement* node,
int min_index,
int range,
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<Label> case_labels,
VirtualFrame* start_frame);
// Fast support for constant-Smi switches.
void GenerateFastCaseSwitchStatement(SwitchStatement* node,
int min_index,
int range,
int default_index);
// Fast support for constant-Smi switches. Tests whether switch statement
// permits optimization and calls GenerateFastCaseSwitch if it does.
// Returns true if the fast-case switch was generated, and false if not.
bool TryGenerateFastCaseSwitchStatement(SwitchStatement* node);
// Methods used to indicate which source code is generated for. Source
// positions are collected by the assembler and emitted with the relocation
// information.
......
......@@ -472,129 +472,6 @@ bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name,
}
void CodeGenerator::GenerateFastCaseSwitchStatement(SwitchStatement* node,
int min_index,
int range,
int default_index) {
ZoneList<CaseClause*>* cases = node->cases();
int length = cases->length();
// Label pointer per number in range.
SmartPointer<Label*> case_targets(NewArray<Label*>(range));
// Label per switch case.
SmartPointer<Label> case_labels(NewArray<Label>(length));
Label* fail_label =
default_index >= 0 ? &(case_labels[default_index]) : NULL;
// Populate array of label pointers for each number in the range.
// Initally put the failure label everywhere.
for (int i = 0; i < range; i++) {
case_targets[i] = fail_label;
}
// Overwrite with label of a case for the number value of that case.
// (In reverse order, so that if the same label occurs twice, the
// first one wins).
for (int i = length - 1; i >= 0 ; i--) {
CaseClause* clause = cases->at(i);
if (!clause->is_default()) {
Object* label_value = *(clause->label()->AsLiteral()->handle());
int case_value = Smi::cast(label_value)->value();
case_targets[case_value - min_index] = &(case_labels[i]);
}
}
GenerateFastCaseSwitchJumpTable(node,
min_index,
range,
fail_label,
Vector<Label*>(*case_targets, range),
Vector<Label>(*case_labels, length));
}
void CodeGenerator::GenerateFastCaseSwitchCases(
SwitchStatement* node,
Vector<Label> case_labels,
VirtualFrame* start_frame) {
ZoneList<CaseClause*>* cases = node->cases();
int length = cases->length();
for (int i = 0; i < length; i++) {
Comment cmnt(masm(), "[ Case clause");
// We may not have a virtual frame if control flow did not fall
// off the end of the previous case. In that case, use the start
// frame. Otherwise, we have to merge the existing one to the
// start frame as part of the previous case.
if (!has_valid_frame()) {
RegisterFile empty;
SetFrame(new VirtualFrame(start_frame), &empty);
} else {
frame_->MergeTo(start_frame);
}
masm()->bind(&case_labels[i]);
VisitStatements(cases->at(i)->statements());
}
}
bool CodeGenerator::TryGenerateFastCaseSwitchStatement(SwitchStatement* node) {
// TODO(238): Due to issue 238, fast case switches can crash on ARM
// and possibly IA32. They are disabled for now.
// See http://code.google.com/p/v8/issues/detail?id=238
return false;
ZoneList<CaseClause*>* cases = node->cases();
int length = cases->length();
if (length < FastCaseSwitchMinCaseCount()) {
return false;
}
// Test whether fast-case should be used.
int default_index = -1;
int min_index = Smi::kMaxValue;
int max_index = Smi::kMinValue;
for (int i = 0; i < length; i++) {
CaseClause* clause = cases->at(i);
if (clause->is_default()) {
if (default_index >= 0) {
// There is more than one default label. Defer to the normal case
// for error.
return false;
}
default_index = i;
} else {
Expression* label = clause->label();
Literal* literal = label->AsLiteral();
if (literal == NULL) {
return false; // fail fast case
}
Object* value = *(literal->handle());
if (!value->IsSmi()) {
return false;
}
int int_value = Smi::cast(value)->value();
min_index = Min(int_value, min_index);
max_index = Max(int_value, max_index);
}
}
// All labels are known to be Smis.
int range = max_index - min_index + 1; // |min..max| inclusive
if (range / FastCaseSwitchMaxOverheadFactor() > length) {
return false; // range of labels is too sparse
}
// Optimization accepted, generate code.
GenerateFastCaseSwitchStatement(node, min_index, range, default_index);
return true;
}
void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) {
if (FLAG_debug_info) {
int pos = fun->start_position();
......
......@@ -61,12 +61,6 @@
// FindInlineRuntimeLUT
// CheckForInlineRuntimeCall
// PatchInlineRuntimeEntry
// GenerateFastCaseSwitchStatement
// GenerateFastCaseSwitchCases
// TryGenerateFastCaseSwitchStatement
// GenerateFastCaseSwitchJumpTable
// FastCaseSwitchMinCaseCount
// FastCaseSwitchMaxOverheadFactor
// CodeForFunctionPosition
// CodeForReturnPosition
// CodeForStatementPosition
......
......@@ -2182,17 +2182,6 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
}
void Assembler::WriteInternalReference(int position, const Label& bound_label) {
ASSERT(bound_label.is_bound());
ASSERT(0 <= position);
ASSERT(position + static_cast<int>(sizeof(uint32_t)) <= pc_offset());
ASSERT(long_at(position) == 0); // only initialize once!
uint32_t label_loc = reinterpret_cast<uint32_t>(addr_at(bound_label.pos()));
long_at_put(position, label_loc);
}
#ifdef GENERATED_CODE_COVERAGE
static FILE* coverage_log = NULL;
......
......@@ -731,11 +731,6 @@ class Assembler : public Malloced {
// Used for inline tables, e.g., jump-tables.
void dd(uint32_t data, RelocInfo::Mode reloc_info);
// Writes the absolute address of a bound label at the given position in
// the generated code. That positions should have the relocation mode
// internal_reference!
void WriteInternalReference(int position, const Label& bound_label);
int pc_offset() const { return pc_ - buffer_; }
int current_statement_position() const { return current_statement_position_; }
int current_position() const { return current_position_; }
......
......@@ -2420,131 +2420,6 @@ void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
}
int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
return kFastSwitchMaxOverheadFactor;
}
int CodeGenerator::FastCaseSwitchMinCaseCount() {
return kFastSwitchMinCaseCount;
}
// Generate a computed jump to a switch case.
void CodeGenerator::GenerateFastCaseSwitchJumpTable(
SwitchStatement* node,
int min_index,
int range,
Label* default_label,
Vector<Label*> case_targets,
Vector<Label> case_labels) {
// Notice: Internal references, used by both the jmp instruction and
// the table entries, need to be relocated if the buffer grows. This
// prevents the forward use of Labels, since a displacement cannot
// survive relocation, and it also cannot safely be distinguished
// from a real address. Instead we put in zero-values as
// placeholders, and fill in the addresses after the labels have been
// bound.
JumpTarget setup_default;
JumpTarget is_smi;
// A non-null default label pointer indicates a default case among
// the case labels. Otherwise we use the break target as a
// "default".
JumpTarget* default_target =
(default_label == NULL) ? node->break_target() : &setup_default;
// Test whether input is a smi.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
Result switch_value = frame_->Pop();
switch_value.ToRegister();
__ test(switch_value.reg(), Immediate(kSmiTagMask));
is_smi.Branch(equal, &switch_value, taken);
// It's a heap object, not a smi or a failure. Check if it is a
// heap number.
Result temp = allocator()->Allocate();
ASSERT(temp.is_valid());
__ CmpObjectType(switch_value.reg(), HEAP_NUMBER_TYPE, temp.reg());
temp.Unuse();
default_target->Branch(not_equal);
// The switch value is a heap number. Convert it to a smi.
frame_->Push(&switch_value);
Result smi_value = frame_->CallRuntime(Runtime::kNumberToSmi, 1);
is_smi.Bind(&smi_value);
smi_value.ToRegister();
// Convert the switch value to a 0-based table index.
if (min_index != 0) {
frame_->Spill(smi_value.reg());
__ sub(Operand(smi_value.reg()), Immediate(min_index << kSmiTagSize));
}
// Go to the default case if the table index is negative or not a smi.
__ test(smi_value.reg(), Immediate(0x80000000 | kSmiTagMask));
default_target->Branch(not_equal, not_taken);
__ cmp(smi_value.reg(), range << kSmiTagSize);
default_target->Branch(greater_equal, not_taken);
// The expected frame at all the case labels is a version of the
// current one (the bidirectional entry frame, which an arbitrary
// frame of the correct height can be merged to). Keep a copy to
// restore at the start of every label. Create a jump target and
// bind it to set its entry frame properly.
JumpTarget entry_target(JumpTarget::BIDIRECTIONAL);
entry_target.Bind(&smi_value);
VirtualFrame* start_frame = new VirtualFrame(frame_);
// 0 is placeholder.
// Jump to the address at table_address + 2 * smi_value.reg().
// The target of the jump is read from table_address + 4 * switch_value.
// The Smi encoding of smi_value.reg() is 2 * switch_value.
smi_value.ToRegister();
__ jmp(Operand(smi_value.reg(), smi_value.reg(),
times_1, 0x0, RelocInfo::INTERNAL_REFERENCE));
smi_value.Unuse();
// Calculate address to overwrite later with actual address of table.
int32_t jump_table_ref = masm_->pc_offset() - sizeof(int32_t);
__ Align(4);
Label table_start;
__ bind(&table_start);
__ WriteInternalReference(jump_table_ref, table_start);
for (int i = 0; i < range; i++) {
// These are the table entries. 0x0 is the placeholder for case address.
__ dd(0x0, RelocInfo::INTERNAL_REFERENCE);
}
GenerateFastCaseSwitchCases(node, case_labels, start_frame);
// If there was a default case, we need to emit the code to match it.
if (default_label != NULL) {
if (has_valid_frame()) {
node->break_target()->Jump();
}
setup_default.Bind();
frame_->MergeTo(start_frame);
__ jmp(default_label);
DeleteFrame();
}
if (node->break_target()->is_linked()) {
node->break_target()->Bind();
}
for (int i = 0, entry_pos = table_start.pos();
i < range;
i++, entry_pos += sizeof(uint32_t)) {
if (case_targets[i] == NULL) {
__ WriteInternalReference(entry_pos,
*node->break_target()->entry_label());
} else {
__ WriteInternalReference(entry_pos, *case_targets[i]);
}
}
}
void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
ASSERT(!in_spilled_code());
Comment cmnt(masm_, "[ SwitchStatement");
......@@ -2554,10 +2429,6 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
// Compile the switch value.
Load(node->tag());
if (TryGenerateFastCaseSwitchStatement(node)) {
return;
}
ZoneList<CaseClause*>* cases = node->cases();
int length = cases->length();
CaseClause* default_clause = NULL;
......
......@@ -527,58 +527,6 @@ class CodeGenerator: public AstVisitor {
inline void GenerateMathSin(ZoneList<Expression*>* args);
inline void GenerateMathCos(ZoneList<Expression*>* args);
// Methods and constants for fast case switch statement support.
//
// Only allow fast-case switch if the range of labels is at most
// this factor times the number of case labels.
// Value is derived from comparing the size of code generated by the normal
// switch code for Smi-labels to the size of a single pointer. If code
// quality increases this number should be decreased to match.
static const int kFastSwitchMaxOverheadFactor = 5;
// Minimal number of switch cases required before we allow jump-table
// optimization.
static const int kFastSwitchMinCaseCount = 5;
// The limit of the range of a fast-case switch, as a factor of the number
// of cases of the switch. Each platform should return a value that
// is optimal compared to the default code generated for a switch statement
// on that platform.
int FastCaseSwitchMaxOverheadFactor();
// The minimal number of cases in a switch before the fast-case switch
// optimization is enabled. Each platform should return a value that
// is optimal compared to the default code generated for a switch statement
// on that platform.
int FastCaseSwitchMinCaseCount();
// Allocate a jump table and create code to jump through it.
// Should call GenerateFastCaseSwitchCases to generate the code for
// all the cases at the appropriate point.
void GenerateFastCaseSwitchJumpTable(SwitchStatement* node,
int min_index,
int range,
Label* fail_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<Label> case_labels,
VirtualFrame* start_frame);
// Fast support for constant-Smi switches.
void GenerateFastCaseSwitchStatement(SwitchStatement* node,
int min_index,
int range,
int default_index);
// Fast support for constant-Smi switches. Tests whether switch statement
// permits optimization and calls GenerateFastCaseSwitch if it does.
// Returns true if the fast-case switch was generated, and false if not.
bool TryGenerateFastCaseSwitchStatement(SwitchStatement* node);
// Methods used to indicate which source code is generated for. Source
// positions are collected by the assembler and emitted with the relocation
// information.
......
......@@ -812,11 +812,6 @@ class Assembler : public Malloced {
// Used for inline tables, e.g., jump-tables.
// void dd(uint64_t data, RelocInfo::Mode reloc_info);
// Writes the absolute address of a bound label at the given position in
// the generated code. That positions should have the relocation mode
// internal_reference!
void WriteInternalReference(int position, const Label& bound_label);
int pc_offset() const { return pc_ - buffer_; }
int current_statement_position() const { return current_statement_position_; }
int current_position() const { return current_position_; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment