[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:
bmeurer 2015-09-03 07:09:55 -07:00 committed by Commit bot
parent 6893da5377
commit af77838994
25 changed files with 169 additions and 432 deletions

View File

@ -2618,39 +2618,27 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
__ JumpIfSmi(input, is_false); __ JumpIfSmi(input, is_false);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CompareObjectType(input, temp, temp2, FIRST_JS_RECEIVER_TYPE);
__ b(lt, is_false);
// 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)) { if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
// Assuming the following assertions, we can use the same compares to test __ b(ne, is_true);
// 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);
__ b(lt, is_false);
__ b(eq, is_true);
__ cmp(temp2, Operand(LAST_SPEC_OBJECT_TYPE));
__ b(eq, is_true);
} else { } else {
// Faster code path to avoid two compares: subtract lower bound from the __ b(ne, is_false);
// 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);
} }
// 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. // Check if the constructor in the map is a function.
Register instance_type = ip; Register instance_type = ip;
__ GetMapConstructor(temp, temp, temp2, instance_type); __ GetMapConstructor(temp, temp, temp2, instance_type);
// Objects with a non-function constructor have class 'Object'. // Objects with a non-function constructor have class 'Object'.
__ cmp(instance_type, Operand(JS_FUNCTION_TYPE)); __ 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); __ b(ne, is_true);
} else { } else {
__ b(ne, is_false); __ b(ne, is_false);

View File

@ -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, void MacroAssembler::IsObjectJSStringType(Register object,
Register scratch, Register scratch,
Label* fail) { Label* fail) {

View File

@ -662,15 +662,6 @@ class MacroAssembler: public Assembler {
InvokeFlag flag, InvokeFlag flag,
const CallWrapper& call_wrapper); 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, void IsObjectJSStringType(Register object,
Register scratch, Register scratch,
Label* fail); Label* fail);

View File

@ -2355,27 +2355,21 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
__ JumpIfSmi(input, false_label); __ JumpIfSmi(input, false_label);
Register map = scratch2; Register map = scratch2;
if (String::Equals(isolate()->factory()->Function_string(), class_name)) { STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
// Assuming the following assertions, we can use the same compares to test __ CompareObjectType(input, map, scratch1, FIRST_JS_RECEIVER_TYPE);
// for both being a function type and being in the object type range. __ B(lt, false_label);
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. // Objects with [[Call]] have class 'Function'.
__ CompareObjectType(input, map, scratch1, FIRST_SPEC_OBJECT_TYPE); Register bit_field = scratch1;
__ B(lt, false_label); __ Ldrb(bit_field, FieldMemOperand(map, Map::kBitFieldOffset));
__ B(eq, true_label); __ Tst(bit_field, 1 << Map::kIsCallable);
__ Cmp(scratch1, LAST_SPEC_OBJECT_TYPE); if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
__ B(eq, true_label); __ B(ne, true_label);
} else { } 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. // Check if the constructor in the map is a function.
{ {
UseScratchRegisterScope temps(masm()); UseScratchRegisterScope temps(masm());

View File

@ -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, void MacroAssembler::IsObjectJSStringType(Register object,
Register type, Register type,
Label* not_string, Label* not_string,

View File

@ -1490,20 +1490,6 @@ class MacroAssembler : public Assembler {
// Fall-through if the object was a string and jump on fail otherwise. // Fall-through if the object was a string and jump on fail otherwise.
inline void IsObjectNameType(Register object, Register type, Label* fail); 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. // Load and check the instance type of an object for being a string.
// Loads the type into the second argument register. // Loads the type into the second argument register.
// The object and type arguments can be the same register; in that case it // The object and type arguments can be the same register; in that case it

View File

@ -3663,7 +3663,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK_EQ(1, args->length());
Label done, null, function, non_function_constructor; Label done, null, function, non_function_constructor;
VisitForAccumulatorValue(args->at(0)); VisitForAccumulatorValue(args->at(0));
@ -3671,24 +3671,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
// If the object is a smi, we return null. // If the object is a smi, we return null.
__ JumpIfSmi(r0, &null); __ JumpIfSmi(r0, &null);
// Check that the object is a JS object but take special care of JS // If the object is not a receiver, we return null.
// functions to make sure they have 'Function' as their class. STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
// Assume that there are only two callable types, and one of them is at __ CompareObjectType(r0, r0, r1, FIRST_JS_RECEIVER_TYPE);
// 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.
__ b(lt, &null); __ 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)); // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == // [[Class]] of builtin objects is "Function" if a [[Call]] internal
LAST_SPEC_OBJECT_TYPE - 1); // method is present.
__ b(eq, &function); __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
// Assume that there is no larger type. __ tst(r1, Operand(1 << Map::kIsCallable));
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); __ b(ne, &function);
// Check if the constructor in the map is a JS function. // Check if the constructor in the map is a JS function.
Register instance_type = r2; Register instance_type = r2;

View File

@ -3390,7 +3390,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ASM_LOCATION("FullCodeGenerator::EmitClassOf"); ASM_LOCATION("FullCodeGenerator::EmitClassOf");
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK_EQ(1, args->length());
Label done, null, function, non_function_constructor; Label done, null, function, non_function_constructor;
VisitForAccumulatorValue(args->at(0)); VisitForAccumulatorValue(args->at(0));
@ -3398,25 +3398,19 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
// If the object is a smi, we return null. // If the object is a smi, we return null.
__ JumpIfSmi(x0, &null); __ JumpIfSmi(x0, &null);
// Check that the object is a JS object but take special care of JS // If the object is not a receiver, we return null.
// functions to make sure they have 'Function' as their class. STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
// Assume that there are only two callable types, and one of them is at __ CompareObjectType(x0, x10, x11, FIRST_JS_RECEIVER_TYPE);
// 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);
// x10: object's map. // x10: object's map.
// x11: object's type. // x11: object's type.
__ B(lt, &null); __ B(lt, &null);
STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
FIRST_SPEC_OBJECT_TYPE + 1);
__ B(eq, &function);
__ Cmp(x11, LAST_SPEC_OBJECT_TYPE); // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == // [[Class]] of builtin objects is "Function" if a [[Call]] internal
LAST_SPEC_OBJECT_TYPE - 1); // method is present.
__ B(eq, &function); __ Ldrb(x11, FieldMemOperand(x10, Map::kBitFieldOffset));
// Assume that there is no larger type. __ Tst(x11, 1 << Map::kIsCallable);
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); __ B(ne, &function);
// Check if the constructor in the map is a JS function. // Check if the constructor in the map is a JS function.
Register instance_type = x14; Register instance_type = x14;

View File

@ -3565,57 +3565,49 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK_EQ(1, args->length());
Label done, null, function, non_function_constructor; Label done, null, function, function_constructor;
VisitForAccumulatorValue(args->at(0)); VisitForAccumulatorValue(args->at(0));
// If the object is a smi, we return null. // 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 // If the object is not a receiver, we return null.
// functions to make sure they have 'Function' as their class. STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
// Assume that there are only two callable types, and one of them is at __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax);
// either end of the type range for JS object types. Saves extra comparisons. __ j(below, &null, Label::kNear);
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);
__ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE); // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == // [[Class]] of builtin objects is "Function" if a [[Call]] internal
LAST_SPEC_OBJECT_TYPE - 1); // method is present.
__ j(equal, &function); __ test_b(FieldOperand(eax, Map::kBitFieldOffset), 1 << Map::kIsCallable);
// Assume that there is no larger type. __ j(not_zero, &function, Label::kNear);
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
// Check if the constructor in the map is a JS function. // Check if the constructor in the map is a JS function.
__ GetMapConstructor(eax, eax, ebx); __ GetMapConstructor(eax, eax, ebx);
__ CmpInstanceType(ebx, JS_FUNCTION_TYPE); __ 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 // eax now contains the constructor function. Grab the
// instance class name from there. // instance class name from there.
__ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
__ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); __ 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. // All done.
__ bind(&done); __ bind(&done);

View File

