Optimize %ClassOf() on IA-32 and use it instead of the
authorkasperl@chromium.org <kasperl@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 29 Jun 2009 10:45:16 +0000 (10:45 +0000)
committerkasperl@chromium.org <kasperl@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 29 Jun 2009 10:45:16 +0000 (10:45 +0000)
custom %HasXXXClass() calls.
Review URL: http://codereview.chromium.org/151018

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2293 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

14 files changed:
src/arm/codegen-arm.cc
src/arm/codegen-arm.h
src/codegen.cc
src/ia32/codegen-ia32.cc
src/ia32/codegen-ia32.h
src/macros.py
src/mirror-delay.js
src/runtime.cc
src/runtime.h
src/runtime.js
src/string.js
src/v8natives.js
src/x64/codegen-x64.cc
src/x64/codegen-x64.h

index eeea560..10c5d82 100644 (file)
@@ -3180,6 +3180,15 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
 }
 
 
+void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
+  VirtualFrame::SpilledScope spilled_scope;
+  ASSERT(args->length() == 1);
+  LoadAndSpill(args->at(0));  // Load the object.
+  frame_->CallRuntime(Runtime::kClassOf, 1);
+  frame_->EmitPush(r0);
+}
+
+
 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
   VirtualFrame::SpilledScope spilled_scope;
   ASSERT(args->length() == 1);
