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


Ignore:
Timestamp:
Apr 20, 2005, 3:14:35 AM (20 years ago)
Author:
darin
Message:

Reviewed by Maciej.

  • speedups, total 12% on JavaScript iBench

I ran the benchmark under Shark and followed its advice a lot, mainly.

  • kjs/collector.cpp: (KJS::Collector::allocate): Take out special case for 0; costing speed but unexercised. Use numLiveObjectsAtLastCollect instead of numAllocationsSinceLastCollect so we don't have to bump it each time we call allocate. Put numLiveObjects into a local variable to cut down on global variable accesses. Make "next" cell pointer be a byte offset rather than a pointer so we don't need a special case for NULL. Allow freeList to point to some bogus item when the entire block is full rather than going out of our way to make it point to NULL. (KJS::Collector::markProtectedObjects): Get table size and pointer into locals outside the loop to avoid re-loading them over and over again. (KJS::Collector::collect): Put numLiveObjects into a local variable to cut down on global variable accesses. Make "next" cell pointer be a byte offset as above. Put numLiveObjects into a local variable to cut down on global variable accesses. Set numLiveObjectsAtLastCollect rather than numAllocationsSinceLastCollect. (KJS::Collector::numReferencedObjects): Get table size and pointer into locals outside the loop to avoid re-loading them over and over again. (KJS::Collector::rootObjectClasses): Ditto.
  • kjs/internal.h: Make Value be a friend of NumberImp so it can construct number objects directly, avoiding the conversion from Number to Value.
  • kjs/internal.cpp: (StringImp::toObject): Don't use Object::dynamicCast, because we know the thing is an object and we don't want to do all the extra work; just cast directly.
  • kjs/list.cpp: (KJS::List::List): Construct valueRefCount in a way that avoids the need for a branch -- in the hot case this just meant avoiding checking a variable we just set to false.
  • kjs/lookup.cpp: (keysMatch): Marked this inline.
  • kjs/nodes.cpp: Disabled KJS_BREAKPOINT, to avoid calling hitStatement all the time. (BooleanNode::evaluate): Make a Value directly, rather than making a Boolean which is converted into a Value. (NumberNode::evaluate): Ditto. (StringNode::evaluate): Ditto. (ArrayNode::evaluate): Ditto. (FunctionCallNode::evaluate): Use new inline baseIfMutable to avoid unnecessary getBase function. Also just use a pointer for func, rather than an Object. (PostfixNode::evaluate): Change code so that it doesn't make an excess Number, and so that it passes a "known to be integer" boolean in, often avoiding a conversion from floating point to integer and back. (DeleteNode::evaluate): Make a Value directly. (TypeOfNode::evaluate): Use new inline baseIfMutable and make Value directly. (PrefixNode::evaluate): Change code so that it doesn't make an excess Number, and so that it passes a "known to be integer" boolean in, often avoiding a conversion from floating point to integer and back. (UnaryPlusNode::evaluate): Make a Value directly. (NegateNode::evaluate): Change code so that it doesn't make an excess Number, and so that it passes a "known to be integer" boolean in, often avoiding a conversion from floating point to integer and back. (BitwiseNotNode::evaluate): Make a Value directly. (LogicalNotNode::evaluate): Ditto. (ShiftNode::evaluate): Don't convert to a double before making a Value. (RelationalNode::evaluate): Make a Value directly. (EqualNode::evaluate): Ditto. (BitOperNode::evaluate): Ditto. (AssignNode::evaluate): Make a Value directly. Change code so that it passes a "known to be integer" boolean in, often avoiding a conversion from floating point to integer and back. (VarDeclNode::evaluate): Make a Value directly. (ForNode::execute): Remove unused local variable.
  • kjs/operations.h: (KJS::isNaN): Inlined. (KJS::isInf): Ditto. (KJS::isPosInf): Ditto. (KJS::isNegInf): Ditto.
  • kjs/operations.cpp: Change isNaN, isInf, isPosInf, and isNegInf to be inlines. (KJS::equal): Rewrite to avoid creating values and recursing back into the function. (KJS::relation): Rearranged code so that we don't need explicit isNaN checks. (KJS::add): Changed code to make Value directly, and so that it passes a "known to be integer" boolean in, often avoiding a conversion from floating point to integer and back. (KJS::mult): Ditto.
  • kjs/property_map.cpp: (KJS::PropertyMap::~PropertyMap): Get size and entries pointer outside loop to avoid re-getting them inside the loop. (KJS::PropertyMap::clear): Ditto. Clear value pointer in addition to key, so we can just look at the value pointer in the mark function. (KJS::PropertyMap::get): Get sizeMask and entries pointer outside loop to avoid re-getting them inside the loop. (KJS::PropertyMap::put): Ditto. (KJS::PropertyMap::insert): Ditto. (KJS::PropertyMap::remove): Ditto. (KJS::PropertyMap::mark): Get size and entries pointer outside loop to avoid re-getting them inside the loop. Don't bother checking key for 0, since we already have to check value for 0. (Also had to change clear() to set value to 0.) (KJS::PropertyMap::addEnumerablesToReferenceList): Get size and entries pointer outside loop to avoid re-getting them inside the loop. (KJS::PropertyMap::addSparseArrayPropertiesToReferenceList): Ditto. (KJS::PropertyMap::save): Ditto.
  • other changes
  • kjs/protected_values.h: Remove unneeded class name qualifiers.
  • kjs/reference.h: (KJS::Reference::baseIfMutable): New inline function: replaces isMutable(). (KJS::Reference::Reference): Inlined.
  • kjs/reference.cpp: (KJS::Reference::getValue): Rewrite to not use getBase. (KJS::Reference::putValue): Ditto. (KJS::Reference::deleteValue): Dittol
  • kjs/simple_number.h: (KJS::SimpleNumber::integerFits): Added. For use when the parameter is known to be integral.
  • kjs/string_object.cpp: (StringProtoFuncImp::call): Create the number without first converting to double in various cases that involve integers.
  • kjs/ustring.h: (KJS::UString::attach): Inlined. (KJS::UString::release): Inlined.
  • kjs/ustring.cpp: (KJS::UString::find): Get first character outside the loop instead of re-fetching it each time.
  • kjs/value.cpp: (Value::Value): Added overloads for all the various specific types of values, so you don't have to convert from, say, Number to Value, just to create one. (Number::Number): Added an overload that takes a boolean to indicate the number is already known to be an integer.
  • kjs/value.h: Added more Value constructors, added a version of toNumber that returns a boolean to indicate if the number is known to be an integer (because it was a "simple number"). (KJS::ValueImp::marked): Inlined. (KJS::ValueImp::dispatchType): Inlined. (KJS::ValueImp::dispatchToPrimitive): Inlined. (KJS::ValueImp::dispatchToBoolean): Inlined. (KJS::ValueImp::dispatchToNumber): Inlined. (KJS::ValueImp::dispatchToString): Inlined. (KJS::ValueImp::dispatchToUInt32): Inlined.
