Revert of [es5] Class of object is "Function" if object has [[Call]]. (patchset ...
authormachenbach <machenbach@chromium.org>
Thu, 3 Sep 2015 15:02:34 +0000 (08:02 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 3 Sep 2015 15:02:48 +0000 (15:02 +0000)
Reason for revert:
[Sheriff] Changes several layout test expectations. Please fix upstream first if intended. E.g.:
https://build.chromium.org/p/client.v8.fyi/builders/V8-Blink%20Linux%2064/builds/1729

Several lines change from PASS to FAIL.

Original issue's description:
> [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
>
> Committed: https://crrev.com/af778389947f1b01fb036756ea3cb8ed8ab98452
> Cr-Commit-Position: refs/heads/master@{#30566}

TBR=jarin@chromium.org,jkummerow@chromium.org,bmeurer@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true

Review URL: https://codereview.chromium.org/1306303005

Cr-Commit-Position: refs/heads/master@{#30568}

25 files changed:
src/arm/lithium-codegen-arm.cc
src/arm/macro-assembler-arm.cc
src/arm/macro-assembler-arm.h
src/arm64/lithium-codegen-arm64.cc
src/arm64/macro-assembler-arm64-inl.h
src/arm64/macro-assembler-arm64.h
src/full-codegen/arm/full-codegen-arm.cc
src/full-codegen/arm64/full-codegen-arm64.cc
src/full-codegen/ia32/full-codegen-ia32.cc
src/full-codegen/mips/full-codegen-mips.cc
src/full-codegen/mips64/full-codegen-mips64.cc
src/full-codegen/x64/full-codegen-x64.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/mips/lithium-codegen-mips.cc
src/mips/macro-assembler-mips.cc
src/mips/macro-assembler-mips.h
src/mips64/lithium-codegen-mips64.cc
src/mips64/macro-assembler-mips64.cc
src/mips64/macro-assembler-mips64.h
src/objects.cc
src/objects.h
src/x64/lithium-codegen-x64.cc
src/x64/macro-assembler-x64.cc

index f82c8b8603e54171e18d16cecf67421fcdf0477f..6e368de036c72366b0f11e5ff6bee38b2233a562 100644 (file)
@@ -2618,27 +2618,39 @@ 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)) {
-    __ b(ne, is_true);
+    // Assuming the following assertions, we can use the same compares to test
+    // for both being a function type and being in the object type range.
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  FIRST_SPEC_OBJECT_TYPE + 1);
+    STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  LAST_SPEC_OBJECT_TYPE - 1);
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+    __ CompareObjectType(input, temp, temp2, FIRST_SPEC_OBJECT_TYPE);
+    __ b(lt, is_false);
+    __ b(eq, is_true);
+    __ cmp(temp2, Operand(LAST_SPEC_OBJECT_TYPE));
+    __ b(eq, is_true);
   } else {
-    __ b(ne, is_false);
+    // Faster code path to avoid two compares: subtract lower bound from the
+    // actual type and do a signed compare with the width of the type range.
+    __ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset));
+    __ ldrb(temp2, FieldMemOperand(temp, Map::kInstanceTypeOffset));
+    __ sub(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ cmp(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
+                          FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ b(gt, is_false);
   }
 
-  // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
   Register instance_type = ip;
   __ GetMapConstructor(temp, temp, temp2, instance_type);
 
   // Objects with a non-function constructor have class 'Object'.
   __ cmp(instance_type, Operand(JS_FUNCTION_TYPE));
-  if (String::Equals(isolate()->factory()->Object_string(), class_name)) {
+  if (class_name->IsOneByteEqualTo(STATIC_CHAR_VECTOR("Object"))) {
     __ b(ne, is_true);
   } else {
     __ b(ne, is_false);
index 057a59cf522fbf89e334d1d618c8c19bb136fccd..3572e1cd30a94fe49de2c8fe74938c9e328dd8fb 100644 (file)
@@ -1390,6 +1390,26 @@ void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
 }
 
 
+void MacroAssembler::IsObjectJSObjectType(Register heap_object,
+                                          Register map,
+                                          Register scratch,
+                                          Label* fail) {
+  ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
+  IsInstanceJSObjectType(map, scratch, fail);
+}
+
+
+void MacroAssembler::IsInstanceJSObjectType(Register map,
+                                            Register scratch,
+                                            Label* fail) {
+  ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  cmp(scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  b(lt, fail);
+  cmp(scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  b(gt, fail);
+}
+
+
 void MacroAssembler::IsObjectJSStringType(Register object,
                                           Register scratch,
                                           Label* fail) {
index d4187857402854045c378799b01618e518acdb16..702cedb57a0208e22ff9da676653bf0f9a99cd20 100644 (file)
@@ -662,6 +662,15 @@ 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);
index fc270c461848a79d5e5026551ea674093bbb701b..529352d77e621eee59eab594d09ac1c1ea55821f 100644 (file)
@@ -2355,21 +2355,27 @@ 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)) {
-    __ B(ne, true_label);
+    // Assuming the following assertions, we can use the same compares to test
+    // for both being a function type and being in the object type range.
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  FIRST_SPEC_OBJECT_TYPE + 1);
+    STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  LAST_SPEC_OBJECT_TYPE - 1);
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+
+    // We expect CompareObjectType to load the object instance type in scratch1.
+    __ CompareObjectType(input, map, scratch1, FIRST_SPEC_OBJECT_TYPE);
+    __ B(lt, false_label);
+    __ B(eq, true_label);
+    __ Cmp(scratch1, LAST_SPEC_OBJECT_TYPE);
+    __ B(eq, true_label);
   } else {
-    __ B(ne, false_label);
+    __ IsObjectJSObjectType(input, map, scratch1, false_label);
   }
 
