Make HTypeofIsAndBranch accept any representation input
when the input is known unbox number value, eliminate the dynamic check BUG= R=jkummerow@chromium.org Review URL: https://codereview.chromium.org/58923004 Patch from Weiliang Lin <weiliang.lin@intel.com>. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17834 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
775201dbd1
commit
0ca68f712e
@ -2579,6 +2579,9 @@ LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
|
||||
LInstruction* goto_instr = CheckElideControlInstruction(instr);
|
||||
if (goto_instr != NULL) return goto_instr;
|
||||
|
||||
return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
|
||||
}
|
||||
|
||||
|
@ -1184,6 +1184,20 @@ void HTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
bool HTypeofIsAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
|
||||
if (value()->representation().IsSpecialization()) {
|
||||
if (compares_number_type()) {
|
||||
*block = FirstSuccessor();
|
||||
} else {
|
||||
*block = SecondSuccessor();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*block = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void HCheckMapValue::PrintDataTo(StringStream* stream) {
|
||||
value()->PrintNameTo(stream);
|
||||
stream->Add(" ");
|
||||
|
@ -4487,20 +4487,27 @@ class HTypeofIsAndBranch V8_FINAL : public HUnaryControlInstruction {
|
||||
DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
|
||||
|
||||
Handle<String> type_literal() { return type_literal_; }
|
||||
bool compares_number_type() { return compares_number_type_; }
|
||||
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
|
||||
return Representation::Tagged();
|
||||
return Representation::None();
|
||||
}
|
||||
|
||||
virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
|
||||
|
||||
private:
|
||||
HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
|
||||
: HUnaryControlInstruction(value, NULL, NULL),
|
||||
type_literal_(type_literal) { }
|
||||
type_literal_(type_literal) {
|
||||
Heap* heap = type_literal->GetHeap();
|
||||
compares_number_type_ = type_literal->Equals(heap->number_string());
|
||||
}
|
||||
|
||||
Handle<String> type_literal_;
|
||||
bool compares_number_type_ : 1;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1114,7 +1114,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
|
||||
__ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx);
|
||||
__ j(above, &non_proxy);
|
||||
__ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
|
||||
__ Set(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
|
||||
__ bind(&non_proxy);
|
||||
__ push(ebx); // Smi
|
||||
__ push(eax); // Array
|
||||
|
@ -160,7 +160,7 @@ bool LCodeGen::GeneratePrologue() {
|
||||
|
||||
if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
|
||||
// Move state of dynamic frame alignment into edx.
|
||||
__ mov(edx, Immediate(kNoAlignmentPadding));
|
||||
__ Set(edx, Immediate(kNoAlignmentPadding));
|
||||
|
||||
Label do_not_pad, align_loop;
|
||||
STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
|
||||
@ -316,7 +316,7 @@ void LCodeGen::GenerateOsrPrologue() {
|
||||
osr_pc_offset_ = masm()->pc_offset();
|
||||
|
||||
// Move state of dynamic frame alignment into edx.
|
||||
__ mov(edx, Immediate(kNoAlignmentPadding));
|
||||
__ Set(edx, Immediate(kNoAlignmentPadding));
|
||||
|
||||
if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
|
||||
Label do_not_pad, align_loop;
|
||||
@ -6056,7 +6056,7 @@ void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
|
||||
// TODO(3095996): Get rid of this. For now, we need to make the
|
||||
// result register contain a valid pointer because it is already
|
||||
// contained in the register pointer map.
|
||||
__ mov(result, Immediate(Smi::FromInt(0)));
|
||||
__ Set(result, Immediate(Smi::FromInt(0)));
|
||||
|
||||
PushSafepointRegistersScope scope(this);
|
||||
if (instr->size()->IsRegister()) {
|
||||
@ -6178,43 +6178,48 @@ void LCodeGen::DoTypeof(LTypeof* instr) {
|
||||
|
||||
void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
|
||||
Register input = ToRegister(instr->value());
|
||||
|
||||
Condition final_branch_condition =
|
||||
EmitTypeofIs(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
|
||||
input, instr->type_literal());
|
||||
Condition final_branch_condition = EmitTypeofIs(instr, input);
|
||||
if (final_branch_condition != no_condition) {
|
||||
EmitBranch(instr, final_branch_condition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
||||
Label* false_label,
|
||||
Register input,
|
||||
Handle<String> type_name) {
|
||||
Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) {
|
||||
Label* true_label = instr->TrueLabel(chunk_);
|
||||
Label* false_label = instr->FalseLabel(chunk_);
|
||||
Handle<String> type_name = instr->type_literal();
|
||||
int left_block = instr->TrueDestination(chunk_);
|
||||
int right_block = instr->FalseDestination(chunk_);
|
||||
int next_block = GetNextEmittedBlock();
|
||||
|
||||
Label::Distance true_distance = left_block == next_block ? Label::kNear
|
||||
: Label::kFar;
|
||||
Label::Distance false_distance = right_block == next_block ? Label::kNear
|
||||
: Label::kFar;
|
||||
Condition final_branch_condition = no_condition;
|
||||
if (type_name->Equals(heap()->number_string())) {
|
||||
__ JumpIfSmi(input, true_label);
|
||||
__ JumpIfSmi(input, true_label, true_distance);
|
||||
__ cmp(FieldOperand(input, HeapObject::kMapOffset),
|
||||
factory()->heap_number_map());
|
||||
final_branch_condition = equal;
|
||||
|
||||
} else if (type_name->Equals(heap()->string_string())) {
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
__ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
|
||||
__ j(above_equal, false_label);
|
||||
__ j(above_equal, false_label, false_distance);
|
||||
__ test_b(FieldOperand(input, Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
final_branch_condition = zero;
|
||||
|
||||
} else if (type_name->Equals(heap()->symbol_string())) {
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
__ CmpObjectType(input, SYMBOL_TYPE, input);
|
||||
final_branch_condition = equal;
|
||||
|
||||
} else if (type_name->Equals(heap()->boolean_string())) {
|
||||
__ cmp(input, factory()->true_value());
|
||||
__ j(equal, true_label);
|
||||
__ j(equal, true_label, true_distance);
|
||||
__ cmp(input, factory()->false_value());
|
||||
final_branch_condition = equal;
|
||||
|
||||
@ -6224,8 +6229,8 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
||||
|
||||
} else if (type_name->Equals(heap()->undefined_string())) {
|
||||
__ cmp(input, factory()->undefined_value());
|
||||
__ j(equal, true_label);
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ j(equal, true_label, true_distance);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
// Check for undetectable objects => true.
|
||||
__ mov(input, FieldOperand(input, HeapObject::kMapOffset));
|
||||
__ test_b(FieldOperand(input, Map::kBitFieldOffset),
|
||||
@ -6234,29 +6239,29 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
||||
|
||||
} else if (type_name->Equals(heap()->function_string())) {
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
__ CmpObjectType(input, JS_FUNCTION_TYPE, input);
|
||||
__ j(equal, true_label);
|
||||
__ j(equal, true_label, true_distance);
|
||||
__ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
|
||||
final_branch_condition = equal;
|
||||
|
||||
} else if (type_name->Equals(heap()->object_string())) {
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
if (!FLAG_harmony_typeof) {
|
||||
__ cmp(input, factory()->null_value());
|
||||
__ j(equal, true_label);
|
||||
__ j(equal, true_label, true_distance);
|
||||
}
|
||||
__ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
|
||||
__ j(below, false_label);
|
||||
__ j(below, false_label, false_distance);
|
||||
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
__ j(above, false_label);
|
||||
__ j(above, false_label, false_distance);
|
||||
// Check for undetectable objects => false.
|
||||
__ test_b(FieldOperand(input, Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
final_branch_condition = zero;
|
||||
|
||||
} else {
|
||||
__ jmp(false_label);
|
||||
__ jmp(false_label, false_distance);
|
||||
}
|
||||
return final_branch_condition;
|
||||
}
|
||||
|
@ -347,10 +347,7 @@ class LCodeGen: public LCodeGenBase {
|
||||
// Emits optimized code for typeof x == "y". Modifies input register.
|
||||
// Returns the condition on which a final split to
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
Condition EmitTypeofIs(Label* true_label,
|
||||
Label* false_label,
|
||||
Register input,
|
||||
Handle<String> type_name);
|
||||
Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input);
|
||||
|
||||
// Emits optimized code for %_IsObject(x). Preserves input register.
|
||||
// Returns the condition on which a final split to
|
||||
|
@ -2656,6 +2656,8 @@ LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
|
||||
LInstruction* goto_instr = CheckElideControlInstruction(instr);
|
||||
if (goto_instr != NULL) return goto_instr;
|
||||
return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
|
||||
}
|
||||
|
||||
|
@ -5367,44 +5367,49 @@ void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
|
||||
|
||||
void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
|
||||
Register input = ToRegister(instr->value());
|
||||
|
||||
Condition final_branch_condition =
|
||||
EmitTypeofIs(instr->TrueLabel(chunk_),
|
||||
instr->FalseLabel(chunk_), input, instr->type_literal());
|
||||
Condition final_branch_condition = EmitTypeofIs(instr, input);
|
||||
if (final_branch_condition != no_condition) {
|
||||
EmitBranch(instr, final_branch_condition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
||||
Label* false_label,
|
||||
Register input,
|
||||
Handle<String> type_name) {
|
||||
Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) {
|
||||
Label* true_label = instr->TrueLabel(chunk_);
|
||||
Label* false_label = instr->FalseLabel(chunk_);
|
||||
Handle<String> type_name = instr->type_literal();
|
||||
int left_block = instr->TrueDestination(chunk_);
|
||||
int right_block = instr->FalseDestination(chunk_);
|
||||
int next_block = GetNextEmittedBlock();
|
||||
|
||||
Label::Distance true_distance = left_block == next_block ? Label::kNear
|
||||
: Label::kFar;
|
||||
Label::Distance false_distance = right_block == next_block ? Label::kNear
|
||||
: Label::kFar;
|
||||
Condition final_branch_condition = no_condition;
|
||||
if (type_name->Equals(heap()->number_string())) {
|
||||
__ JumpIfSmi(input, true_label);
|
||||
__ JumpIfSmi(input, true_label, true_distance);
|
||||
__ CompareRoot(FieldOperand(input, HeapObject::kMapOffset),
|
||||
Heap::kHeapNumberMapRootIndex);
|
||||
|
||||
final_branch_condition = equal;
|
||||
|
||||
} else if (type_name->Equals(heap()->string_string())) {
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
__ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
|
||||
__ j(above_equal, false_label);
|
||||
__ j(above_equal, false_label, false_distance);
|
||||
__ testb(FieldOperand(input, Map::kBitFieldOffset),
|
||||
Immediate(1 << Map::kIsUndetectable));
|
||||
final_branch_condition = zero;
|
||||
|
||||
} else if (type_name->Equals(heap()->symbol_string())) {
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
__ CmpObjectType(input, SYMBOL_TYPE, input);
|
||||
final_branch_condition = equal;
|
||||
|
||||
} else if (type_name->Equals(heap()->boolean_string())) {
|
||||
__ CompareRoot(input, Heap::kTrueValueRootIndex);
|
||||
__ j(equal, true_label);
|
||||
__ j(equal, true_label, true_distance);
|
||||
__ CompareRoot(input, Heap::kFalseValueRootIndex);
|
||||
final_branch_condition = equal;
|
||||
|
||||
@ -5414,8 +5419,8 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
||||
|
||||
} else if (type_name->Equals(heap()->undefined_string())) {
|
||||
__ CompareRoot(input, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, true_label);
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ j(equal, true_label, true_distance);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
// Check for undetectable objects => true.
|
||||
__ movq(input, FieldOperand(input, HeapObject::kMapOffset));
|
||||
__ testb(FieldOperand(input, Map::kBitFieldOffset),
|
||||
@ -5424,29 +5429,29 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
||||
|
||||
} else if (type_name->Equals(heap()->function_string())) {
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
__ CmpObjectType(input, JS_FUNCTION_TYPE, input);
|
||||
__ j(equal, true_label);
|
||||
__ j(equal, true_label, true_distance);
|
||||
__ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
|
||||
final_branch_condition = equal;
|
||||
|
||||
} else if (type_name->Equals(heap()->object_string())) {
|
||||
__ JumpIfSmi(input, false_label);
|
||||
__ JumpIfSmi(input, false_label, false_distance);
|
||||
if (!FLAG_harmony_typeof) {
|
||||
__ CompareRoot(input, Heap::kNullValueRootIndex);
|
||||
__ j(equal, true_label);
|
||||
__ j(equal, true_label, true_distance);
|
||||
}
|
||||
__ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
|
||||
__ j(below, false_label);
|
||||
__ j(below, false_label, false_distance);
|
||||
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
__ j(above, false_label);
|
||||
__ j(above, false_label, false_distance);
|
||||
// Check for undetectable objects => false.
|
||||
__ testb(FieldOperand(input, Map::kBitFieldOffset),
|
||||
Immediate(1 << Map::kIsUndetectable));
|
||||
final_branch_condition = zero;
|
||||
|
||||
} else {
|
||||
__ jmp(false_label);
|
||||
__ jmp(false_label, false_distance);
|
||||
}
|
||||
|
||||
return final_branch_condition;
|
||||
|
@ -287,10 +287,7 @@ class LCodeGen: public LCodeGenBase {
|
||||
// Emits optimized code for typeof x == "y". Modifies input register.
|
||||
// Returns the condition on which a final split to
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
Condition EmitTypeofIs(Label* true_label,
|
||||
Label* false_label,
|
||||
Register input,
|
||||
Handle<String> type_name);
|
||||
Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input);
|
||||
|
||||
// Emits optimized code for %_IsObject(x). Preserves input register.
|
||||
// Returns the condition on which a final split to
|
||||
|
@ -2504,6 +2504,9 @@ LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
|
||||
LInstruction* goto_instr = CheckElideControlInstruction(instr);
|
||||
if (goto_instr != NULL) return goto_instr;
|
||||
|
||||
return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user