[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);
|
__ 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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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'.
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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));
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user