Commit cbf3ca98 authored by weinig@apple.com's avatar weinig@apple.com

JavaScriptCore:

2008-09-22  Sam Weinig  <sam@webkit.org>

        Reviewed by Darin Adler.

        Patch for https://bugs.webkit.org/show_bug.cgi?id=20982
        Speed up the apply method of functions by special-casing array and 'arguments' objects

        1% speedup on v8-raytrace.

        Test: fast/js/function-apply.html

        * kjs/Arguments.cpp:
        (JSC::Arguments::fillArgList):
        * kjs/Arguments.h:
        * kjs/FunctionPrototype.cpp:
        (JSC::functionProtoFuncApply):
        * kjs/JSArray.cpp:
        (JSC::JSArray::fillArgList):
        * kjs/JSArray.h:

LayoutTests:

2008-09-22  Sam Weinig  <sam@webkit.org>

        Reviewed by Darin Adler.

        Test for https://bugs.webkit.org/show_bug.cgi?id=20982

        * fast/js/function-apply-expected.txt: Added.
        * fast/js/function-apply.html: Added.
        * fast/js/resources/function-apply.js: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@36779 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ef5124b0
2008-09-22 Sam Weinig <sam@webkit.org>
Reviewed by Darin Adler.
Patch for https://bugs.webkit.org/show_bug.cgi?id=20982
Speed up the apply method of functions by special-casing array and 'arguments' objects
1% speedup on v8-raytrace.
Test: fast/js/function-apply.html
* kjs/Arguments.cpp:
(JSC::Arguments::fillArgList):
* kjs/Arguments.h:
* kjs/FunctionPrototype.cpp:
(JSC::functionProtoFuncApply):
* kjs/JSArray.cpp:
(JSC::JSArray::fillArgList):
* kjs/JSArray.h:
2008-09-22 Darin Adler <darin@apple.com>
Reviewed by Sam Weinig.
......
......@@ -66,6 +66,18 @@ namespace JSC {
{
}
void initialize(Register* buffer, size_t size)
{
ASSERT(!m_markSet);
ASSERT(isEmpty());
m_buffer = buffer;
m_size = size;
#ifndef NDEBUG
m_isReadOnly = true;
#endif
}
~ArgList()
{
if (m_markSet)
......
......@@ -91,6 +91,39 @@ void Arguments::mark()
d->activation->mark();
}
void Arguments::fillArgList(ExecState* exec, ArgList& args)
{
if (!d->deletedArguments) {
if (d->numParameters == d->numArguments) {
args.initialize(&d->activation->registerAt(d->firstArgumentIndex), d->numArguments);
return;
}
unsigned parametersLength = min(d->numParameters, d->numArguments);
unsigned i = 0;
for (; i < parametersLength; ++i)
args.append(d->activation->uncheckedSymbolTableGetValue(d->firstArgumentIndex + i));
for (; i < d->numArguments; ++i)
args.append(d->extraArguments[i - d->numParameters]);
return;
}
unsigned parametersLength = min(d->numParameters, d->numArguments);
unsigned i = 0;
for (; i < parametersLength; ++i) {
if (!d->deletedArguments[i])
args.append(d->activation->uncheckedSymbolTableGetValue(d->firstArgumentIndex + i));
else
args.append(get(exec, i));
}
for (; i < d->numArguments; ++i) {
if (!d->deletedArguments[i])
args.append(d->extraArguments[i - d->numParameters]);
else
args.append(get(exec, i));
}
}
bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
{
if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
......
......@@ -43,6 +43,8 @@ namespace JSC {
virtual void mark();
void fillArgList(ExecState*, ArgList&);
private:
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
......
......@@ -95,14 +95,15 @@ JSValue* functionProtoFuncApply(ExecState* exec, JSObject*, JSValue* thisValue,
ArgList applyArgs;
if (!argArray->isUndefinedOrNull()) {
if (argArray->isObject() &&
(static_cast<JSObject*>(argArray)->inherits(&JSArray::info) ||
static_cast<JSObject*>(argArray)->inherits(&Arguments::info))) {
JSObject* argArrayObj = static_cast<JSObject*>(argArray);
unsigned int length = argArrayObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
for (unsigned int i = 0; i < length; i++)
applyArgs.append(argArrayObj->get(exec, i));
if (argArray->isObject()) {
if (static_cast<JSObject*>(argArray)->classInfo() == &Arguments::info)
static_cast<Arguments*>(argArray)->fillArgList(exec, applyArgs);
else if (exec->machine()->isJSArray(argArray))
static_cast<JSArray*>(argArray)->fillArgList(exec, applyArgs);
else if (static_cast<JSObject*>(argArray)->inherits(&JSArray::info))
static_cast<JSArray*>(argArray)->fillArgList(exec, applyArgs);
else
return throwError(exec, TypeError);
} else
return throwError(exec, TypeError);
}
......
......@@ -857,6 +857,16 @@ void JSArray::sort(ExecState* exec, JSValue* compareFunction, CallType callType,
checkConsistency(SortConsistencyCheck);
}
void JSArray::fillArgList(ExecState* exec, ArgList& args)
{
unsigned fastAccessLength = min(m_storage->m_length, m_fastAccessCutoff);
unsigned i = 0;
for (; i < fastAccessLength; ++i)
args.append(getIndex(i));
for (; i < m_storage->m_length; ++i)
args.append(get(exec, i));
}
unsigned JSArray::compactForSorting()
{
checkConsistency();
......
......@@ -74,6 +74,8 @@ namespace JSC {
return m_storage->m_vector[i] = v;
}
void fillArgList(ExecState*, ArgList&);
protected:
virtual void put(ExecState*, const Identifier& propertyName, JSValue*, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
......
2008-09-22 Sam Weinig <sam@webkit.org>
Reviewed by Darin Adler.
Test for https://bugs.webkit.org/show_bug.cgi?id=20982
* fast/js/function-apply-expected.txt: Added.
* fast/js/function-apply.html: Added.
* fast/js/resources/function-apply.js: Added.
2008-09-22 Simon Fraser <simon.fraser@apple.com>
Reviewed by Sam Weinig
......
Tests to ensure that Function.apply works correctly for Arrays and arguments.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS argumentsApply1(1, 2, 3) is 1
PASS argumentsApply2(1, 2, 3) is 2
PASS argumentsApply3(1, 2, 3) is 3
PASS argumentsApplyLength(1, 2, 3) is 3
PASS arrayApply1([1, 2, 3]) is 1
PASS arrayApply2([1, 2, 3]) is 2
PASS arrayApply3([1, 2, 3]) is 3
PASS arrayApplyLength([1, 2, 3]) is 3
PASS argumentsApplyDelete1(1, 2, 3) is 1
PASS argumentsApplyDelete2(1, 2, 3) is undefined
PASS argumentsApplyDelete3(1, 2, 3) is 3
PASS argumentsApplyDeleteLength(1, 2, 3) is 3
PASS arrayApplyDelete1([1, 2, 3]) is 1
PASS arrayApplyDelete2([1, 2, 3]) is undefined
PASS arrayApplyDelete3([1, 2, 3]) is 3
PASS arrayApplyDeleteLength([1, 2, 3]) is 3
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="resources/js-test-style.css">
<script src="resources/js-test-pre.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script src="resources/function-apply.js"></script>
<script src="resources/js-test-post.js"></script>
</body>
</html>
description('Tests to ensure that Function.apply works correctly for Arrays and arguments.');
function argumentsApply1(a, b, c)
{
function t(a, b, c)
{
return a;
}
return t.apply(null, arguments);
}
function argumentsApply2(a, b, c)
{
function t(a, b, c)
{
return b;
}
return t.apply(null, arguments);
}
function argumentsApply3(a, b, c)
{
function t(a, b, c)
{
return c;
}
return t.apply(null, arguments);
}
function argumentsApplyLength(a, b, c)
{
function t(a, b, c)
{
return arguments.length;
}
return t.apply(null, arguments);
}
shouldBe("argumentsApply1(1, 2, 3)", "1");
shouldBe("argumentsApply2(1, 2, 3)", "2");
shouldBe("argumentsApply3(1, 2, 3)", "3");
shouldBe("argumentsApplyLength(1, 2, 3)", "3");
function arrayApply1(array)
{
function t(a, b, c)
{
return a;
}
return t.apply(null, array);
}
function arrayApply2(array)
{
function t(a, b, c)
{
return b;
}
return t.apply(null, array);
}
function arrayApply3(array)
{
function t(a, b, c)
{
return c;
}
return t.apply(null, array);
}
function arrayApplyLength(array)
{
function t(a, b, c)
{
return arguments.length;
}
return t.apply(null, array);
}
shouldBe("arrayApply1([1, 2, 3])", "1");
shouldBe("arrayApply2([1, 2, 3])", "2");
shouldBe("arrayApply3([1, 2, 3])", "3");
shouldBe("arrayApplyLength([1, 2, 3])", "3");
function argumentsApplyDelete1(a, b, c)
{
function t(a, b, c)
{
return a;
}
delete arguments[1];
return t.apply(null, arguments);
}
function argumentsApplyDelete2(a, b, c)
{
function t(a, b, c)
{
return b;
}
delete arguments[1];
return t.apply(null, arguments);
}
function argumentsApplyDelete3(a, b, c)
{
function t(a, b, c)
{
return c;
}
delete arguments[1];
return t.apply(null, arguments);
}
function argumentsApplyDeleteLength(a, b, c)
{
function t(a, b, c)
{
return arguments.length;
}
delete arguments[1];
return t.apply(null, arguments);
}
shouldBe("argumentsApplyDelete1(1, 2, 3)", "1");
shouldBe("argumentsApplyDelete2(1, 2, 3)", "undefined");
shouldBe("argumentsApplyDelete3(1, 2, 3)", "3");
shouldBe("argumentsApplyDeleteLength(1, 2, 3)", "3");
function arrayApplyDelete1(array)
{
function t(a, b, c)
{
return a;
}
delete array[1];
return t.apply(null, array);
}
function arrayApplyDelete2(array)
{
function t(a, b, c)
{
return b;
}
delete array[1];
return t.apply(null, array);
}
function arrayApplyDelete3(array)
{
function t(a, b, c)
{
return c;
}
delete array[1];
return t.apply(null, array);
}
function arrayApplyDeleteLength(array)
{
function t(a, b, c)
{
return arguments.length;
}
delete array[1];
return t.apply(null, array);
}
shouldBe("arrayApplyDelete1([1, 2, 3])", "1");
shouldBe("arrayApplyDelete2([1, 2, 3])", "undefined");
shouldBe("arrayApplyDelete3([1, 2, 3])", "3");
shouldBe("arrayApplyDeleteLength([1, 2, 3])", "3");
var successfullyParsed = 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