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
This commit is contained in:
parent
cfad01282c
commit
400b1be449
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user