@ -3663,7 +3663,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK_EQ(1, args->length());
Label done, null, function, non_function_constructor; Label done, null, function, non_function_constructor;
VisitForAccumulatorValue(args->at(0)); VisitForAccumulatorValue(args->at(0));
@ -3671,23 +3671,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
// If the object is a smi, we return null. // If the object is a smi, we return null.
__ JumpIfSmi(v0, &null); __ JumpIfSmi(v0, &null);
// Check that the object is a JS object but take special care of JS // If the object is not a receiver, we return null.
// functions to make sure they have 'Function' as their class. STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
// 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);
__ GetObjectType(v0, v0, a1); // Map is now in v0. __ 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 == // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
FIRST_SPEC_OBJECT_TYPE + 1); // [[Class]] of builtin objects is "Function" if a [[Call]] internal
__ Branch(&function, eq, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); // method is present.
__ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == __ And(a1, a1, Operand(1 << Map::kIsCallable));
LAST_SPEC_OBJECT_TYPE - 1); __ Branch(&function, ne, a1, Operand(zero_reg));
__ 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);
// Check if the constructor in the map is a JS function. // Check if the constructor in the map is a JS function.
Register instance_type = a2; Register instance_type = a2;

View File

@ -3674,23 +3674,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
// If the object is a smi, we return null. // If the object is a smi, we return null.
__ JumpIfSmi(v0, &null); __ JumpIfSmi(v0, &null);
// Check that the object is a JS object but take special care of JS // If the object is not a receiver, we return null.
// functions to make sure they have 'Function' as their class. STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
// 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);
__ GetObjectType(v0, v0, a1); // Map is now in v0. __ 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 == // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
FIRST_SPEC_OBJECT_TYPE + 1); // [[Class]] of builtin objects is "Function" if a [[Call]] internal
__ Branch(&function, eq, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); // method is present.
__ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == __ And(a1, a1, Operand(1 << Map::kIsCallable));
LAST_SPEC_OBJECT_TYPE - 1); __ Branch(&function, ne, a1, Operand(zero_reg));
__ 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);
// Check if the constructor in the map is a JS function. // Check if the constructor in the map is a JS function.
Register instance_type = a2; Register instance_type = a2;

View File

@ -3548,57 +3548,50 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK_EQ(1, args->length());
Label done, null, function, non_function_constructor; Label done, null, function, function_constructor;
VisitForAccumulatorValue(args->at(0)); VisitForAccumulatorValue(args->at(0));
// If the object is a smi, we return null. // 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 // If the object is not a receiver, we return null.
// functions to make sure they have 'Function' as their class. STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
// Assume that there are only two callable types, and one of them is at __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rax);
// either end of the type range for JS object types. Saves extra comparisons. __ j(below, &null, Label::kNear);
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);
__ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE); // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == // [[Class]] of builtin objects is "Function" if a [[Call]] internal
LAST_SPEC_OBJECT_TYPE - 1); // method is present.
__ j(equal, &function); __ testb(FieldOperand(rax, Map::kBitFieldOffset),
// Assume that there is no larger type. Immediate(1 << Map::kIsCallable));
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); __ j(not_zero, &function, Label::kNear);
// Check if the constructor in the map is a JS function. // Check if the constructor in the map is a JS function.
__ GetMapConstructor(rax, rax, rbx); __ GetMapConstructor(rax, rax, rbx);
__ CmpInstanceType(rbx, JS_FUNCTION_TYPE); __ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
__ j(not_equal, &non_function_constructor); __ j(equal, &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'. // Objects with a non-function constructor have class 'Object'.
__ bind(&non_function_constructor); __ LoadRoot(rax, Heap::kObject_stringRootIndex);
__ Move(rax, isolate()->factory()->Object_string()); __ jmp(&done, Label::kNear);
__ jmp(&done);
// Non-JS objects have class null. // Non-JS objects have class null.
__ bind(&null); __ bind(&null);
__ LoadRoot(rax, Heap::kNullValueRootIndex); __ 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. // All done.
__ bind(&done); __ bind(&done);

View File

@ -2521,32 +2521,19 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
DCHECK(!temp.is(temp2)); DCHECK(!temp.is(temp2));
__ JumpIfSmi(input, is_false); __ JumpIfSmi(input, is_false);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(input, FIRST_JS_RECEIVER_TYPE, temp);
__ j(below, is_false);
// Objects with [[Call]] have class 'Function'.
__ test_b(FieldOperand(temp, Map::kBitFieldOffset), 1 << Map::kIsCallable);
if (String::Equals(isolate()->factory()->Function_string(), class_name)) { if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
// Assuming the following assertions, we can use the same compares to test __ j(not_zero, is_true);
// 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);
__ j(below, is_false);
__ j(equal, is_true);
__ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
__ j(equal, is_true);
} else { } else {
// Faster code path to avoid two compares: subtract lower bound from the __ j(not_zero, is_false);
// 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);
} }
// 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. // Check if the constructor in the map is a function.
__ GetMapConstructor(temp, temp, temp2); __ GetMapConstructor(temp, temp, temp2);
// Objects with a non-function constructor have class 'Object'. // Objects with a non-function constructor have class 'Object'.

