}
-void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if is_string(");
- InputAt(0)->PrintTo(stream);
- stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_smi(");
InputAt(0)->PrintTo(stream);
}
-void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if compare_generic(");
- InputAt(0)->PrintTo(stream);
- InputAt(1)->PrintTo(stream);
- stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_instance_type(");
InputAt(0)->PrintTo(stream);
}
-LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
- ASSERT(instr->value()->representation().IsTagged());
- LOperand* temp = TempRegister();
- return new LIsStringAndBranch(UseRegisterAtStart(instr->value()), temp);
-}
-
-
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
return new LIsSmiAndBranch(Use(instr->value()));
}
-LInstruction* LChunkBuilder::DoStringCompareAndBranch(
- HStringCompareAndBranch* instr) {
-
- ASSERT(instr->left()->representation().IsTagged());
- ASSERT(instr->right()->representation().IsTagged());
- LOperand* left = UseFixed(instr->left(), r1);
- LOperand* right = UseFixed(instr->right(), r0);
- LStringCompareAndBranch* result = new LStringCompareAndBranch(left, right);
- return MarkAsCall(result, instr);
-}
-
-
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
HHasInstanceTypeAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
V(IsConstructCallAndBranch) \
V(IsNilAndBranch) \
V(IsObjectAndBranch) \
- V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(StringCompareAndBranch) \
V(JSArrayLength) \
V(Label) \
V(LazyBailout) \
};
-class LIsStringAndBranch: public LControlInstruction<1, 1> {
- public:
- LIsStringAndBranch(LOperand* value, LOperand* temp) {
- inputs_[0] = value;
- temps_[0] = temp;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LIsSmiAndBranch: public LControlInstruction<1, 0> {
public:
explicit LIsSmiAndBranch(LOperand* value) {
};
-class LStringCompareAndBranch: public LControlInstruction<2, 0> {
- public:
- LStringCompareAndBranch(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
- "compare-generic-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
-
- Token::Value op() const { return hydrogen()->token(); }
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
public:
explicit LHasInstanceTypeAndBranch(LOperand* value) {
}
-Condition LCodeGen::EmitIsString(Register input,
- Register temp1,
- Label* is_not_string,
- Label* is_string) {
- __ JumpIfSmi(input, is_not_string);
- __ CompareObjectType(input, temp1, temp1, FIRST_NONSTRING_TYPE);
-
- return lt;
-}
-
-
-void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
- Register reg = ToRegister(instr->InputAt(0));
- Register temp1 = ToRegister(instr->TempAt(0));
-
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
- Label* true_label = chunk_->GetAssemblyLabel(true_block);
- Label* false_label = chunk_->GetAssemblyLabel(false_block);
-
- Condition true_cond =
- EmitIsString(reg, temp1, false_label, true_label);
-
- EmitBranch(true_block, false_block, true_cond);
-}
-
-
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
}
-static Condition ComputeCompareCondition(Token::Value op) {
- switch (op) {
- case Token::EQ_STRICT:
- case Token::EQ:
- return eq;
- case Token::LT:
- return lt;
- case Token::GT:
- return gt;
- case Token::LTE:
- return le;
- case Token::GTE:
- return ge;
- default:
- UNREACHABLE();
- return kNoCondition;
- }
-}
-
-
-void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
- Token::Value op = instr->op();
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
-
- Handle<Code> ic = CompareIC::GetUninitialized(op);
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- __ cmp(r0, Operand(0)); // This instruction also signals no smi code inlined.
-
- Condition condition = ComputeCompareCondition(op);
-
- EmitBranch(true_block, false_block, condition);
-}
-
-
static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from();
InstanceType to = instr->to();
}
+static Condition ComputeCompareCondition(Token::Value op) {
+ switch (op) {
+ case Token::EQ_STRICT:
+ case Token::EQ:
+ return eq;
+ case Token::LT:
+ return lt;
+ case Token::GT:
+ return gt;
+ case Token::LTE:
+ return le;
+ case Token::GTE:
+ return ge;
+ default:
+ UNREACHABLE();
+ return kNoCondition;
+ }
+}
+
+
void LCodeGen::DoCmpT(LCmpT* instr) {
Token::Value op = instr->op();
Label* is_not_object,
Label* is_object);
- // Emits optimized code for %_IsString(x). Preserves input register.
- // Returns the condition on which a final split to
- // true and false label should be made, to optimize fallthrough.
- Condition EmitIsString(Register input,
- Register temp1,
- Label* is_not_object,
- Label* is_object);
-
// Emits optimized code for %_IsConstructCall().
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp1, Register temp2);
TypeInfo info = oracle->SwitchType(this);
if (info.IsSmi()) {
compare_type_ = SMI_ONLY;
- } else if (info.IsSymbol()) {
- compare_type_ = SYMBOL_ONLY;
- } else if (info.IsNonSymbol()) {
- compare_type_ = STRING_ONLY;
} else if (info.IsNonPrimitive()) {
compare_type_ = OBJECT_ONLY;
} else {
// Type feedback information.
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
bool IsSmiCompare() { return compare_type_ == SMI_ONLY; }
- bool IsSymbolCompare() { return compare_type_ == SYMBOL_ONLY; }
- bool IsStringCompare() { return compare_type_ == STRING_ONLY; }
bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; }
private:
Label body_target_;
ZoneList<Statement*>* statements_;
int position_;
- enum CompareTypeFeedback {
- NONE,
- SMI_ONLY,
- SYMBOL_ONLY,
- STRING_ONLY,
- OBJECT_ONLY
- };
+ enum CompareTypeFeedback { NONE, SMI_ONLY, OBJECT_ONLY };
CompareTypeFeedback compare_type_;
int compare_id_;
int entry_id_;
}
-void HStringCompareAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add(Token::Name(token()));
- stream->Add(" ");
- HControlInstruction::PrintDataTo(stream);
-}
-
-
void HCompareIDAndBranch::PrintDataTo(StringStream* stream) {
stream->Add(Token::Name(token()));
stream->Add(" ");
V(IsConstructCallAndBranch) \
V(IsNilAndBranch) \
V(IsObjectAndBranch) \
- V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(StringCompareAndBranch) \
V(JSArrayLength) \
V(LeaveInlined) \
V(LoadContextSlot) \
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
};
-class HIsStringAndBranch: public HUnaryControlInstruction {
- public:
- explicit HIsStringAndBranch(HValue* value)
- : HUnaryControlInstruction(value, NULL, NULL) { }
-
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
- }
-
- DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
-};
-
class HIsSmiAndBranch: public HUnaryControlInstruction {
public:
};
-class HStringCompareAndBranch: public HTemplateControlInstruction<2, 3> {
- public:
- HStringCompareAndBranch(HValue* context,
- HValue* left,
- HValue* right,
- Token::Value token)
- : token_(token) {
- ASSERT(Token::IsCompareOp(token));
- SetOperandAt(0, context);
- SetOperandAt(1, left);
- SetOperandAt(2, right);
- set_representation(Representation::Tagged());
- }
-
- HValue* context() { return OperandAt(0); }
- HValue* left() { return OperandAt(1); }
- HValue* right() { return OperandAt(2); }
- Token::Value token() const { return token_; }
-
- virtual void PrintDataTo(StringStream* stream);
-
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
- }
-
- Representation GetInputRepresentation() const {
- return Representation::Tagged();
- }
-
- DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
-
- private:
- Token::Value token_;
-};
-
-
class HIsConstructCallAndBranch: public HTemplateControlInstruction<2, 0> {
public:
virtual Representation RequiredInputRepresentation(int index) {
Postorder(it.Current(), visited, order, block);
}
} else {
- ASSERT(block->IsFinished());
for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) {
Postorder(it.Current(), visited, order, loop_header);
}
return Bailout("SwitchStatement: too many clauses");
}
- HValue* context = environment()->LookupContext();
-
CHECK_ALIVE(VisitForValue(stmt->tag()));
AddSimulate(stmt->EntryId());
HValue* tag_value = Pop();
HBasicBlock* first_test_block = current_block();
- SwitchType switch_type = UNKNOWN_SWITCH;
-
- // 1. Extract clause type
+ // 1. Build all the tests, with dangling true branches. Unconditionally
+ // deoptimize if we encounter a non-smi comparison.
for (int i = 0; i < clause_count; ++i) {
CaseClause* clause = clauses->at(i);
if (clause->is_default()) continue;
-
- if (switch_type == UNKNOWN_SWITCH) {
- if (clause->label()->IsSmiLiteral()) {
- switch_type = SMI_SWITCH;
- } else if (clause->label()->IsStringLiteral()) {
- switch_type = STRING_SWITCH;
- } else {
- return Bailout("SwitchStatement: non-literal switch label");
- }
- } else if ((switch_type == STRING_SWITCH &&
- !clause->label()->IsStringLiteral()) ||
- (switch_type == SMI_SWITCH &&
- !clause->label()->IsSmiLiteral())) {
- return Bailout("SwitchStatemnt: mixed label types are not supported");
+ if (!clause->label()->IsSmiLiteral()) {
+ return Bailout("SwitchStatement: non-literal switch label");
}
- }
-
- HUnaryControlInstruction* string_check = NULL;
- HBasicBlock* not_string_block = NULL;
-
- // Test switch's tag value if all clauses are string literals
- if (switch_type == STRING_SWITCH) {
- string_check = new(zone()) HIsStringAndBranch(tag_value);
- first_test_block = graph()->CreateBasicBlock();
- not_string_block = graph()->CreateBasicBlock();
- string_check->SetSuccessorAt(0, first_test_block);
- string_check->SetSuccessorAt(1, not_string_block);
- current_block()->Finish(string_check);
-
- set_current_block(first_test_block);
- }
-
- // 2. Build all the tests, with dangling true branches
- for (int i = 0; i < clause_count; ++i) {
- CaseClause* clause = clauses->at(i);
- if (clause->is_default()) continue;
-
- if (switch_type == SMI_SWITCH) {
- clause->RecordTypeFeedback(oracle());
+ // Unconditionally deoptimize on the first non-smi compare.
+ clause->RecordTypeFeedback(oracle());
+ if (!clause->IsSmiCompare()) {
+ // Finish with deoptimize and add uses of enviroment values to
+ // account for invisible uses.
+ current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
+ set_current_block(NULL);
+ break;
}
- // Generate a compare and branch.
+ // Otherwise generate a compare and branch.
CHECK_ALIVE(VisitForValue(clause->label()));
HValue* label_value = Pop();
-
- HBasicBlock* next_test_block = graph()->CreateBasicBlock();
+ HCompareIDAndBranch* compare =
+ new(zone()) HCompareIDAndBranch(tag_value,
+ label_value,
+ Token::EQ_STRICT);
+ compare->SetInputRepresentation(Representation::Integer32());
HBasicBlock* body_block = graph()->CreateBasicBlock();
-
- HControlInstruction* compare;
-
- if (switch_type == SMI_SWITCH) {
- if (!clause->IsSmiCompare()) {
- // Finish with deoptimize and add uses of enviroment values to
- // account for invisible uses.
- current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
- set_current_block(NULL);
- break;
- }
-
- HCompareIDAndBranch* compare_ =
- new(zone()) HCompareIDAndBranch(tag_value,
- label_value,
- Token::EQ_STRICT);
- compare_->SetInputRepresentation(Representation::Integer32());
- compare = compare_;
- } else {
- compare = new(zone()) HStringCompareAndBranch(context, tag_value,
- label_value,
- Token::EQ_STRICT);
- }
-
+ HBasicBlock* next_test_block = graph()->CreateBasicBlock();
compare->SetSuccessorAt(0, body_block);
compare->SetSuccessorAt(1, next_test_block);
current_block()->Finish(compare);
-
set_current_block(next_test_block);
}
// exit. This block is NULL if we deoptimized.
HBasicBlock* last_block = current_block();
- if (not_string_block != NULL) {
- last_block = CreateJoin(last_block, not_string_block, stmt->ExitId());
- }
-
- // 3. Loop over the clauses and the linked list of tests in lockstep,
+ // 2. Loop over the clauses and the linked list of tests in lockstep,
// translating the clause bodies.
HBasicBlock* curr_test_block = first_test_block;
HBasicBlock* fall_through_block = NULL;
-
BreakAndContinueInfo break_info(stmt);
{ BreakAndContinueScope push(&break_info, this);
for (int i = 0; i < clause_count; ++i) {
class HGraphBuilder: public AstVisitor {
public:
enum BreakType { BREAK, CONTINUE };
- enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH };
// A class encapsulating (lazily-allocated) break and continue blocks for
// a breakable statement. Separated from BreakAndContinueScope so that it
}
-Condition LCodeGen::EmitIsString(Register input,
- Register temp1,
- Label* is_not_string,
- Label* is_string) {
- __ JumpIfSmi(input, is_not_string);
-
- Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
-
- return cond;
-}
-
-
-void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
- Register reg = ToRegister(instr->InputAt(0));
- Register temp = ToRegister(instr->TempAt(0));
-
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
- Label* true_label = chunk_->GetAssemblyLabel(true_block);
- Label* false_label = chunk_->GetAssemblyLabel(false_block);
-
- Condition true_cond = EmitIsString(reg, temp, false_label, true_label);
-
- EmitBranch(true_block, false_block, true_cond);
-}
-
-
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
Operand input = ToOperand(instr->InputAt(0));
}
-static Condition ComputeCompareCondition(Token::Value op) {
- switch (op) {
- case Token::EQ_STRICT:
- case Token::EQ:
- return equal;
- case Token::LT:
- return less;
- case Token::GT:
- return greater;
- case Token::LTE:
- return less_equal;
- case Token::GTE:
- return greater_equal;
- default:
- UNREACHABLE();
- return no_condition;
- }
-}
-
-
-void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
- Token::Value op = instr->op();
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
-
- Handle<Code> ic = CompareIC::GetUninitialized(op);
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
-
- Condition condition = ComputeCompareCondition(op);
- __ test(eax, Operand(eax));
-
- EmitBranch(true_block, false_block, condition);
-}
-
-
static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from();
InstanceType to = instr->to();
}
+static Condition ComputeCompareCondition(Token::Value op) {
+ switch (op) {
+ case Token::EQ_STRICT:
+ case Token::EQ:
+ return equal;
+ case Token::LT:
+ return less;
+ case Token::GT:
+ return greater;
+ case Token::LTE:
+ return less_equal;
+ case Token::GTE:
+ return greater_equal;
+ default:
+ UNREACHABLE();
+ return no_condition;
+ }
+}
+
+
void LCodeGen::DoCmpT(LCmpT* instr) {
Token::Value op = instr->op();
Label* is_not_object,
Label* is_object);
- // Emits optimized code for %_IsString(x). Preserves input register.
- // Returns the condition on which a final split to
- // true and false label should be made, to optimize fallthrough.
- Condition EmitIsString(Register input,
- Register temp1,
- Label* is_not_string,
- Label* is_string);
-
// Emits optimized code for %_IsConstructCall().
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp);
}
-void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if is_string(");
- InputAt(0)->PrintTo(stream);
- stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_smi(");
InputAt(0)->PrintTo(stream);
}
-void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if compare_generic(");
- InputAt(1)->PrintTo(stream);
- InputAt(2)->PrintTo(stream);
- stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_instance_type(");
InputAt(0)->PrintTo(stream);
}
-LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
- ASSERT(instr->value()->representation().IsTagged());
- LOperand* temp = TempRegister();
- return new LIsStringAndBranch(UseRegister(instr->value()), temp);
-}
-
-
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
return new(zone()) LIsSmiAndBranch(Use(instr->value()));
}
-LInstruction* LChunkBuilder::DoStringCompareAndBranch(
- HStringCompareAndBranch* instr) {
- ASSERT(instr->left()->representation().IsTagged());
- ASSERT(instr->right()->representation().IsTagged());
- LOperand* context = UseFixed(instr->context(), esi);
- LOperand* left = UseFixed(instr->left(), edx);
- LOperand* right = UseFixed(instr->right(), eax);
-
- LStringCompareAndBranch* result = new
- LStringCompareAndBranch(context, left, right);
-
- return MarkAsCall(result, instr);
-}
-
-
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
HHasInstanceTypeAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
V(IsConstructCallAndBranch) \
V(IsNilAndBranch) \
V(IsObjectAndBranch) \
- V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(StringCompareAndBranch) \
V(JSArrayLength) \
V(Label) \
V(LazyBailout) \
};
-class LIsStringAndBranch: public LControlInstruction<1, 1> {
- public:
- LIsStringAndBranch(LOperand* value, LOperand* temp) {
- inputs_[0] = value;
- temps_[0] = temp;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LIsSmiAndBranch: public LControlInstruction<1, 0> {
public:
explicit LIsSmiAndBranch(LOperand* value) {
};
-class LStringCompareAndBranch: public LControlInstruction<3, 0> {
- public:
- LStringCompareAndBranch(LOperand* context, LOperand* left, LOperand* right) {
- inputs_[0] = context;
- inputs_[1] = left;
- inputs_[2] = right;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
- "compare-generic-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
-
- virtual void PrintDataTo(StringStream* stream);
-
- Token::Value op() const { return hydrogen()->token(); }
-};
-
-
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 1> {
public:
LHasInstanceTypeAndBranch(LOperand* value, LOperand* temp) {
}
-Condition LCodeGen::EmitIsString(Register input,
- Register temp1,
- Label* is_not_string,
- Label* is_string) {
- __ JumpIfSmi(input, is_not_string);
- __ GetObjectType(input, temp1, temp1);
- __ Branch(is_not_string, ge, temp1, Operand(FIRST_NONSTRING_TYPE));
-
- return lt;
-}
-
-
-void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
- Register reg = ToRegister(instr->InputAt(0));
- Register temp1 = ToRegister(instr->TempAt(0));
- Register temp2 = scratch0();
-
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
- Label* true_label = chunk_->GetAssemblyLabel(true_block);
- Label* false_label = chunk_->GetAssemblyLabel(false_block);
-
- Condition true_cond =
- EmitIsString(reg, temp1, false_label, true_label);
-
- EmitBranch(true_block, false_block, true_cond, temp2,
- Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
-}
-
-
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
}
-static Condition ComputeCompareCondition(Token::Value op) {
- switch (op) {
- case Token::EQ_STRICT:
- case Token::EQ:
- return eq;
- case Token::LT:
- return lt;
- case Token::GT:
- return gt;
- case Token::LTE:
- return le;
- case Token::GTE:
- return ge;
- default:
- UNREACHABLE();
- return kNoCondition;
- }
-}
-
-
-void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
- Token::Value op = instr->op();
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
-
- Handle<Code> ic = CompareIC::GetUninitialized(op);
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- // On MIPS there is no need for a "no inlined smi code" marker (nop).
-
- Condition condition = ComputeCompareCondition(op);
-
- EmitBranch(true_block, false_block, condition, at,
- Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
-}
-
-
static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from();
InstanceType to = instr->to();
}
+static Condition ComputeCompareCondition(Token::Value op) {
+ switch (op) {
+ case Token::EQ_STRICT:
+ case Token::EQ:
+ return eq;
+ case Token::LT:
+ return lt;
+ case Token::GT:
+ return gt;
+ case Token::LTE:
+ return le;
+ case Token::GTE:
+ return ge;
+ default:
+ UNREACHABLE();
+ return kNoCondition;
+ }
+}
+
+
void LCodeGen::DoCmpT(LCmpT* instr) {
Token::Value op = instr->op();
Label* is_not_object,
Label* is_object);
- // Emits optimized code for %_IsString(x). Preserves input register.
- // Returns the condition on which a final split to
- // true and false label should be made, to optimize fallthrough.
- Condition EmitIsString(Register input,
- Register temp1,
- Label* is_not_object,
- Label* is_object);
-
// Emits optimized code for %_IsConstructCall().
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp1, Register temp2);
}
-void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if is_string(");
- InputAt(0)->PrintTo(stream);
- stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_smi(");
InputAt(0)->PrintTo(stream);
}
-void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if compare_generic(");
- InputAt(0)->PrintTo(stream);
- InputAt(1)->PrintTo(stream);
- stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_instance_type(");
InputAt(0)->PrintTo(stream);
LOperand* left = UseFixed(instr->left(), a1);
LOperand* right = UseFixed(instr->right(), a0);
LCmpT* result = new LCmpT(left, right);
- return AssignEnvironment(MarkAsCall(DefineFixed(result, v0), instr));
+ return MarkAsCall(DefineFixed(result, v0), instr);
}
}
-LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
- ASSERT(instr->value()->representation().IsTagged());
- LOperand* temp = TempRegister();
- return new LIsStringAndBranch(UseRegisterAtStart(instr->value()), temp);
-}
-
-
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
return new LIsSmiAndBranch(Use(instr->value()));
}
-LInstruction* LChunkBuilder::DoStringCompareAndBranch(
- HStringCompareAndBranch* instr) {
- Representation r = instr->GetInputRepresentation();
- ASSERT(instr->left()->representation().IsTagged());
- ASSERT(instr->right()->representation().IsTagged());
- LOperand* left = UseFixed(instr->left(), a1);
- LOperand* right = UseFixed(instr->right(), a0);
- LStringCompareAndBranch* result = new LStringCompareAndBranch(left, right);
- return MarkAsCall(result, instr);
-}
-
-
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
HHasInstanceTypeAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
V(IsConstructCallAndBranch) \
V(IsNilAndBranch) \
V(IsObjectAndBranch) \
- V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(StringCompareAndBranch) \
V(JSArrayLength) \
V(Label) \
V(LazyBailout) \
};
-class LIsStringAndBranch: public LControlInstruction<1, 1> {
- public:
- LIsStringAndBranch(LOperand* value, LOperand* temp) {
- inputs_[0] = value;
- temps_[0] = temp;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LIsSmiAndBranch: public LControlInstruction<1, 0> {
public:
explicit LIsSmiAndBranch(LOperand* value) {
};
-class LStringCompareAndBranch: public LControlInstruction<2, 0> {
- public:
- LStringCompareAndBranch(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
- "compare-generic-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
-
- Token::Value op() const { return hydrogen()->token(); }
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
public:
explicit LHasInstanceTypeAndBranch(LOperand* value) {
return unknown;
case CompareIC::SMIS:
return TypeInfo::Smi();
- case CompareIC::STRINGS:
- return TypeInfo::String();
- case CompareIC::SYMBOLS:
- return TypeInfo::Symbol();
case CompareIC::HEAP_NUMBERS:
return TypeInfo::Number();
case CompareIC::OBJECTS:
static TypeInfo Integer32() { return TypeInfo(kInteger32); }
// We know it's a Smi.
static TypeInfo Smi() { return TypeInfo(kSmi); }
- // We know it's a Symbol.
- static TypeInfo Symbol() { return TypeInfo(kSymbol); }
// We know it's a heap number.
static TypeInfo Double() { return TypeInfo(kDouble); }
// We know it's a string.
return ((type_ & kSmi) == kSmi);
}
- inline bool IsSymbol() {
- ASSERT(type_ != kUninitialized);
- return ((type_ & kSymbol) == kSymbol);
- }
-
- inline bool IsNonSymbol() {
- ASSERT(type_ != kUninitialized);
- return ((type_ & kSymbol) == kString);
- }
-
inline bool IsInteger32() {
ASSERT(type_ != kUninitialized);
return ((type_ & kInteger32) == kInteger32);
case kNumber: return "Number";
case kInteger32: return "Integer32";
case kSmi: return "Smi";
- case kSymbol: return "Symbol";
case kDouble: return "Double";
case kString: return "String";
case kNonPrimitive: return "Object";
kSmi = 0x17, // 0010111
kDouble = 0x19, // 0011001
kString = 0x30, // 0110000
- kSymbol = 0x32, // 0110010
kNonPrimitive = 0x40, // 1000000
kUninitialized = 0x7f // 1111111
};
}
-Condition LCodeGen::EmitIsString(Register input,
- Label* is_not_string,
- Label* is_string) {
-
- __ JumpIfSmi(input, is_not_string);
- __ CmpObjectType(input, FIRST_NONSTRING_TYPE, rcx);
-
- return below;
-}
-
-
-void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
- Register reg = ToRegister(instr->InputAt(0));
-
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
- Label* true_label = chunk_->GetAssemblyLabel(true_block);
- Label* false_label = chunk_->GetAssemblyLabel(false_block);
-
- Condition true_cond = EmitIsString(reg, false_label, true_label);
-
- EmitBranch(true_block, false_block, true_cond);
-}
-
-
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
}
-void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
- Token::Value op = instr->op();
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
-
- Handle<Code> ic = CompareIC::GetUninitialized(op);
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
-
- Condition condition = TokenToCondition(op, false);
- __ testq(rax, rax);
-
- EmitBranch(true_block, false_block, condition);
-}
-
-
static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from();
InstanceType to = instr->to();
Label* is_not_object,
Label* is_object);
- // Emits optimized code for %_IsString(x). Preserves input register.
- // Returns the condition on which a final split to
- // true and false label should be made, to optimize fallthrough.
- Condition EmitIsString(Register input,
- Label* is_not_object,
- Label* is_object);
-
// Emits optimized code for %_IsConstructCall().
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp);
}
-void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if is_string(");
- InputAt(0)->PrintTo(stream);
- stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_smi(");
InputAt(0)->PrintTo(stream);
}
-void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if compare_generic(");
- InputAt(0)->PrintTo(stream);
- InputAt(1)->PrintTo(stream);
- stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_instance_type(");
InputAt(0)->PrintTo(stream);
LOperand* left = UseFixed(instr->left(), rdx);
LOperand* right = UseFixed(instr->right(), rax);
LCmpT* result = new LCmpT(left, right);
- return AssignEnvironment(MarkAsCall(DefineFixed(result, rax), instr));
+ return MarkAsCall(DefineFixed(result, rax), instr);
}
}
-LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
- ASSERT(instr->value()->representation().IsTagged());
- return new LIsStringAndBranch(UseRegisterAtStart(instr->value()));
-}
-
-
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
return new LIsSmiAndBranch(Use(instr->value()));
}
-LInstruction* LChunkBuilder::DoStringCompareAndBranch(
- HStringCompareAndBranch* instr) {
-
- ASSERT(instr->left()->representation().IsTagged());
- ASSERT(instr->right()->representation().IsTagged());
- LOperand* left = UseFixed(instr->left(), rdx);
- LOperand* right = UseFixed(instr->right(), rax);
- LStringCompareAndBranch* result = new LStringCompareAndBranch(left, right);
-
- return MarkAsCall(result, instr);
-}
-
-
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
HHasInstanceTypeAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
V(IsConstructCallAndBranch) \
V(IsNilAndBranch) \
V(IsObjectAndBranch) \
- V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(StringCompareAndBranch) \
V(JSArrayLength) \
V(Label) \
V(LazyBailout) \
};
-class LIsStringAndBranch: public LControlInstruction<1, 0> {
- public:
- explicit LIsStringAndBranch(LOperand* value) {
- inputs_[0] = value;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LIsSmiAndBranch: public LControlInstruction<1, 0> {
public:
explicit LIsSmiAndBranch(LOperand* value) {
};
-class LStringCompareAndBranch: public LControlInstruction<2, 0> {
- public:
- explicit LStringCompareAndBranch(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
- "compare-generic-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
-
- virtual void PrintDataTo(StringStream* stream);
-
- Token::Value op() const { return hydrogen()->token(); }
-};
-
-
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
public:
explicit LHasInstanceTypeAndBranch(LOperand* value) {
assertEquals(3, f4(2), "fallthrough-switch.2");
assertEquals(5, f4(3), "fallthrough-switch.3");
-function f4_string(tag, x) {
- switch(tag) {
- case 'zero':
- x++;
- case 'two':
- x++;
- }
- return x;
-}
-
-// Symbols
-assertEquals(2, f4_string('zero', 0), "fallthrough-string-switch.0");
-assertEquals(1, f4_string('one', 1), "fallthrough-string-switch.1");
-assertEquals(3, f4_string('two', 2), "fallthrough-string-switch.2");
-
-// Strings
-assertEquals(2, f4_string('_zero'.slice(1), 0), "fallthrough-string-switch.3");
-assertEquals(1, f4_string('_one'.slice(1), 1), "fallthrough-string-switch.4");
-assertEquals(3, f4_string('_two'.slice(1), 2), "fallthrough-string-switch.5");
-
-// Oddball
-assertEquals(3, f4_string(null, 3), "fallthrough-string-switch.6");
-
-// Test for regression
-function regress_string(value) {
- var json = 1;
- switch (typeof value) {
- case 'object':
- break;
-
- default:
-
- }
- return json;
-};
-assertEquals(1, regress_string('object'), 'regression-string');
function f5(x) {
switch(x) {