-  // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
   {
     UseScratchRegisterScope temps(masm());
index a915058d3164edfd5b1a584685c005b5bcaeca15..445513bf5abb619ca68d959fc1f4866b7c8fb393 100644 (file)
@@ -1434,6 +1434,32 @@ 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,
index 9e81efe1b14db1ea1ec2073fafc3ef2270fd4ac0..a050a74fcbc9311db13a74d2a363426595f21446 100644 (file)
@@ -1490,6 +1490,20 @@ 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
index 988e9a73852729e2399e107b9c12c3bfe7e6f34c..7d8181774c6bf96f71f254d784bb10ca39c374ff 100644 (file)
@@ -3663,7 +3663,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
 
 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
-  DCHECK_EQ(1, args->length());
+  DCHECK(args->length() == 1);
   Label done, null, function, non_function_constructor;
 
   VisitForAccumulatorValue(args->at(0));
@@ -3671,17 +3671,24 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   // If the object is a smi, we return null.
   __ JumpIfSmi(r0, &null);
 
-  // If the object is not a receiver, we return null.
-  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
-  __ CompareObjectType(r0, r0, r1, FIRST_JS_RECEIVER_TYPE);
+  // Check that the object is a JS object but take special care of JS
+  // functions to make sure they have 'Function' as their class.
+  // Assume that there are only two callable types, and one of them is at
+  // either end of the type range for JS object types. Saves extra comparisons.
+  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+  __ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE);
+  // Map is now in r0.
   __ b(lt, &null);
-
-  // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
-  // [[Class]] of builtin objects is "Function" if a [[Call]] internal
-  // method is present.
-  __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
-  __ tst(r1, Operand(1 << Map::kIsCallable));
-  __ b(ne, &function);
+  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                FIRST_SPEC_OBJECT_TYPE + 1);
+  __ b(eq, &function);
+
+  __ cmp(r1, Operand(LAST_SPEC_OBJECT_TYPE));
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                LAST_SPEC_OBJECT_TYPE - 1);
+  __ b(eq, &function);
+  // Assume that there is no larger type.
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
   Register instance_type = r2;
index cf238e59470d74fde6f3692353da238495dbb1df..8b32fc9dcab80683c15d72a9221f6b4ebf762717 100644 (file)
@@ -3390,7 +3390,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   ASM_LOCATION("FullCodeGenerator::EmitClassOf");
   ZoneList<Expression*>* args = expr->arguments();
-  DCHECK_EQ(1, args->length());
+  DCHECK(args->length() == 1);
   Label done, null, function, non_function_constructor;
 
   VisitForAccumulatorValue(args->at(0));