View File

@ -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() { void MacroAssembler::FCmp() {
fucomip(); fucomip();
fstp(0); fstp(0);
@ -1784,9 +1764,9 @@ void MacroAssembler::GetMapConstructor(Register result, Register map,
Label done, loop; Label done, loop;
mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
bind(&loop); bind(&loop);
JumpIfSmi(result, &done); JumpIfSmi(result, &done, Label::kNear);
CmpObjectType(result, MAP_TYPE, temp); CmpObjectType(result, MAP_TYPE, temp);
j(not_equal, &done); j(not_equal, &done, Label::kNear);
mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
jmp(&loop); jmp(&loop);
bind(&done); bind(&done);

View File

@ -452,18 +452,6 @@ class MacroAssembler: public Assembler {
Register map, Register map,
Register instance_type); 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 // FCmp is similar to integer cmp, but requires unsigned
// jcc instructions (je, ja, jae, jb, jbe, je, and jz). // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
void FCmp(); void FCmp();

View File

@ -2544,30 +2544,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
__ JumpIfSmi(input, is_false); __ JumpIfSmi(input, is_false);
if (String::Equals(isolate()->factory()->Function_string(), class_name)) { STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
// Assuming the following assertions, we can use the same compares to test __ GetObjectType(input, temp, temp2);
// for both being a function type and being in the object type range. __ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
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);
__ GetObjectType(input, temp, temp2); // Objects with [[Call]] have class 'Function'.
__ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); __ lbu(temp2, FieldMemOperand(temp, Map::kBitFieldOffset));
__ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); __ And(temp2, temp2, Operand(1 << Map::kIsCallable));
__ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE)); if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
__ Branch(is_true, ne, temp2, Operand(zero_reg));
} else { } else {
// Faster code path to avoid two compares: subtract lower bound from the __ Branch(is_false, ne, temp2, Operand(zero_reg));
// 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));
} }
// 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. // Check if the constructor in the map is a function.
Register instance_type = scratch1(); Register instance_type = scratch1();
DCHECK(!instance_type.is(temp)); DCHECK(!instance_type.is(temp));

View File

@ -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, void MacroAssembler::IsObjectJSStringType(Register object,
Register scratch, Register scratch,
Label* fail) { Label* fail) {

View File

@ -977,16 +977,6 @@ class MacroAssembler: public Assembler {
InvokeFlag flag, InvokeFlag flag,
const CallWrapper& call_wrapper); 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, void IsObjectJSStringType(Register object,
Register scratch, Register scratch,
Label* fail); Label* fail);

View File

@ -2648,30 +2648,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
__ JumpIfSmi(input, is_false); __ JumpIfSmi(input, is_false);
if (String::Equals(isolate()->factory()->Function_string(), class_name)) { STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
// Assuming the following assertions, we can use the same compares to test __ GetObjectType(input, temp, temp2);
// for both being a function type and being in the object type range. __ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
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);
__ GetObjectType(input, temp, temp2); // Objects with [[Call]] have class 'Function'.
__ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); __ lbu(temp2, FieldMemOperand(temp, Map::kBitFieldOffset));
__ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); __ And(temp2, temp2, Operand(1 << Map::kIsCallable));
__ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE)); if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
__ Branch(is_true, ne, temp2, Operand(zero_reg));
} else { } else {
// Faster code path to avoid two compares: subtract lower bound from the __ Branch(is_false, ne, temp2, Operand(zero_reg));
// 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));
} }
// 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. // Check if the constructor in the map is a function.
Register instance_type = scratch1(); Register instance_type = scratch1();
DCHECK(!instance_type.is(temp)); DCHECK(!instance_type.is(temp));

View File

@ -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, void MacroAssembler::IsObjectJSStringType(Register object,
Register scratch, Register scratch,
Label* fail) { Label* fail) {

View File

@ -1008,15 +1008,6 @@ class MacroAssembler: public Assembler {
const CallWrapper& call_wrapper); 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, void IsObjectJSStringType(Register object,
Register scratch, Register scratch,
Label* fail); Label* fail);

View File

@ -58,9 +58,9 @@ Handle<HeapType> Object::OptimalType(Isolate* isolate,
if (representation.IsHeapObject() && IsHeapObject()) { if (representation.IsHeapObject() && IsHeapObject()) {
// We can track only JavaScript objects with stable maps. // We can track only JavaScript objects with stable maps.
Handle<Map> map(HeapObject::cast(this)->map(), isolate); Handle<Map> map(HeapObject::cast(this)->map(), isolate);
if (map->is_stable() && if (map->is_stable() && !map->is_callable() &&
map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE && map->instance_type() >= FIRST_JS_RECEIVER_TYPE &&
map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) { map->instance_type() <= LAST_JS_RECEIVER_TYPE) {
return HeapType::Class(map, isolate); return HeapType::Class(map, isolate);
} }
} }
@ -1650,7 +1650,10 @@ void Simd128Value::CopyBits(void* destination) const {
String* JSReceiver::class_name() { 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(); return GetHeap()->Function_string();
} }
Object* maybe_constructor = map()->GetConstructor(); Object* maybe_constructor = map()->GetConstructor();

View File

@ -708,8 +708,7 @@ enum InstanceType {
// All the following types are subtypes of JSReceiver, which corresponds to // 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 // 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 // the two forms of function. This organization enables using the same
// compares for checking the JS_RECEIVER/SPEC_OBJECT range and the // compares for checking the JS_RECEIVER/SPEC_OBJECT range.
// NONCALLABLE_JS_OBJECT range.
JS_FUNCTION_PROXY_TYPE, // FIRST_JS_RECEIVER_TYPE, FIRST_JS_PROXY_TYPE JS_FUNCTION_PROXY_TYPE, // FIRST_JS_RECEIVER_TYPE, FIRST_JS_PROXY_TYPE
JS_PROXY_TYPE, // LAST_JS_PROXY_TYPE JS_PROXY_TYPE, // LAST_JS_PROXY_TYPE
JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE
@ -766,13 +765,7 @@ enum InstanceType {
LAST_JS_PROXY_TYPE = JS_PROXY_TYPE, LAST_JS_PROXY_TYPE = JS_PROXY_TYPE,
// Boundaries for testing whether the type is a JavaScript object. // Boundaries for testing whether the type is a JavaScript object.
FIRST_SPEC_OBJECT_TYPE = FIRST_JS_RECEIVER_TYPE, FIRST_SPEC_OBJECT_TYPE = FIRST_JS_RECEIVER_TYPE,
LAST_SPEC_OBJECT_TYPE = LAST_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
}; };
STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType); STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType);

View File

@ -2572,32 +2572,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
__ JumpIfSmi(input, is_false); __ JumpIfSmi(input, is_false);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(input, FIRST_JS_RECEIVER_TYPE, temp);
__ j(below, is_false);
// Objects with [[Call]] have class 'Function'.
__ testb(FieldOperand(temp, Map::kBitFieldOffset),
Immediate(1 << Map::kIsCallable));
if (String::Equals(isolate()->factory()->Function_string(), class_name)) { if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
// Assuming the following assertions, we can use the same compares to test __ j(not_zero, is_true);
// 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);
__ j(below, is_false);
__ j(equal, is_true);
__ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
__ j(equal, is_true);
} else { } else {
// Faster code path to avoid two compares: subtract lower bound from the __ j(not_zero, is_false);
// 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);
} }
// 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. // Check if the constructor in the map is a function.
__ GetMapConstructor(temp, temp, kScratchRegister); __ GetMapConstructor(temp, temp, kScratchRegister);

View File

@ -3446,9 +3446,9 @@ void MacroAssembler::GetMapConstructor(Register result, Register map,
Label done, loop; Label done, loop;
movp(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); movp(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
bind(&loop); bind(&loop);
JumpIfSmi(result, &done); JumpIfSmi(result, &done, Label::kNear);
CmpObjectType(result, MAP_TYPE, temp); CmpObjectType(result, MAP_TYPE, temp);
j(not_equal, &done); j(not_equal, &done, Label::kNear);
movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
jmp(&loop); jmp(&loop);
bind(&done); bind(&done);