Commit 400b1be4 authored by antonm@chromium.org's avatar antonm@chromium.org

Faster invocation of custom comparator function.

Review URL: http://codereview.chromium.org/1623004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4381 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent cfad0128
......@@ -4033,6 +4033,22 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
}
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) {
ASSERT_EQ(args->length(), 1);
// Load the argument on the stack and jump to the runtime.
......
......@@ -410,6 +410,9 @@ class CodeGenerator: public AstVisitor {
// 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);
......
......@@ -255,6 +255,20 @@ void VirtualFrame::PushTryHandler(HandlerType 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) {
Forget(arg_count);
ASSERT(cgen()->HasValidEntryRegisters());
......
......@@ -289,6 +289,10 @@ class VirtualFrame : public ZoneObject {
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.
void CallRuntime(Runtime::Function* f, int arg_count);
......
......@@ -644,6 +644,8 @@ function ArraySort(comparefn) {
// 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 @@ function ArraySort(comparefn) {
// 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 @@ function ArraySort(comparefn) {
// 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 @@ function ArraySort(comparefn) {
}
if(IS_FUNCTION(comparefn)) {
global_receiver = %GetGlobalReceiver();
QuickSortWithFunc(this, 0, num_non_undefined);
} else {
QuickSort(this, 0, num_non_undefined);
......
......@@ -104,6 +104,7 @@ namespace internal {
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) \
......
......@@ -6522,6 +6522,22 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
}
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
// the runtime system if not.Please note - this function assumes that
// the callsite has executed ToNumber on both arguments and that the
......
......@@ -631,6 +631,9 @@ class CodeGenerator: public AstVisitor {
// 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);
......
......@@ -909,6 +909,25 @@ Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) {
}
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) {
PrepareForCall(arg_count, arg_count);
ASSERT(cgen()->HasValidEntryRegisters());
......
......@@ -331,6 +331,10 @@ class VirtualFrame: public ZoneObject {
// 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);
......
......@@ -1363,6 +1363,13 @@ static Object* Runtime_SpecialArrayFunctions(Arguments args) {
}
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) {
HandleScope scope;
ASSERT(args.length() == 4);
......
......@@ -62,6 +62,7 @@ namespace internal {
F(ToSlowProperties, 1, 1) \
F(FinishArrayPrototypeSetup, 1, 1) \
F(SpecialArrayFunctions, 1, 1) \
F(GetGlobalReceiver, 0, 1) \
\
F(IsInPrototypeChain, 2, 1) \
F(SetHiddenPrototype, 2, 1) \
......
......@@ -4140,6 +4140,22 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
}
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) {
ASSERT_EQ(args->length(), 1);
// Load the argument on the stack and jump to the runtime.
......
......@@ -585,6 +585,9 @@ class CodeGenerator: public AstVisitor {
// 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);
......
......@@ -824,6 +824,25 @@ Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) {
}
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) {
// Emit code to write elements below the stack pointer to their
// (already allocated) stack address.
......
......@@ -318,6 +318,10 @@ class VirtualFrame : public ZoneObject {
// 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);
......
......@@ -160,6 +160,9 @@ var knownProblems = {
// 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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment