Revision: 4381
Author: [email protected]
Date: Mon Apr 12 00:05:24 2010
Log: Faster invocation of custom comparator function.

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

Modified:
 /branches/bleeding_edge/src/arm/codegen-arm.cc
 /branches/bleeding_edge/src/arm/codegen-arm.h
 /branches/bleeding_edge/src/arm/virtual-frame-arm.cc
 /branches/bleeding_edge/src/arm/virtual-frame-arm.h
 /branches/bleeding_edge/src/array.js
 /branches/bleeding_edge/src/codegen.h
 /branches/bleeding_edge/src/ia32/codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/codegen-ia32.h
 /branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc
 /branches/bleeding_edge/src/ia32/virtual-frame-ia32.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/runtime.h
 /branches/bleeding_edge/src/x64/codegen-x64.cc
 /branches/bleeding_edge/src/x64/codegen-x64.h
 /branches/bleeding_edge/src/x64/virtual-frame-x64.cc
 /branches/bleeding_edge/src/x64/virtual-frame-x64.h
 /branches/bleeding_edge/test/mjsunit/fuzz-natives.js

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Fri Apr  9 11:25:51 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Mon Apr 12 00:05:24 2010
@@ -4031,6 +4031,22 @@
   frame_->CallStub(&stub, 1);
   frame_->EmitPush(r0);
 }
+
+
+void CodeGenerator::GenerateCallFunction(ZoneList<Expression*>* args) {
+  Comment cmnt(masm_, "[ GenerateCallFunction");
+
+  ASSERT(args->length() >= 2);
+
+  int n_args = args->length() - 2;  // for receiver and function.
+  Load(args->at(0));  // receiver
+  for (int i = 0; i < n_args; i++) {
+    Load(args->at(i + 1));
+  }
+  Load(args->at(n_args + 1));  // function
+  frame_->CallJSFunction(n_args);
+  frame_->EmitPush(r0);
+}


 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h       Fri Apr  9 11:25:51 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h       Mon Apr 12 00:05:24 2010
@@ -410,6 +410,9 @@
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);

+  // Fast call for custom callbacks.
+  void GenerateCallFunction(ZoneList<Expression*>* args);
+
   // Fast call to math functions.
   void GenerateMathPow(ZoneList<Expression*>* args);
   void GenerateMathSin(ZoneList<Expression*>* args);
=======================================
--- /branches/bleeding_edge/src/arm/virtual-frame-arm.cc Thu Apr 8 15:30:30 2010 +++ /branches/bleeding_edge/src/arm/virtual-frame-arm.cc Mon Apr 12 00:05:24 2010
@@ -253,6 +253,20 @@
   Adjust(kHandlerSize - 1);
   __ PushTryHandler(IN_JAVASCRIPT, type);
 }
+
+
+void VirtualFrame::CallJSFunction(int arg_count) {
+  // InvokeFunction requires function in r1.
+  EmitPop(r1);
+
+  // +1 for receiver.
+  Forget(arg_count + 1);
+  ASSERT(cgen()->HasValidEntryRegisters());
+  ParameterCount count(arg_count);
+  __ InvokeFunction(r1, count, CALL_FUNCTION);
+  // Restore the context.
+  __ ldr(cp, Context());
+}


 void VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
=======================================
--- /branches/bleeding_edge/src/arm/virtual-frame-arm.h Thu Apr 8 15:30:30 2010 +++ /branches/bleeding_edge/src/arm/virtual-frame-arm.h Mon Apr 12 00:05:24 2010
@@ -288,6 +288,10 @@
     ASSERT(cgen()->HasValidEntryRegisters());
     masm()->CallStub(stub);
   }
+
+  // Call JS function from top of the stack with arguments
+  // taken from the stack.
+  void CallJSFunction(int arg_count);

   // Call runtime given the number of arguments expected on (and
   // removed from) the stack.
=======================================
--- /branches/bleeding_edge/src/array.js        Wed Apr  7 06:13:06 2010
+++ /branches/bleeding_edge/src/array.js        Mon Apr 12 00:05:24 2010
@@ -644,6 +644,8 @@
   // In-place QuickSort algorithm.
// For short (length <= 22) arrays, insertion sort is used for efficiency.

