Commit c6f36966 authored by darin@apple.com's avatar darin@apple.com

Reviewed by Geoff.

        - http://bugs.webkit.org/show_bug.cgi?id=16685
          eliminate List::empty() to cut down on PIC branches

        Also included one other speed-up -- remove the call to reserveCapacity from
        FunctionBodyNode::processDeclarations in all but the most unusual cases.

        Together these make SunSpider 1.016x as fast.

        * JavaScriptCore.exp: Updated.
        * kjs/ExecState.cpp:
        (KJS::globalEmptyList): Added. Called only when creating global ExecState
        instances.
        (KJS::ExecState::ExecState): Broke constructor up into three separate functions,
        for the three separate node types. Also went through each of the three and
        streamlined as much as possible, removing dead code. This prevents us from having
        to access the global in the function body version of the constructor.

        * kjs/ExecState.h: Added emptyList(). Replaced the constructor with a set of
        three that are specific to the different node types that can create new execution
        state objects.

        * kjs/array_object.cpp:
        (KJS::ArrayProtoFuncToLocaleString::callAsFunction): Use exec->emptyList() instead
        of List::empty().
        (KJS::ArrayProtoFuncConcat::callAsFunction): Ditto.
        (KJS::ArrayProtoFuncSlice::callAsFunction): Ditto.
        (KJS::ArrayProtoFuncSplice::callAsFunction): Ditto.
        (KJS::ArrayProtoFuncFilter::callAsFunction): Ditto.
        * kjs/function.cpp:
        (KJS::FunctionImp::callAsFunction): Updated to call new ExecState constructor.
        (KJS::GlobalFuncImp::callAsFunction): Ditto (for eval).
        * kjs/function_object.cpp:
        (FunctionObjectImp::construct): Use exec->emptyList() instead of List::empty().

        * kjs/list.cpp: Removed List::empty.
        * kjs/list.h: Ditto.

        * kjs/nodes.cpp:
        (KJS::ElementNode::evaluate): Use exec->emptyList() instead of List::empty().
        (KJS::ArrayNode::evaluate): Ditto.
        (KJS::ObjectLiteralNode::evaluate): Ditto.
        (KJS::PropertyListNode::evaluate): Ditto.
        (KJS::FunctionBodyNode::processDeclarations): Another speed-up. Check the capacity
        before calling reserveCapacity, because it doesn't get inlined the local storage
        vector is almost always big enough -- saving the function call overhead is a big
        deal.
        (KJS::FuncDeclNode::makeFunction): Use exec->emptyList() instead of List::empty().
        (KJS::FuncExprNode::evaluate): Ditto.
        * kjs/object.cpp:
        (KJS::tryGetAndCallProperty): Ditto.
        * kjs/property_slot.cpp:
        (KJS::PropertySlot::functionGetter): Ditto.
        * kjs/string_object.cpp:
        (KJS::StringProtoFuncSplit::callAsFunction): Ditto.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@29067 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent d7817270
