Author: [EMAIL PROTECTED]
Date: Wed Oct  8 06:33:16 2008
New Revision: 470

Modified:
    branches/bleeding_edge/src/code-stubs.cc
    branches/bleeding_edge/src/code-stubs.h
    branches/bleeding_edge/src/codegen-arm.cc
    branches/bleeding_edge/src/codegen-ia32.cc
    branches/bleeding_edge/src/macro-assembler-ia32.cc
    branches/bleeding_edge/src/macro-assembler-ia32.h
    branches/bleeding_edge/src/runtime.js
    branches/bleeding_edge/src/stub-cache-ia32.cc
    branches/bleeding_edge/test/mjsunit/instanceof.js

Log:
Improve the generated code for the instanceof operator,
and extended the instanceof test case.
Review URL: http://codereview.chromium.org/6341

Modified: branches/bleeding_edge/src/code-stubs.cc
==============================================================================
--- branches/bleeding_edge/src/code-stubs.cc    (original)
+++ branches/bleeding_edge/src/code-stubs.cc    Wed Oct  8 06:33:16 2008
@@ -110,6 +110,8 @@
        return "RevertToNumber";
      case ToBoolean:
        return "ToBoolean";
+    case Instanceof:
+      return "Instanceof";
      case CounterOp:
        return "CounterOp";
      case ArgumentsAccess:

Modified: branches/bleeding_edge/src/code-stubs.h
==============================================================================
--- branches/bleeding_edge/src/code-stubs.h     (original)
+++ branches/bleeding_edge/src/code-stubs.h     Wed Oct  8 06:33:16 2008
@@ -44,6 +44,7 @@
      UnarySub,
      RevertToNumber,
      ToBoolean,
+    Instanceof,
      CounterOp,
      ArgumentsAccess,
      Runtime,
@@ -82,7 +83,7 @@
    virtual int MinorKey() = 0;

    // Returns a name for logging/debugging purposes.
-  virtual const char* GetName() = 0;
+  virtual const char* GetName() { return MajorName(MajorKey()); }

  #ifdef DEBUG
    virtual void Print() { PrintF("%s\n", GetName()); }

Modified: branches/bleeding_edge/src/codegen-arm.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.cc   (original)
+++ branches/bleeding_edge/src/codegen-arm.cc   Wed Oct  8 06:33:16 2008
@@ -887,8 +887,6 @@
    Major MajorKey() { return GetProperty; }
    int MinorKey() { return 0; }
    void Generate(MacroAssembler* masm);
-
-  const char* GetName() { return "GetPropertyStub"; }
  };


@@ -900,8 +898,6 @@
    Major MajorKey() { return SetProperty; }
    int MinorKey() { return 0; }
    void Generate(MacroAssembler* masm);
-
-  const char* GetName() { return "GetPropertyStub"; }
  };


@@ -951,8 +947,6 @@
    int MinorKey() { return (argc_ << 3) | static_cast<int>(kind_); }
    void Generate(MacroAssembler* masm);

-  const char* GetName() { return "InvokeBuiltinStub"; }
-
  #ifdef DEBUG
    void Print() {
      PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n",
@@ -1294,8 +1288,6 @@
   private:
    int argc_;

-  const char* GetName() { return "CallFuntionStub"; }
-
  #if defined(DEBUG)
    void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
  #endif  // defined(DEBUG)
@@ -3386,7 +3378,8 @@
      case Token::INSTANCEOF:
        __ mov(r0, Operand(1));  // not counting receiver
        __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS);
-      __ push(r0);
+      __ tst(r0, Operand(r0));
+      cc_reg_ = eq;
        break;

      default:

Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc  (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc  Wed Oct  8 06:33:16 2008
@@ -894,18 +894,8 @@
    void Generate(MacroAssembler* masm);

   private:
-
    Major MajorKey() { return ToBoolean; }
-
    int MinorKey() { return 0; }
-
-  const char* GetName() { return "ToBooleanStub"; }
-
-#ifdef DEBUG
-  void Print() {
-    PrintF("ToBooleanStub\n");
-  }
-#endif
  };


@@ -1476,8 +1466,6 @@
      return (static_cast<int>(cc_) << 1) | (strict_ ? 1 : 0);
    }