+  var global_receiver;
+
   function InsertionSortWithFunc(a, from, to) {
     for (var i = from + 1; i < to; i++) {
       var element = a[i];
@@ -654,8 +656,7 @@
       // The search interval is a[min..max[
       while (min < max) {
         var mid = min + ((max - min) >> 1);
-        var order = (a[mid] === element) ?
-            0 : comparefn.call(null, a[mid], element);
+ var order = %_CallFunction(global_receiver, a[mid], element, comparefn);
         if (order == 0) {
           min = max = mid;
           break;
@@ -692,8 +693,7 @@
     // From i to high_start are elements that haven't been compared yet.
     for (var i = from + 1; i < high_start; ) {
       var element = a[i];
-      var order = (element === pivot) ?
-          0 : comparefn.call(null, element, pivot);
+ var order = %_CallFunction(global_receiver, element, pivot, comparefn);
       if (order < 0) {
         a[i] = a[low_end];
         a[low_end] = element;
@@ -938,6 +938,7 @@
   }

   if(IS_FUNCTION(comparefn)) {
+    global_receiver = %GetGlobalReceiver();
     QuickSortWithFunc(this, 0, num_non_undefined);
   } else {
     QuickSort(this, 0, num_non_undefined);
=======================================
--- /branches/bleeding_edge/src/codegen.h       Thu Apr  8 15:30:30 2010
+++ /branches/bleeding_edge/src/codegen.h       Mon Apr 12 00:05:24 2010
@@ -104,6 +104,7 @@
F(IsNonNegativeSmi, 1, 1) \ F(IsArray, 1, 1) \ F(IsRegExp, 1, 1) \ + F(CallFunction, -1 /* receiver + n args + function */, 1) \ F(IsConstructCall, 0, 1) \ F(ArgumentsLength, 0, 1) \ F(Arguments, 1, 1) \
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Apr 8 06:41:11 2010 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Mon Apr 12 00:05:24 2010
@@ -6520,6 +6520,22 @@
   Result result = frame_->CallStub(&stub, 1);
   frame_->Push(&result);
 }
+
+
+void CodeGenerator::GenerateCallFunction(ZoneList<Expression*>* args) {
+  Comment cmnt(masm_, "[ GenerateCallFunction");
+
+  ASSERT(args->length() >= 2);
+
+  int n_args = args->length() - 2;  // for receiver and function.
+  Load(args->at(0));  // receiver
+  for (int i = 0; i < n_args; i++) {
+    Load(args->at(i + 1));
+  }
+  Load(args->at(n_args + 1));  // function
+  Result result = frame_->CallJSFunction(n_args);
+  frame_->Push(&result);
+}


// Generates the Math.pow method - only handles special cases and branches to
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h     Wed Apr  7 01:18:51 2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h     Mon Apr 12 00:05:24 2010
@@ -631,6 +631,9 @@
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);

+  // Fast call for custom callbacks.
+  void GenerateCallFunction(ZoneList<Expression*>* args);
+
   // Fast call to math functions.
   void GenerateMathPow(ZoneList<Expression*>* args);
   void GenerateMathSin(ZoneList<Expression*>* args);
=======================================
--- /branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc Thu Mar 25 05:44:15 2010 +++ /branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc Mon Apr 12 00:05:24 2010
@@ -907,6 +907,25 @@
   arg1->Unuse();
   return RawCallStub(stub);
 }
+
+
+Result VirtualFrame::CallJSFunction(int arg_count) {
+  Result function = Pop();
+
+  // InvokeFunction requires function in edi.  Move it in there.
+  function.ToRegister(edi);
+  function.Unuse();
+
+  // +1 for receiver.
+  PrepareForCall(arg_count + 1, arg_count + 1);
+  ASSERT(cgen()->HasValidEntryRegisters());
+  ParameterCount count(arg_count);
+  __ InvokeFunction(edi, count, CALL_FUNCTION);
+  RestoreContextRegister();
+  Result result = cgen()->allocator()->Allocate(eax);
+  ASSERT(result.is_valid());
+  return result;
+}


 Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
=======================================
--- /branches/bleeding_edge/src/ia32/virtual-frame-ia32.h Thu Mar 25 06:18:00 2010 +++ /branches/bleeding_edge/src/ia32/virtual-frame-ia32.h Mon Apr 12 00:05:24 2010
@@ -331,6 +331,10 @@
   // arguments are consumed by the call.
   Result CallStub(CodeStub* stub, Result* arg0, Result* arg1);

+  // Call JS function from top of the stack with arguments
+  // taken from the stack.
+  Result CallJSFunction(int arg_count);
+
   // Call runtime given the number of arguments expected on (and
   // removed from) the stack.
   Result CallRuntime(Runtime::Function* f, int arg_count);
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Thu Apr  8 05:37:10 2010
+++ /branches/bleeding_edge/src/runtime.cc      Mon Apr 12 00:05:24 2010
@@ -1361,6 +1361,13 @@

   return *holder;
 }
+
+
+static Object* Runtime_GetGlobalReceiver(Arguments args) {
+  // Returns a real global receiver, not one of builtins object.
+  Context* global_context = Top::context()->global()->global_context();
+  return global_context->global()->global_receiver();
+}


 static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
=======================================
--- /branches/bleeding_edge/src/runtime.h       Wed Apr  7 04:13:05 2010
+++ /branches/bleeding_edge/src/runtime.h       Mon Apr 12 00:05:24 2010
@@ -62,6 +62,7 @@
   F(ToSlowProperties, 1, 1) \
   F(FinishArrayPrototypeSetup, 1, 1) \
   F(SpecialArrayFunctions, 1, 1) \
+  F(GetGlobalReceiver, 0, 1) \
   \
   F(IsInPrototypeChain, 2, 1) \
   F(SetHiddenPrototype, 2, 1) \
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Thu Apr  8 06:41:11 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Mon Apr 12 00:05:24 2010
@@ -4138,6 +4138,22 @@
   Result result = frame_->CallStub(&stub, 1);
   frame_->Push(&result);
 }
+
+
+void CodeGenerator::GenerateCallFunction(ZoneList<Expression*>* args) {
+  Comment cmnt(masm_, "[ GenerateCallFunction");
+
+  ASSERT(args->length() >= 2);
+
+  int n_args = args->length() - 2;  // for receiver and function.
+  Load(args->at(0));  // receiver
+  for (int i = 0; i < n_args; i++) {
+    Load(args->at(i + 1));
+  }
+  Load(args->at(n_args + 1));  // function
+  Result result = frame_->CallJSFunction(n_args);
+  frame_->Push(&result);
+}


 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h       Wed Apr  7 01:18:51 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.h       Mon Apr 12 00:05:24 2010
@@ -585,6 +585,9 @@
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);

