__ 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)) {
- __ b(ne, is_true);
+ // 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);
+ __ b(lt, is_false);
+ __ b(eq, is_true);
+ __ cmp(temp2, Operand(LAST_SPEC_OBJECT_TYPE));
+ __ b(eq, is_true);
} else {
- __ b(ne, is_false);
+ // 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);
}
- // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+ // 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 (String::Equals(isolate()->factory()->Object_string(), class_name)) {
+ if (class_name->IsOneByteEqualTo(STATIC_CHAR_VECTOR("Object"))) {
__ b(ne, is_true);
} else {
__ b(ne, is_false);
}
+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) {
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);
__ JumpIfSmi(input, false_label);
Register map = scratch2;
- STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
- __ CompareObjectType(input, map, scratch1, FIRST_JS_RECEIVER_TYPE);
- __ B(lt, false_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);
+ // 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);
+ __ B(lt, false_label);
+ __ B(eq, true_label);
+ __ Cmp(scratch1, LAST_SPEC_OBJECT_TYPE);
+ __ B(eq, true_label);
} else {
- __ B(ne, false_label);
+ __ IsObjectJSObjectType(input, map, scratch1, false_label);
}
- // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+ // 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());
}
+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,
// 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
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
- DCHECK_EQ(1, args->length());
+ DCHECK(args->length() == 1);
Label done, null, function, non_function_constructor;
VisitForAccumulatorValue(args->at(0));
// If the object is a smi, we return null.
__ JumpIfSmi(r0, &null);
- // 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);
+ // 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.
__ b(lt, &null);
-
- // 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);
+ 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);
// Check if the constructor in the map is a JS function.
Register instance_type = r2;
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ASM_LOCATION("FullCodeGenerator::EmitClassOf");
ZoneList<Expression*>* args = expr->arguments();
- DCHECK_EQ(1, args->length());
+ DCHECK(args->length() == 1);
Label done, null, function, non_function_constructor;
VisitForAccumulatorValue(args->at(0));
// If the object is a smi, we return null.
__ JumpIfSmi(x0, &null);
- // 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);
+ // 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);
// x10: object's map.
// x11: object's type.
__ B(lt, &null);
-
- // 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);
+ 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);
// Check if the constructor in the map is a JS function.
Register instance_type = x14;
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
- DCHECK_EQ(1, args->length());
- Label done, null, function, function_constructor;
+ DCHECK(args->length() == 1);
+ Label done, null, function, non_function_constructor;
VisitForAccumulatorValue(args->at(0));
// If the object is a smi, we return null.
- __ JumpIfSmi(eax, &null, Label::kNear);
-
- // 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);
-
- // 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);
+ __ 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);
+ __ 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);
+ 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);
// Check if the constructor in the map is a JS function.
__ GetMapConstructor(eax, eax, ebx);
__ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
- __ 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);
+ __ j(not_equal, &non_function_constructor);
- __ 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);
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
- DCHECK_EQ(1, args->length());
+ DCHECK(args->length() == 1);
Label done, null, function, non_function_constructor;
VisitForAccumulatorValue(args->at(0));
// If the object is a smi, we return null.
__ JumpIfSmi(v0, &null);
- // If the object is not a receiver, we return null.
- STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+ // 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);
__ GetObjectType(v0, v0, a1); // Map is now in v0.
- __ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
-
- // 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));
+ __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_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);
// Check if the constructor in the map is a JS function.
Register instance_type = a2;
// If the object is a smi, we return null.
__ JumpIfSmi(v0, &null);
- // If the object is not a receiver, we return null.
- STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+ // 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);
__ GetObjectType(v0, v0, a1); // Map is now in v0.
- __ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
-
- // 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));
+ __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_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);
// Check if the constructor in the map is a JS function.
Register instance_type = a2;
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
- DCHECK_EQ(1, args->length());
- Label done, null, function, function_constructor;
+ DCHECK(args->length() == 1);
+ Label done, null, function, non_function_constructor;
VisitForAccumulatorValue(args->at(0));
// If the object is a smi, we return null.
- __ JumpIfSmi(rax, &null, Label::kNear);
-
- // 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);
-
- // 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);
+ __ 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);
+ __ 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);
+ 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);
// Check if the constructor in the map is a JS function.
__ GetMapConstructor(rax, rax, rbx);
__ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
- __ j(equal, &function_constructor, Label::kNear);
+ __ 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);
// Objects with a non-function constructor have class 'Object'.
- __ LoadRoot(rax, Heap::kObject_stringRootIndex);
- __ jmp(&done, Label::kNear);
+ __ bind(&non_function_constructor);
+ __ Move(rax, isolate()->factory()->Object_string());
+ __ jmp(&done);
// 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);
DCHECK(!temp.is(temp2));
__ 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)) {
- __ j(not_zero, is_true);
+ // 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);
+ __ j(below, is_false);
+ __ j(equal, is_true);
+ __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
+ __ j(equal, is_true);
} else {
- __ j(not_zero, is_false);
+ // 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);
}
- // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+ // 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, temp2);
// Objects with a non-function constructor have class '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);
Label done, loop;
mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
bind(&loop);
- JumpIfSmi(result, &done, Label::kNear);
+ JumpIfSmi(result, &done);
CmpObjectType(result, MAP_TYPE, temp);
- j(not_equal, &done, Label::kNear);
+ j(not_equal, &done);
mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
jmp(&loop);
bind(&done);
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();
__ JumpIfSmi(input, is_false);
- STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
- __ GetObjectType(input, temp, temp2);
- __ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_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));
+ // 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);
+
+ __ 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));
} else {
- __ Branch(is_false, ne, temp2, Operand(zero_reg));
+ // 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));
}
- // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+ // 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));
}
+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) {
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);
__ JumpIfSmi(input, is_false);
- STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
- __ GetObjectType(input, temp, temp2);
- __ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_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));
+ // 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);
+
+ __ 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));
} else {
- __ Branch(is_false, ne, temp2, Operand(zero_reg));
+ // 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));
}
- // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+ // 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));
}
+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) {
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);
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->is_callable() &&
- map->instance_type() >= FIRST_JS_RECEIVER_TYPE &&
- map->instance_type() <= LAST_JS_RECEIVER_TYPE) {
+ if (map->is_stable() &&
+ map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
+ map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
return HeapType::Class(map, isolate);
}
}
String* JSReceiver::class_name() {
- // 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()) {
+ if (IsJSFunction() || IsJSFunctionProxy()) {
return GetHeap()->Function_string();
}
Object* maybe_constructor = map()->GetConstructor();
// 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.
+ // compares for checking the JS_RECEIVER/SPEC_OBJECT range and the
+ // NONCALLABLE_JS_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
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
+ 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);
__ 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)) {
- __ j(not_zero, is_true);
+ // 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);
+ __ j(below, is_false);
+ __ j(equal, is_true);
+ __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
+ __ j(equal, is_true);
} else {
- __ j(not_zero, is_false);
+ // 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);
}
- // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+ // 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);
Label done, loop;
movp(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
bind(&loop);
- JumpIfSmi(result, &done, Label::kNear);
+ JumpIfSmi(result, &done);
CmpObjectType(result, MAP_TYPE, temp);
- j(not_equal, &done, Label::kNear);
+ j(not_equal, &done);
movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
jmp(&loop);
bind(&done);