2008-01-01 Darin Adler <darin@apple.com>
Reviewed by Geoff.
- http://bugs.webkit.org/show_bug.cgi?id=16685
eliminate List::empty() to cut down on PIC branches
Also included one other speed-up -- remove the call to reserveCapacity from
FunctionBodyNode::processDeclarations in all but the most unusual cases.
Together these make SunSpider 1.016x as fast.
* JavaScriptCore.exp: Updated.
* kjs/ExecState.cpp:
(KJS::globalEmptyList): Added. Called only when creating global ExecState
instances.
(KJS::ExecState::ExecState): Broke constructor up into three separate functions,
for the three separate node types. Also went through each of the three and
streamlined as much as possible, removing dead code. This prevents us from having
to access the global in the function body version of the constructor.
* kjs/ExecState.h: Added emptyList(). Replaced the constructor with a set of
three that are specific to the different node types that can create new execution
state objects.
* kjs/array_object.cpp:
(KJS::ArrayProtoFuncToLocaleString::callAsFunction): Use exec->emptyList() instead
of List::empty().
(KJS::ArrayProtoFuncConcat::callAsFunction): Ditto.
(KJS::ArrayProtoFuncSlice::callAsFunction): Ditto.
(KJS::ArrayProtoFuncSplice::callAsFunction): Ditto.
(KJS::ArrayProtoFuncFilter::callAsFunction): Ditto.
* kjs/function.cpp:
(KJS::FunctionImp::callAsFunction): Updated to call new ExecState constructor.
(KJS::GlobalFuncImp::callAsFunction): Ditto (for eval).
* kjs/function_object.cpp:
(FunctionObjectImp::construct): Use exec->emptyList() instead of List::empty().
* kjs/list.cpp: Removed List::empty.
* kjs/list.h: Ditto.
* kjs/nodes.cpp:
(KJS::ElementNode::evaluate): Use exec->emptyList() instead of List::empty().
(KJS::ArrayNode::evaluate): Ditto.
(KJS::ObjectLiteralNode::evaluate): Ditto.
(KJS::PropertyListNode::evaluate): Ditto.
(KJS::FunctionBodyNode::processDeclarations): Another speed-up. Check the capacity
before calling reserveCapacity, because it doesn't get inlined the local storage
vector is almost always big enough -- saving the function call overhead is a big
deal.
(KJS::FuncDeclNode::makeFunction): Use exec->emptyList() instead of List::empty().
(KJS::FuncExprNode::evaluate): Ditto.
* kjs/object.cpp:
(KJS::tryGetAndCallProperty): Ditto.
* kjs/property_slot.cpp:
(KJS::PropertySlot::functionGetter): Ditto.
* kjs/string_object.cpp:
(KJS::StringProtoFuncSplit::callAsFunction): Ditto.
2008-01-01 Darin Adler <darin@apple.com>
Reviewed by Geoff.
......
......@@ -230,7 +230,7 @@ __ZN3KJS9Collector4sizeEv
__ZN3KJS9Collector7collectEv
__ZN3KJS9Collector7protectEPNS_7JSValueE
__ZN3KJS9Collector9unprotectEPNS_7JSValueE
__ZN3KJS9ExecStateC1EPNS_14JSGlobalObjectEPNS_8JSObjectEPNS_9ScopeNodeENS_8CodeTypeEPS0_S8_PNS_11FunctionImpEPKNS_4ListE
__ZN3KJS9ExecStateC1EPNS_14JSGlobalObjectEPNS_8JSObjectEPNS_11ProgramNodeE
__ZN3KJS9ExecStateD1Ev
__ZN3KJSeqERKNS_7UStringEPKc
__ZN3WTF10fastCallocEmm
......
......@@ -31,56 +31,86 @@
namespace KJS {
static inline List* globalEmptyList()
{
static List staticEmptyList;
return &staticEmptyList;
}
// ECMA 10.2
ExecState::ExecState(JSGlobalObject* globalObject, JSObject* thisV,
ScopeNode* scopeNode, CodeType type, ExecState* callingExec, ExecState* currentExec,
FunctionImp* func, const List* args)
ExecState::ExecState(JSGlobalObject* globalObject, JSObject* /*thisObject*/, ProgramNode* programNode)
: m_globalObject(globalObject)
, m_exception(0)
, m_propertyNames(CommonIdentifiers::shared())
, m_emptyList(globalEmptyList())
, m_callingExec(0)
, m_savedExec(0)
, m_scopeNode(programNode)
, m_function(0)
, m_arguments(0)
, m_activation(0)
, m_localStorage(&globalObject->localStorage())
, m_variableObject(globalObject)
, m_thisVal(globalObject)
, m_iterationDepth(0)
, m_switchDepth(0)
, m_codeType(GlobalCode)
{
// FIXME: This function ignores the "thisObject" parameter, which means that the API for evaluating
// a script with a this object that's not the same as the global object is broken, and probably
// has been for some time.
m_scopeChain.push(globalObject);
if (programNode)
globalObject->setCurrentExec(this);
}
ExecState::ExecState(JSGlobalObject* globalObject, EvalNode* evalNode, ExecState* callingExec)
: m_globalObject(globalObject)
, m_exception(0)
, m_propertyNames(callingExec->m_propertyNames)
, m_emptyList(callingExec->m_emptyList)
, m_callingExec(callingExec)
, m_savedExec(currentExec)
, m_scopeNode(scopeNode)
, m_savedExec(globalObject->currentExec())
, m_scopeNode(evalNode)
, m_function(0)
, m_arguments(0)
, m_activation(0)
, m_localStorage(callingExec->m_localStorage)
, m_scopeChain(callingExec->m_scopeChain)
, m_variableObject(callingExec->m_variableObject)
, m_thisVal(callingExec->m_thisVal)
, m_iterationDepth(0)
, m_switchDepth(0)
, m_codeType(EvalCode)
{
globalObject->setCurrentExec(this);
}
ExecState::ExecState(JSGlobalObject* globalObject, JSObject* thisObject,
FunctionBodyNode* functionBodyNode, ExecState* callingExec,
FunctionImp* func, const List& args)
: m_globalObject(globalObject)
, m_exception(0)
, m_propertyNames(callingExec->m_propertyNames)
, m_emptyList(callingExec->m_emptyList)
, m_callingExec(callingExec)
, m_savedExec(globalObject->currentExec())
, m_scopeNode(functionBodyNode)
, m_function(func)
, m_arguments(args)
, m_arguments(&args)
, m_scopeChain(func->scope())
, m_thisVal(thisObject)
, m_iterationDepth(0)
, m_switchDepth(0)
, m_codeType(type)
, m_codeType(FunctionCode)
{
// create and initialize activation object (ECMA 10.1.6)
if (type == FunctionCode) {
m_activation = new ActivationImp(this);
m_variableObject = m_activation;
} else {
m_activation = 0;
m_variableObject = globalObject;
}
// ECMA 10.2
switch(type) {
case EvalCode:
if (m_callingExec) {
m_scopeChain = m_callingExec->scopeChain();
m_variableObject = m_callingExec->variableObject();
m_thisVal = m_callingExec->thisValue();
break;
} // else same as GlobalCode
case GlobalCode:
m_scopeChain.push(globalObject);
m_thisVal = globalObject;
break;
case FunctionCode:
m_scopeChain = func->scope();
m_scopeChain.push(m_activation);
m_variableObject = m_activation;
m_thisVal = thisV;
break;
}
m_localStorage = &m_variableObject->localStorage();
if (scopeNode)
m_globalObject->setCurrentExec(this);
ActivationImp* activation = new ActivationImp(this);
m_activation = activation;
m_localStorage = &activation->localStorage();
m_variableObject = activation;
m_scopeChain.push(activation);
globalObject->setCurrentExec(this);
}
ExecState::~ExecState()
......
......@@ -39,11 +39,14 @@ namespace KJS {
class ActivationImp;
class CommonIdentifiers;
class EvalNode;
class FunctionBodyNode;
class FunctionImp;
class GlobalFuncImp;
class Interpreter;
class JSGlobalObject;
class JSVariableObject;
class ProgramNode;
class ScopeChain;
class ScopeNode;
struct LocalStorageEntry;
......@@ -103,9 +106,10 @@ namespace KJS {
void mark();
// This is a workaround to avoid accessing the global variables for these identifiers in
// important property lookup functions, to avoid taking PIC branches in Mach-O binaries
// These pointers are used to avoid accessing global variables for these,
// to avoid taking PIC branches in Mach-O binaries.
const CommonIdentifiers& propertyNames() const { return *m_propertyNames; }
const List& emptyList() const { return *m_emptyList; }
LocalStorage& localStorage() { return *m_localStorage; }
......@@ -171,11 +175,10 @@ namespace KJS {
return 0;
}
public:
ExecState(JSGlobalObject* glob, JSObject* thisV,
ScopeNode* scopeNode, CodeType type = GlobalCode,
ExecState* callingExecState = 0, ExecState* currentExec = 0,
FunctionImp* function = 0, const List* args = 0);
ExecState(JSGlobalObject*, JSObject* thisObject, ProgramNode*);
ExecState(JSGlobalObject*, EvalNode*, ExecState* callingExecState);
ExecState(JSGlobalObject*, JSObject* thisObject, FunctionBodyNode*,
ExecState* callingExecState, FunctionImp*, const List& args);
~ExecState();
private:
......@@ -185,6 +188,7 @@ namespace KJS {
JSGlobalObject* m_globalObject;
JSValue* m_exception;
CommonIdentifiers* m_propertyNames;
const List* m_emptyList;
ExecState* m_callingExec;
ExecState* m_savedExec;
......
......@@ -160,7 +160,7 @@ JSValue* ArrayProtoFuncToLocaleString::callAsFunction(ExecState* exec, JSObject*
JSObject* o = element->toObject(exec);
JSValue* conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
if (conversionFunction->isObject() && static_cast<JSObject*>(conversionFunction)->implementsCall())
str += static_cast<JSObject*>(conversionFunction)->call(exec, o, List::empty())->toString(exec);
str += static_cast<JSObject*>(conversionFunction)->call(exec, o, exec->emptyList())->toString(exec);
else
str += element->toString(exec);
......@@ -220,7 +220,7 @@ JSValue* ArrayProtoFuncJoin::callAsFunction(ExecState* exec, JSObject* thisObj,
JSValue* ArrayProtoFuncConcat::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
JSObject* arr = static_cast<JSObject*>(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, List::empty()));
JSObject* arr = static_cast<JSObject*>(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList()));
int n = 0;
JSValue* curArg = thisObj;
JSObject* curObj = static_cast<JSObject* >(thisObj);
......@@ -327,7 +327,7 @@ JSValue* ArrayProtoFuncSlice::callAsFunction(ExecState* exec, JSObject* thisObj,
// http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
// We return a new array
JSObject* resObj = static_cast<JSObject* >(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, List::empty()));
JSObject* resObj = static_cast<JSObject* >(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList()));
JSValue* result = resObj;
double begin = args[0]->toInteger(exec);
unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
......@@ -427,7 +427,7 @@ JSValue* ArrayProtoFuncSort::callAsFunction(ExecState* exec, JSObject* thisObj,
JSValue* ArrayProtoFuncSplice::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
// 15.4.4.12
JSObject* resObj = static_cast<JSObject* >(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, List::empty()));
JSObject* resObj = static_cast<JSObject* >(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList()));
JSValue* result = resObj;
unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
int begin = args[0]->toUInt32(exec);
......@@ -496,7 +496,7 @@ JSValue* ArrayProtoFuncFilter::callAsFunction(ExecState* exec, JSObject* thisObj
return throwError(exec, TypeError);
JSObject* applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicGlobalObject() : args[1]->toObject(exec);
JSObject* resultArray = static_cast<JSObject*>(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, List::empty()));
JSObject* resultArray = static_cast<JSObject*>(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList()));
unsigned filterIndex = 0;
unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
......
......@@ -70,7 +70,7 @@ void FunctionImp::mark()
JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
ExecState newExec(exec->dynamicGlobalObject(), thisObj, body.get(), FunctionCode, exec, exec->dynamicGlobalObject()->currentExec(), this, &args);
ExecState newExec(exec->dynamicGlobalObject(), thisObj, body.get(), exec, this, args);
JSValue* result = body->execute(&newExec);
if (newExec.completionType() == Throw) {
exec->setException(result);
......@@ -697,8 +697,7 @@ JSValue* GlobalFuncImp::callAsFunction(ExecState* exec, JSObject* thisObj, const
// enter a new execution context
JSGlobalObject* globalObject = switchGlobal ? static_cast<JSGlobalObject*>(thisObj) : exec->dynamicGlobalObject();
JSObject* thisVal = static_cast<JSObject*>(exec->thisValue());
ExecState newExec(globalObject, thisVal, evalNode.get(), EvalCode, exec, globalObject->currentExec());
ExecState newExec(globalObject, evalNode.get(), exec);
if (switchGlobal) {
newExec.pushScope(thisObj);
......
......@@ -247,7 +247,7 @@ JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const
List consArgs;
JSObject* objCons = exec->lexicalGlobalObject()->objectConstructor();
JSObject* prototype = objCons->construct(exec,List::empty());
JSObject* prototype = objCons->construct(exec, exec->emptyList());
prototype->put(exec, exec->propertyNames().constructor, fimp, DontEnum|DontDelete|ReadOnly);
fimp->put(exec, exec->propertyNames().prototype, prototype, Internal|DontDelete);
return fimp;
......
......@@ -31,12 +31,6 @@ void List::getSlice(int startIndex, List& result) const
result.m_vector.appendRange(start, end());
}
const List& List::empty()
{
static const List staticList;
return staticList;
}
List::ListSet& List::markSet()
{
static ListSet staticMarkSet;
......
......@@ -92,8 +92,6 @@ namespace KJS {
markProtectedListsSlowCase();
}
static const List& empty(); // Fast path for an empty list.
private:
static ListSet& markSet();
static void markProtectedListsSlowCase();
......
......@@ -635,7 +635,7 @@ void ElementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeSt
// ECMA 11.1.4
JSValue *ElementNode::evaluate(ExecState *exec)
{
JSObject *array = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, List::empty());
JSObject* array = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList());
int length = 0;
for (ElementNode *n = this; n; n = n->next.get()) {
JSValue *val = n->node->evaluate(exec);
......@@ -666,7 +666,7 @@ JSValue *ArrayNode::evaluate(ExecState *exec)
KJS_CHECKEXCEPTIONVALUE
length = opt ? array->get(exec, exec->propertyNames().length)->toInt32(exec) : 0;
} else {
JSValue *newArr = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec,List::empty());
JSValue* newArr = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList());
array = static_cast<JSObject*>(newArr);
length = 0;
}
......@@ -691,7 +691,7 @@ JSValue *ObjectLiteralNode::evaluate(ExecState *exec)
if (list)
return list->evaluate(exec);
return exec->lexicalGlobalObject()->objectConstructor()->construct(exec,List::empty());
return exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
}
// ------------------------------ PropertyListNode -----------------------------
......@@ -706,7 +706,7 @@ void PropertyListNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::N
// ECMA 11.1.5
JSValue *PropertyListNode::evaluate(ExecState *exec)
{
JSObject *obj = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, List::empty());
JSObject* obj = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
for (PropertyListNode *p = this; p; p = p->next.get()) {
JSValue *v = p->node->assign->evaluate(exec);
......@@ -4361,7 +4361,9 @@ void FunctionBodyNode::processDeclarations(ExecState* exec)
// We can't just resize localStorage here because that would temporarily
// leave uninitialized entries, which would crash GC during the mark phase.
localStorage.reserveCapacity(m_varStack.size() + m_parameters.size() + m_functionStack.size());
size_t totalSize = m_varStack.size() + m_parameters.size() + m_functionStack.size();
if (totalSize > localStorage.capacity()) // Doing this check inline avoids function call overhead.
localStorage.reserveCapacity(totalSize);
int minAttributes = Internal | DontDelete;
......@@ -4543,7 +4545,7 @@ FunctionImp* FuncDeclNode::makeFunction(ExecState* exec)
{
FunctionImp *func = new FunctionImp(exec, ident, body.get(), exec->scopeChain());
JSObject *proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, List::empty());
JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
proto->put(exec, exec->propertyNames().constructor, func, ReadOnly | DontDelete | DontEnum);
func->put(exec, exec->propertyNames().prototype, proto, Internal|DontDelete);
......@@ -4579,7 +4581,7 @@ JSValue *FuncExprNode::evaluate(ExecState *exec)
}
FunctionImp* func = new FunctionImp(exec, ident, body.get(), exec->scopeChain());
JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, List::empty());
JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
proto->put(exec, exec->propertyNames().constructor, func, ReadOnly | DontDelete | DontEnum);
func->put(exec, exec->propertyNames().prototype, proto, Internal | DontDelete);
......
......@@ -353,7 +353,7 @@ static ALWAYS_INLINE JSValue *tryGetAndCallProperty(ExecState *exec, const JSObj
JSObject *o = static_cast<JSObject*>(v);
if (o->implementsCall()) { // spec says "not primitive type" but ...
JSObject *thisObj = const_cast<JSObject*>(object);
JSValue *def = o->call(exec, thisObj, List::empty());
JSValue* def = o->call(exec, thisObj, exec->emptyList());
JSType defType = def->type();
ASSERT(defType != GetterSetterType);
if (defType != ObjectType)
......
......@@ -34,7 +34,7 @@ JSValue *PropertySlot::undefinedGetter(ExecState*, JSObject*, const Identifier&,
JSValue *PropertySlot::functionGetter(ExecState* exec, JSObject* originalObject, const Identifier&, const PropertySlot& slot)
{
return slot.m_data.getterFunc->call(exec, originalObject, List::empty());
return slot.m_data.getterFunc->call(exec, originalObject, exec->emptyList());
}
}
......@@ -662,7 +662,7 @@ JSValue* StringProtoFuncSplit::callAsFunction(ExecState* exec, JSObject* thisObj
JSValue* a1 = args[1];
JSObject *constructor = exec->lexicalGlobalObject()->arrayConstructor();
JSObject *res = static_cast<JSObject *>(constructor->construct(exec,List::empty()));
JSObject* res = static_cast<JSObject*>(constructor->construct(exec, exec->emptyList()));
JSValue* result = res;
UString u = s;
int pos;
......
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