+  // Fast call for custom callbacks.
+  void GenerateCallFunction(ZoneList<Expression*>* args);
+
   // Fast call to math functions.
   void GenerateMathPow(ZoneList<Expression*>* args);
   void GenerateMathSin(ZoneList<Expression*>* args);
=======================================
--- /branches/bleeding_edge/src/x64/virtual-frame-x64.cc Thu Mar 25 05:44:15 2010 +++ /branches/bleeding_edge/src/x64/virtual-frame-x64.cc Mon Apr 12 00:05:24 2010
@@ -822,6 +822,25 @@
   arg1->Unuse();
   return RawCallStub(stub);
 }
+
+
+Result VirtualFrame::CallJSFunction(int arg_count) {
+  Result function = Pop();
+
+  // InvokeFunction requires function in rdi.  Move it in there.
+  function.ToRegister(rdi);
+  function.Unuse();
+
+  // +1 for receiver.
+  PrepareForCall(arg_count + 1, arg_count + 1);
+  ASSERT(cgen()->HasValidEntryRegisters());
+  ParameterCount count(arg_count);
+  __ InvokeFunction(rdi, count, CALL_FUNCTION);
+  RestoreContextRegister();
+  Result result = cgen()->allocator()->Allocate(rax);
+  ASSERT(result.is_valid());
+  return result;
+}


 void VirtualFrame::SyncElementBelowStackPointer(int index) {
=======================================
--- /branches/bleeding_edge/src/x64/virtual-frame-x64.h Thu Mar 25 06:18:00 2010 +++ /branches/bleeding_edge/src/x64/virtual-frame-x64.h Mon Apr 12 00:05:24 2010
@@ -318,6 +318,10 @@
   // arguments are consumed by the call.
   Result CallStub(CodeStub* stub, Result* arg0, Result* arg1);

+  // Call JS function from top of the stack with arguments
+  // taken from the stack.
+  Result CallJSFunction(int arg_count);
+
   // Call runtime given the number of arguments expected on (and
   // removed from) the stack.
   Result CallRuntime(Runtime::Function* f, int arg_count);
=======================================
--- /branches/bleeding_edge/test/mjsunit/fuzz-natives.js Thu Mar 11 01:27:12 2010 +++ /branches/bleeding_edge/test/mjsunit/fuzz-natives.js Mon Apr 12 00:05:24 2010
@@ -160,6 +160,9 @@
   // That can only be invoked on Array.prototype.
   "FinishArrayPrototypeSetup": true,

+  // Performance critical function which cannot afford type checks.
+  "_CallFunction": true,
+
   // LiveEdit feature is under development currently and has fragile input.
   "LiveEditFindSharedFunctionInfosForScript": true,
   "LiveEditGatherCompileInfo": true,

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

To unsubscribe, reply using "remove me" as the subject.

Reply via email to