index 2048a17..5ddecd3 100644 (file)
@@ -340,7 +340,8 @@ class CodeGenerator: public AstVisitor {
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
   void GenerateArgumentsAccess(ZoneList<Expression*>* args);
 
-  // Support for accessing the value field of an object (used by Date).
+  // Support for accessing the class and value fields of an object.
+  void GenerateClassOf(ZoneList<Expression*>* args);
   void GenerateValueOf(ZoneList<Expression*>* args);
   void GenerateSetValueOf(ZoneList<Expression*>* args);
 
index 6a41b9d..b7297d7 100644 (file)
@@ -419,6 +419,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
   {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
   {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
   {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
+  {&CodeGenerator::GenerateClassOf, "_ClassOf"},
   {&CodeGenerator::GenerateValueOf, "_ValueOf"},
   {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
   {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
index fa407c2..948c123 100644 (file)
@@ -5022,6 +5022,70 @@ void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  JumpTarget leave, null, function, non_function_constructor;
+  Load(args->at(0));  // Load the object.
+  Result obj = frame_->Pop();
+  obj.ToRegister();
+  frame_->Spill(obj.reg());
+
+  // If the object is a smi, we return null.
+  __ test(obj.reg(), Immediate(kSmiTagMask));
+  null.Branch(zero);
+
+  // Check that the object is a JS object but take special care of JS
+  // functions to make sure they have 'Function' as their class.
+  { Result tmp = allocator()->Allocate();
+    __ mov(obj.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
+    __ movzx_b(tmp.reg(), FieldOperand(obj.reg(), Map::kInstanceTypeOffset));
+    __ cmp(tmp.reg(), FIRST_JS_OBJECT_TYPE);
+    null.Branch(less);
+
+    // As long as JS_FUNCTION_TYPE is the last instance type and it is
+    // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
+    // LAST_JS_OBJECT_TYPE.
+    ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+    ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
+    __ cmp(tmp.reg(), JS_FUNCTION_TYPE);
+    function.Branch(equal);
+  }
+
+  // Check if the constructor in the map is a function.
+  { Result tmp = allocator()->Allocate();
+    __ mov(obj.reg(), FieldOperand(obj.reg(), Map::kConstructorOffset));
+    __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, tmp.reg());
+    non_function_constructor.Branch(not_equal);
+  }
+
+  // The map register now contains the constructor function. Grab the
+  // instance class name from there.
+  __ mov(obj.reg(),
+         FieldOperand(obj.reg(), JSFunction::kSharedFunctionInfoOffset));
+  __ mov(obj.reg(),
+         FieldOperand(obj.reg(), SharedFunctionInfo::kInstanceClassNameOffset));
+  frame_->Push(&obj);
+  leave.Jump();
+
+  // Functions have class 'Function'.
+  function.Bind();
+  frame_->Push(Factory::function_class_symbol());
+  leave.Jump();
+
+  // Objects with a non-function constructor have class 'Object'.
+  non_function_constructor.Bind();
+  frame_->Push(Factory::Object_symbol());
+  leave.Jump();
+
+  // Non-JS objects have class null.
+  null.Bind();
+  frame_->Push(Factory::null_value());
+
+  // All done.
+  leave.Bind();
+}
+
+
 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   JumpTarget leave;
index a7e0b06..5cd50b8 100644 (file)
@@ -529,7 +529,8 @@ class CodeGenerator: public AstVisitor {
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
   void GenerateArgumentsAccess(ZoneList<Expression*>* args);
 
-  // Support for accessing the value field of an object (used by Date).
+  // Support for accessing the class and value fields of an object.
+  void GenerateClassOf(ZoneList<Expression*>* args);
   void GenerateValueOf(ZoneList<Expression*>* args);
   void GenerateSetValueOf(ZoneList<Expression*>* args);
 
index fdbdb58..a3f896d 100644 (file)
@@ -82,13 +82,15 @@ macro IS_NUMBER(arg)            = (typeof(arg) === 'number');
 macro IS_STRING(arg)            = (typeof(arg) === 'string');
 macro IS_OBJECT(arg)            = (typeof(arg) === 'object');
 macro IS_BOOLEAN(arg)           = (typeof(arg) === 'boolean');
-macro IS_REGEXP(arg)            = %HasRegExpClass(arg);
-macro IS_ARRAY(arg)             = %HasArrayClass(arg);
-macro IS_DATE(arg)              = %HasDateClass(arg);
-macro IS_NUMBER_WRAPPER(arg)    = %HasNumberClass(arg);
-macro IS_STRING_WRAPPER(arg)    = %HasStringClass(arg);
-macro IS_ERROR(arg)             = (%ClassOf(arg) === 'Error');
-macro IS_SCRIPT(arg)            = (%ClassOf(arg) === 'Script');
+macro IS_ARRAY(arg)             = (%_IsArray(arg));
+macro IS_REGEXP(arg)            = (%_ClassOf(arg) === 'RegExp');
+macro IS_DATE(arg)              = (%_ClassOf(arg) === 'Date');
+macro IS_NUMBER_WRAPPER(arg)    = (%_ClassOf(arg) === 'Number');
+macro IS_STRING_WRAPPER(arg)    = (%_ClassOf(arg) === 'String');
+macro IS_BOOLEAN_WRAPPER(arg)   = (%_ClassOf(arg) === 'Boolean');
+macro IS_ERROR(arg)             = (%_ClassOf(arg) === 'Error');
+macro IS_SCRIPT(arg)            = (%_ClassOf(arg) === 'Script');
+macro IS_ARGUMENTS(arg)         = (%_ClassOf(arg) === 'Arguments');
 macro FLOOR(arg)                = %Math_floor(arg);
 
 # Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
index d0e8aa4..76ae75b 100644 (file)
@@ -580,7 +580,7 @@ inherits(ObjectMirror, ValueMirror);
 
 
 ObjectMirror.prototype.className = function() {
-  return %ClassOf(this.value_);
+  return %_ClassOf(this.value_);
 };
 
 
index dcff28b..2555ba4 100644 (file)
@@ -413,48 +413,6 @@ static Object* Runtime_ClassOf(Arguments args) {
 }
 
 
-static Object* Runtime_HasStringClass(Arguments args) {
-  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::String_symbol()));
-}
-
-
-static Object* Runtime_HasDateClass(Arguments args) {
-  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Date_symbol()));
-}
-
-
-static Object* Runtime_HasArrayClass(Arguments args) {
-  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Array_symbol()));
-}
-
-
-static Object* Runtime_HasFunctionClass(Arguments args) {
-  return Heap::ToBoolean(
-             args[0]->HasSpecificClassOf(Heap::function_class_symbol()));
-}
-
-
-static Object* Runtime_HasNumberClass(Arguments args) {
-  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Number_symbol()));
-}
-
-
-static Object* Runtime_HasBooleanClass(Arguments args) {
-  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Boolean_symbol()));
-}
-
-
-static Object* Runtime_HasArgumentsClass(Arguments args) {
-  return Heap::ToBoolean(
-             args[0]->HasSpecificClassOf(Heap::Arguments_symbol()));
-}
-
-
-static Object* Runtime_HasRegExpClass(Arguments args) {
-  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::RegExp_symbol()));
-}
-
-
 static Object* Runtime_IsInPrototypeChain(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 2);
