[es5] Class of object is "Function" if object has [[Call]].
The concept of class was mostly removed from ES6, but we still use the class of objects to distinguish object kinds in our builtins. So update this to be in sync with IsCallable (thereby getting rid of the previous instance type based tests for callable things completely). R=jarin@chromium.org, jkummerow@chromium.org Review URL: https://codereview.chromium.org/1307943013 Cr-Commit-Position: refs/heads/master@{#30566}
This commit is contained in:
parent
6893da5377
commit
af77838994
@ -2618,39 +2618,27 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
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(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
|
||||
__ CompareObjectType(input, temp, temp2, FIRST_SPEC_OBJECT_TYPE);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CompareObjectType(input, temp, temp2, FIRST_JS_RECEIVER_TYPE);
|
||||
__ b(lt, is_false);
|
||||
__ b(eq, is_true);
|
||||
__ cmp(temp2, Operand(LAST_SPEC_OBJECT_TYPE));
|
||||
__ b(eq, is_true);
|
||||
|
||||
// Objects with [[Call]] have class 'Function'.
|
||||
__ ldrb(temp2, FieldMemOperand(temp, Map::kBitFieldOffset));
|
||||
__ tst(temp2, Operand(1 << Map::kIsCallable));
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
__ b(ne, 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_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ cmp(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
|
||||
FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ b(gt, is_false);
|
||||
__ b(ne, is_false);
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Now we are in the FIRST-LAST_JS_RECEIVER_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);
|
||||
|
@ -1390,26 +1390,6 @@ void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
cmp(scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
b(lt, fail);
|
||||
cmp(scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
b(gt, fail);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectJSStringType(Register object,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
|
@ -662,15 +662,6 @@ class MacroAssembler: public Assembler {
|
||||
InvokeFlag flag,
|
||||
const CallWrapper& call_wrapper);
|
||||
|
||||
void IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
void IsInstanceJSObjectType(Register map,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
void IsObjectJSStringType(Register object,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
@ -2355,27 +2355,21 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
|
||||
__ JumpIfSmi(input, false_label);
|
||||
|
||||
Register map = scratch2;
|
||||
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(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
|
||||
|
||||
// We expect CompareObjectType to load the object instance type in scratch1.
|
||||
__ CompareObjectType(input, map, scratch1, FIRST_SPEC_OBJECT_TYPE);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CompareObjectType(input, map, scratch1, FIRST_JS_RECEIVER_TYPE);
|
||||
__ B(lt, false_label);
|
||||
__ B(eq, true_label);
|
||||
__ Cmp(scratch1, LAST_SPEC_OBJECT_TYPE);
|
||||
__ B(eq, true_label);
|
||||
|
||||
// Objects with [[Call]] have class 'Function'.
|
||||
Register bit_field = scratch1;
|
||||
__ Ldrb(bit_field, FieldMemOperand(map, Map::kBitFieldOffset));
|
||||
__ Tst(bit_field, 1 << Map::kIsCallable);
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
__ B(ne, true_label);
|
||||
} else {
|
||||
__ IsObjectJSObjectType(input, map, scratch1, false_label);
|
||||
__ B(ne, false_label);
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
|
||||
// Check if the constructor in the map is a function.
|
||||
{
|
||||
UseScratchRegisterScope temps(masm());
|
||||
|
@ -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_NONCALLABLE_SPEC_OBJECT_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,
|
||||
|
@ -1490,20 +1490,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
|
||||
|
@ -3663,7 +3663,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
DCHECK_EQ(1, args->length());
|
||||
Label done, null, function, non_function_constructor;
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
@ -3671,24 +3671,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
// If the object is a smi, 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);
|
||||
__ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE);
|
||||
// Map is now in r0.
|
||||
// If the object is not a receiver, we return null.
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CompareObjectType(r0, r0, r1, FIRST_JS_RECEIVER_TYPE);
|
||||
__ b(lt, &null);
|
||||
STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
__ b(eq, &function);
|
||||
|
||||
__ cmp(r1, Operand(LAST_SPEC_OBJECT_TYPE));
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
__ b(eq, &function);
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// According to ES5 section 15 Standard Built-in ECMAScript Objects, the
|
||||
// [[Class]] of builtin objects is "Function" if a [[Call]] internal
|
||||
// method is present.
|
||||
__ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
|
||||
__ tst(r1, Operand(1 << Map::kIsCallable));
|
||||
__ b(ne, &function);
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
Register instance_type = r2;
|
||||
|
@ -3390,7 +3390,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ASM_LOCATION("FullCodeGenerator::EmitClassOf");
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
DCHECK_EQ(1, args->length());
|
||||
Label done, null, function, non_function_constructor;
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
@ -3398,25 +3398,19 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
// If the object is a smi, 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);
|
||||
__ CompareObjectType(x0, x10, x11, FIRST_SPEC_OBJECT_TYPE);
|
||||
// If the object is not a receiver, we return null.
|
||||
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);
|
||||
STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
__ B(eq, &function);
|
||||
|
||||
__ Cmp(x11, LAST_SPEC_OBJECT_TYPE);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
__ B(eq, &function);
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// According to ES5 section 15 Standard Built-in ECMAScript Objects, the
|
||||
// [[Class]] of builtin objects is "Function" if a [[Call]] internal
|
||||
// method is present.
|
||||
__ Ldrb(x11, FieldMemOperand(x10, Map::kBitFieldOffset));
|
||||
__ Tst(x11, 1 << Map::kIsCallable);
|
||||
__ B(ne, &function);
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
Register instance_type = x14;
|
||||
|
@ -3565,57 +3565,49 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
Label done, null, function, non_function_constructor;
|
||||
DCHECK_EQ(1, args->length());
|
||||
Label done, null, function, function_constructor;
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
// If the object is a smi, we return null.
|
||||
__ JumpIfSmi(eax, &null);
|
||||
__ JumpIfSmi(eax, &null, Label::kNear);
|
||||
|
||||
// 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);
|
||||
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
|
||||
// Map is now in eax.
|
||||
__ j(below, &null);
|
||||
STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
__ j(equal, &function);
|
||||
// If the object is not a receiver, we return null.
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax);
|
||||
__ j(below, &null, Label::kNear);
|
||||
|
||||
__ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
__ j(equal, &function);
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// According to ES5 section 15 Standard Built-in ECMAScript Objects, the
|
||||
// [[Class]] of builtin objects is "Function" if a [[Call]] internal
|
||||
// method is present.
|
||||
__ test_b(FieldOperand(eax, Map::kBitFieldOffset), 1 << Map::kIsCallable);
|
||||
__ j(not_zero, &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(equal, &function_constructor, Label::kNear);
|
||||
|
||||
// Objects with a non-function constructor have class 'Object'.
|
||||
__ LoadRoot(eax, Heap::kObject_stringRootIndex);
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
// Non-JS objects have class null.
|
||||
__ bind(&null);
|
||||
__ LoadRoot(eax, Heap::kNullValueRootIndex);
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
// Functions have class 'Function'.
|
||||
__ bind(&function);
|
||||
__ LoadRoot(eax, Heap::kFunction_stringRootIndex);
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
__ bind(&function_constructor);
|
||||
// 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);
|
||||
|
||||
// Non-JS objects have class null.
|
||||
__ bind(&null);
|
||||
__ mov(eax, isolate()->factory()->null_value());
|
||||
|
||||
// All done.
|
||||
__ bind(&done);
|
||||
|
@ -3663,7 +3663,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
DCHECK_EQ(1, args->length());
|
||||
Label done, null, function, non_function_constructor;
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
@ -3671,23 +3671,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
// If the object is a smi, 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);
|
||||
// If the object is not a receiver, we return null.
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ GetObjectType(v0, v0, a1); // Map is now in v0.
|
||||
__ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
__ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
|
||||
STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
__ Branch(&function, eq, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
__ Branch(&function, eq, a1, Operand(LAST_SPEC_OBJECT_TYPE));
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// According to ES5 section 15 Standard Built-in ECMAScript Objects, the
|
||||
// [[Class]] of builtin objects is "Function" if a [[Call]] internal
|
||||
// method is present.
|
||||
__ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
|
||||
__ And(a1, a1, Operand(1 << Map::kIsCallable));
|
||||
__ Branch(&function, ne, a1, Operand(zero_reg));
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
Register instance_type = a2;
|
||||
|
@ -3674,23 +3674,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
// If the object is a smi, 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);
|
||||
// If the object is not a receiver, we return null.
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ GetObjectType(v0, v0, a1); // Map is now in v0.
|
||||
__ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
__ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
|
||||
STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
__ Branch(&function, eq, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
__ Branch(&function, eq, a1, Operand(LAST_SPEC_OBJECT_TYPE));
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// According to ES5 section 15 Standard Built-in ECMAScript Objects, the
|
||||
// [[Class]] of builtin objects is "Function" if a [[Call]] internal
|
||||
// method is present.
|
||||
__ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
|
||||
__ And(a1, a1, Operand(1 << Map::kIsCallable));
|
||||
__ Branch(&function, ne, a1, Operand(zero_reg));
|
||||
|
||||
// Check if the constructor in the map is a JS function.
|
||||
Register instance_type = a2;
|
||||
|
@ -3548,57 +3548,50 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
Label done, null, function, non_function_constructor;
|
||||
DCHECK_EQ(1, args->length());
|
||||
Label done, null, function, function_constructor;
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
// If the object is a smi, we return null.
|
||||
__ JumpIfSmi(rax, &null);
|
||||
__ JumpIfSmi(rax, &null, Label::kNear);
|
||||
|
||||
// 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);
|
||||
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
|
||||
// Map is now in rax.
|
||||
__ j(below, &null);
|
||||
STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
__ j(equal, &function);
|
||||
// If the object is not a receiver, we return null.
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rax);
|
||||
__ j(below, &null, Label::kNear);
|
||||
|
||||
__ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
__ j(equal, &function);
|
||||
// Assume that there is no larger type.
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
|
||||
// According to ES5 section 15 Standard Built-in ECMAScript Objects, the
|
||||
// [[Class]] of builtin objects is "Function" if a [[Call]] internal
|
||||
// method is present.
|
||||
__ testb(FieldOperand(rax, Map::kBitFieldOffset),
|
||||
Immediate(1 << Map::kIsCallable));
|
||||
__ j(not_zero, &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);
|
||||
|
||||
// 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);
|
||||
__ j(equal, &function_constructor, Label::kNear);
|
||||
|
||||
// Objects with a non-function constructor have class 'Object'.
|
||||
__ bind(&non_function_constructor);
|
||||
__ Move(rax, isolate()->factory()->Object_string());
|
||||
__ jmp(&done);
|
||||
__ LoadRoot(rax, Heap::kObject_stringRootIndex);
|
||||
__ 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);
|
||||
|
||||
__ bind(&function_constructor);
|
||||
// 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));
|
||||
|
||||
// All done.
|
||||
__ bind(&done);
|
||||
|
@ -2521,32 +2521,19 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
DCHECK(!temp.is(temp2));
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
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(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(input, FIRST_JS_RECEIVER_TYPE, temp);
|
||||
__ j(below, is_false);
|
||||
__ j(equal, is_true);
|
||||
__ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
|
||||
__ j(equal, is_true);
|
||||
|
||||
// Objects with [[Call]] have class 'Function'.
|
||||
__ test_b(FieldOperand(temp, Map::kBitFieldOffset), 1 << Map::kIsCallable);
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
__ j(not_zero, 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_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
|
||||
FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ j(above, is_false);
|
||||
__ j(not_zero, is_false);
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
|
||||
// Check if the constructor in the map is a function.
|
||||
__ GetMapConstructor(temp, temp, temp2);
|
||||
// Objects with a non-function constructor have class 'Object'.
|
||||
|
@ -752,26 +752,6 @@ Condition MacroAssembler::IsObjectNameType(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(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
cmp(scratch,
|
||||
LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
j(above, fail);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::FCmp() {
|
||||
fucomip();
|
||||
fstp(0);
|
||||
@ -1784,9 +1764,9 @@ void MacroAssembler::GetMapConstructor(Register result, Register map,
|
||||
Label done, loop;
|
||||
mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
|
||||
bind(&loop);
|
||||
JumpIfSmi(result, &done);
|
||||
JumpIfSmi(result, &done, Label::kNear);
|
||||
CmpObjectType(result, MAP_TYPE, temp);
|
||||
j(not_equal, &done);
|
||||
j(not_equal, &done, Label::kNear);
|
||||
mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
|
||||
jmp(&loop);
|
||||
bind(&done);
|
||||
|
@ -452,18 +452,6 @@ 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();
|
||||
|
@ -2544,30 +2544,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
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(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
__ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
__ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
__ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
__ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE));
|
||||
// Objects with [[Call]] have class 'Function'.
|
||||
__ lbu(temp2, FieldMemOperand(temp, Map::kBitFieldOffset));
|
||||
__ And(temp2, temp2, Operand(1 << Map::kIsCallable));
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
__ Branch(is_true, ne, temp2, Operand(zero_reg));
|
||||
} 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_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
|
||||
FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ Branch(is_false, ne, temp2, Operand(zero_reg));
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
|
||||
// Check if the constructor in the map is a function.
|
||||
Register instance_type = scratch1();
|
||||
DCHECK(!instance_type.is(temp));
|
||||
|
@ -4214,24 +4214,6 @@ void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
lw(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
|
||||
IsInstanceJSObjectType(map, scratch, fail);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsInstanceJSObjectType(Register map,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
|
||||
Branch(fail, lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
Branch(fail, gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectJSStringType(Register object,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
|
@ -977,16 +977,6 @@ class MacroAssembler: public Assembler {
|
||||
InvokeFlag flag,
|
||||
const CallWrapper& call_wrapper);
|
||||
|
||||
|
||||
void IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
void IsInstanceJSObjectType(Register map,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
void IsObjectJSStringType(Register object,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
@ -2648,30 +2648,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
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(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
__ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
|
||||
|
||||
__ GetObjectType(input, temp, temp2);
|
||||
__ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
__ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
__ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE));
|
||||
// Objects with [[Call]] have class 'Function'.
|
||||
__ lbu(temp2, FieldMemOperand(temp, Map::kBitFieldOffset));
|
||||
__ And(temp2, temp2, Operand(1 << Map::kIsCallable));
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
__ Branch(is_true, ne, temp2, Operand(zero_reg));
|
||||
} 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_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
|
||||
FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ Branch(is_false, ne, temp2, Operand(zero_reg));
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
|
||||
// Check if the constructor in the map is a function.
|
||||
Register instance_type = scratch1();
|
||||
DCHECK(!instance_type.is(temp));
|
||||
|
@ -4217,24 +4217,6 @@ void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
ld(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
|
||||
IsInstanceJSObjectType(map, scratch, fail);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsInstanceJSObjectType(Register map,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
|
||||
Branch(fail, lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
Branch(fail, gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectJSStringType(Register object,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
|
@ -1008,15 +1008,6 @@ class MacroAssembler: public Assembler {
|
||||
const CallWrapper& call_wrapper);
|
||||
|
||||
|
||||
void IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
void IsInstanceJSObjectType(Register map,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
void IsObjectJSStringType(Register object,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
@ -58,9 +58,9 @@ 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->is_callable() &&
|
||||
map->instance_type() >= FIRST_JS_RECEIVER_TYPE &&
|
||||
map->instance_type() <= LAST_JS_RECEIVER_TYPE) {
|
||||
return HeapType::Class(map, isolate);
|
||||
}
|
||||
}
|
||||
@ -1650,7 +1650,10 @@ void Simd128Value::CopyBits(void* destination) const {
|
||||
|
||||
|
||||
String* JSReceiver::class_name() {
|
||||
if (IsJSFunction() || IsJSFunctionProxy()) {
|
||||
// According to ES5 section 15 Standard Built-in ECMAScript Objects, the
|
||||
// [[Class]] of builtin objects is "Function" if a [[Call]] internal
|
||||
// method is present.
|
||||
if (IsCallable()) {
|
||||
return GetHeap()->Function_string();
|
||||
}
|
||||
Object* maybe_constructor = map()->GetConstructor();
|
||||
|
@ -708,8 +708,7 @@ enum InstanceType {
|
||||
// All the following types are subtypes of JSReceiver, which corresponds to
|
||||
// objects in the JS sense. The first and the last type in this range are
|
||||
// the two forms of function. This organization enables using the same
|
||||
// compares for checking the JS_RECEIVER/SPEC_OBJECT range and the
|
||||
// NONCALLABLE_JS_OBJECT range.
|
||||
// compares for checking the JS_RECEIVER/SPEC_OBJECT range.
|
||||
JS_FUNCTION_PROXY_TYPE, // FIRST_JS_RECEIVER_TYPE, FIRST_JS_PROXY_TYPE
|
||||
JS_PROXY_TYPE, // LAST_JS_PROXY_TYPE
|
||||
JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE
|
||||
@ -766,13 +765,7 @@ enum InstanceType {
|
||||
LAST_JS_PROXY_TYPE = JS_PROXY_TYPE,
|
||||
// Boundaries for testing whether the type is a JavaScript object.
|
||||
FIRST_SPEC_OBJECT_TYPE = FIRST_JS_RECEIVER_TYPE,
|
||||
LAST_SPEC_OBJECT_TYPE = LAST_JS_RECEIVER_TYPE,
|
||||
// Boundaries for testing the types for which typeof is "object".
|
||||
FIRST_NONCALLABLE_SPEC_OBJECT_TYPE = JS_PROXY_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
|
||||
LAST_SPEC_OBJECT_TYPE = LAST_JS_RECEIVER_TYPE
|
||||
};
|
||||
|
||||
STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType);
|
||||
|
@ -2572,32 +2572,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
|
||||
|
||||
__ JumpIfSmi(input, is_false);
|
||||
|
||||
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(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
FIRST_SPEC_OBJECT_TYPE + 1);
|
||||
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
|
||||
LAST_SPEC_OBJECT_TYPE - 1);
|
||||
STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(input, FIRST_JS_RECEIVER_TYPE, temp);
|
||||
__ j(below, is_false);
|
||||
__ j(equal, is_true);
|
||||
__ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
|
||||
__ j(equal, is_true);
|
||||
|
||||
// Objects with [[Call]] have class 'Function'.
|
||||
__ testb(FieldOperand(temp, Map::kBitFieldOffset),
|
||||
Immediate(1 << Map::kIsCallable));
|
||||
if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
|
||||
__ j(not_zero, 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_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ cmpp(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
|
||||
FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ j(above, is_false);
|
||||
__ j(not_zero, is_false);
|
||||
}
|
||||
|
||||
// Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
|
||||
// Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
|
||||
// Check if the constructor in the map is a function.
|
||||
__ GetMapConstructor(temp, temp, kScratchRegister);
|
||||
|
||||
|
@ -3446,9 +3446,9 @@ void MacroAssembler::GetMapConstructor(Register result, Register map,
|
||||
Label done, loop;
|
||||
movp(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
|
||||
bind(&loop);
|
||||
JumpIfSmi(result, &done);
|
||||
JumpIfSmi(result, &done, Label::kNear);
|
||||
CmpObjectType(result, MAP_TYPE, temp);
|
||||
j(not_equal, &done);
|
||||
j(not_equal, &done, Label::kNear);
|
||||
movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
|
||||
jmp(&loop);
|
||||
bind(&done);
|
||||
|
Loading…
Reference in New Issue
Block a user