File:
1 edited

Legend:

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

    r7239 r9033  
    4848using namespace KJS;
    4949
     50// Disabled for now because it shows up on benchmark (0.5%).
     51#if DEBUGGER_SUPPORT
     52
    5053#define KJS_BREAKPOINT \
    5154  if (!hitStatement(exec)) \
     
    5659      exec->dynamicInterpreter()->imp()->debugger()->imp()->aborted()) \
    5760    return Completion(Normal);
     61
     62#else
     63
     64#define KJS_BREAKPOINT
     65#define KJS_ABORTPOINT
     66
     67#endif
    5868
    5969#define KJS_CHECKEXCEPTION \
     
    210220Value BooleanNode::evaluate(ExecState */*exec*/)
    211221{
    212   return Boolean(value);
     222  return Value(value);
    213223}
    214224
     
    217227Value NumberNode::evaluate(ExecState */*exec*/)
    218228{
    219   return Number(value);
     229  return Value(value);
    220230}
    221231
     
    224234Value StringNode::evaluate(ExecState */*exec*/)
    225235{
    226   return String(value);
     236  return value;
    227237}
    228238
     
    379389
    380390  if (opt)
    381     array.put(exec,lengthPropertyName, Number(elision + length), DontEnum | DontDelete);
     391    array.put(exec,lengthPropertyName, Value(elision + length), DontEnum | DontDelete);
    382392
    383393  return array;
     
    699709  }
    700710
    701   Object func = Object(static_cast<ObjectImp*>(v.imp()));
    702 
    703   if (!func.implementsCall()) {
     711  ObjectImp *func = static_cast<ObjectImp*>(v.imp());
     712
     713  if (!func->implementsCall()) {
    704714    return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, expr);
    705715  }
    706716
    707   Value thisVal;
    708   if (ref.isMutable())
    709     thisVal = ref.getBase(exec);
    710   else
    711     thisVal = Null();
    712 
    713   if (thisVal.type() == ObjectType &&
    714       Object::dynamicCast(thisVal).inherits(&ActivationImp::info))
    715     thisVal = Null();
    716 
    717   if (thisVal.type() != ObjectType) {
     717  ObjectImp *thisObjImp = 0;
     718  ValueImp *thisValImp = ref.baseIfMutable();
     719  if (thisValImp && thisValImp->type() == ObjectType && !static_cast<ObjectImp *>(thisValImp)->inherits(&ActivationImp::info))
     720    thisObjImp = static_cast<ObjectImp *>(thisValImp);
     721
     722  if (!thisObjImp) {
    718723    // ECMA 11.2.3 says that in this situation the this value should be null.
    719724    // However, section 10.2.3 says that in the case where the value provided
     
    722727    // of implementation we use the global object anyway here. This guarantees
    723728    // that in host objects you always get a valid object for this.
    724     // thisVal = Null();
    725     thisVal = exec->dynamicInterpreter()->globalObject();
    726   }
    727 
    728   Object thisObj = Object::dynamicCast(thisVal);
    729   Value result = func.call(exec,thisObj, argList);
    730 
    731   return result;
     729    thisObjImp = exec->dynamicInterpreter()->globalObject().imp();
     730  }
     731
     732  Object thisObj(thisObjImp);
     733  return func->call(exec, thisObj, argList);
    732734}
    733735
     
    754756  KJS_CHECKEXCEPTIONVALUE
    755757  Value v = ref.getValue(exec);
    756   Number n = v.toNumber(exec);
    757 
    758   double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1;
    759   Value n2 = Number(newValue);
    760 
    761   ref.putValue(exec,n2);
    762 
    763   return n;
     758
     759  bool knownToBeInteger;
     760  double n = v.toNumber(exec, knownToBeInteger);
     761
     762  double newValue = (oper == OpPlusPlus) ? n + 1 : n - 1;
     763  ref.putValue(exec, Value(newValue, knownToBeInteger));
     764
     765  return Value(n, knownToBeInteger);
    764766}
    765767
     
    785787  Reference ref = expr->evaluateReference(exec);
    786788  KJS_CHECKEXCEPTIONVALUE
    787   return Boolean(ref.deleteValue(exec));
     789  return Value(ref.deleteValue(exec));
    788790}
    789791
     
    835837  Reference ref = expr->evaluateReference(exec);
    836838  KJS_CHECKEXCEPTIONVALUE
    837   if (ref.isMutable()) {
    838     Value b = ref.getBase(exec);
    839     if (b.type() == NullType)
    840       return String("undefined");
    841   }
     839  ValueImp *b = ref.baseIfMutable();
     840  if (b && b->dispatchType() == NullType)
     841    return Value("undefined");
    842842  Value v = ref.getValue(exec);
    843843  switch (v.type())
     
    866866    }
    867867
    868   return String(s);
     868  return Value(s);
    869869}
    870870
     
    891891  KJS_CHECKEXCEPTIONVALUE
    892892  Value v = ref.getValue(exec);
    893   Number n = v.toNumber(exec);
    894 
    895   double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1;
    896   Value n2 = Number(newValue);
    897 
    898   ref.putValue(exec,n2);
     893
     894  bool knownToBeInteger;
     895  double n = v.toNumber(exec, knownToBeInteger);
     896
     897  double newValue = (oper == OpPlusPlus) ? n + 1 : n - 1;
     898  Value n2(newValue, knownToBeInteger);
     899
     900  ref.putValue(exec, n2);
    899901
    900902  return n2;
     
    923925  KJS_CHECKEXCEPTIONVALUE
    924926
    925   return Number(v.toNumber(exec)); /* TODO: optimize */
     927  return Value(v.toNumber(exec)); /* TODO: optimize */
    926928}
    927929
     
    947949  Value v = expr->evaluate(exec);
    948950  KJS_CHECKEXCEPTIONVALUE
    949   Number n = v.toNumber(exec);
    950 
    951   double d = -n.value();
    952 
    953   return Number(d);
     951
     952  bool knownToBeInteger;
     953  double n = v.toNumber(exec, knownToBeInteger);
     954  return Value(-n, knownToBeInteger && n != 0);
    954955}
    955956
     
    975976  Value v = expr->evaluate(exec);
    976977  KJS_CHECKEXCEPTIONVALUE
    977   int i32 = v.toInt32(exec);
    978 
    979   return Number(~i32);
     978  return Value(~v.toInt32(exec));
    980979}
    981980
     
    10011000  Value v = expr->evaluate(exec);
    10021001  KJS_CHECKEXCEPTIONVALUE
    1003   bool b = v.toBoolean(exec);
    1004 
    1005   return Boolean(!b);
     1002  return Value(!v.toBoolean(exec));
    10061003}
    10071004
     
    10351032  KJS_CHECKEXCEPTIONVALUE
    10361033
    1037   return mult(exec,v1, v2, oper);
     1034  return mult(exec, v1, v2, oper);
    10381035}
    10391036
     
    10671064  KJS_CHECKEXCEPTIONVALUE
    10681065
    1069   return add(exec,v1, v2, oper);
     1066  return add(exec, v1, v2, oper);
    10701067}
    10711068
     
    11001097  i2 &= 0x1f;
    11011098
    1102   double result;
    11031099  switch (oper) {
    11041100  case OpLShift:
    1105     result = v1.toInt32(exec) << i2;
    1106     break;
     1101    return Value(v1.toInt32(exec) << i2);
    11071102  case OpRShift:
    1108     result = v1.toInt32(exec) >> i2;
    1109     break;
     1103    return Value(v1.toInt32(exec) >> i2);
    11101104  case OpURShift:
    1111     result = v1.toUInt32(exec) >> i2;
    1112     break;
     1105    return Value(v1.toUInt32(exec) >> i2);
    11131106  default:
    11141107    assert(!"ShiftNode: unhandled switch case");
    1115     result = 0;
    1116   }
    1117 
    1118   return Number(result);
     1108    return Undefined();
     1109  }
    11191110}
    11201111
     
    11781169      // property. It seems that all object have the property, but not all implement it, so in this
    11791170      // case we return false (consistent with mozilla)
    1180       return Boolean(false);
     1171      return Value(false);
    11811172      //      return throwError(exec, TypeError,
    11821173      //                        "Object does not implement the [[HasInstance]] method." );
     
    11851176  }
    11861177
    1187   return Boolean(b);
     1178  return Value(b);
    11881179}
    11891180
     
    12261217    result = oper == OpStrEq ? eq : !eq;
    12271218  }
    1228   return Boolean(result);
     1219  return Value(result);
    12291220}
    12301221
     
    12661257    result = i1 | i2;
    12671258
    1268   return Number(result);
     1259  return Value(result);
    12691260}
    12701261
     
    13961387      i1 = v1.toInt32(exec);
    13971388      i2 = v2.toInt32(exec);
    1398       v = Number(i1 <<= i2);
     1389      v = Value(i1 << i2);
    13991390      break;
    14001391    case OpRShift:
    14011392      i1 = v1.toInt32(exec);
    14021393      i2 = v2.toInt32(exec);
    1403       v = Number(i1 >>= i2);
     1394      v = Value(i1 >> i2);
    14041395      break;
    14051396    case OpURShift:
    14061397      ui = v1.toUInt32(exec);
    14071398      i2 = v2.toInt32(exec);
    1408       v = Number(ui >>= i2);
     1399      v = Value(ui >> i2);
    14091400      break;
    14101401    case OpAndEq:
    14111402      i1 = v1.toInt32(exec);
    14121403      i2 = v2.toInt32(exec);
    1413       v = Number(i1 &= i2);
     1404      v = Value(i1 & i2);
    14141405      break;
    14151406    case OpXOrEq:
    14161407      i1 = v1.toInt32(exec);
    14171408      i2 = v2.toInt32(exec);
    1418       v = Number(i1 ^= i2);
     1409      v = Value(i1 ^ i2);
    14191410      break;
    14201411    case OpOrEq:
    14211412      i1 = v1.toInt32(exec);
    14221413      i2 = v2.toInt32(exec);
    1423       v = Number(i1 |= i2);
     1414      v = Value(i1 | i2);
    14241415      break;
    14251416    case OpModEq: {
    1426       double d1 = v1.toNumber(exec);
    1427       double d2 = v2.toNumber(exec);
    1428       v = Number(fmod(d1,d2));
     1417      bool d1KnownToBeInteger;
     1418      double d1 = v1.toNumber(exec, d1KnownToBeInteger);
     1419      bool d2KnownToBeInteger;
     1420      double d2 = v2.toNumber(exec, d2KnownToBeInteger);
     1421      v = Value(fmod(d1, d2), d1KnownToBeInteger && d2KnownToBeInteger && d2 != 0);
    14291422    }
    14301423      break;
     
    15961589Value VarDeclNode::evaluate(ExecState *exec)
    15971590{
    1598   Object variable = Object::dynamicCast(exec->context().imp()->variableObject());
     1591  Object variable = exec->context().imp()->variableObject();
    15991592
    16001593  Value val;
     
    16171610  variable.put(exec, ident, val, DontDelete | Internal);
    16181611
    1619   return String(ident.ustring());
     1612  return ident.ustring();
    16201613}
    16211614
     
    19781971Completion ForNode::execute(ExecState *exec)
    19791972{
    1980   Value e, v, cval;
    1981   bool b;
     1973  Value v, cval;
    19821974
    19831975  if (expr1) {
     
    19891981      v = expr2->evaluate(exec);
    19901982      KJS_CHECKEXCEPTION
    1991       b = v.toBoolean(exec);
    1992       if (b == false)
     1983      if (!v.toBoolean(exec))
    19931984        return Completion(Normal, cval);
    19941985    }
Note: See TracChangeset for help on using the changeset viewer.