@@ -3398,19 +3398,25 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   // If the object is a smi, we return null.
   __ JumpIfSmi(x0, &null);
 
-  // If the object is not a receiver, we return null.
-  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
-  __ CompareObjectType(x0, x10, x11, FIRST_JS_RECEIVER_TYPE);
+  // Check that the object is a JS object but take special care of JS
+  // functions to make sure they have 'Function' as their class.
+  // Assume that there are only two callable types, and one of them is at
+  // either end of the type range for JS object types. Saves extra comparisons.
+  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+  __ CompareObjectType(x0, x10, x11, FIRST_SPEC_OBJECT_TYPE);
   // x10: object's map.
   // x11: object's type.
   __ B(lt, &null);
-
-  // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
-  // [[Class]] of builtin objects is "Function" if a [[Call]] internal
-  // method is present.
-  __ Ldrb(x11, FieldMemOperand(x10, Map::kBitFieldOffset));
-  __ Tst(x11, 1 << Map::kIsCallable);
-  __ B(ne, &function);
+  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                FIRST_SPEC_OBJECT_TYPE + 1);
+  __ B(eq, &function);
+
+  __ Cmp(x11, LAST_SPEC_OBJECT_TYPE);
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                LAST_SPEC_OBJECT_TYPE - 1);
+  __ B(eq, &function);
+  // Assume that there is no larger type.
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
   Register instance_type = x14;
index 6df2ce2778c95a7356a6a7459064ab44217c5ca9..df7ae9c5ec3b1f540e4068ff75a48515412490e6 100644 (file)
@@ -3565,49 +3565,57 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
 
 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
-  DCHECK_EQ(1, args->length());
-  Label done, null, function, function_constructor;
+  DCHECK(args->length() == 1);
+  Label done, null, function, non_function_constructor;
 
   VisitForAccumulatorValue(args->at(0));
 
   // If the object is a smi, we return null.
-  __ JumpIfSmi(eax, &null, Label::kNear);
-
-  // If the object is not a receiver, we return null.
-  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
-  __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax);
-  __ j(below, &null, Label::kNear);
-
-  // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
-  // [[Class]] of builtin objects is "Function" if a [[Call]] internal
-  // method is present.
-  __ test_b(FieldOperand(eax, Map::kBitFieldOffset), 1 << Map::kIsCallable);
-  __ j(not_zero, &function, Label::kNear);
+  __ JumpIfSmi(eax, &null);
+
+  // Check that the object is a JS object but take special care of JS
+  // functions to make sure they have 'Function' as their class.
+  // Assume that there are only two callable types, and one of them is at
+  // either end of the type range for JS object types. Saves extra comparisons.
+  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+  __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
+  // Map is now in eax.
+  __ j(below, &null);
+  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                FIRST_SPEC_OBJECT_TYPE + 1);
+  __ j(equal, &function);
+
+  __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                LAST_SPEC_OBJECT_TYPE - 1);
+  __ j(equal, &function);
+  // Assume that there is no larger type.
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
   __ GetMapConstructor(eax, eax, ebx);
   __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
-  __ j(equal, &function_constructor, Label::kNear);
-
-  // Objects with a non-function constructor have class 'Object'.
-  __ LoadRoot(eax, Heap::kObject_stringRootIndex);
-  __ jmp(&done, Label::kNear);
-
-  // Non-JS objects have class null.
-  __ bind(&null);
-  __ LoadRoot(eax, Heap::kNullValueRootIndex);
-  __ jmp(&done, Label::kNear);
-
-  // Functions have class 'Function'.
-  __ bind(&function);
-  __ LoadRoot(eax, Heap::kFunction_stringRootIndex);
-  __ jmp(&done, Label::kNear);
+  __ j(not_equal, &non_function_constructor);
 
-  __ bind(&function_constructor);
   // eax now contains the constructor function. Grab the
   // instance class name from there.
   __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
   __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