index 15dd9b4..3c09495 100644 (file)
@@ -173,14 +173,6 @@ namespace internal {
   F(GetScript, 1) \
   \
   F(ClassOf, 1) \
-  F(HasDateClass, 1) \
-  F(HasStringClass, 1) \
-  F(HasArrayClass, 1) \
-  F(HasFunctionClass, 1) \
-  F(HasNumberClass, 1) \
-  F(HasBooleanClass, 1) \
-  F(HasArgumentsClass, 1) \
-  F(HasRegExpClass, 1) \
   F(SetCode, 2) \
   \
   F(CreateApiFunction, 1) \
index df26b88..25cc5ba 100644 (file)
@@ -394,7 +394,7 @@ function APPLY_PREPARE(args) {
   // First check whether length is a positive Smi and args is an
   // array. This is the fast case. If this fails, we do the slow case
   // that takes care of more eventualities.
-  if (%_IsArray(args)) {
+  if (IS_ARRAY(args)) {
     length = args.length;
     if (%_IsSmi(length) && length >= 0 && length < 0x800000 && IS_FUNCTION(this)) {
       return length;
@@ -415,9 +415,7 @@ function APPLY_PREPARE(args) {
   }
 
   // Make sure the arguments list has the right type.
-  if (args != null &&
-      !%HasArrayClass(args) &&
-      !%HasArgumentsClass(args)) {
+  if (args != null && !IS_ARRAY(args) && !IS_ARGUMENTS(args)) {
     throw %MakeTypeError('apply_wrong_args', []);
   }
 
index 604f925..6164eb8 100644 (file)
@@ -46,7 +46,7 @@
 
 // ECMA-262 section 15.5.4.2
 function StringToString() {
-  if (!IS_STRING(this) && !%HasStringClass(this))
+  if (!IS_STRING(this) && !IS_STRING_WRAPPER(this))
     throw new $TypeError('String.prototype.toString is not generic');
   return %_ValueOf(this);
 }
@@ -54,7 +54,7 @@ function StringToString() {
 
 // ECMA-262 section 15.5.4.3
 function StringValueOf() {
-  if (!IS_STRING(this) && !%HasStringClass(this))
+  if (!IS_STRING(this) && !IS_STRING_WRAPPER(this))
     throw new $TypeError('String.prototype.valueOf is not generic');
   return %_ValueOf(this);
 }
index 97363e9..841c920 100644 (file)
@@ -192,7 +192,7 @@ $Object.prototype.constructor = $Object;
 
 // ECMA-262 - 15.2.4.2
 function ObjectToString() {
-  var c = %ClassOf(this);
+  var c = %_ClassOf(this);
   // Hide Arguments from the outside.
   if (c === 'Arguments') c  = 'Object';
   return "[object " + c + "]";
@@ -311,7 +311,7 @@ SetupObject();
 function BooleanToString() {
   // NOTE: Both Boolean objects and values can enter here as
   // 'this'. This is not as dictated by ECMA-262.
-  if (!IS_BOOLEAN(this) && !%HasBooleanClass(this))
+  if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
     throw new $TypeError('Boolean.prototype.toString is not generic');
   return ToString(%_ValueOf(this));
 }
@@ -320,7 +320,7 @@ function BooleanToString() {
 function BooleanValueOf() {
   // NOTE: Both Boolean objects and values can enter here as
   // 'this'. This is not as dictated by ECMA-262.
-  if (!IS_BOOLEAN(this) && !%HasBooleanClass(this))
+  if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
     throw new $TypeError('Boolean.prototype.valueOf is not generic');
   return %_ValueOf(this);
 }
@@ -365,7 +365,7 @@ function NumberToString(radix) {
   // 'this'. This is not as dictated by ECMA-262.
   var number = this;
   if (!IS_NUMBER(this)) {
-    if (!%HasNumberClass(this))
+    if (!IS_NUMBER_WRAPPER(this))
       throw new $TypeError('Number.prototype.toString is not generic');
     // Get the value of this number in case it's an object.
     number = %_ValueOf(this);
@@ -395,7 +395,7 @@ function NumberToLocaleString() {
 function NumberValueOf() {
   // NOTE: Both Number objects and values can enter here as
   // 'this'. This is not as dictated by ECMA-262.
-  if (!IS_NUMBER(this) && !%HasNumberClass(this))
+  if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
     throw new $TypeError('Number.prototype.valueOf is not generic');
   return %_ValueOf(this);
 }
@@ -502,10 +502,9 @@ SetupNumber();
 $Function.prototype.constructor = $Function;
 
 function FunctionSourceString(func) {
-  // NOTE: Both Function objects and values can enter here as
-  // 'func'. This is not as dictated by ECMA-262.
-  if (!IS_FUNCTION(func) && !%HasFunctionClass(func))
+  if (!IS_FUNCTION(func)) {
     throw new $TypeError('Function.prototype.toString is not generic');
+  }
 
   var source = %FunctionGetSourceCode(func);
   if (!IS_STRING(source)) {
index 24e3ec3..e2cb95f 100644 (file)
@@ -3430,6 +3430,15 @@ void CodeGenerator::GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
+  // TODO(X64): Optimize this like it's done on IA-32.
+  ASSERT(args->length() == 1);
+  Load(args->at(0));  // Load the object.
+  Result result = frame_->CallRuntime(Runtime::kClassOf, 1);
+  frame_->Push(&result);
+}
+
+
 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 2);
   JumpTarget leave;
index a174c51..4488558 100644 (file)
@@ -529,7 +529,8 @@ class CodeGenerator: public AstVisitor {
   void GenerateArgumentsLength(ZoneList<Expression*>* args);
   void GenerateArgumentsAccess(ZoneList<Expression*>* args);
 
-  // Support for accessing the value field of an object (used by Date).
+  // Support for accessing the class and value fields of an object.
+  void GenerateClassOf(ZoneList<Expression*>* args);
   void GenerateValueOf(ZoneList<Expression*>* args);
   void GenerateSetValueOf(ZoneList<Expression*>* args);