[runtime] Drop FIRST/LAST_NONCALLABLE_SPEC_OBJECT instance type range.
The FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range was accidentially used in field type tracking, where we should check for JSReceiver instead (there's no need to exclude JSProxy or JSFunction from tracking). And the use in %_ClassOf was actually wrong and didn't match the C++ implementation in JSReceiver::class_name() anymore. Now it's consistent again. R=yangguo@chromium.org BUG=chromium:535408 LOG=n Review URL: https://codereview.chromium.org/1535523003 . Cr-Commit-Position: refs/heads/master@{#32926}
This commit is contained in:
parent
d0cfc9bfb8
commit
aafc3e5484
@ -1434,32 +1434,6 @@ void MacroAssembler::IsObjectNameType(Register object,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
Ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
|
||||
IsInstanceJSObjectType(map, scratch, fail);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsInstanceJSObjectType(Register map,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
Ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
|
||||
// If cmp result is lt, the following ccmp will clear all flags.
|
||||
// Z == 0, N == V implies gt condition.
|
||||
Cmp(scratch, FIRST_JS_RECEIVER_TYPE);
|
||||
Ccmp(scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE, NoFlag, ge);
|
||||
|
||||
// If we didn't get a valid label object just fall through and leave the
|
||||
// flags updated.
|
||||
if (fail != NULL) {
|
||||
B(gt, fail);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectJSStringType(Register object,
|
||||
Register type,
|
||||
Label* not_string,
|
||||
|
@ -1466,20 +1466,6 @@ class MacroAssembler : public Assembler {
|
||||
// Fall-through if the object was a string and jump on fail otherwise.
|
||||
inline void IsObjectNameType(Register object, Register type, Label* fail);
|
||||
|
||||
inline void IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
// Check the instance type in the given map to see if it corresponds to a
|
||||
// JS object type. Jump to the fail label if this is not the case and fall
|
||||
// through otherwise. However if fail label is NULL, no branch will be
|
||||
// performed and the flag will be updated. You can test the flag for "le"
|
||||
// condition to test if it is a valid JS object type.
|
||||
inline void IsInstanceJSObjectType(Register map,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
// Load and check the instance type of an object for being a string.
|
||||
// Loads the type into the second argument register.
|
||||
// The object and type arguments can be the same register; in that case it
|
||||
|
@ -2538,36 +2538,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
__ CompareObjectType(input, temp, temp2, JS_FUNCTION_TYPE);
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
// Assuming the following assertions, we can use the same compares to test
|
||||
// for both being a function type and being in the object type range.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CompareObjectType(input, temp, temp2, FIRST_JS_RECEIVER_TYPE);
|
||||
__ b(lt, is_false);
|
||||
__ cmp(temp2, Operand(LAST_JS_RECEIVER_TYPE));
|
||||
__ b(eq, is_true);
|
||||
} else {
|
||||
// Faster code path to avoid two compares: subtract lower bound from the
|
||||
// actual type and do a signed compare with the width of the type range.
|
||||
__ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset));
|
||||
__ ldrb(temp2, FieldMemOperand(temp, Map::kInstanceTypeOffset));
|
||||
__ sub(temp2, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
__ cmp(temp2,
|
||||
Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_JS_RECEIVER_TYPE));
|
||||
__ b(gt, is_false);
|
||||
__ b(eq, is_false);
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Check if the constructor in the map is a function.
|
||||
Register instance_type = ip;
|
||||
__ GetMapConstructor(temp, temp, temp2, instance_type);
|
||||
|
||||
// Objects with a non-function constructor have class 'Object'.
|
||||
__ cmp(instance_type, Operand(JS_FUNCTION_TYPE));
|
||||
if (class_name->IsOneByteEqualTo(STATIC_CHAR_VECTOR("Object"))) {
|
||||
if (String::Equals(isolate()->factory()->Object_string(), class_name)) {
|
||||
__ b(ne, is_true);
|
||||
} else {
|
||||
__ b(ne, is_false);
|
||||
|
@ -2259,24 +2259,13 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
|
||||
__ JumpIfSmi(input, false_label);
|
||||
|
||||
Register map = scratch2;
|
||||
__ CompareObjectType(input, map, scratch1, JS_FUNCTION_TYPE);
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
// Assuming the following assertions, we can use the same compares to test
|
||||
// for both being a function type and being in the object type range.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
|
||||
// We expect CompareObjectType to load the object instance type in scratch1.
|
||||
__ CompareObjectType(input, map, scratch1, FIRST_JS_RECEIVER_TYPE);
|
||||
__ B(lt, false_label);
|
||||
__ Cmp(scratch1, LAST_JS_RECEIVER_TYPE);
|
||||
__ B(eq, true_label);
|
||||
} else {
|
||||
__ IsObjectJSObjectType(input, map, scratch1, false_label);
|
||||
__ B(eq, false_label);
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Check if the constructor in the map is a function.
|
||||
{
|
||||
UseScratchRegisterScope temps(masm());
|
||||
|
@ -2441,26 +2441,11 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
DCHECK(!temp.is(temp2));
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
__ CmpObjectType(input, JS_FUNCTION_TYPE, temp);
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
// Assuming the following assertions, we can use the same compares to test
|
||||
// for both being a function type and being in the object type range.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(input, FIRST_JS_RECEIVER_TYPE, temp);
|
||||
__ j(below, is_false);
|
||||
__ CmpInstanceType(temp, LAST_JS_RECEIVER_TYPE);
|
||||
__ j(equal, is_true);
|
||||
} else {
|
||||
// Faster code path to avoid two compares: subtract lower bound from the
|
||||
// actual type and do a signed compare with the width of the type range.
|
||||
__ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
|
||||
__ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
|
||||
__ sub(Operand(temp2), Immediate(FIRST_JS_RECEIVER_TYPE));
|
||||
__ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
|
||||
FIRST_JS_RECEIVER_TYPE));
|
||||
__ j(above, is_false);
|
||||
__ j(equal, is_false);
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
|
@ -2448,28 +2448,13 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
DCHECK(!temp.is(temp2));
|
||||
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
// Assuming the following assertions, we can use the same compares to test
|
||||
// for both being a function type and being in the object type range.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
__ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
__ Branch(is_true, eq, temp2, Operand(LAST_JS_RECEIVER_TYPE));
|
||||
__ Branch(is_true, eq, temp2, Operand(JS_FUNCTION_TYPE));
|
||||
} else {
|
||||
// Faster code path to avoid two compares: subtract lower bound from the
|
||||
// actual type and do a signed compare with the width of the type range.
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
__ Subu(temp2, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
__ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
|
||||
FIRST_JS_RECEIVER_TYPE));
|
||||
__ Branch(is_false, eq, temp2, Operand(JS_FUNCTION_TYPE));
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Check if the constructor in the map is a function.
|
||||
Register instance_type = scratch1();
|
||||
DCHECK(!instance_type.is(temp));
|
||||
|
@ -2570,24 +2570,11 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
// Assuming the following assertions, we can use the same compares to test
|
||||
// for both being a function type and being in the object type range.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
__ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
__ Branch(is_true, eq, temp2, Operand(LAST_JS_RECEIVER_TYPE));
|
||||
__ Branch(is_true, eq, temp2, Operand(JS_FUNCTION_TYPE));
|
||||
} else {
|
||||
// Faster code path to avoid two compares: subtract lower bound from the
|
||||
// actual type and do a signed compare with the width of the type range.
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
__ Dsubu(temp2, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
__ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
|
||||
FIRST_JS_RECEIVER_TYPE));
|
||||
__ Branch(is_false, eq, temp2, Operand(JS_FUNCTION_TYPE));
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
|
@ -2498,29 +2498,13 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
__ CmpObjectType(input, JS_FUNCTION_TYPE, temp);
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
// Assuming the following assertions, we can use the same compares to test
|
||||
// for both being a function type and being in the object type range.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(input, FIRST_JS_RECEIVER_TYPE, temp);
|
||||
__ j(below, is_false);
|
||||
__ CmpInstanceType(temp, LAST_JS_RECEIVER_TYPE);
|
||||
__ j(equal, is_true);
|
||||
} else {
|
||||
// Faster code path to avoid two compares: subtract lower bound from the
|
||||
// actual type and do a signed compare with the width of the type range.
|
||||
__ movp(temp, FieldOperand(input, HeapObject::kMapOffset));
|
||||
__ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
|
||||
__ subp(temp2, Immediate(FIRST_JS_RECEIVER_TYPE));
|
||||
__ cmpp(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
|
||||
FIRST_JS_RECEIVER_TYPE));
|
||||
__ j(above, is_false);
|
||||
__ j(equal, is_false);
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Check if the constructor in the map is a function.
|
||||
__ GetMapConstructor(temp, temp, kScratchRegister);
|
||||
|
||||
|
@ -3322,24 +3322,16 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
// If the object is a smi, we return null.
|
||||
// If the object is not a JSReceiver, we return null.
|
||||
__ JumpIfSmi(r0, &null);
|
||||
|
||||
// Check that the object is a JS object but take special care of JS
|
||||
// functions to make sure they have 'Function' as their class.
|
||||
// Assume that there are only two callable types, and one of them is at
|
||||
// either end of the type range for JS object types. Saves extra comparisons.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CompareObjectType(r0, r0, r1, FIRST_JS_RECEIVER_TYPE);
|
||||
// Map is now in r0.
|
||||
__ b(lt, &null);
|
||||
|
||||
__ cmp(r1, Operand(LAST_JS_RECEIVER_TYPE));
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
// Return 'Function' for JSFunction objects.
|
||||
__ cmp(r1, Operand(JS_FUNCTION_TYPE));
|
||||
__ b(eq, &function);
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
Register instance_type = r2;
|
||||
|
@ -3034,25 +3034,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
// If the object is a smi, we return null.
|
||||
// If the object is not a JSReceiver, we return null.
|
||||
__ JumpIfSmi(x0, &null);
|
||||
|
||||
// Check that the object is a JS object but take special care of JS
|
||||
// functions to make sure they have 'Function' as their class.
|
||||
// Assume that there are only two callable types, and one of them is at
|
||||
// either end of the type range for JS object types. Saves extra comparisons.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CompareObjectType(x0, x10, x11, FIRST_JS_RECEIVER_TYPE);
|
||||
// x10: object's map.
|
||||
// x11: object's type.
|
||||
__ B(lt, &null);
|
||||
|
||||
__ Cmp(x11, LAST_JS_RECEIVER_TYPE);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
// Return 'Function' for JSFunction objects.
|
||||
__ Cmp(x11, JS_FUNCTION_TYPE);
|
||||
__ B(eq, &function);
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
Register instance_type = x14;
|
||||
|
@ -3203,49 +3203,40 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
// If the object is a smi, we return null.
|
||||
__ JumpIfSmi(eax, &null);
|
||||
|
||||
// Check that the object is a JS object but take special care of JS
|
||||
// functions to make sure they have 'Function' as their class.
|
||||
// Assume that there are only two callable types, and one of them is at
|
||||
// either end of the type range for JS object types. Saves extra comparisons.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
// If the object is not a JSReceiver, we return null.
|
||||
__ JumpIfSmi(eax, &null, Label::kNear);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax);
|
||||
// Map is now in eax.
|
||||
__ j(below, &null);
|
||||
__ j(below, &null, Label::kNear);
|
||||
|
||||
__ CmpInstanceType(eax, LAST_JS_RECEIVER_TYPE);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
__ j(equal, &function);
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// Return 'Function' for JSFunction objects.
|
||||
__ CmpInstanceType(eax, JS_FUNCTION_TYPE);
|
||||
__ j(equal, &function, Label::kNear);
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
__ GetMapConstructor(eax, eax, ebx);
|
||||
__ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
|
||||
__ j(not_equal, &non_function_constructor);
|
||||
__ j(not_equal, &non_function_constructor, Label::kNear);
|
||||
|
||||
// eax now contains the constructor function. Grab the
|
||||
// instance class name from there.
|
||||
__ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
|
||||
__ jmp(&done);
|
||||
|
||||
// Functions have class 'Function'.
|
||||
__ bind(&function);
|
||||
__ mov(eax, isolate()->factory()->Function_string());
|
||||
__ jmp(&done);
|
||||
|
||||
// Objects with a non-function constructor have class 'Object'.
|
||||
__ bind(&non_function_constructor);
|
||||
__ mov(eax, isolate()->factory()->Object_string());
|
||||
__ jmp(&done);
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
// Non-JS objects have class null.
|
||||
__ bind(&null);
|
||||
__ mov(eax, isolate()->factory()->null_value());
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
// Functions have class 'Function'.
|
||||
__ bind(&function);
|
||||
__ mov(eax, isolate()->factory()->Function_string());
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
// Objects with a non-function constructor have class 'Object'.
|
||||
__ bind(&non_function_constructor);
|
||||
__ mov(eax, isolate()->factory()->Object_string());
|
||||
|
||||
// All done.
|
||||
__ bind(&done);
|
||||
|
@ -3316,22 +3316,14 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
// If the object is a smi, we return null.
|
||||
// If the object is not a JSReceiver, we return null.
|
||||
__ JumpIfSmi(v0, &null);
|
||||
|
||||
// Check that the object is a JS object but take special care of JS
|
||||
// functions to make sure they have 'Function' as their class.
|
||||
// Assume that there are only two callable types, and one of them is at
|
||||
// either end of the type range for JS object types. Saves extra comparisons.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ GetObjectType(v0, v0, a1); // Map is now in v0.
|
||||
__ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
__ Branch(&function, eq, a1, Operand(LAST_JS_RECEIVER_TYPE));
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// Return 'Function' for JSFunction objects.
|
||||
__ Branch(&function, eq, a1, Operand(JS_FUNCTION_TYPE));
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
Register instance_type = a2;
|
||||
|
@ -3322,22 +3322,14 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
// If the object is a smi, we return null.
|
||||
// If the object is not a JSReceiver, we return null.
|
||||
__ JumpIfSmi(v0, &null);
|
||||
|
||||
// Check that the object is a JS object but take special care of JS
|
||||
// functions to make sure they have 'Function' as their class.
|
||||
// Assume that there are only two callable types, and one of them is at
|
||||
// either end of the type range for JS object types. Saves extra comparisons.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ GetObjectType(v0, v0, a1); // Map is now in v0.
|
||||
__ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
__ Branch(&function, eq, a1, Operand(LAST_JS_RECEIVER_TYPE));
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// Return 'Function' for JSFunction objects.
|
||||
__ Branch(&function, eq, a1, Operand(JS_FUNCTION_TYPE));
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
Register instance_type = a2;
|
||||
|
@ -3190,49 +3190,40 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
// If the object is a smi, we return null.
|
||||
__ JumpIfSmi(rax, &null);
|
||||
|
||||
// Check that the object is a JS object but take special care of JS
|
||||
// functions to make sure they have 'Function' as their class.
|
||||
// Assume that there are only two callable types, and one of them is at
|
||||
// either end of the type range for JS object types. Saves extra comparisons.
|
||||
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
|
||||
// If the object is not a JSReceiver, we return null.
|
||||
__ JumpIfSmi(rax, &null, Label::kNear);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rax);
|
||||
// Map is now in rax.
|
||||
__ j(below, &null);
|
||||
__ j(below, &null, Label::kNear);
|
||||
|
||||
__ CmpInstanceType(rax, LAST_JS_RECEIVER_TYPE);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_JS_RECEIVER_TYPE - 1);
|
||||
__ j(equal, &function);
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// Return 'Function' for JSFunction objects.
|
||||
__ CmpInstanceType(rax, JS_FUNCTION_TYPE);
|
||||
__ j(equal, &function, Label::kNear);
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
__ GetMapConstructor(rax, rax, rbx);
|
||||
__ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
|
||||
__ j(not_equal, &non_function_constructor);
|
||||
__ j(not_equal, &non_function_constructor, Label::kNear);
|
||||
|
||||
// rax now contains the constructor function. Grab the
|
||||
// instance class name from there.
|
||||
__ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ movp(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
|
||||
__ jmp(&done);
|
||||
|
||||
// Functions have class 'Function'.
|
||||
__ bind(&function);
|
||||
__ Move(rax, isolate()->factory()->Function_string());
|
||||
__ jmp(&done);
|
||||
|
||||
// Objects with a non-function constructor have class 'Object'.
|
||||
__ bind(&non_function_constructor);
|
||||
__ Move(rax, isolate()->factory()->Object_string());
|
||||
__ jmp(&done);
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
// Non-JS objects have class null.
|
||||
__ bind(&null);
|
||||
__ LoadRoot(rax, Heap::kNullValueRootIndex);
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
// Functions have class 'Function'.
|
||||
__ bind(&function);
|
||||
__ LoadRoot(rax, Heap::kFunction_stringRootIndex);
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
// Objects with a non-function constructor have class 'Object'.
|
||||
__ bind(&non_function_constructor);
|
||||
__ LoadRoot(rax, Heap::kObject_stringRootIndex);
|
||||
|
||||
// All done.
|
||||
__ bind(&done);
|
||||
|
@ -4813,6 +4813,10 @@ bool Map::IsPrimitiveMap() {
|
||||
STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
|
||||
return instance_type() <= LAST_PRIMITIVE_TYPE;
|
||||
}
|
||||
bool Map::IsJSReceiverMap() {
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
return instance_type() >= FIRST_JS_RECEIVER_TYPE;
|
||||
}
|
||||
bool Map::IsJSObjectMap() {
|
||||
STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
|
||||
return instance_type() >= FIRST_JS_OBJECT_TYPE;
|
||||
|
@ -77,9 +77,7 @@ Handle<HeapType> Object::OptimalType(Isolate* isolate,
|
||||
if (representation.IsHeapObject() && IsHeapObject()) {
|
||||
// We can track only JavaScript objects with stable maps.
|
||||
Handle<Map> map(HeapObject::cast(this)->map(), isolate);
|
||||
if (map->is_stable() &&
|
||||
map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
|
||||
map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
|
||||
if (map->is_stable() && map->IsJSReceiverMap()) {
|
||||
return HeapType::Class(map, isolate);
|
||||
}
|
||||
}
|
||||
|
@ -759,12 +759,6 @@ enum InstanceType {
|
||||
// Boundaries for testing the types represented as JSObject
|
||||
FIRST_JS_OBJECT_TYPE = JS_VALUE_TYPE,
|
||||
LAST_JS_OBJECT_TYPE = LAST_TYPE,
|
||||
//
|
||||
FIRST_NONCALLABLE_SPEC_OBJECT_TYPE = JS_VALUE_TYPE,
|
||||
LAST_NONCALLABLE_SPEC_OBJECT_TYPE = JS_REGEXP_TYPE,
|
||||
// Note that the types for which typeof is "function" are not continuous.
|
||||
// Define this so that we can put assertions on discrete checks.
|
||||
NUM_OF_CALLABLE_SPEC_OBJECT_TYPES = 2
|
||||
};
|
||||
|
||||
STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType);
|
||||
@ -5928,6 +5922,7 @@ class Map: public HeapObject {
|
||||
|
||||
inline bool IsBooleanMap();
|
||||
inline bool IsPrimitiveMap();
|
||||
inline bool IsJSReceiverMap();
|
||||
inline bool IsJSObjectMap();
|
||||
inline bool IsJSArrayMap();
|
||||
inline bool IsJSFunctionMap();
|
||||
|
@ -1380,9 +1380,10 @@ TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) {
|
||||
|
||||
void UpdateExpectations(int property_index, Expectations& expectations) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Handle<HeapType> any_type = HeapType::Any(isolate);
|
||||
Handle<HeapType> function_type =
|
||||
HeapType::Class(isolate->sloppy_function_map(), isolate);
|
||||
expectations.SetDataField(property_index, Representation::HeapObject(),
|
||||
any_type);
|
||||
function_type);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2136,7 +2137,8 @@ TEST(TransitionDataConstantToAnotherDataConstant) {
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<HeapType> any_type = HeapType::Any(isolate);
|
||||
Handle<HeapType> function_type =
|
||||
HeapType::Class(isolate->sloppy_function_map(), isolate);
|
||||
|
||||
Handle<JSFunction> js_func1 = factory->NewFunction(factory->empty_string());
|
||||
TransitionToDataConstantOperator transition_op1(js_func1);
|
||||
@ -2144,8 +2146,8 @@ TEST(TransitionDataConstantToAnotherDataConstant) {
|
||||
Handle<JSFunction> js_func2 = factory->NewFunction(factory->empty_string());
|
||||
TransitionToDataConstantOperator transition_op2(js_func2);
|
||||
|
||||
FieldGeneralizationChecker checker(kPropCount - 1,
|
||||
Representation::HeapObject(), any_type);
|
||||
FieldGeneralizationChecker checker(
|
||||
kPropCount - 1, Representation::HeapObject(), function_type);
|
||||
TestTransitionTo(transition_op1, transition_op2, checker);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user