Add test_b(Operand, immediate) to ia32 assembler, and use it where possible. Improve comparison to a constant one-character string. Use CmpInstanceType in more places on ia32. Add IsObjectJSObjectType and IsInstanceJSObjectType to ia32 macro assembler, using a single branch for a range test.
Review URL: http://codereview.chromium.org/2586001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4795 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
723bed3105
commit
0fc3dca698
@ -1328,6 +1328,15 @@ void Assembler::test(const Operand& op, const Immediate& imm) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::test_b(const Operand& op, uint8_t imm8) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
EMIT(0xF6);
|
||||
emit_operand(eax, op);
|
||||
EMIT(imm8);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::xor_(Register dst, int32_t imm32) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
|
@ -637,6 +637,7 @@ class Assembler : public Malloced {
|
||||
void test(Register reg, const Operand& op);
|
||||
void test_b(Register reg, const Operand& op);
|
||||
void test(const Operand& op, const Immediate& imm);
|
||||
void test_b(const Operand& op, uint8_t imm8);
|
||||
|
||||
void xor_(Register dst, int32_t imm32);
|
||||
void xor_(Register dst, const Operand& src);
|
||||
|
@ -331,10 +331,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
|
||||
// If the type of the result (stored in its map) is less than
|
||||
// FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
|
||||
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
__ j(greater_equal, &exit, not_taken);
|
||||
__ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
|
||||
__ j(above_equal, &exit, not_taken);
|
||||
|
||||
// Throw away the result of the constructor invocation and use the
|
||||
// on-stack receiver as the result.
|
||||
@ -469,11 +467,11 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ cmp(ebx, Factory::undefined_value());
|
||||
__ j(equal, &use_global_receiver);
|
||||
|
||||
// We don't use IsObjectJSObjectType here because we jump on success.
|
||||
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
__ j(below, &convert_to_object);
|
||||
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
|
||||
__ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
|
||||
__ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
|
||||
__ j(below_equal, &shift_arguments);
|
||||
|
||||
__ bind(&convert_to_object);
|
||||
@ -617,12 +615,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
|
||||
// If given receiver is already a JavaScript object then there's no
|
||||
// reason for converting it.
|
||||
// We don't use IsObjectJSObjectType here because we jump on success.
|
||||
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
__ j(less, &call_to_object);
|
||||
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
|
||||
__ j(less_equal, &push_receiver);
|
||||
__ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
|
||||
__ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
|
||||
__ j(below_equal, &push_receiver);
|
||||
|
||||
// Convert the receiver to an object.
|
||||
__ bind(&call_to_object);
|
||||
|
@ -2624,9 +2624,8 @@ void CodeGenerator::Comparison(AstNode* node,
|
||||
ASSERT(temp.is_valid());
|
||||
__ mov(temp.reg(),
|
||||
FieldOperand(operand.reg(), HeapObject::kMapOffset));
|
||||
__ movzx_b(temp.reg(),
|
||||
FieldOperand(temp.reg(), Map::kBitFieldOffset));
|
||||
__ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
|
||||
__ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
temp.Unuse();
|
||||
operand.Unuse();
|
||||
dest->Split(not_zero);
|
||||
@ -2720,11 +2719,9 @@ void CodeGenerator::Comparison(AstNode* node,
|
||||
// left_side is a sequential ASCII string.
|
||||
left_side = Result(left_reg);
|
||||
right_side = Result(right_val);
|
||||
Result temp2 = allocator_->Allocate();
|
||||
ASSERT(temp2.is_valid());
|
||||
// Test string equality and comparison.
|
||||
Label comparison_done;
|
||||
if (cc == equal) {
|
||||
Label comparison_done;
|
||||
__ cmp(FieldOperand(left_side.reg(), String::kLengthOffset),
|
||||
Immediate(Smi::FromInt(1)));
|
||||
__ j(not_equal, &comparison_done);
|
||||
@ -2732,34 +2729,25 @@ void CodeGenerator::Comparison(AstNode* node,
|
||||
static_cast<uint8_t>(String::cast(*right_val)->Get(0));
|
||||
__ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize),
|
||||
char_value);
|
||||
__ bind(&comparison_done);
|
||||
} else {
|
||||
__ mov(temp2.reg(),
|
||||
FieldOperand(left_side.reg(), String::kLengthOffset));
|
||||
__ SmiUntag(temp2.reg());
|
||||
__ sub(Operand(temp2.reg()), Immediate(1));
|
||||
Label comparison;
|
||||
// If the length is 0 then the subtraction gave -1 which compares less
|
||||
// than any character.
|
||||
__ j(negative, &comparison);
|
||||
// Otherwise load the first character.
|
||||
__ movzx_b(temp2.reg(),
|
||||
FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize));
|
||||
__ bind(&comparison);
|
||||
__ cmp(FieldOperand(left_side.reg(), String::kLengthOffset),
|
||||
Immediate(Smi::FromInt(1)));
|
||||
// If the length is 0 then the jump is taken and the flags
|
||||
// correctly represent being less than the one-character string.
|
||||
__ j(below, &comparison_done);
|
||||
// Compare the first character of the string with the
|
||||
// constant 1-character string.
|
||||
uint8_t char_value =
|
||||
static_cast<uint8_t>(String::cast(*right_val)->Get(0));
|
||||
__ cmp(Operand(temp2.reg()), Immediate(char_value));
|
||||
Label characters_were_different;
|
||||
__ j(not_equal, &characters_were_different);
|
||||
__ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize),
|
||||
char_value);
|
||||
__ j(not_equal, &comparison_done);
|
||||
// If the first character is the same then the long string sorts after
|
||||
// the short one.
|
||||
__ cmp(FieldOperand(left_side.reg(), String::kLengthOffset),
|
||||
Immediate(Smi::FromInt(1)));
|
||||
__ bind(&characters_were_different);
|
||||
}
|
||||
temp2.Unuse();
|
||||
__ bind(&comparison_done);
|
||||
left_side.Unuse();
|
||||
right_side.Unuse();
|
||||
dest->Split(cc);
|
||||
@ -4148,9 +4136,7 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
|
||||
// eax: value to be iterated over
|
||||
__ test(eax, Immediate(kSmiTagMask));
|
||||
primitive.Branch(zero);
|
||||
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
__ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
|
||||
jsobject.Branch(above_equal);
|
||||
|
||||
primitive.Bind();
|
||||
@ -6357,14 +6343,15 @@ void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
|
||||
ASSERT(map.is_valid());
|
||||
__ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined when tested with typeof.
|
||||
__ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset));
|
||||
__ test(map.reg(), Immediate(1 << Map::kIsUndetectable));
|
||||
__ test_b(FieldOperand(map.reg(), Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
destination()->false_target()->Branch(not_zero);
|
||||
__ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
|
||||
// Do a range test for JSObject type. We can't use
|
||||
// MacroAssembler::IsInstanceJSObjectType, because we are using a
|
||||
// ControlDestination, so we copy its implementation here.
|
||||
__ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset));
|
||||
__ cmp(map.reg(), FIRST_JS_OBJECT_TYPE);
|
||||
destination()->false_target()->Branch(below);
|
||||
__ cmp(map.reg(), LAST_JS_OBJECT_TYPE);
|
||||
__ sub(Operand(map.reg()), Immediate(FIRST_JS_OBJECT_TYPE));
|
||||
__ cmp(map.reg(), LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
|
||||
obj.Unuse();
|
||||
map.Unuse();
|
||||
destination()->Split(below_equal);
|
||||
@ -6400,9 +6387,8 @@ void CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) {
|
||||
ASSERT(temp.is_valid());
|
||||
__ mov(temp.reg(),
|
||||
FieldOperand(obj.reg(), HeapObject::kMapOffset));
|
||||
__ movzx_b(temp.reg(),
|
||||
FieldOperand(temp.reg(), Map::kBitFieldOffset));
|
||||
__ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
|
||||
__ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
obj.Unuse();
|
||||
temp.Unuse();
|
||||
destination()->Split(not_zero);
|
||||
@ -6476,20 +6462,16 @@ void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
|
||||
|
||||
// Check that the object is a JS object but take special care of JS
|
||||
// functions to make sure they have 'Function' as their class.
|
||||
{ Result tmp = allocator()->Allocate();
|
||||
__ mov(obj.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
|
||||
__ movzx_b(tmp.reg(), FieldOperand(obj.reg(), Map::kInstanceTypeOffset));
|
||||
__ cmp(tmp.reg(), FIRST_JS_OBJECT_TYPE);
|
||||
null.Branch(below);
|
||||
__ CmpObjectType(obj.reg(), FIRST_JS_OBJECT_TYPE, obj.reg());
|
||||
null.Branch(below);
|
||||
|
||||
// As long as JS_FUNCTION_TYPE is the last instance type and it is
|
||||
// right after LAST_JS_OBJECT_TYPE, we can avoid checking for
|
||||
// LAST_JS_OBJECT_TYPE.
|
||||
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
|
||||
ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
|
||||
__ cmp(tmp.reg(), JS_FUNCTION_TYPE);
|
||||
function.Branch(equal);
|
||||
}
|
||||
// As long as JS_FUNCTION_TYPE is the last instance type and it is
|
||||
// right after LAST_JS_OBJECT_TYPE, we can avoid checking for
|
||||
// LAST_JS_OBJECT_TYPE.
|
||||
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
|
||||
ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
|
||||
__ CmpInstanceType(obj.reg(), JS_FUNCTION_TYPE);
|
||||
function.Branch(equal);
|
||||
|
||||
// Check if the constructor in the map is a function.
|
||||
{ Result tmp = allocator()->Allocate();
|
||||
@ -7070,8 +7052,8 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
|
||||
// has no indexed interceptor.
|
||||
__ CmpObjectType(object.reg(), FIRST_JS_OBJECT_TYPE, tmp1.reg());
|
||||
deferred->Branch(below);
|
||||
__ movzx_b(tmp1.reg(), FieldOperand(tmp1.reg(), Map::kBitFieldOffset));
|
||||
__ test(tmp1.reg(), Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
|
||||
__ test_b(FieldOperand(tmp1.reg(), Map::kBitFieldOffset),
|
||||
KeyedLoadIC::kSlowCaseBitFieldMask);
|
||||
deferred->Branch(not_zero);
|
||||
|
||||
// Check the object's elements are in fast case.
|
||||
@ -8325,10 +8307,10 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
|
||||
Result temp = allocator()->Allocate();
|
||||
ASSERT(temp.is_valid());
|
||||
__ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
|
||||
__ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset));
|
||||
__ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
|
||||
__ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
destination()->false_target()->Branch(not_zero);
|
||||
__ CmpObjectType(answer.reg(), FIRST_NONSTRING_TYPE, temp.reg());
|
||||
__ CmpInstanceType(temp.reg(), FIRST_NONSTRING_TYPE);
|
||||
temp.Unuse();
|
||||
answer.Unuse();
|
||||
destination()->Split(below);
|
||||
@ -8350,9 +8332,8 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
|
||||
// It can be an undetectable object.
|
||||
frame_->Spill(answer.reg());
|
||||
__ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
|
||||
__ movzx_b(answer.reg(),
|
||||
FieldOperand(answer.reg(), Map::kBitFieldOffset));
|
||||
__ test(answer.reg(), Immediate(1 << Map::kIsUndetectable));
|
||||
__ test_b(FieldOperand(answer.reg(), Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
answer.Unuse();
|
||||
destination()->Split(not_zero);
|
||||
|
||||
@ -8379,14 +8360,15 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
|
||||
destination()->false_target()->Branch(equal);
|
||||
|
||||
// It can be an undetectable object.
|
||||
__ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset));
|
||||
__ test(map.reg(), Immediate(1 << Map::kIsUndetectable));
|
||||
__ test_b(FieldOperand(map.reg(), Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
destination()->false_target()->Branch(not_zero);
|
||||
__ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
|
||||
// Do a range test for JSObject type. We can't use
|
||||
// MacroAssembler::IsInstanceJSObjectType, because we are using a
|
||||
// ControlDestination, so we copy its implementation here.
|
||||
__ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset));
|
||||
__ cmp(map.reg(), FIRST_JS_OBJECT_TYPE);
|
||||
destination()->false_target()->Branch(below);
|
||||
__ cmp(map.reg(), LAST_JS_OBJECT_TYPE);
|
||||
__ sub(Operand(map.reg()), Immediate(FIRST_JS_OBJECT_TYPE));
|
||||
__ cmp(map.reg(), LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
|
||||
answer.Unuse();
|
||||
map.Unuse();
|
||||
destination()->Split(below_equal);
|
||||
@ -9313,20 +9295,19 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
|
||||
__ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
|
||||
|
||||
// Undetectable => false.
|
||||
__ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset));
|
||||
__ and_(ebx, 1 << Map::kIsUndetectable);
|
||||
__ test_b(FieldOperand(edx, Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
__ j(not_zero, &false_result);
|
||||
|
||||
// JavaScript object => true.
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
__ CmpInstanceType(edx, FIRST_JS_OBJECT_TYPE);
|
||||
__ j(above_equal, &true_result);
|
||||
|
||||
// String value => false iff empty.
|
||||
__ cmp(ecx, FIRST_NONSTRING_TYPE);
|
||||
__ CmpInstanceType(edx, FIRST_NONSTRING_TYPE);
|
||||
__ j(above_equal, ¬_string);
|
||||
__ mov(edx, FieldOperand(eax, String::kLengthOffset));
|
||||
ASSERT(kSmiTag == 0);
|
||||
__ test(edx, Operand(edx));
|
||||
__ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0));
|
||||
__ j(zero, &false_result);
|
||||
__ jmp(&true_result);
|
||||
|
||||
@ -11782,13 +11763,10 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
||||
// There is no test for undetectability in strict equality.
|
||||
|
||||
// Get the type of the first operand.
|
||||
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
|
||||
// If the first object is a JS object, we have done pointer comparison.
|
||||
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
|
||||
Label first_non_object;
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
|
||||
__ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
|
||||
__ j(below, &first_non_object);
|
||||
|
||||
// Return non-zero (eax is not zero)
|
||||
@ -11799,17 +11777,14 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
__ bind(&first_non_object);
|
||||
// Check for oddballs: true, false, null, undefined.
|
||||
__ cmp(ecx, ODDBALL_TYPE);
|
||||
__ CmpInstanceType(ecx, ODDBALL_TYPE);
|
||||
__ j(equal, &return_not_equal);
|
||||
|
||||
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
__ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx);
|
||||
__ j(above_equal, &return_not_equal);
|
||||
|
||||
// Check for oddballs: true, false, null, undefined.
|
||||
__ cmp(ecx, ODDBALL_TYPE);
|
||||
__ CmpInstanceType(ecx, ODDBALL_TYPE);
|
||||
__ j(equal, &return_not_equal);
|
||||
|
||||
// Fall through to the general case.
|
||||
@ -12451,12 +12426,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
|
||||
__ j(zero, &slow, not_taken);
|
||||
|
||||
// Check that the left hand is a JS object.
|
||||
__ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); // eax - object map
|
||||
__ movzx_b(ecx, FieldOperand(eax, Map::kInstanceTypeOffset)); // ecx - type
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
__ j(below, &slow, not_taken);
|
||||
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
|
||||
__ j(above, &slow, not_taken);
|
||||
__ IsObjectJSObjectType(eax, eax, edx, &slow);
|
||||
|
||||
// Get the prototype of the function.
|
||||
__ mov(edx, Operand(esp, 1 * kPointerSize)); // 1 ~ return address
|
||||
@ -12481,12 +12451,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
|
||||
// Check that the function prototype is a JS object.
|
||||
__ test(ebx, Immediate(kSmiTagMask));
|
||||
__ j(zero, &slow, not_taken);
|
||||
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
||||
__ j(below, &slow, not_taken);
|
||||
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
|
||||
__ j(above, &slow, not_taken);
|
||||
__ IsObjectJSObjectType(ebx, ecx, ecx, &slow);
|
||||
|
||||
// Register mapping:
|
||||
// eax is object map.
|
||||
@ -12921,14 +12886,12 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
||||
// ebx: length of resulting flat string as a smi
|
||||
// edx: second string
|
||||
Label non_ascii_string_add_flat_result;
|
||||
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
ASSERT(kStringEncodingMask == kAsciiStringTag);
|
||||
__ test(ecx, Immediate(kAsciiStringTag));
|
||||
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
__ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
|
||||
__ j(zero, &non_ascii_string_add_flat_result);
|
||||
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
__ test(ecx, Immediate(kAsciiStringTag));
|
||||
__ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
|
||||
__ j(zero, &string_add_runtime);
|
||||
|
||||
__ bind(&make_flat_ascii_string);
|
||||
@ -12969,8 +12932,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
||||
// edx: second string
|
||||
__ bind(&non_ascii_string_add_flat_result);
|
||||
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
|
||||
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
__ and_(ecx, kAsciiStringTag);
|
||||
__ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
|
||||
__ j(not_zero, &string_add_runtime);
|
||||
// Both strings are two byte strings. As they are short they are both
|
||||
// flat.
|
||||
|
@ -315,8 +315,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
|
||||
|
||||
// Check bit field.
|
||||
__ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
|
||||
__ test(ebx, Immediate(kSlowCaseBitFieldMask));
|
||||
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), kSlowCaseBitFieldMask);
|
||||
__ j(not_zero, &slow, not_taken);
|
||||
// Check that the object is some kind of JS object EXCEPT JS Value type.
|
||||
// In the case that the object is a value-wrapper object,
|
||||
@ -410,9 +409,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
|
||||
// Is the string a symbol?
|
||||
// ecx: key map.
|
||||
__ movzx_b(ebx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||
ASSERT(kSymbolTag != 0);
|
||||
__ test(ebx, Immediate(kIsSymbolMask));
|
||||
__ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kIsSymbolMask);
|
||||
__ j(zero, &slow, not_taken);
|
||||
|
||||
// If the receiver is a fast-case object, check the keyed lookup
|
||||
@ -564,8 +562,8 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
|
||||
// Check that the receiver does not require access checks. We need
|
||||
// to check this explicitly since this generic stub does not perform
|
||||
// map checks.
|
||||
__ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
|
||||
__ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
|
||||
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
|
||||
1 << Map::kIsAccessCheckNeeded);
|
||||
__ j(not_zero, &slow, not_taken);
|
||||
|
||||
__ CmpInstanceType(ecx, JS_OBJECT_TYPE);
|
||||
@ -754,8 +752,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
|
||||
// Check that the receiver does not require access checks. We need
|
||||
// to do this because this generic stub does not perform map checks.
|
||||
__ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
|
||||
__ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
|
||||
__ test_b(FieldOperand(edi, Map::kBitFieldOffset),
|
||||
1 << Map::kIsAccessCheckNeeded);
|
||||
__ j(not_zero, &slow, not_taken);
|
||||
// Check that the key is a smi.
|
||||
__ test(ecx, Immediate(kSmiTagMask));
|
||||
@ -872,8 +870,8 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
|
||||
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
|
||||
// Check that the receiver does not require access checks. We need
|
||||
// to do this because this generic stub does not perform map checks.
|
||||
__ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
|
||||
__ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
|
||||
__ test_b(FieldOperand(edi, Map::kBitFieldOffset),
|
||||
1 << Map::kIsAccessCheckNeeded);
|
||||
__ j(not_zero, &slow);
|
||||
// Check that the key is a smi.
|
||||
__ test(ecx, Immediate(kSmiTagMask));
|
||||
@ -1179,8 +1177,8 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
// Accessing global object: Load and invoke.
|
||||
__ bind(&global_object);
|
||||
// Check that the global object does not require access checks.
|
||||
__ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
|
||||
__ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
|
||||
__ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
|
||||
1 << Map::kIsAccessCheckNeeded);
|
||||
__ j(not_equal, &miss, not_taken);
|
||||
GenerateNormalHelper(masm, argc, true, &miss);
|
||||
|
||||
@ -1191,8 +1189,8 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
__ j(equal, &global_proxy, not_taken);
|
||||
// Check that the non-global, non-global-proxy object does not
|
||||
// require access checks.
|
||||
__ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
|
||||
__ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
|
||||
__ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
|
||||
1 << Map::kIsAccessCheckNeeded);
|
||||
__ j(not_equal, &miss, not_taken);
|
||||
__ bind(&invoke);
|
||||
GenerateNormalHelper(masm, argc, false, &miss);
|
||||
@ -1308,8 +1306,8 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||
__ j(equal, &global, not_taken);
|
||||
|
||||
// Check for non-global object that requires access check.
|
||||
__ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
|
||||
__ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
|
||||
__ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
|
||||
1 << Map::kIsAccessCheckNeeded);
|
||||
__ j(not_zero, &miss, not_taken);
|
||||
|
||||
// Search the dictionary placing the result in eax.
|
||||
|
@ -296,6 +296,25 @@ Condition MacroAssembler::IsObjectStringType(Register heap_object,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
|
||||
IsInstanceJSObjectType(map, scratch, fail);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsInstanceJSObjectType(Register map,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset));
|
||||
sub(Operand(scratch), Immediate(FIRST_JS_OBJECT_TYPE));
|
||||
cmp(scratch, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
|
||||
j(above, fail);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::FCmp() {
|
||||
if (CpuFeatures::IsSupported(CMOV)) {
|
||||
fucomip();
|
||||
|
@ -188,6 +188,18 @@ class MacroAssembler: public Assembler {
|
||||
Register map,
|
||||
Register instance_type);
|
||||
|
||||
// Check if a heap object's type is in the JSObject range, not including
|
||||
// JSFunction. The object's map will be loaded in the map register.
|
||||
// Any or all of the three registers may be the same.
|
||||
// The contents of the scratch register will always be overwritten.
|
||||
void IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
// The contents of the scratch register will be overwritten.
|
||||
void IsInstanceJSObjectType(Register map, Register scratch, Label* fail);
|
||||
|
||||
// FCmp is similar to integer cmp, but requires unsigned
|
||||
// jcc instructions (je, ja, jae, jb, jbe, je, and jz).
|
||||
void FCmp();
|
||||
|
@ -1520,9 +1520,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
__ jmp(&miss);
|
||||
} else {
|
||||
// Check that the object is a string or a symbol.
|
||||
__ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
|
||||
__ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
|
||||
__ cmp(eax, FIRST_NONSTRING_TYPE);
|
||||
__ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
|
||||
__ j(above_equal, &miss, not_taken);
|
||||
// Check that the maps starting from the prototype haven't changed.
|
||||
GenerateLoadGlobalFunctionPrototype(masm(),
|
||||
|
@ -7476,7 +7476,7 @@ Result CodeGenerator::EmitKeyedLoad() {
|
||||
__ bind(deferred->patch_site());
|
||||
// Use masm-> here instead of the double underscore macro since extra
|
||||
// coverage code can interfere with the patching. Do not use a load
|
||||
// from the root away to load null_value, since the load must be patched
|
||||
// from the root array to load null_value, since the load must be patched
|
||||
// with the expected receiver map, which is not in the root array.
|
||||
masm_->movq(kScratchRegister, Factory::null_value(),
|
||||
RelocInfo::EMBEDDED_OBJECT);
|
||||
|
Loading…
Reference in New Issue
Block a user