Revision: 3335
Author: [email protected]
Date: Wed Nov 18 23:41:32 2009
Log: Implement IS_OBJECT and IS_FUNCTION as inlined runtime functions.

Summary:
This change fixes a performance regression introduced by the special
handling of regular expressions in typeof expressions.
As a result we regain ~8% speedup on 3d-raytrace and ~13% on boyer
(vs bleeding edge)

Description:
The macros IS_OBJECT and IS_FUNCTION are frequently used in the
JS runtime functions.
By introducing new inlined runtime functions %_IsFunction and %_IsObject
we avoid invoking the more expensive %_ClassOf function plus comparing
its result to a string.


Review URL: http://codereview.chromium.org/399111
http://code.google.com/p/v8/source/detail?r=3335

Modified:
  /branches/bleeding_edge/src/arm/codegen-arm.cc
  /branches/bleeding_edge/src/arm/codegen-arm.h
  /branches/bleeding_edge/src/codegen.cc
  /branches/bleeding_edge/src/ia32/codegen-ia32.cc
  /branches/bleeding_edge/src/ia32/codegen-ia32.h
  /branches/bleeding_edge/src/macros.py
  /branches/bleeding_edge/src/x64/codegen-x64.cc
  /branches/bleeding_edge/src/x64/codegen-x64.h

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Wed Nov 18 04:14:21 2009
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Wed Nov 18 23:41:32 2009
@@ -3383,6 +3383,51 @@
    answer.Bind();
    cc_reg_ = eq;
  }
+
+
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
+  VirtualFrame::SpilledScope spilled_scope;
+  ASSERT(args->length() == 1);
+  LoadAndSpill(args->at(0));
+  frame_->EmitPop(r1);
+  __ tst(r1, Operand(kSmiTagMask));
+  false_target()->Branch(eq);
+
+  __ LoadRoot(ip, Heap::kNullValueRootIndex);
+  __ cmp(r1, ip);
+  true_target()->Branch(eq);
+
+  Register map_reg = r2;
+  __ ldr(map_reg, FieldMemOperand(r1, HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined when tested with typeof.
+  __ ldrb(r1, FieldMemOperand(map_reg, Map::kBitFieldOffset));
+  __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
+  __ cmp(r1, Operand(1 << Map::kIsUndetectable));
+  false_target()->Branch(eq);
+
+  __ ldrb(r1, FieldMemOperand(map_reg, Map::kInstanceTypeOffset));
+  __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
+  false_target()->Branch(lt);
+  __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
+  cc_reg_ = le;
+}
+
+
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (%_ClassOf(arg) === 'Function')
+  VirtualFrame::SpilledScope spilled_scope;
+  ASSERT(args->length() == 1);
+  LoadAndSpill(args->at(0));
+  frame_->EmitPop(r0);
+  __ tst(r0, Operand(kSmiTagMask));
+  false_target()->Branch(eq);
+  Register map_reg = r2;
+  __ CompareObjectType(r0, map_reg, r1, JS_FUNCTION_TYPE);
+  cc_reg_ = eq;
+}


  void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h       Mon Nov 16 13:59:31 2009
+++ /branches/bleeding_edge/src/arm/codegen-arm.h       Wed Nov 18 23:41:32 2009
@@ -334,6 +334,8 @@
    void GenerateIsSmi(ZoneList<Expression*>* args);
    void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
    void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsObject(ZoneList<Expression*>* args);
+  void GenerateIsFunction(ZoneList<Expression*>* args);

    // Support for construct call checks.
    void GenerateIsConstructCall(ZoneList<Expression*>* args);
=======================================
--- /branches/bleeding_edge/src/codegen.cc      Mon Nov 16 13:59:31 2009
+++ /branches/bleeding_edge/src/codegen.cc      Wed Nov 18 23:41:32 2009
@@ -343,7 +343,9 @@
    {&CodeGenerator::GenerateLog, "_Log"},
    {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
    {&CodeGenerator::GenerateMathSin, "_Math_sin"},
-  {&CodeGenerator::GenerateMathCos, "_Math_cos"}
+  {&CodeGenerator::GenerateMathCos, "_Math_cos"},
+  {&CodeGenerator::GenerateIsObject, "_IsObject"},
+  {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
  };


=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc    Tue Nov 17 02:28:04  
2009
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc    Wed Nov 18 23:41:32  
2009
@@ -4868,6 +4868,55 @@
    temp.Unuse();
    destination()->Split(equal);
  }