-  const char* GetName() { return "CompareStub"; }
-
  #ifdef DEBUG
    void Print() {
      PrintF("CompareStub (cc %d), (strict %s)\n",
@@ -1585,8 +1573,6 @@
   private:
    int argc_;

-  const char* GetName() { return "CallFunctionStub"; }
-
  #ifdef DEBUG
    void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
  #endif
@@ -3521,8 +3507,6 @@
    int MinorKey() { return is_increment_ ? 1 : 0; }
    void Generate(MacroAssembler* masm);

-  const char* GetName() { return "RevertToNumberStub"; }
-
  #ifdef DEBUG
    void Print() {
      PrintF("RevertToNumberStub (is_increment %s)\n",
@@ -3552,8 +3536,6 @@
    }
    void Generate(MacroAssembler* masm);

-  const char* GetName() { return "CounterOpStub"; }
-
  #ifdef DEBUG
    void Print() {
      PrintF("CounterOpStub (result_offset %d), (is_postfix %s),"
@@ -3754,6 +3736,18 @@
  }


+class InstanceofStub: public CodeStub {
+ public:
+  InstanceofStub() { }
+
+  void Generate(MacroAssembler* masm);
+
+ private:
+  Major MajorKey() { return Instanceof; }
+  int MinorKey() { return 0; }
+};
+
+
  void Ia32CodeGenerator::VisitCompareOperation(CompareOperation* node) {
    Comment cmnt(masm_, "[ CompareOperation");

@@ -3934,8 +3928,10 @@
      case Token::INSTANCEOF: {
        Load(left);
        Load(right);
-      __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
-      __ push(eax);  // push the result
+      InstanceofStub stub;
+      __ CallStub(&stub);
+      __ test(eax, Operand(eax));
+      cc_reg_ = zero;
        return;
      }
      default:
@@ -5286,6 +5282,53 @@
    // Restore frame pointer and return.
    __ pop(ebp);
    __ ret(0);
+}
+
+
+void InstanceofStub::Generate(MacroAssembler* masm) {
+  // Get the object - go slow case if it's a smi.
+  Label slow;
+  __ mov(eax, Operand(esp, 2 * kPointerSize));  // 2 ~ return address,  
function
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &slow, not_taken);
+
+  // Check that the left hand is a JS object.
+  __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));  // ebx - object  
map
+  __ movzx_b(ecx, FieldOperand(eax, Map::kInstanceTypeOffset));  // ecx -  
type
+  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+  __ j(less, &slow, not_taken);
+  __ cmp(ecx, LAST_JS_OBJECT_TYPE);
+  __ j(greater, &slow, not_taken);
+
+  // Get the prototype of the function.
+  __ mov(edx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
+  __ TryGetFunctionPrototype(edx, ebx, ecx, &slow);
+
+  // Register mapping: eax is object map and ebx is function prototype.
+  __ mov(ecx, FieldOperand(eax, Map::kPrototypeOffset));
+
+  // Loop through the prototype chain looking for the function prototype.
+  Label loop, is_instance, is_not_instance;
+  __ bind(&loop);
+  __ cmp(ecx, Operand(ebx));
+  __ j(equal, &is_instance);
+  __ cmp(Operand(ecx), Immediate(Factory::null_value()));
+  __ j(equal, &is_not_instance);
+  __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
+  __ mov(ecx, FieldOperand(ecx, Map::kPrototypeOffset));
+  __ jmp(&loop);
+
+  __ bind(&is_instance);
+  __ Set(eax, Immediate(0));
+  __ ret(2 * kPointerSize);
+
+  __ bind(&is_not_instance);
+  __ Set(eax, Immediate(Smi::FromInt(1)));
+  __ ret(2 * kPointerSize);
+
+  // Slow-case: Go through the JavaScript implementation.
+  __ bind(&slow);
+  __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
  }



Modified: branches/bleeding_edge/src/macro-assembler-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/macro-assembler-ia32.cc  (original)
+++ branches/bleeding_edge/src/macro-assembler-ia32.cc  Wed Oct  8 06:33:16  
2008
@@ -99,8 +99,6 @@
    Register addr_;
    Register scratch_;

-  const char* GetName() { return "RecordWriteStub"; }
-
  #ifdef DEBUG
    void Print() {
      PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch  
reg %d)\n",
@@ -586,6 +584,57 @@
    or_(scratch, Operand(op2));
    j(sign, then_label, not_taken);
    bind(&ok);
+}
+
+
+void MacroAssembler::TryGetFunctionPrototype(Register function,
+                                             Register result,
+                                             Register scratch,
+                                             Label* miss) {
+  // Check that the receiver isn't a smi.
+  test(function, Immediate(kSmiTagMask));
+  j(zero, miss, not_taken);
+
+  // Check that the function really is a function.
+  mov(result, FieldOperand(function, HeapObject::kMapOffset));
+  movzx_b(scratch, FieldOperand(result, Map::kInstanceTypeOffset));
+  cmp(scratch, JS_FUNCTION_TYPE);
+  j(not_equal, miss, not_taken);
+
+  // Make sure that the function has an instance prototype.
+  Label non_instance;
+  movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
+  test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
+  j(not_zero, &non_instance, not_taken);
+
+  // Get the prototype or initial map from the function.
+  mov(result,
+      FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+
+  // If the prototype or initial map is the hole, don't return it and
+  // simply miss the cache instead. This will allow us to allocate a
+  // prototype object on-demand in the runtime system.
+  cmp(Operand(result), Immediate(Factory::the_hole_value()));
+  j(equal, miss, not_taken);
+
+  // If the function does not have an initial map, we're done.
+  Label done;
+  mov(scratch, FieldOperand(result, HeapObject::kMapOffset));
+  movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+  cmp(scratch, MAP_TYPE);
+  j(not_equal, &done);
+
+  // Get the prototype from the initial map.
+  mov(result, FieldOperand(result, Map::kPrototypeOffset));
+  jmp(&done);
+
+  // Non-instance prototype: Fetch prototype from constructor field
+  // in initial map.
+  bind(&non_instance);
+  mov(result, FieldOperand(result, Map::kConstructorOffset));
+
+  // All done.
+  bind(&done);
  }



Modified: branches/bleeding_edge/src/macro-assembler-ia32.h
==============================================================================
--- branches/bleeding_edge/src/macro-assembler-ia32.h   (original)
+++ branches/bleeding_edge/src/macro-assembler-ia32.h   Wed Oct  8 06:33:16  
2008
@@ -179,6 +179,16 @@
    void NegativeZeroTest(Register result, Register op1, Register op2,
                          Register scratch, Label* then_label);

+  // Try to get function prototype of a function and puts the value in
+  // the result register. Checks that the function really is a
+  // function and jumps to the miss label if the fast checks fail. The
+  // function register will be untouched; the other registers may be
+  // clobbered.
+  void TryGetFunctionPrototype(Register function,
+                               Register result,
+                               Register scratch,
+                               Label* miss);
+
    // Generates code for reporting that an illegal operation has
    // occurred.
    void IllegalOperation(int num_arguments);

Modified: branches/bleeding_edge/src/runtime.js
==============================================================================
--- branches/bleeding_edge/src/runtime.js       (original)
+++ branches/bleeding_edge/src/runtime.js       Wed Oct  8 06:33:16 2008
@@ -274,7 +274,10 @@
  }


-// ECMA-262, section 11.8.6, page 54.
+// ECMA-262, section 11.8.6, page 54. To make the implementation more
+// efficient, the return value should be zero if the 'this' is an
+// instance of F, and non-zero if not. This makes it possible to avoid
+// an expensive ToBoolean conversion in the generated code.
  function INSTANCE_OF(F) {
    var V = this;
    if (!IS_FUNCTION(F)) {
@@ -283,7 +286,7 @@

    // If V is not an object, return false.
    if (IS_NULL(V) || (!IS_OBJECT(V) && !IS_FUNCTION(V))) {
-    return false;
+    return 1;
    }

    // Get the prototype of F; if it is not an object, throw an error.
@@ -293,7 +296,7 @@
    }

    // Return whether or not O is in the prototype chain of V.
-  return %IsInPrototypeChain(O, V);
+  return %IsInPrototypeChain(O, V) ? 0 : 1;
  }



Modified: branches/bleeding_edge/src/stub-cache-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/stub-cache-ia32.cc       (original)
+++ branches/bleeding_edge/src/stub-cache-ia32.cc       Wed Oct  8 06:33:16 2008
@@ -232,51 +232,9 @@
                                                   Register scratch1,
                                                   Register scratch2,
                                                   Label* miss_label) {
-  // Check that the receiver isn't a smi.
-  __ test(receiver, Immediate(kSmiTagMask));
-  __ j(zero, miss_label, not_taken);

-  // Check that the receiver is a function.
-  __ mov(scratch1, FieldOperand(receiver, HeapObject::kMapOffset));
-  __ movzx_b(scratch2, FieldOperand(scratch1, Map::kInstanceTypeOffset));
-  __ cmp(scratch2, JS_FUNCTION_TYPE);
-  __ j(not_equal, miss_label, not_taken);
-
-  // Make sure that the function has an instance prototype.
-  Label non_instance;
-  __ movzx_b(scratch2, FieldOperand(scratch1, Map::kBitFieldOffset));
-  __ test(scratch2, Immediate(1 << Map::kHasNonInstancePrototype));
-  __ j(not_zero, &non_instance, not_taken);
-
-  // Get the prototype or initial map from the function.
-  __ mov(scratch1,
-         FieldOperand(receiver, JSFunction::kPrototypeOrInitialMapOffset));
-
-  // If the prototype or initial map is the hole, don't return it and
-  // simply miss the cache instead. This will allow us to allocate a
-  // prototype object on-demand in the runtime system.
-  __ cmp(Operand(scratch1), Immediate(Factory::the_hole_value()));
-  __ j(equal, miss_label, not_taken);
+  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
    __ mov(eax, Operand(scratch1));
-
-  // If the function does not have an initial map, we're done.
-  Label done;
-  __ mov(scratch1, FieldOperand(eax, HeapObject::kMapOffset));
-  __ movzx_b(scratch2, FieldOperand(scratch1, Map::kInstanceTypeOffset));
-  __ cmp(scratch2, MAP_TYPE);
-  __ j(not_equal, &done);
-
-  // Get the prototype from the initial map.
-  __ mov(eax, FieldOperand(eax, Map::kPrototypeOffset));
-
-  // All done: Return the prototype.
-  __ bind(&done);
-  __ ret(0);
-
-  // Non-instance prototype: Fetch prototype from constructor field
-  // in initial map.
-  __ bind(&non_instance);
-  __ mov(eax, FieldOperand(scratch1, Map::kConstructorOffset));
    __ ret(0);
  }