+  __ jmp(&done);
+
+  // Functions have class 'Function'.
+  __ bind(&function);
+  __ mov(eax, isolate()->factory()->Function_string());
+  __ jmp(&done);
+
+  // Objects with a non-function constructor have class 'Object'.
+  __ bind(&non_function_constructor);
+  __ mov(eax, isolate()->factory()->Object_string());
+  __ jmp(&done);
+
+  // Non-JS objects have class null.
+  __ bind(&null);
+  __ mov(eax, isolate()->factory()->null_value());
 
   // All done.
   __ bind(&done);
index 215d7ae0321798f62b5930284a65f835df9ec00d..e985f440c780d0b099f4d8e94ca4d93a28994076 100644 (file)
@@ -3663,7 +3663,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
 
 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
-  DCHECK_EQ(1, args->length());
+  DCHECK(args->length() == 1);
   Label done, null, function, non_function_constructor;
 
   VisitForAccumulatorValue(args->at(0));
@@ -3671,17 +3671,23 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   // If the object is a smi, we return null.
   __ JumpIfSmi(v0, &null);
 
-  // If the object is not a receiver, we return null.
-  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+  // Check that the object is a JS object but take special care of JS
+  // functions to make sure they have 'Function' as their class.
+  // Assume that there are only two callable types, and one of them is at
+  // either end of the type range for JS object types. Saves extra comparisons.
+  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
   __ GetObjectType(v0, v0, a1);  // Map is now in v0.
-  __ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
-
-  // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
-  // [[Class]] of builtin objects is "Function" if a [[Call]] internal
-  // method is present.
-  __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
-  __ And(a1, a1, Operand(1 << Map::kIsCallable));
-  __ Branch(&function, ne, a1, Operand(zero_reg));
+  __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
+
+  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                FIRST_SPEC_OBJECT_TYPE + 1);
+  __ Branch(&function, eq, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
+
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                LAST_SPEC_OBJECT_TYPE - 1);
+  __ Branch(&function, eq, a1, Operand(LAST_SPEC_OBJECT_TYPE));
+  // Assume that there is no larger type.
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
   Register instance_type = a2;
index fcaa99a0ddef45d16968f0be3775d396801184c8..bd1fea27d5839113b4bd443066e4eddc0b7e5e6d 100644 (file)
@@ -3674,17 +3674,23 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   // If the object is a smi, we return null.
   __ JumpIfSmi(v0, &null);
 
-  // If the object is not a receiver, we return null.
-  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+  // Check that the object is a JS object but take special care of JS
+  // functions to make sure they have 'Function' as their class.
+  // Assume that there are only two callable types, and one of them is at
+  // either end of the type range for JS object types. Saves extra comparisons.
+  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
   __ GetObjectType(v0, v0, a1);  // Map is now in v0.
-  __ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
-
-  // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
-  // [[Class]] of builtin objects is "Function" if a [[Call]] internal
-  // method is present.
-  __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
-  __ And(a1, a1, Operand(1 << Map::kIsCallable));
-  __ Branch(&function, ne, a1, Operand(zero_reg));
+  __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
+
+  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                FIRST_SPEC_OBJECT_TYPE + 1);
+  __ Branch(&function, eq, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
+
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                LAST_SPEC_OBJECT_TYPE - 1);
+  __ Branch(&function, eq, a1, Operand(LAST_SPEC_OBJECT_TYPE));
+  // Assume that there is no larger type.
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
   Register instance_type = a2;
index a7710072babe329c9fdee9204acd3c5da450cee6..2010590a0427c5064a0c31739d11bfbceed63128 100644 (file)
@@ -3548,50 +3548,57 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
 
 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
-  DCHECK_EQ(1, args->length());
-  Label done, null, function, function_constructor;
+  DCHECK(args->length() == 1);
+  Label done, null, function, non_function_constructor;
 
   VisitForAccumulatorValue(args->at(0));
 
   // If the object is a smi, we return null.
