[webkit-changes] cvs commit: JavaScriptCore/kjs function.h
grammar.y nodes.cpp nodes.h nodes2string.cpp object.h
Maciej
mjs at opensource.apple.com
Fri Aug 12 00:36:01 PDT 2005
mjs 05/08/12 00:36:01
Modified: . ChangeLog
kjs function.h grammar.y nodes.cpp nodes.h
nodes2string.cpp object.h
Log:
Reviewed by hyatt.
- refactor function calls, 3% speedup on JS iBench.
* kjs/grammar.y:
* kjs/nodes.cpp:
(Node::throwError): Added new useful variants.
(FunctionCallValueNode::evaluate): New node to handle calls on expressions
that are strictly values, not references.
(FunctionCallValueNode::ref): ditto
(FunctionCallValueNode::deref): ditto
(FunctionCallResolveNode::evaluate): New node to handle calls on identifier
expressions, so that they are looked up in the scope chain.
(FunctionCallResolveNode::ref): ditto
(FunctionCallResolveNode::deref): ditto
(FunctionCallBracketNode::evaluate): New node to handle calls on bracket
dereferences, so that the expression before brackets is used as the this
object.
(FunctionCallBracketNode::ref): ditto
(FunctionCallBracketNode::deref): ditto
(FunctionCallDotNode::evaluate): New node to handle calls on dot
dereferences, so that the expression before the dot is used as the this
object.
(FunctionCallDotNode::ref): ditto
(FunctionCallDotNode::deref): ditto
(dotExprNotAnObjectString): helper function to avoid global variable access.
(dotExprDoesNotAllowCallsString): ditto
* kjs/nodes.h: Declared new classes.
* kjs/nodes2string.cpp:
(FunctionCallValueNode::streamTo): Added - serializes the appropriate function call
(FunctionCallResolveNode::streamTo): ditto
(FunctionCallBracketNode::streamTo): ditto
(FunctionCallParenBracketNode::streamTo): ditto
(FunctionCallDotNode::streamTo): ditto
(FunctionCallParenDotNode::streamTo): ditto
* kjs/object.h:
(KJS::ObjectImp::isActivation): Change how activation objects are
detected in the scope chain, a virtual function is cheaper than the
old inheritance test.
* kjs/function.h:
(KJS::ActivationImp::isActivation): Ditto.
Revision Changes Path
1.789 +44 -0 JavaScriptCore/ChangeLog
Index: ChangeLog
===================================================================
RCS file: /cvs/root/JavaScriptCore/ChangeLog,v
retrieving revision 1.788
retrieving revision 1.789
diff -u -r1.788 -r1.789
--- ChangeLog 11 Aug 2005 20:57:04 -0000 1.788
+++ ChangeLog 12 Aug 2005 07:35:59 -0000 1.789
@@ -1,3 +1,47 @@
+2005-08-12 Maciej Stachowiak <mjs at apple.com>
+
+ Reviewed by hyatt.
+
+ - refactor function calls, 3% speedup on JS iBench.
+
+ * kjs/grammar.y:
+ * kjs/nodes.cpp:
+ (Node::throwError): Added new useful variants.
+ (FunctionCallValueNode::evaluate): New node to handle calls on expressions
+ that are strictly values, not references.
+ (FunctionCallValueNode::ref): ditto
+ (FunctionCallValueNode::deref): ditto
+ (FunctionCallResolveNode::evaluate): New node to handle calls on identifier
+ expressions, so that they are looked up in the scope chain.
+ (FunctionCallResolveNode::ref): ditto
+ (FunctionCallResolveNode::deref): ditto
+ (FunctionCallBracketNode::evaluate): New node to handle calls on bracket
+ dereferences, so that the expression before brackets is used as the this
+ object.
+ (FunctionCallBracketNode::ref): ditto
+ (FunctionCallBracketNode::deref): ditto
+ (FunctionCallDotNode::evaluate): New node to handle calls on dot
+ dereferences, so that the expression before the dot is used as the this
+ object.
+ (FunctionCallDotNode::ref): ditto
+ (FunctionCallDotNode::deref): ditto
+ (dotExprNotAnObjectString): helper function to avoid global variable access.
+ (dotExprDoesNotAllowCallsString): ditto
+ * kjs/nodes.h: Declared new classes.
+ * kjs/nodes2string.cpp:
+ (FunctionCallValueNode::streamTo): Added - serializes the appropriate function call
+ (FunctionCallResolveNode::streamTo): ditto
+ (FunctionCallBracketNode::streamTo): ditto
+ (FunctionCallParenBracketNode::streamTo): ditto
+ (FunctionCallDotNode::streamTo): ditto
+ (FunctionCallParenDotNode::streamTo): ditto
+ * kjs/object.h:
+ (KJS::ObjectImp::isActivation): Change how activation objects are
+ detected in the scope chain, a virtual function is cheaper than the
+ old inheritance test.
+ * kjs/function.h:
+ (KJS::ActivationImp::isActivation): Ditto.
+
2005-08-11 Maciej Stachowiak <mjs at apple.com>
- added missing file from earlier checkin
1.31 +1 -0 JavaScriptCore/kjs/function.h
Index: function.h
===================================================================
RCS file: /cvs/root/JavaScriptCore/kjs/function.h,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -r1.30 -r1.31
--- function.h 8 Aug 2005 04:07:28 -0000 1.30
+++ function.h 12 Aug 2005 07:36:00 -0000 1.31
@@ -135,6 +135,7 @@
virtual void mark();
+ bool isActivation() { return true; }
private:
static PropertySlot::GetValueFunc getArgumentsGetter();
static ValueImp *argumentsGetter(ExecState *exec, const Identifier &, const PropertySlot& slot);
1.25 +9 -2 JavaScriptCore/kjs/grammar.y
Index: grammar.y
===================================================================
RCS file: /cvs/root/JavaScriptCore/kjs/grammar.y,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- grammar.y 11 Aug 2005 10:26:53 -0000 1.24
+++ grammar.y 12 Aug 2005 07:36:00 -0000 1.25
@@ -279,8 +279,15 @@
;
CallExpr:
- MemberExpr Arguments { $$ = new FunctionCallNode($1, $2); }
- | CallExpr Arguments { $$ = new FunctionCallNode($1, $2); }
+ ParenthesizedIdent Arguments { $$ = new FunctionCallResolveNode(*$1, $2); }
+ | MemberBracketExpr Arguments { $$ = new FunctionCallBracketNode($1.first, $1.second, $2); }
+ | CallBracketExpr Arguments { $$ = new FunctionCallBracketNode($1.first, $1.second, $2); }
+ | ParenthesizedBracketExpr Arguments { $$ = new FunctionCallParenBracketNode($1.first, $1.second, $2); }
+ | MemberDotExpr Arguments { $$ = new FunctionCallDotNode($1.node, *$1.ident, $2); }
+ | CallDotExpr Arguments { $$ = new FunctionCallDotNode($1.node, *$1.ident, $2); }
+ | ParenthesizedDotExpr Arguments { $$ = new FunctionCallParenDotNode($1.node, *$1.ident, $2); }
+ | MemberExpr Arguments { $$ = new FunctionCallValueNode($1, $2); }
+ | CallExpr Arguments { $$ = new FunctionCallValueNode($1, $2); }
| CallBracketExpr { $$ = new BracketAccessorNode($1.first, $1.second); }
| CallDotExpr { $$ = new DotAccessorNode($1.node, *$1.ident); }
;
1.72 +253 -30 JavaScriptCore/kjs/nodes.cpp
Index: nodes.cpp
===================================================================
RCS file: /cvs/root/JavaScriptCore/kjs/nodes.cpp,v
retrieving revision 1.71
retrieving revision 1.72
diff -u -r1.71 -r1.72
--- nodes.cpp 11 Aug 2005 10:26:53 -0000 1.71
+++ nodes.cpp 12 Aug 2005 07:36:00 -0000 1.72
@@ -171,6 +171,58 @@
return result;
}
+ValueImp *Node::throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Node *e1, Node *e2)
+{
+ char *vStr = strdup(v->toString(exec).ascii());
+ char *e1Str = strdup(e1->toString().ascii());
+ char *e2Str = strdup(e2->toString().ascii());
+
+ int length = strlen(msg) - 6 /* three %s */ + strlen(vStr) + strlen(e1Str) + strlen(e2Str) + 1 /* null terminator */;
+ char *str = new char[length];
+ sprintf(str, msg, vStr, e1Str, e2Str);
+ free(vStr);
+ free(e1Str);
+ free(e2Str);
+
+ ValueImp *result = throwError(exec, e, str);
+ delete [] str;
+
+ return result;
+}
+
+ValueImp *Node::throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Node *expr, Identifier label)
+{
+ char *vStr = strdup(v->toString(exec).ascii());
+ char *exprStr = strdup(expr->toString().ascii());
+ const char *l = label.ascii();
+ int length = strlen(msg) - 6 /* three %s */ + strlen(vStr) + strlen(exprStr) + strlen(l) + 1 /* null terminator */;
+ char *message = new char[length];
+ sprintf(message, msg, vStr, exprStr, l);
+ free(vStr);
+ free(exprStr);
+
+ ValueImp *result = throwError(exec, e, message);
+ delete [] message;
+
+ return result;
+}
+
+ValueImp *Node::throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Identifier label)
+{
+ char *vStr = strdup(v->toString(exec).ascii());
+ const char *l = label.ascii();
+ int length = strlen(msg) - 4 /* two %s */ + strlen(vStr) + strlen(l) + 1 /* null terminator */;
+ char *message = new char[length];
+ sprintf(message, msg, vStr, l);
+ free(vStr);
+
+ ValueImp *result = throwError(exec, e, message);
+ delete [] message;
+
+ return result;
+}
+
+
void Node::setExceptionDetailsIfNeeded(ExecState *exec)
{
if (exec->hadException()) {
@@ -705,38 +757,30 @@
return constr->construct(exec, argList);
}
-// ------------------------------ FunctionCallNode -----------------------------
-
-void FunctionCallNode::ref()
+void FunctionCallValueNode::ref()
{
Node::ref();
- if ( expr )
+ if (expr)
expr->ref();
- if ( args )
+ if (args)
args->ref();
}
-bool FunctionCallNode::deref()
+bool FunctionCallValueNode::deref()
{
- if ( expr && expr->deref() )
+ if (expr && expr->deref())
delete expr;
- if ( args && args->deref() )
+ if (args && args->deref())
delete args;
return Node::deref();
}
// ECMA 11.2.3
-ValueImp *FunctionCallNode::evaluate(ExecState *exec)
+ValueImp *FunctionCallValueNode::evaluate(ExecState *exec)
{
- Reference ref = expr->evaluateReference(exec);
- KJS_CHECKEXCEPTIONVALUE
-
- List argList = args->evaluateList(exec);
+ ValueImp *v = expr->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
- ValueImp *v = ref.getValue(exec);
- KJS_CHECKEXCEPTIONVALUE
-
if (!v->isObject()) {
return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, expr);
}
@@ -747,22 +791,201 @@
return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, expr);
}
- ObjectImp *thisObjImp = 0;
- ValueImp *thisValImp = ref.baseIfMutable();
- if (thisValImp && thisValImp->isObject() && !static_cast<ObjectImp *>(thisValImp)->inherits(&ActivationImp::info))
- thisObjImp = static_cast<ObjectImp *>(thisValImp);
-
- if (!thisObjImp) {
- // ECMA 11.2.3 says that in this situation the this value should be null.
- // However, section 10.2.3 says that in the case where the value provided
- // by the caller is null, the global object should be used. It also says
- // that the section does not apply to interal functions, but for simplicity
- // of implementation we use the global object anyway here. This guarantees
- // that in host objects you always get a valid object for this.
- thisObjImp = exec->dynamicInterpreter()->globalObject();
+ List argList = args->evaluateList(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ ObjectImp *thisObj = exec->dynamicInterpreter()->globalObject();
+
+ return func->call(exec, thisObj, argList);
+}
+
+
+void FunctionCallResolveNode::ref()
+{
+ Node::ref();
+ if (args)
+ args->ref();
+}
+
+bool FunctionCallResolveNode::deref()
+{
+ if (args && args->deref())
+ delete args;
+ return Node::deref();
+}
+
+// ECMA 11.2.3
+ValueImp *FunctionCallResolveNode::evaluate(ExecState *exec)
+{
+ ScopeChain chain = exec->context().imp()->scopeChain();
+
+ assert(!chain.isEmpty());
+
+ PropertySlot slot;
+ ObjectImp *base;
+ do {
+ base = chain.top();
+ if (base->getPropertySlot(exec, ident, slot)) {
+ ValueImp *v = slot.getValue(exec, ident);
+ KJS_CHECKEXCEPTIONVALUE
+
+ if (!v->isObject()) {
+ return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, ident);
+ }
+
+ ObjectImp *func = static_cast<ObjectImp*>(v);
+
+ if (!func->implementsCall()) {
+ return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, ident);
+ }
+
+ List argList = args->evaluateList(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ ObjectImp *thisObj = base;
+ // ECMA 11.2.3 says that in this situation the this value should be null.
+ // However, section 10.2.3 says that in the case where the value provided
+ // by the caller is null, the global object should be used. It also says
+ // that the section does not apply to interal functions, but for simplicity
+ // of implementation we use the global object anyway here. This guarantees
+ // that in host objects you always get a valid object for this.
+ if (thisObj->isActivation())
+ thisObj = exec->dynamicInterpreter()->globalObject();
+
+ return func->call(exec, thisObj, argList);
+ }
+ chain.pop();
+ } while (!chain.isEmpty());
+
+ return undefinedVariableError(exec, ident);
+}
+
+void FunctionCallBracketNode::ref()
+{
+ Node::ref();
+ if (base)
+ base->ref();
+ if (subscript)
+ base->ref();
+ if (args)
+ args->ref();
+}
+
+bool FunctionCallBracketNode::deref()
+{
+ if (base && base->deref())
+ delete base;
+ if (subscript && subscript->deref())
+ delete subscript;
+ if (args && args->deref())
+ delete args;
+ return Node::deref();
+}
+
+// ECMA 11.2.3
+ValueImp *FunctionCallBracketNode::evaluate(ExecState *exec)
+{
+ ValueImp *baseVal = base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ ValueImp *subscriptVal = subscript->evaluate(exec);
+
+ ObjectImp *baseObj = baseVal->toObject(exec);
+ uint32_t i;
+ PropertySlot slot;
+
+ ValueImp *funcVal;
+ if (subscriptVal->getUInt32(i)) {
+ if (baseObj->getPropertySlot(exec, i, slot))
+ funcVal = slot.getValue(exec, i);
+ else
+ funcVal = Undefined();
+ } else {
+ Identifier ident(subscriptVal->toString(exec));
+ if (baseObj->getPropertySlot(exec, ident, slot))
+ funcVal = baseObj->get(exec, ident);
+ else
+ funcVal = Undefined();
+ }
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ if (!funcVal->isObject()) {
+ return throwError(exec, TypeError, "Value %s (result of expression %s[%s]) is not object.", funcVal, base, subscript);
+ }
+
+ ObjectImp *func = static_cast<ObjectImp*>(funcVal);
+
+ if (!func->implementsCall()) {
+ return throwError(exec, TypeError, "Object %s (result of expression %s[%s]) does not allow calls.", funcVal, base, subscript);
}
- ObjectImp *thisObj(thisObjImp);
+ List argList = args->evaluateList(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ ObjectImp *thisObj = baseObj;
+ assert(thisObj);
+ assert(thisObj->isObject());
+ assert(!thisObj->isActivation());
+
+ return func->call(exec, thisObj, argList);
+}
+
+
+void FunctionCallDotNode::ref()
+{
+ Node::ref();
+ if (base)
+ base->ref();
+ if (args)
+ args->ref();
+}
+
+bool FunctionCallDotNode::deref()
+{
+ if (base && base->deref())
+ delete base;
+ if (args && args->deref())
+ delete args;
+ return Node::deref();
+}
+
+static const char *dotExprNotAnObjectString()
+{
+ return "Value %s (result of expression %s.%s) is not object.";
+}
+
+static const char *dotExprDoesNotAllowCallsString()
+{
+ return "Object %s (result of expression %s.%s) does not allow calls.";
+}
+
+// ECMA 11.2.3
+ValueImp *FunctionCallDotNode::evaluate(ExecState *exec)
+{
+ ValueImp *baseVal = base->evaluate(exec);
+
+ ObjectImp *baseObj = baseVal->toObject(exec);
+ PropertySlot slot;
+ ValueImp *funcVal = baseObj->getPropertySlot(exec, ident, slot) ? slot.getValue(exec, ident) : Undefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ if (!funcVal->isObject())
+ return throwError(exec, TypeError, dotExprNotAnObjectString(), funcVal, base, ident);
+
+ ObjectImp *func = static_cast<ObjectImp*>(funcVal);
+
+ if (!func->implementsCall())
+ return throwError(exec, TypeError, dotExprDoesNotAllowCallsString(), funcVal, base, ident);
+
+ List argList = args->evaluateList(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ ObjectImp *thisObj = baseObj;
+ assert(thisObj);
+ assert(thisObj->isObject());
+ assert(!thisObj->isActivation());
+
return func->call(exec, thisObj, argList);
}
1.26 +56 -2 JavaScriptCore/kjs/nodes.h
Index: nodes.h
===================================================================
RCS file: /cvs/root/JavaScriptCore/kjs/nodes.h,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- nodes.h 11 Aug 2005 10:26:53 -0000 1.25
+++ nodes.h 12 Aug 2005 07:36:00 -0000 1.26
@@ -106,6 +106,10 @@
ValueImp *throwError(ExecState *exec, ErrorType e, const char *msg);
ValueImp *throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Node *expr);
ValueImp *throwError(ExecState *exec, ErrorType e, const char *msg, Identifier label);
+ ValueImp *throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Identifier ident);
+ ValueImp *throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Node *e1, Node *e2);
+ ValueImp *throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Node *expr, Identifier ident);
+
void setExceptionDetailsIfNeeded(ExecState *exec);
int line;
UString sourceURL;
@@ -360,9 +364,9 @@
ArgumentsNode *args;
};
- class FunctionCallNode : public Node {
+ class FunctionCallValueNode : public Node {
public:
- FunctionCallNode(Node *e, ArgumentsNode *a) : expr(e), args(a) {}
+ FunctionCallValueNode(Node *e, ArgumentsNode *a) : expr(e), args(a) {}
virtual void ref();
virtual bool deref();
ValueImp *evaluate(ExecState *exec);
@@ -372,6 +376,56 @@
ArgumentsNode *args;
};
+ class FunctionCallResolveNode : public Node {
+ public:
+ FunctionCallResolveNode(const Identifier& i, ArgumentsNode *a) : ident(i), args(a) {}
+ virtual void ref();
+ virtual bool deref();
+ ValueImp *evaluate(ExecState *exec);
+ virtual void streamTo(SourceStream &s) const;
+ private:
+ Identifier ident;
+ ArgumentsNode *args;
+ };
+
+ class FunctionCallBracketNode : public Node {
+ public:
+ FunctionCallBracketNode(Node *b, Node *s, ArgumentsNode *a) : base(b), subscript(s), args(a) {}
+ virtual void ref();
+ virtual bool deref();
+ ValueImp *evaluate(ExecState *exec);
+ virtual void streamTo(SourceStream &s) const;
+ private:
+ Node *base;
+ Node *subscript;
+ ArgumentsNode *args;
+ };
+
+ class FunctionCallParenBracketNode : public Node {
+ public:
+ FunctionCallParenBracketNode(Node *b, Node *s, ArgumentsNode *a) : FunctionCallBracketNode(b, s, a) {}
+ virtual void streamTo(SourceStream &s) const;
+ };
+
+ class FunctionCallDotNode : public Node {
+ public:
+ FunctionCallDotNode(Node *b, const Identifier &i, ArgumentsNode *a) : base(b), ident(i), args(a) {}
+ virtual void ref();
+ virtual bool deref();
+ ValueImp *evaluate(ExecState *exec);
+ virtual void streamTo(SourceStream &s) const;
+ private:
+ Node *base;
+ Identifier ident;
+ ArgumentsNode *args;
+ };
+
+ class FunctionCallParenDotNode : public Node {
+ public:
+ FunctionCallDotNode(Node *b, const Identifier &i, ArgumentsNode *a) : FunctionCallDotNode(b, i, a) {}
+ virtual void streamTo(SourceStream &s) const;
+ };
+
class PostfixNode : public Node {
public:
PostfixNode(Node *e, Operator o) : expr(e), oper(o) {}
1.13 +26 -1 JavaScriptCore/kjs/nodes2string.cpp
Index: nodes2string.cpp
===================================================================
RCS file: /cvs/root/JavaScriptCore/kjs/nodes2string.cpp,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- nodes2string.cpp 11 Aug 2005 10:26:53 -0000 1.12
+++ nodes2string.cpp 12 Aug 2005 07:36:00 -0000 1.13
@@ -195,11 +195,36 @@
s << "new " << expr << args;
}
-void FunctionCallNode::streamTo(SourceStream &s) const
+void FunctionCallValueNode::streamTo(SourceStream &s) const
{
s << expr << args;
}
+void FunctionCallResolveNode::streamTo(SourceStream &s) const
+{
+ s << ident << args;
+}
+
+void FunctionCallBracketNode::streamTo(SourceStream &s) const
+{
+ s << base << "[" << subscript << "]" << args;
+}
+
+void FunctionCallParenBracketNode::streamTo(SourceStream &s) const
+{
+ s << "(" << base << "[" << subscript << "])" << args;
+}
+
+void FunctionCallDotNode::streamTo(SourceStream &s) const
+{
+ s << base << "." << ident << args;
+}
+
+void FunctionCallParenDotNode::streamTo(SourceStream &s) const
+{
+ s << "(" << base << "." << ident << ")" << args;
+}
+
void PostfixNode::streamTo(SourceStream &s) const
{
s << expr;
1.42 +1 -0 JavaScriptCore/kjs/object.h
Index: object.h
===================================================================
RCS file: /cvs/root/JavaScriptCore/kjs/object.h,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- object.h 8 Aug 2005 04:07:29 -0000 1.41
+++ object.h 12 Aug 2005 07:36:00 -0000 1.42
@@ -527,6 +527,7 @@
void saveProperties(SavedProperties &p) const { _prop.save(p); }
void restoreProperties(const SavedProperties &p) { _prop.restore(p); }
+ virtual bool isActivation() { return false; }
protected:
PropertyMap _prop;
private:
More information about the webkit-changes
mailing list