Modified: branches/bleeding_edge/test/mjsunit/instanceof.js
==============================================================================
--- branches/bleeding_edge/test/mjsunit/instanceof.js   (original)
+++ branches/bleeding_edge/test/mjsunit/instanceof.js   Wed Oct  8 06:33:16  
2008
@@ -30,3 +30,58 @@

  assertFalse({} instanceof Array);
  assertTrue([] instanceof Array);
+
+function TestChains() {
+  var A = {};
+  var B = {};
+  var C = {};
+  B.__proto__ = A;
+  C.__proto__ = B;
+
+  function F() { }
+  F.prototype = A;
+  assertTrue(C instanceof F);
+  assertTrue(B instanceof F);
+  assertFalse(A instanceof F);
+
+  F.prototype = B;
+  assertTrue(C instanceof F);
+  assertFalse(B instanceof F);
+  assertFalse(A instanceof F);
+
+  F.prototype = C;
+  assertFalse(C instanceof F);
+  assertFalse(B instanceof F);
+  assertFalse(A instanceof F);
+}
+
+TestChains();
+
+
+function TestExceptions() {
+  function F() { }
+  var items = [ 1, new Number(42),
+                true,
+                'string', new String('hest'),
+                {}, [],
+                F, new F(),
+                Object, String ];
+
+  var exceptions = 0;
+  var instanceofs = 0;
+
+  for (var i = 0; i < items.length; i++) {
+    for (var j = 0; j < items.length; j++) {
+      try {
+        if (items[i] instanceof items[j]) instanceofs++;
+      } catch (e) {
+        assertTrue(e instanceof TypeError);
+        exceptions++;
+      }
+    }
+  }
+  assertEquals(10, instanceofs);
+  assertEquals(88, exceptions);
+}
+
+TestExceptions();

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

Reply via email to