-  __ JumpIfSmi(rax, &null, Label::kNear);
-
-  // If the object is not a receiver, we return null.
-  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
-  __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rax);
-  __ j(below, &null, Label::kNear);
-
-  // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
-  // [[Class]] of builtin objects is "Function" if a [[Call]] internal
-  // method is present.
-  __ testb(FieldOperand(rax, Map::kBitFieldOffset),
-           Immediate(1 << Map::kIsCallable));
-  __ j(not_zero, &function, Label::kNear);
+  __ JumpIfSmi(rax, &null);
+
+  // Check that the object is a JS object but take special care of JS
+  // functions to make sure they have 'Function' as their class.
+  // Assume that there are only two callable types, and one of them is at
+  // either end of the type range for JS object types. Saves extra comparisons.
+  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+  __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
+  // Map is now in rax.
+  __ j(below, &null);
+  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                FIRST_SPEC_OBJECT_TYPE + 1);
+  __ j(equal, &function);
+
+  __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                LAST_SPEC_OBJECT_TYPE - 1);
+  __ j(equal, &function);
+  // Assume that there is no larger type.
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
   __ GetMapConstructor(rax, rax, rbx);
   __ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
-  __ j(equal, &function_constructor, Label::kNear);
+  __ j(not_equal, &non_function_constructor);
+
+  // rax now contains the constructor function. Grab the
+  // instance class name from there.
+  __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
+  __ movp(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
+  __ jmp(&done);
+
+  // Functions have class 'Function'.
+  __ bind(&function);
+  __ Move(rax, isolate()->factory()->Function_string());
+  __ jmp(&done);
 
   // Objects with a non-function constructor have class 'Object'.
-  __ LoadRoot(rax, Heap::kObject_stringRootIndex);
-  __ jmp(&done, Label::kNear);
+  __ bind(&non_function_constructor);
+  __ Move(rax, isolate()->factory()->Object_string());
+  __ jmp(&done);
 
   // Non-JS objects have class null.
   __ bind(&null);
   __ LoadRoot(rax, Heap::kNullValueRootIndex);
-  __ jmp(&done, Label::kNear);
-
-  // Functions have class 'Function'.
-  __ bind(&function);
-  __ LoadRoot(rax, Heap::kFunction_stringRootIndex);
-  __ jmp(&done, Label::kNear);
-
-  __ bind(&function_constructor);
-  // rax now contains the constructor function. Grab the
-  // instance class name from there.
-  __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
-  __ movp(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
 
   // All done.
   __ bind(&done);
index aa0ab58ff94911c3b20dc7a93907cb14ba7c1326..7f44b9e77eda404aa4d9206821d1fa0ffee950a9 100644 (file)
@@ -2521,19 +2521,32 @@ 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)) {
-    __ j(not_zero, is_true);
+    // Assuming the following assertions, we can use the same compares to test
+    // for both being a function type and being in the object type range.
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  FIRST_SPEC_OBJECT_TYPE + 1);
+    STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  LAST_SPEC_OBJECT_TYPE - 1);
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+    __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
+    __ j(below, is_false);
+    __ j(equal, is_true);
+    __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
+    __ j(equal, is_true);
   } else {
-    __ j(not_zero, is_false);
+    // Faster code path to avoid two compares: subtract lower bound from the
+    // actual type and do a signed compare with the width of the type range.
+    __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
+    __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
+    __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
+                                     FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ j(above, is_false);
   }
 
-  // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
   __ GetMapConstructor(temp, temp, temp2);
   // Objects with a non-function constructor have class 'Object'.