+
+
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result obj = frame_->Pop();
+  obj.ToRegister();
+
+  __ test(obj.reg(), Immediate(kSmiTagMask));
+  destination()->false_target()->Branch(zero);
+  __ cmp(obj.reg(), Factory::null_value());
+  destination()->true_target()->Branch(equal);
+
+  Result map = allocator()->Allocate();
+  ASSERT(map.is_valid());
+  __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined when tested with typeof.
+  __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset));
+  __ test(map.reg(), Immediate(1 << Map::kIsUndetectable));
+  destination()->false_target()->Branch(not_zero);
+  __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
+  __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset));
+  __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE);
+  destination()->false_target()->Branch(less);
+  __ cmp(map.reg(), LAST_JS_OBJECT_TYPE);
+  obj.Unuse();
+  map.Unuse();
+  destination()->Split(less_equal);
+}
+
+
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (%_ClassOf(arg) === 'Function')
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result obj = frame_->Pop();
+  obj.ToRegister();
+  __ test(obj.reg(), Immediate(kSmiTagMask));
+  destination()->false_target()->Branch(zero);
+  Result temp = allocator()->Allocate();
+  ASSERT(temp.is_valid());
+  __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, temp.reg());
+  obj.Unuse();
+  temp.Unuse();
+  destination()->Split(equal);
+}


  void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h     Mon Nov 16 15:11:19 2009
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h     Wed Nov 18 23:41:32 2009
@@ -512,6 +512,8 @@
    void GenerateIsSmi(ZoneList<Expression*>* args);
    void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
    void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsObject(ZoneList<Expression*>* args);
+  void GenerateIsFunction(ZoneList<Expression*>* args);

    // Support for construct call checks.
    void GenerateIsConstructCall(ZoneList<Expression*>* args);
=======================================
--- /branches/bleeding_edge/src/macros.py       Thu Nov  5 08:08:48 2009
+++ /branches/bleeding_edge/src/macros.py       Wed Nov 18 23:41:32 2009
@@ -79,11 +79,10 @@
  macro IS_UNDEFINED(arg)         = (typeof(arg) === 'undefined');
  macro IS_NUMBER(arg)            = (typeof(arg) === 'number');
  macro IS_STRING(arg)            = (typeof(arg) === 'string');
-macro IS_OBJECT(arg)            = (typeof(arg) === 'object' | 
| %_ClassOf(arg) == 'RegExp');
  macro IS_BOOLEAN(arg)           = (typeof(arg) === 'boolean');
+macro IS_OBJECT(arg)            = (%_IsObject(arg));
  macro IS_ARRAY(arg)             = (%_IsArray(arg));
-# IS_FUNCTION uses %_ClassOf rather than typeof so as to exclude regexps.
-macro IS_FUNCTION(arg)          = (%_ClassOf(arg) === 'Function');
+macro IS_FUNCTION(arg)          = (%_IsFunction(arg));
  macro IS_REGEXP(arg)            = (%_ClassOf(arg) === 'RegExp');
  macro IS_DATE(arg)              = (%_ClassOf(arg) === 'Date');
  macro IS_NUMBER_WRAPPER(arg)    = (%_ClassOf(arg) === 'Number');
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Wed Nov 18 02:20:24 2009
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Wed Nov 18 23:41:32 2009
@@ -3614,6 +3614,48 @@
    value.Unuse();
    destination()->Split(equal);
  }
+
+
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result obj = frame_->Pop();
+  obj.ToRegister();
+  Condition is_smi = masm_->CheckSmi(obj.reg());
+  destination()->false_target()->Branch(is_smi);
+
+  __ Move(kScratchRegister, Factory::null_value());
+  __ cmpq(obj.reg(), kScratchRegister);
+  destination()->true_target()->Branch(equal);
+
+  __ movq(kScratchRegister, FieldOperand(obj.reg(),  
HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined when tested with typeof.
+  __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
+          Immediate(1 << Map::kIsUndetectable));
+  destination()->false_target()->Branch(not_zero);
+  __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE);
+  destination()->false_target()->Branch(less);
+  __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
+  obj.Unuse();
+  destination()->Split(less_equal);
+}
+
+
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+  // This generates a fast version of:
+  // (%_ClassOf(arg) === 'Function')
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Result obj = frame_->Pop();
+  obj.ToRegister();
+  Condition is_smi = masm_->CheckSmi(obj.reg());
+  destination()->false_target()->Branch(is_smi);
+  __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, kScratchRegister);
+  obj.Unuse();
+  destination()->Split(equal);
+}


  void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h       Mon Nov 16 13:59:31 2009
+++ /branches/bleeding_edge/src/x64/codegen-x64.h       Wed Nov 18 23:41:32 2009
@@ -510,6 +510,8 @@
    void GenerateIsSmi(ZoneList<Expression*>* args);
    void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
    void GenerateIsArray(ZoneList<Expression*>* args);
+  void GenerateIsObject(ZoneList<Expression*>* args);
+  void GenerateIsFunction(ZoneList<Expression*>* args);

    // Support for construct call checks.
    void GenerateIsConstructCall(ZoneList<Expression*>* args);

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to