From af778389947f1b01fb036756ea3cb8ed8ab98452 Mon Sep 17 00:00:00 2001 From: bmeurer Date: Thu, 3 Sep 2015 07:09:55 -0700 Subject: [PATCH] [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} --- src/arm/lithium-codegen-arm.cc | 34 +++------- src/arm/macro-assembler-arm.cc | 20 ------ src/arm/macro-assembler-arm.h | 9 --- src/arm64/lithium-codegen-arm64.cc | 28 +++----- src/arm64/macro-assembler-arm64-inl.h | 26 ------- src/arm64/macro-assembler-arm64.h | 14 ---- src/full-codegen/arm/full-codegen-arm.cc | 29 +++----- src/full-codegen/arm64/full-codegen-arm64.cc | 28 +++----- src/full-codegen/ia32/full-codegen-ia32.cc | 68 ++++++++----------- src/full-codegen/mips/full-codegen-mips.cc | 28 +++----- .../mips64/full-codegen-mips64.cc | 26 +++---- src/full-codegen/x64/full-codegen-x64.cc | 67 ++++++++---------- src/ia32/lithium-codegen-ia32.cc | 31 +++------ src/ia32/macro-assembler-ia32.cc | 24 +------ src/ia32/macro-assembler-ia32.h | 12 ---- src/mips/lithium-codegen-mips.cc | 30 +++----- src/mips/macro-assembler-mips.cc | 18 ----- src/mips/macro-assembler-mips.h | 10 --- src/mips64/lithium-codegen-mips64.cc | 30 +++----- src/mips64/macro-assembler-mips64.cc | 18 ----- src/mips64/macro-assembler-mips64.h | 9 --- src/objects.cc | 11 +-- src/objects.h | 11 +-- src/x64/lithium-codegen-x64.cc | 32 +++------ src/x64/macro-assembler-x64.cc | 4 +- 25 files changed, 177 insertions(+), 440 deletions(-) diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 6e368de03..f82c8b860 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -2618,39 +2618,27 @@ void LCodeGen::EmitClassOfTest(Label* is_true, __ 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)) { - // 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); + __ b(ne, is_true); } else { - // Faster code path to avoid two compares: subtract lower bound from the - // actual type and do a signed compare with the width of the type range. - __ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset)); - __ ldrb(temp2, FieldMemOperand(temp, Map::kInstanceTypeOffset)); - __ sub(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ cmp(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ b(gt, is_false); + __ b(ne, is_false); } - // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. + // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range. // Check if the constructor in the map is a function. Register instance_type = ip; __ GetMapConstructor(temp, temp, temp2, instance_type); // Objects with a non-function constructor have class 'Object'. __ cmp(instance_type, Operand(JS_FUNCTION_TYPE)); - if (class_name->IsOneByteEqualTo(STATIC_CHAR_VECTOR("Object"))) { + if (String::Equals(isolate()->factory()->Object_string(), class_name)) { __ b(ne, is_true); } else { __ b(ne, is_false); diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 3572e1cd3..057a59cf5 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -1390,26 +1390,6 @@ void MacroAssembler::InvokeFunction(Handle function, } -void MacroAssembler::IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail) { - ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset)); - IsInstanceJSObjectType(map, scratch, fail); -} - - -void MacroAssembler::IsInstanceJSObjectType(Register map, - Register scratch, - Label* fail) { - ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); - cmp(scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - b(lt, fail); - cmp(scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); - b(gt, fail); -} - - void MacroAssembler::IsObjectJSStringType(Register object, Register scratch, Label* fail) { diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 702cedb57..d41878574 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -662,15 +662,6 @@ class MacroAssembler: public Assembler { InvokeFlag flag, const CallWrapper& call_wrapper); - void IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail); - - void IsInstanceJSObjectType(Register map, - Register scratch, - Label* fail); - void IsObjectJSStringType(Register object, Register scratch, Label* fail); diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index 529352d77..fc270c461 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -2355,27 +2355,21 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { __ 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)) { - // 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); + __ B(ne, true_label); } else { - __ IsObjectJSObjectType(input, map, scratch1, false_label); + __ B(ne, false_label); } - // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. + // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range. // Check if the constructor in the map is a function. { UseScratchRegisterScope temps(masm()); diff --git a/src/arm64/macro-assembler-arm64-inl.h b/src/arm64/macro-assembler-arm64-inl.h index 445513bf5..a915058d3 100644 --- a/src/arm64/macro-assembler-arm64-inl.h +++ b/src/arm64/macro-assembler-arm64-inl.h @@ -1434,32 +1434,6 @@ void MacroAssembler::IsObjectNameType(Register object, } -void MacroAssembler::IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail) { - Ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset)); - IsInstanceJSObjectType(map, scratch, fail); -} - - -void MacroAssembler::IsInstanceJSObjectType(Register map, - Register scratch, - Label* fail) { - Ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); - // If cmp result is lt, the following ccmp will clear all flags. - // Z == 0, N == V implies gt condition. - Cmp(scratch, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); - Ccmp(scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE, NoFlag, ge); - - // If we didn't get a valid label object just fall through and leave the - // flags updated. - if (fail != NULL) { - B(gt, fail); - } -} - - void MacroAssembler::IsObjectJSStringType(Register object, Register type, Label* not_string, diff --git a/src/arm64/macro-assembler-arm64.h b/src/arm64/macro-assembler-arm64.h index a050a74fc..9e81efe1b 100644 --- a/src/arm64/macro-assembler-arm64.h +++ b/src/arm64/macro-assembler-arm64.h @@ -1490,20 +1490,6 @@ class MacroAssembler : public Assembler { // Fall-through if the object was a string and jump on fail otherwise. inline void IsObjectNameType(Register object, Register type, Label* fail); - inline void IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail); - - // Check the instance type in the given map to see if it corresponds to a - // JS object type. Jump to the fail label if this is not the case and fall - // through otherwise. However if fail label is NULL, no branch will be - // performed and the flag will be updated. You can test the flag for "le" - // condition to test if it is a valid JS object type. - inline void IsInstanceJSObjectType(Register map, - Register scratch, - Label* fail); - // Load and check the instance type of an object for being a string. // Loads the type into the second argument register. // The object and type arguments can be the same register; in that case it diff --git a/src/full-codegen/arm/full-codegen-arm.cc b/src/full-codegen/arm/full-codegen-arm.cc index 7d8181774..988e9a738 100644 --- a/src/full-codegen/arm/full-codegen-arm.cc +++ b/src/full-codegen/arm/full-codegen-arm.cc @@ -3663,7 +3663,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); + DCHECK_EQ(1, args->length()); Label done, null, function, non_function_constructor; VisitForAccumulatorValue(args->at(0)); @@ -3671,24 +3671,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { // If the object is a smi, we return null. __ JumpIfSmi(r0, &null); - // Check that the object is a JS object but take special care of JS - // functions to make sure they have 'Function' as their class. - // Assume that there are only two callable types, and one of them is at - // either end of the type range for JS object types. Saves extra comparisons. - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - __ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE); - // Map is now in r0. + // If the object is not a receiver, we return null. + STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); + __ CompareObjectType(r0, r0, r1, FIRST_JS_RECEIVER_TYPE); __ b(lt, &null); - STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == - FIRST_SPEC_OBJECT_TYPE + 1); - __ b(eq, &function); - - __ cmp(r1, Operand(LAST_SPEC_OBJECT_TYPE)); - STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == - LAST_SPEC_OBJECT_TYPE - 1); - __ b(eq, &function); - // Assume that there is no larger type. - STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); + + // According to ES5 section 15 Standard Built-in ECMAScript Objects, the + // [[Class]] of builtin objects is "Function" if a [[Call]] internal + // method is present. + __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); + __ tst(r1, Operand(1 << Map::kIsCallable)); + __ b(ne, &function); // Check if the constructor in the map is a JS function. Register instance_type = r2; diff --git a/src/full-codegen/arm64/full-codegen-arm64.cc b/src/full-codegen/arm64/full-codegen-arm64.cc index 8b32fc9dc..cf238e594 100644 --- a/src/full-codegen/arm64/full-codegen-arm64.cc +++ b/src/full-codegen/arm64/full-codegen-arm64.cc @@ -3390,7 +3390,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { ASM_LOCATION("FullCodeGenerator::EmitClassOf"); ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); + DCHECK_EQ(1, args->length()); Label done, null, function, non_function_constructor; VisitForAccumulatorValue(args->at(0)); @@ -3398,25 +3398,19 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { // If the object is a smi, we return null. __ JumpIfSmi(x0, &null); - // Check that the object is a JS object but take special care of JS - // functions to make sure they have 'Function' as their class. - // Assume that there are only two callable types, and one of them is at - // either end of the type range for JS object types. Saves extra comparisons. - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - __ CompareObjectType(x0, x10, x11, FIRST_SPEC_OBJECT_TYPE); + // If the object is not a receiver, we return null. + STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); + __ CompareObjectType(x0, x10, x11, FIRST_JS_RECEIVER_TYPE); // x10: object's map. // x11: object's type. __ B(lt, &null); - STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == - FIRST_SPEC_OBJECT_TYPE + 1); - __ B(eq, &function); - - __ Cmp(x11, LAST_SPEC_OBJECT_TYPE); - STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == - LAST_SPEC_OBJECT_TYPE - 1); - __ B(eq, &function); - // Assume that there is no larger type. - STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); + + // According to ES5 section 15 Standard Built-in ECMAScript Objects, the + // [[Class]] of builtin objects is "Function" if a [[Call]] internal + // method is present. + __ Ldrb(x11, FieldMemOperand(x10, Map::kBitFieldOffset)); + __ Tst(x11, 1 << Map::kIsCallable); + __ B(ne, &function); // Check if the constructor in the map is a JS function. Register instance_type = x14; diff --git a/src/full-codegen/ia32/full-codegen-ia32.cc b/src/full-codegen/ia32/full-codegen-ia32.cc index df7ae9c5e..6df2ce277 100644 --- a/src/full-codegen/ia32/full-codegen-ia32.cc +++ b/src/full-codegen/ia32/full-codegen-ia32.cc @@ -3565,57 +3565,49 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; + DCHECK_EQ(1, args->length()); + Label done, null, function, function_constructor; VisitForAccumulatorValue(args->at(0)); // If the object is a smi, we return null. - __ JumpIfSmi(eax, &null); - - // 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); + __ 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); // Check if the constructor in the map is a JS function. __ GetMapConstructor(eax, eax, ebx); __ CmpInstanceType(ebx, JS_FUNCTION_TYPE); - __ j(not_equal, &non_function_constructor); - - // 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); + __ j(equal, &function_constructor, Label::kNear); // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ mov(eax, isolate()->factory()->Object_string()); - __ jmp(&done); + __ LoadRoot(eax, Heap::kObject_stringRootIndex); + __ jmp(&done, Label::kNear); // Non-JS objects have class null. __ bind(&null); - __ mov(eax, isolate()->factory()->null_value()); + __ LoadRoot(eax, Heap::kNullValueRootIndex); + __ jmp(&done, Label::kNear); + + // Functions have class 'Function'. + __ bind(&function); + __ LoadRoot(eax, Heap::kFunction_stringRootIndex); + __ jmp(&done, Label::kNear); + + __ bind(&function_constructor); + // eax now contains the constructor function. Grab the + // instance class name from there. + __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); + __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); // All done. __ bind(&done); diff --git a/src/full-codegen/mips/full-codegen-mips.cc b/src/full-codegen/mips/full-codegen-mips.cc index e985f440c..215d7ae03 100644 --- a/src/full-codegen/mips/full-codegen-mips.cc +++ b/src/full-codegen/mips/full-codegen-mips.cc @@ -3663,7 +3663,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); + DCHECK_EQ(1, args->length()); Label done, null, function, non_function_constructor; VisitForAccumulatorValue(args->at(0)); @@ -3671,23 +3671,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { // If the object is a smi, we return null. __ JumpIfSmi(v0, &null); - // Check that the object is a JS object but take special care of JS - // functions to make sure they have 'Function' as their class. - // Assume that there are only two callable types, and one of them is at - // either end of the type range for JS object types. Saves extra comparisons. - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); + // If the object is not a receiver, we return null. + STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); __ GetObjectType(v0, v0, a1); // Map is now in v0. - __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); - - 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); + __ 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)); // Check if the constructor in the map is a JS function. Register instance_type = a2; diff --git a/src/full-codegen/mips64/full-codegen-mips64.cc b/src/full-codegen/mips64/full-codegen-mips64.cc index bd1fea27d..fcaa99a0d 100644 --- a/src/full-codegen/mips64/full-codegen-mips64.cc +++ b/src/full-codegen/mips64/full-codegen-mips64.cc @@ -3674,23 +3674,17 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { // If the object is a smi, we return null. __ JumpIfSmi(v0, &null); - // Check that the object is a JS object but take special care of JS - // functions to make sure they have 'Function' as their class. - // Assume that there are only two callable types, and one of them is at - // either end of the type range for JS object types. Saves extra comparisons. - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); + // If the object is not a receiver, we return null. + STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); __ GetObjectType(v0, v0, a1); // Map is now in v0. - __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); - - 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); + __ 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)); // Check if the constructor in the map is a JS function. Register instance_type = a2; diff --git a/src/full-codegen/x64/full-codegen-x64.cc b/src/full-codegen/x64/full-codegen-x64.cc index 2010590a0..a7710072b 100644 --- a/src/full-codegen/x64/full-codegen-x64.cc +++ b/src/full-codegen/x64/full-codegen-x64.cc @@ -3548,57 +3548,50 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; + DCHECK_EQ(1, args->length()); + Label done, null, function, function_constructor; VisitForAccumulatorValue(args->at(0)); // If the object is a smi, we return null. - __ JumpIfSmi(rax, &null); - - // 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); + __ 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); // Check if the constructor in the map is a JS function. __ GetMapConstructor(rax, rax, rbx); __ CmpInstanceType(rbx, JS_FUNCTION_TYPE); - __ j(not_equal, &non_function_constructor); - - // rax now contains the constructor function. Grab the - // instance class name from there. - __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); - __ movp(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset)); - __ jmp(&done); - - // Functions have class 'Function'. - __ bind(&function); - __ Move(rax, isolate()->factory()->Function_string()); - __ jmp(&done); + __ j(equal, &function_constructor, Label::kNear); // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ Move(rax, isolate()->factory()->Object_string()); - __ jmp(&done); + __ LoadRoot(rax, Heap::kObject_stringRootIndex); + __ jmp(&done, Label::kNear); // Non-JS objects have class null. __ bind(&null); __ LoadRoot(rax, Heap::kNullValueRootIndex); + __ jmp(&done, Label::kNear); + + // Functions have class 'Function'. + __ bind(&function); + __ LoadRoot(rax, Heap::kFunction_stringRootIndex); + __ jmp(&done, Label::kNear); + + __ bind(&function_constructor); + // rax now contains the constructor function. Grab the + // instance class name from there. + __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); + __ movp(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset)); // All done. __ bind(&done); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 7f44b9e77..aa0ab58ff 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -2521,32 +2521,19 @@ void LCodeGen::EmitClassOfTest(Label* is_true, 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)) { - // 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); + __ j(not_zero, is_true); } else { - // Faster code path to avoid two compares: subtract lower bound from the - // actual type and do a signed compare with the width of the type range. - __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); - __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset)); - __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ j(above, is_false); + __ j(not_zero, is_false); } - // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. + // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range. // Check if the constructor in the map is a function. __ GetMapConstructor(temp, temp, temp2); // Objects with a non-function constructor have class 'Object'. diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index a6b130b5a..b05384d05 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -752,26 +752,6 @@ Condition MacroAssembler::IsObjectNameType(Register heap_object, } -void MacroAssembler::IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail) { - mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); - IsInstanceJSObjectType(map, scratch, fail); -} - - -void MacroAssembler::IsInstanceJSObjectType(Register map, - Register scratch, - Label* fail) { - movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset)); - sub(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - cmp(scratch, - LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); - j(above, fail); -} - - void MacroAssembler::FCmp() { fucomip(); fstp(0); @@ -1784,9 +1764,9 @@ void MacroAssembler::GetMapConstructor(Register result, Register map, Label done, loop; mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); bind(&loop); - JumpIfSmi(result, &done); + JumpIfSmi(result, &done, Label::kNear); CmpObjectType(result, MAP_TYPE, temp); - j(not_equal, &done); + j(not_equal, &done, Label::kNear); mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); jmp(&loop); bind(&done); diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index 8f7cae92b..dd90650f6 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -452,18 +452,6 @@ class MacroAssembler: public Assembler { Register map, Register instance_type); - // Check if a heap object's type is in the JSObject range, not including - // JSFunction. The object's map will be loaded in the map register. - // Any or all of the three registers may be the same. - // The contents of the scratch register will always be overwritten. - void IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail); - - // The contents of the scratch register will be overwritten. - void IsInstanceJSObjectType(Register map, Register scratch, Label* fail); - // FCmp is similar to integer cmp, but requires unsigned // jcc instructions (je, ja, jae, jb, jbe, je, and jz). void FCmp(); diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 5586ed1ab..c98da6294 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -2544,30 +2544,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true, __ JumpIfSmi(input, is_false); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - // Assuming the following assertions, we can use the same compares to test - // for both being a function type and being in the object type range. - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == - FIRST_SPEC_OBJECT_TYPE + 1); - STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == - LAST_SPEC_OBJECT_TYPE - 1); - STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); + __ GetObjectType(input, temp, temp2); + __ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE)); - __ GetObjectType(input, temp, temp2); - __ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); - __ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); - __ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE)); + // Objects with [[Call]] have class 'Function'. + __ lbu(temp2, FieldMemOperand(temp, Map::kBitFieldOffset)); + __ And(temp2, temp2, Operand(1 << Map::kIsCallable)); + if (String::Equals(isolate()->factory()->Function_string(), class_name)) { + __ Branch(is_true, ne, temp2, Operand(zero_reg)); } else { - // Faster code path to avoid two compares: subtract lower bound from the - // actual type and do a signed compare with the width of the type range. - __ GetObjectType(input, temp, temp2); - __ Subu(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); + __ Branch(is_false, ne, temp2, Operand(zero_reg)); } - // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. + // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range. // Check if the constructor in the map is a function. Register instance_type = scratch1(); DCHECK(!instance_type.is(temp)); diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc index 8a75ae934..9ba814ae2 100644 --- a/src/mips/macro-assembler-mips.cc +++ b/src/mips/macro-assembler-mips.cc @@ -4214,24 +4214,6 @@ void MacroAssembler::InvokeFunction(Handle function, } -void MacroAssembler::IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail) { - lw(map, FieldMemOperand(heap_object, HeapObject::kMapOffset)); - IsInstanceJSObjectType(map, scratch, fail); -} - - -void MacroAssembler::IsInstanceJSObjectType(Register map, - Register scratch, - Label* fail) { - lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); - Branch(fail, lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - Branch(fail, gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); -} - - void MacroAssembler::IsObjectJSStringType(Register object, Register scratch, Label* fail) { diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h index a126e55ac..5e1d2c625 100644 --- a/src/mips/macro-assembler-mips.h +++ b/src/mips/macro-assembler-mips.h @@ -977,16 +977,6 @@ class MacroAssembler: public Assembler { InvokeFlag flag, const CallWrapper& call_wrapper); - - void IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail); - - void IsInstanceJSObjectType(Register map, - Register scratch, - Label* fail); - void IsObjectJSStringType(Register object, Register scratch, Label* fail); diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc index a612681c5..80befa531 100644 --- a/src/mips64/lithium-codegen-mips64.cc +++ b/src/mips64/lithium-codegen-mips64.cc @@ -2648,30 +2648,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true, __ JumpIfSmi(input, is_false); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - // Assuming the following assertions, we can use the same compares to test - // for both being a function type and being in the object type range. - STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); - STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == - FIRST_SPEC_OBJECT_TYPE + 1); - STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == - LAST_SPEC_OBJECT_TYPE - 1); - STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); + STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); + __ GetObjectType(input, temp, temp2); + __ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE)); - __ GetObjectType(input, temp, temp2); - __ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); - __ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); - __ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE)); + // Objects with [[Call]] have class 'Function'. + __ lbu(temp2, FieldMemOperand(temp, Map::kBitFieldOffset)); + __ And(temp2, temp2, Operand(1 << Map::kIsCallable)); + if (String::Equals(isolate()->factory()->Function_string(), class_name)) { + __ Branch(is_true, ne, temp2, Operand(zero_reg)); } else { - // Faster code path to avoid two compares: subtract lower bound from the - // actual type and do a signed compare with the width of the type range. - __ GetObjectType(input, temp, temp2); - __ Dsubu(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); + __ Branch(is_false, ne, temp2, Operand(zero_reg)); } - // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. + // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range. // Check if the constructor in the map is a function. Register instance_type = scratch1(); DCHECK(!instance_type.is(temp)); diff --git a/src/mips64/macro-assembler-mips64.cc b/src/mips64/macro-assembler-mips64.cc index 1e9aebd9a..a379d847a 100644 --- a/src/mips64/macro-assembler-mips64.cc +++ b/src/mips64/macro-assembler-mips64.cc @@ -4217,24 +4217,6 @@ void MacroAssembler::InvokeFunction(Handle function, } -void MacroAssembler::IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail) { - ld(map, FieldMemOperand(heap_object, HeapObject::kMapOffset)); - IsInstanceJSObjectType(map, scratch, fail); -} - - -void MacroAssembler::IsInstanceJSObjectType(Register map, - Register scratch, - Label* fail) { - lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); - Branch(fail, lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - Branch(fail, gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); -} - - void MacroAssembler::IsObjectJSStringType(Register object, Register scratch, Label* fail) { diff --git a/src/mips64/macro-assembler-mips64.h b/src/mips64/macro-assembler-mips64.h index 7691ba4d8..17e0857ba 100644 --- a/src/mips64/macro-assembler-mips64.h +++ b/src/mips64/macro-assembler-mips64.h @@ -1008,15 +1008,6 @@ class MacroAssembler: public Assembler { const CallWrapper& call_wrapper); - void IsObjectJSObjectType(Register heap_object, - Register map, - Register scratch, - Label* fail); - - void IsInstanceJSObjectType(Register map, - Register scratch, - Label* fail); - void IsObjectJSStringType(Register object, Register scratch, Label* fail); diff --git a/src/objects.cc b/src/objects.cc index c0539c493..60f1e5bdc 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -58,9 +58,9 @@ Handle Object::OptimalType(Isolate* isolate, if (representation.IsHeapObject() && IsHeapObject()) { // We can track only JavaScript objects with stable maps. Handle map(HeapObject::cast(this)->map(), isolate); - if (map->is_stable() && - map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE && - map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) { + if (map->is_stable() && !map->is_callable() && + map->instance_type() >= FIRST_JS_RECEIVER_TYPE && + map->instance_type() <= LAST_JS_RECEIVER_TYPE) { return HeapType::Class(map, isolate); } } @@ -1650,7 +1650,10 @@ void Simd128Value::CopyBits(void* destination) const { String* JSReceiver::class_name() { - if (IsJSFunction() || IsJSFunctionProxy()) { + // According to ES5 section 15 Standard Built-in ECMAScript Objects, the + // [[Class]] of builtin objects is "Function" if a [[Call]] internal + // method is present. + if (IsCallable()) { return GetHeap()->Function_string(); } Object* maybe_constructor = map()->GetConstructor(); diff --git a/src/objects.h b/src/objects.h index 4ece658d3..a07ab50e3 100644 --- a/src/objects.h +++ b/src/objects.h @@ -708,8 +708,7 @@ enum InstanceType { // All the following types are subtypes of JSReceiver, which corresponds to // objects in the JS sense. The first and the last type in this range are // the two forms of function. This organization enables using the same - // compares for checking the JS_RECEIVER/SPEC_OBJECT range and the - // NONCALLABLE_JS_OBJECT range. + // compares for checking the JS_RECEIVER/SPEC_OBJECT range. JS_FUNCTION_PROXY_TYPE, // FIRST_JS_RECEIVER_TYPE, FIRST_JS_PROXY_TYPE JS_PROXY_TYPE, // LAST_JS_PROXY_TYPE JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE @@ -766,13 +765,7 @@ enum InstanceType { LAST_JS_PROXY_TYPE = JS_PROXY_TYPE, // Boundaries for testing whether the type is a JavaScript object. FIRST_SPEC_OBJECT_TYPE = FIRST_JS_RECEIVER_TYPE, - LAST_SPEC_OBJECT_TYPE = LAST_JS_RECEIVER_TYPE, - // Boundaries for testing the types for which typeof is "object". - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE = JS_PROXY_TYPE, - LAST_NONCALLABLE_SPEC_OBJECT_TYPE = JS_REGEXP_TYPE, - // Note that the types for which typeof is "function" are not continuous. - // Define this so that we can put assertions on discrete checks. - NUM_OF_CALLABLE_SPEC_OBJECT_TYPES = 2 + LAST_SPEC_OBJECT_TYPE = LAST_JS_RECEIVER_TYPE }; STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType); diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 250589097..322de11f5 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -2572,32 +2572,20 @@ void LCodeGen::EmitClassOfTest(Label* is_true, __ 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)) { - // 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); + __ j(not_zero, is_true); } else { - // Faster code path to avoid two compares: subtract lower bound from the - // actual type and do a signed compare with the width of the type range. - __ movp(temp, FieldOperand(input, HeapObject::kMapOffset)); - __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset)); - __ subp(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ cmpp(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - __ j(above, is_false); + __ j(not_zero, is_false); } - // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. + // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range. // Check if the constructor in the map is a function. __ GetMapConstructor(temp, temp, kScratchRegister); diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 8898f7bae..c67d955a8 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -3446,9 +3446,9 @@ void MacroAssembler::GetMapConstructor(Register result, Register map, Label done, loop; movp(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); bind(&loop); - JumpIfSmi(result, &done); + JumpIfSmi(result, &done, Label::kNear); CmpObjectType(result, MAP_TYPE, temp); - j(not_equal, &done); + j(not_equal, &done, Label::kNear); movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); jmp(&loop); bind(&done); -- 2.34.1