index b05384d05257068bead0af1cc966fe4bd77cb379..a6b130b5a29c779d9aa39a73f9f73c163f97cab7 100644 (file)
@@ -752,6 +752,26 @@ 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);
@@ -1764,9 +1784,9 @@ void MacroAssembler::GetMapConstructor(Register result, Register map,
   Label done, loop;
   mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
   bind(&loop);
-  JumpIfSmi(result, &done, Label::kNear);
+  JumpIfSmi(result, &done);
   CmpObjectType(result, MAP_TYPE, temp);
-  j(not_equal, &done, Label::kNear);
+  j(not_equal, &done);
   mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
   jmp(&loop);
   bind(&done);
index dd90650f6d588d63fa260a7f8bfd43399f64b63c..8f7cae92b5bdda2a152500340bbc72b8013e75ca 100644 (file)
@@ -452,6 +452,18 @@ 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();
index c98da629475efb8275e07af656779109583dbffa..5586ed1ab264e7dd1f1a68ed40a313ff71e370e3 100644 (file)
@@ -2544,20 +2544,30 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
 
   __ JumpIfSmi(input, is_false);
 
-  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
-  __ GetObjectType(input, temp, temp2);
-  __ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
-
-  // Objects with [[Call]] have class 'Function'.
-  __ lbu(temp2, FieldMemOperand(temp, Map::kBitFieldOffset));
-  __ And(temp2, temp2, Operand(1 << Map::kIsCallable));
   if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
-    __ Branch(is_true, ne, temp2, Operand(zero_reg));
+    // Assuming the following assertions, we can use the same compares to test
+    // for both being a function type and being in the object type range.
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  FIRST_SPEC_OBJECT_TYPE + 1);
+    STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  LAST_SPEC_OBJECT_TYPE - 1);
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+
+    __ GetObjectType(input, temp, temp2);
+    __ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
+    __ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
+    __ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE));
   } else {
-    __ Branch(is_false, ne, temp2, Operand(zero_reg));
+    // Faster code path to avoid two compares: subtract lower bound from the
+    // actual type and do a signed compare with the width of the type range.
+    __ GetObjectType(input, temp, temp2);
+    __ Subu(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
+                                           FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
   }
 
-  // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
   Register instance_type = scratch1();
   DCHECK(!instance_type.is(temp));
index 9ba814ae2ff85887350cd57c7d0cbe739834f1a1..8a75ae934fb54975b80e52e08ba6ebb22ab5fe43 100644 (file)
@@ -4214,6 +4214,24 @@ void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
 }
 
 
+void MacroAssembler::IsObjectJSObjectType(Register heap_object,
+                                          Register map,
+                                          Register scratch,
+                                          Label* fail) {
+  lw(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
+  IsInstanceJSObjectType(map, scratch, fail);
+}
+
+
+void MacroAssembler::IsInstanceJSObjectType(Register map,
+                                            Register scratch,
+                                            Label* fail) {
+  lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  Branch(fail, lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  Branch(fail, gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
+}
+
+
 void MacroAssembler::IsObjectJSStringType(Register object,
                                           Register scratch,
                                           Label* fail) {
index 5e1d2c6253c2022fad0ab860ec85bde1f13c580e..a126e55ac671fb5a73c86eb299ac80106ac3000b 100644 (file)
@@ -977,6 +977,16 @@ 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);
index 80befa531dc93016f07ad858783ad08eff710e97..a612681c5b37086779db837e4ec22f94da26eecd 100644 (file)
@@ -2648,20 +2648,30 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
 
   __ JumpIfSmi(input, is_false);
 
-  STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
-  __ GetObjectType(input, temp, temp2);
-  __ Branch(is_false, lt, temp2, Operand(FIRST_JS_RECEIVER_TYPE));
-
-  // Objects with [[Call]] have class 'Function'.
-  __ lbu(temp2, FieldMemOperand(temp, Map::kBitFieldOffset));
-  __ And(temp2, temp2, Operand(1 << Map::kIsCallable));
   if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
-    __ Branch(is_true, ne, temp2, Operand(zero_reg));
+    // Assuming the following assertions, we can use the same compares to test
+    // for both being a function type and being in the object type range.
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  FIRST_SPEC_OBJECT_TYPE + 1);
+    STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  LAST_SPEC_OBJECT_TYPE - 1);
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+
+    __ GetObjectType(input, temp, temp2);
+    __ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
+    __ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
+    __ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE));
   } else {
-    __ Branch(is_false, ne, temp2, Operand(zero_reg));
+    // Faster code path to avoid two compares: subtract lower bound from the
+    // actual type and do a signed compare with the width of the type range.
+    __ GetObjectType(input, temp, temp2);
+    __ Dsubu(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
+                                           FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
   }
 
-  // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
   Register instance_type = scratch1();
   DCHECK(!instance_type.is(temp));
index a379d847ae597d4e6afe2600ef1b44b39aa89dd8..1e9aebd9a5c551e2c1d0eb2a9f5e5bd98cd79c76 100644 (file)
@@ -4217,6 +4217,24 @@ void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
 }
 
 
