Changeset 10148 in webkit for trunk/JavaScriptCore/kjs/nodes.cpp


Ignore:
Timestamp:
Aug 12, 2005, 12:36:00 AM (20 years ago)
Author:
mjs
Message:

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.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/nodes.cpp

    r10135 r10148  
    172172}
    173173
     174ValueImp *Node::throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Node *e1, Node *e2)
     175{
     176  char *vStr = strdup(v->toString(exec).ascii());
     177  char *e1Str = strdup(e1->toString().ascii());
     178  char *e2Str = strdup(e2->toString().ascii());
     179 
     180  int length =  strlen(msg) - 6 /* three %s */ + strlen(vStr) + strlen(e1Str) + strlen(e2Str) + 1 /* null terminator */;
     181  char *str = new char[length];
     182  sprintf(str, msg, vStr, e1Str, e2Str);
     183  free(vStr);
     184  free(e1Str);
     185  free(e2Str);
     186
     187  ValueImp *result = throwError(exec, e, str);
     188  delete [] str;
     189 
     190  return result;
     191}
     192
     193ValueImp *Node::throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Node *expr, Identifier label)
     194{
     195  char *vStr = strdup(v->toString(exec).ascii());
     196  char *exprStr = strdup(expr->toString().ascii());
     197  const char *l = label.ascii();
     198  int length = strlen(msg) - 6 /* three %s */ + strlen(vStr) + strlen(exprStr) + strlen(l) + 1 /* null terminator */;
     199  char *message = new char[length];
     200  sprintf(message, msg, vStr, exprStr, l);
     201  free(vStr);
     202  free(exprStr);
     203
     204  ValueImp *result = throwError(exec, e, message);
     205  delete [] message;
     206
     207  return result;
     208}
     209
     210ValueImp *Node::throwError(ExecState *exec, ErrorType e, const char *msg, ValueImp *v, Identifier label)
     211{
     212  char *vStr = strdup(v->toString(exec).ascii());
     213  const char *l = label.ascii();
     214  int length = strlen(msg) - 4 /* two %s */ + strlen(vStr) + strlen(l) + 1 /* null terminator */;
     215  char *message = new char[length];
     216  sprintf(message, msg, vStr, l);
     217  free(vStr);
     218
     219  ValueImp *result = throwError(exec, e, message);
     220  delete [] message;
     221
     222  return result;
     223}
     224
     225
    174226void Node::setExceptionDetailsIfNeeded(ExecState *exec)
    175227{
     
    706758}
    707759
    708 // ------------------------------ FunctionCallNode -----------------------------
    709 
    710 void FunctionCallNode::ref()
    711 {
    712   Node::ref();
    713   if ( expr )
     760void FunctionCallValueNode::ref()
     761{
     762  Node::ref();
     763  if (expr)
    714764    expr->ref();
    715   if ( args )
     765  if (args)
    716766    args->ref();
    717767}
    718768
    719 bool FunctionCallNode::deref()
    720 {
    721   if ( expr && expr->deref() )
     769bool FunctionCallValueNode::deref()
     770{
     771  if (expr && expr->deref())
    722772    delete expr;
    723   if ( args && args->deref() )
     773  if (args && args->deref())
    724774    delete args;
    725775  return Node::deref();
     
    727777
    728778// ECMA 11.2.3
    729 ValueImp *FunctionCallNode::evaluate(ExecState *exec)
    730 {
    731   Reference ref = expr->evaluateReference(exec);
    732   KJS_CHECKEXCEPTIONVALUE
    733 
    734   List argList = args->evaluateList(exec);
    735   KJS_CHECKEXCEPTIONVALUE
    736 
    737   ValueImp *v = ref.getValue(exec);
    738   KJS_CHECKEXCEPTIONVALUE
    739  
     779ValueImp *FunctionCallValueNode::evaluate(ExecState *exec)
     780{
     781  ValueImp *v = expr->evaluate(exec);
     782  KJS_CHECKEXCEPTIONVALUE
     783
    740784  if (!v->isObject()) {
    741785    return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, expr);
     
    748792  }
    749793
    750   ObjectImp *thisObjImp = 0;
    751   ValueImp *thisValImp = ref.baseIfMutable();
    752   if (thisValImp && thisValImp->isObject() && !static_cast<ObjectImp *>(thisValImp)->inherits(&ActivationImp::info))
    753     thisObjImp = static_cast<ObjectImp *>(thisValImp);
    754 
    755   if (!thisObjImp) {
    756     // ECMA 11.2.3 says that in this situation the this value should be null.
    757     // However, section 10.2.3 says that in the case where the value provided
    758     // by the caller is null, the global object should be used. It also says
    759     // that the section does not apply to interal functions, but for simplicity
    760     // of implementation we use the global object anyway here. This guarantees
    761     // that in host objects you always get a valid object for this.
    762     thisObjImp = exec->dynamicInterpreter()->globalObject();
    763   }
    764 
    765   ObjectImp *thisObj(thisObjImp);
     794  List argList = args->evaluateList(exec);
     795  KJS_CHECKEXCEPTIONVALUE
     796
     797  ObjectImp *thisObj =  exec->dynamicInterpreter()->globalObject();
     798
     799  return func->call(exec, thisObj, argList);
     800}
     801
     802
     803void FunctionCallResolveNode::ref()
     804{
     805  Node::ref();
     806  if (args)
     807    args->ref();
     808}
     809
     810bool FunctionCallResolveNode::deref()
     811{
     812  if (args && args->deref())
     813    delete args;
     814  return Node::deref();
     815}
     816
     817// ECMA 11.2.3
     818ValueImp *FunctionCallResolveNode::evaluate(ExecState *exec)
     819{
     820  ScopeChain chain = exec->context().imp()->scopeChain();
     821
     822  assert(!chain.isEmpty());
     823
     824  PropertySlot slot;
     825  ObjectImp *base;
     826  do {
     827    base = chain.top();
     828    if (base->getPropertySlot(exec, ident, slot)) {
     829      ValueImp *v = slot.getValue(exec, ident);
     830      KJS_CHECKEXCEPTIONVALUE
     831       
     832      if (!v->isObject()) {
     833        return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, ident);
     834      }
     835     
     836      ObjectImp *func = static_cast<ObjectImp*>(v);
     837     
     838      if (!func->implementsCall()) {
     839        return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, ident);
     840      }
     841     
     842      List argList = args->evaluateList(exec);
     843      KJS_CHECKEXCEPTIONVALUE
     844       
     845      ObjectImp *thisObj = base;
     846      // ECMA 11.2.3 says that in this situation the this value should be null.
     847      // However, section 10.2.3 says that in the case where the value provided
     848      // by the caller is null, the global object should be used. It also says
     849      // that the section does not apply to interal functions, but for simplicity
     850      // of implementation we use the global object anyway here. This guarantees
     851      // that in host objects you always get a valid object for this.
     852      if (thisObj->isActivation())
     853        thisObj = exec->dynamicInterpreter()->globalObject();
     854
     855      return func->call(exec, thisObj, argList);
     856    }
     857    chain.pop();
     858  } while (!chain.isEmpty());
     859 
     860  return undefinedVariableError(exec, ident);
     861}
     862
     863void FunctionCallBracketNode::ref()
     864{
     865  Node::ref();
     866  if (base)
     867    base->ref();
     868  if (subscript)
     869    base->ref();
     870  if (args)
     871    args->ref();
     872}
     873
     874bool FunctionCallBracketNode::deref()
     875{
     876  if (base && base->deref())
     877    delete base;
     878  if (subscript && subscript->deref())
     879    delete subscript;
     880  if (args && args->deref())
     881    delete args;
     882  return Node::deref();
     883}
     884
     885// ECMA 11.2.3
     886ValueImp *FunctionCallBracketNode::evaluate(ExecState *exec)
     887{
     888  ValueImp *baseVal = base->evaluate(exec);
     889  KJS_CHECKEXCEPTIONVALUE
     890
     891  ValueImp *subscriptVal = subscript->evaluate(exec);
     892
     893  ObjectImp *baseObj = baseVal->toObject(exec);
     894  uint32_t i;
     895  PropertySlot slot;
     896
     897  ValueImp *funcVal;
     898  if (subscriptVal->getUInt32(i)) {
     899    if (baseObj->getPropertySlot(exec, i, slot))
     900      funcVal = slot.getValue(exec, i);
     901    else
     902      funcVal = Undefined();
     903  } else {
     904    Identifier ident(subscriptVal->toString(exec));
     905    if (baseObj->getPropertySlot(exec, ident, slot))
     906      funcVal = baseObj->get(exec, ident);
     907    else
     908      funcVal = Undefined();
     909  }
     910
     911  KJS_CHECKEXCEPTIONVALUE
     912 
     913  if (!funcVal->isObject()) {
     914    return throwError(exec, TypeError, "Value %s (result of expression %s[%s]) is not object.", funcVal, base, subscript);
     915  }
     916 
     917  ObjectImp *func = static_cast<ObjectImp*>(funcVal);
     918
     919  if (!func->implementsCall()) {
     920    return throwError(exec, TypeError, "Object %s (result of expression %s[%s]) does not allow calls.", funcVal, base, subscript);
     921  }
     922
     923  List argList = args->evaluateList(exec);
     924  KJS_CHECKEXCEPTIONVALUE
     925
     926  ObjectImp *thisObj = baseObj;
     927  assert(thisObj);
     928  assert(thisObj->isObject());
     929  assert(!thisObj->isActivation());
     930
     931  return func->call(exec, thisObj, argList);
     932}
     933
     934
     935void FunctionCallDotNode::ref()
     936{
     937  Node::ref();
     938  if (base)
     939    base->ref();
     940  if (args)
     941    args->ref();
     942}
     943
     944bool FunctionCallDotNode::deref()
     945{
     946  if (base && base->deref())
     947    delete base;
     948  if (args && args->deref())
     949    delete args;
     950  return Node::deref();
     951}
     952
     953static const char *dotExprNotAnObjectString()
     954{
     955  return "Value %s (result of expression %s.%s) is not object.";
     956}
     957
     958static const char *dotExprDoesNotAllowCallsString()
     959{
     960  return "Object %s (result of expression %s.%s) does not allow calls.";
     961}
     962
     963// ECMA 11.2.3
     964ValueImp *FunctionCallDotNode::evaluate(ExecState *exec)
     965{
     966  ValueImp *baseVal = base->evaluate(exec);
     967
     968  ObjectImp *baseObj = baseVal->toObject(exec);
     969  PropertySlot slot;
     970  ValueImp *funcVal = baseObj->getPropertySlot(exec, ident, slot) ? slot.getValue(exec, ident) : Undefined();
     971  KJS_CHECKEXCEPTIONVALUE
     972
     973  if (!funcVal->isObject())
     974    return throwError(exec, TypeError, dotExprNotAnObjectString(), funcVal, base, ident);
     975 
     976  ObjectImp *func = static_cast<ObjectImp*>(funcVal);
     977
     978  if (!func->implementsCall())
     979    return throwError(exec, TypeError, dotExprDoesNotAllowCallsString(), funcVal, base, ident);
     980
     981  List argList = args->evaluateList(exec);
     982  KJS_CHECKEXCEPTIONVALUE
     983
     984  ObjectImp *thisObj = baseObj;
     985  assert(thisObj);
     986  assert(thisObj->isObject());
     987  assert(!thisObj->isActivation());
     988
    766989  return func->call(exec, thisObj, argList);
    767990}
Note: See TracChangeset for help on using the changeset viewer.