+void MacroAssembler::IsObjectJSObjectType(Register heap_object,
+                                          Register map,
+                                          Register scratch,
+                                          Label* fail) {
+  ld(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
+  IsInstanceJSObjectType(map, scratch, fail);
+}
+
+
+void MacroAssembler::IsInstanceJSObjectType(Register map,
+                                            Register scratch,
+                                            Label* fail) {
+  lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  Branch(fail, lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  Branch(fail, gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
+}
+
+
 void MacroAssembler::IsObjectJSStringType(Register object,
                                           Register scratch,
                                           Label* fail) {
index 17e0857ba59d905ffb7203741d7be7965c1d60ae..7691ba4d89c0a568f0263a2a53081cb5905613ec 100644 (file)
@@ -1008,6 +1008,15 @@ 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);
index 60f1e5bdc955273e4ae56f9049061ad10ea79cbc..c0539c493fa432fc0d8dde8993c02a3ded2c5178 100644 (file)
@@ -58,9 +58,9 @@ Handle<HeapType> Object::OptimalType(Isolate* isolate,
     if (representation.IsHeapObject() && IsHeapObject()) {
       // We can track only JavaScript objects with stable maps.
       Handle<Map> map(HeapObject::cast(this)->map(), isolate);
-      if (map->is_stable() && !map->is_callable() &&
-          map->instance_type() >= FIRST_JS_RECEIVER_TYPE &&
-          map->instance_type() <= LAST_JS_RECEIVER_TYPE) {
+      if (map->is_stable() &&
+          map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
+          map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
         return HeapType::Class(map, isolate);
       }
     }
@@ -1650,10 +1650,7 @@ void Simd128Value::CopyBits(void* destination) const {
 
 
 String* JSReceiver::class_name() {
-  // According to ES5 section 15 Standard Built-in ECMAScript Objects, the
-  // [[Class]] of builtin objects is "Function" if a [[Call]] internal
-  // method is present.
-  if (IsCallable()) {
+  if (IsJSFunction() || IsJSFunctionProxy()) {
     return GetHeap()->Function_string();
   }
   Object* maybe_constructor = map()->GetConstructor();
index a07ab50e3acd3c167b37575738bce9db27119cd7..4ece658d38414e1f6d9e308bfb9977a7c647c6e8 100644 (file)
@@ -708,7 +708,8 @@ 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.
+  // compares for checking the JS_RECEIVER/SPEC_OBJECT range and the
+  // NONCALLABLE_JS_OBJECT range.
   JS_FUNCTION_PROXY_TYPE,  // FIRST_JS_RECEIVER_TYPE, FIRST_JS_PROXY_TYPE
   JS_PROXY_TYPE,           // LAST_JS_PROXY_TYPE
   JS_VALUE_TYPE,           // FIRST_JS_OBJECT_TYPE
@@ -765,7 +766,13 @@ 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
+  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);
index 322de11f5d267a89d9cc18eb1aa4527d6062ce04..250589097452890ef6631493e43d4ccf17269d27 100644 (file)
@@ -2572,20 +2572,32 @@ 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)) {
-    __ j(not_zero, is_true);
+    // Assuming the following assertions, we can use the same compares to test
+    // for both being a function type and being in the object type range.
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  FIRST_SPEC_OBJECT_TYPE + 1);
+    STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  LAST_SPEC_OBJECT_TYPE - 1);
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+    __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
+    __ j(below, is_false);
+    __ j(equal, is_true);
+    __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
+    __ j(equal, is_true);
   } else {
-    __ j(not_zero, is_false);
+    // Faster code path to avoid two compares: subtract lower bound from the
+    // actual type and do a signed compare with the width of the type range.
+    __ movp(temp, FieldOperand(input, HeapObject::kMapOffset));
+    __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
+    __ subp(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ cmpp(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
+                             FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ j(above, is_false);
   }
 
-  // Now we are in the FIRST-LAST_JS_RECEIVER_TYPE range.
+  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
   __ GetMapConstructor(temp, temp, kScratchRegister);
 
index c67d955a897e4dfc67623626f334f02f3b92f279..8898f7bae02ed1ef1c8743bdf1dca6846f65948d 100644 (file)
@@ -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, Label::kNear);
+  JumpIfSmi(result, &done);
   CmpObjectType(result, MAP_TYPE, temp);
-  j(not_equal, &done, Label::kNear);
+  j(not_equal, &done);
   movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
   jmp(&loop);
   bind(&done);