SVN commit 1134903 by orlovich: - Don't explicitly manage property name array in ExecState, but rather just use a register/GC heap. for ... in creates enough garbage as is, and we don't want to slow down normal code for it. ~0.5% speedup on SunSpider, and less code. Part of the 'let's put ExecState on a diet' metaproject. M +0 -11 ExecState.cpp M +0 -37 ExecState.h M +12 -17 bytecode/codes.def M +15 -0 bytecode/machine.cpp.in M +9 -14 nodes2bytecode.cpp --- trunk/KDE/kdelibs/kjs/ExecState.cpp #1134902:1134903 @@ -116,8 +116,6 @@ ExecState::~ExecState() { - for (size_t c = 0; c < m_activePropertyNameArrays.size(); ++c) - delete m_activePropertyNameArrays[c].array; m_interpreter->setExecState(m_savedExec); } @@ -208,11 +206,6 @@ m_deferredCompletions.removeLast(); m_exceptionHandlers.removeLast(); continue; // get the next handler - case RemovePNA: - delete m_activePropertyNameArrays.last().array; - m_activePropertyNameArrays.removeLast(); - m_exceptionHandlers.removeLast(); - continue; // get the next handler case Silent: // Exception blocked by tracing code. nothing to do. return; @@ -236,10 +229,6 @@ case RemoveDeferred: m_deferredCompletions.removeLast(); break; - case RemovePNA: - delete m_activePropertyNameArrays.last().array; - m_activePropertyNameArrays.removeLast(); - break; case Silent: ASSERT(0); // Should not happen in the middle of the code. break; --- trunk/KDE/kdelibs/kjs/ExecState.h #1134902:1134903 @@ -69,44 +69,13 @@ */ Interpreter* lexicalInterpreter() const; - /** - These methods are used to keep track of PropertyNameArrays for ... in loops are going through - */ - void pushPropertyNameArray() { - pushExceptionHandler(RemovePNA); - - PropertyNameArrayInfo inf; - inf.array = new PropertyNameArray; - inf.pos = 0; - m_activePropertyNameArrays.append(inf); - } - - void popPropertyNameArray() { - ASSERT(m_exceptionHandlers.last().type == RemovePNA); - popExceptionHandler(); - - delete m_activePropertyNameArrays.last().array; - m_activePropertyNameArrays.removeLast(); - } - - PropertyNameArray& activePropertyNameArray() { - return *m_activePropertyNameArrays.last().array; - } - - int& activePropertyNameIter() { - return m_activePropertyNameArrays.last().pos; - } - - - /** * This describes how an exception should be handled */ enum HandlerType { JumpToCatch, ///< jump to the specified address PopScope, ///< remove a scope chain entry, and run the next handler RemoveDeferred, ///< remove any deferred exception object, and run the next entry - RemovePNA, ///< remove + delete top PropertyNameArray Silent ///< just update the exception object. For debugger-type use only }; @@ -304,12 +273,6 @@ WTF::Vector m_exceptionHandlers; WTF::Vector m_deferredCompletions; - struct PropertyNameArrayInfo { - PropertyNameArray* array; - int pos; - }; - WTF::Vector m_activePropertyNameArrays; - CodeType m_codeType; }; --- trunk/KDE/kdelibs/kjs/bytecode/codes.def #1134902:1134903 @@ -264,39 +264,34 @@ tile (value, addr) as executeIfNotJump; } -// Fetches the propertly list, if any, and sets up the iterator stack in execState appropriately -// Returns the object to operate on +// Fetches the propertly list, if any, and sets up the iterator state in given +// register. Returns the value to iterator operation BeginForIn[endsBB] { - impl value (value e) [[ - exec->pushPropertyNameArray(); + impl value (value e, reg stateReg) [[ + ForInState* st = new ForInState(); + localStore[stateReg].val.valueVal = st; if (!e->isUndefinedOrNull()) { JSObject* v = e->toObject(exec); - // The above might raise an exception, which would cleanup the array! + // The above might raise an exception.. if (pc != localPC) continue; - v->getPropertyNames(exec, exec->activePropertyNameArray()); + v->getPropertyNames(exec, *st->array); $$ = v; } else { - // The array is empty here, so this will never be accessed + // empty array, so this doesn't matter. $$ = jsUndefined(); } ]] } -// Cleans up the property list -operation EndForIn { - impl void() [[ - exec->popPropertyNameArray(); - ]] -} - operation NextForInEntry { - impl value(value e, addr jumpToIfDone) [[ - PropertyNameArray& pa = exec->activePropertyNameArray(); + impl value(value[noimm] e, value[noimm] ctx, addr jumpToIfDone) [[ + ForInState* st = static_cast(ctx); + PropertyNameArray& pa = *st->array; // Invariant: pos = next entry to consider. - int& pos = exec->activePropertyNameIter(); + int& pos = st->pos; $$ = jsUndefined(); while (pos < pa.size()) { --- trunk/KDE/kdelibs/kjs/bytecode/machine.cpp.in #1134902:1134903 @@ -203,6 +203,21 @@ dbg->exitContext(exec, body->sourceId(), body->lastLine(), fn); } +class ForInState: public JSObject { +public: + PropertyNameArray* array; + int pos; + + ForInState() { + array = new PropertyNameArray; + pos = 0; + } + + ~ForInState() { + delete array; + } +}; + struct DepthCleanup { ~DepthCleanup() { --depth; } --- trunk/KDE/kdelibs/kjs/nodes2bytecode.cpp #1134902:1134903 @@ -1268,17 +1268,18 @@ OpValue val = expr->generateEvalCode(comp); OpValue obj; // version of val after toObject, returned by BeginForIn. + OpValue stateVal, stateReg; + comp->requestTemporary(OpType_value, &stateVal, &stateReg); + // Fetch the property name array.. - CodeGen::emitOp(comp, Op_BeginForIn, &obj, &val); + CodeGen::emitOp(comp, Op_BeginForIn, &obj, &val, &stateReg); - // ... as the array is store on an iterator stack, this introduces a cleanup entry. - comp->pushNest(CompileState::OtherCleanup, this); + comp->enterLoop(this); - comp->enterLoop(this); // must do this here, since continue shouldn't pop our iterator! - // We put the test first here, since the test and the fetch are combined. OpValue sym; - Addr fetchNext = CodeGen::emitOp(comp, Op_NextForInEntry, &sym, &obj, OpValue::dummyAddr()); + Addr fetchNext = CodeGen::emitOp(comp, Op_NextForInEntry, &sym, &obj, + &stateVal, OpValue::dummyAddr()); // Write to the variable assert (lexpr->isLocation()); @@ -1298,16 +1299,10 @@ OpValue backVal = OpValue::immAddr(fetchNext); CodeGen::emitOp(comp, Op_Jump, 0, &backVal); - // The end address is here (#2 since return val..) - CodeGen::patchJumpToNext(comp, fetchNext, 2); + // The end address is here (3 argument + return val) + CodeGen::patchJumpToNext(comp, fetchNext, 3); - // The looping action ends here.. We need to do it before the EndForIn instruction so we always cleanup - // right on breaks. comp->exitLoop(this); - comp->popNest(); // Remove the cleanup entry.. Note that the breaks go to before here.. - - // Cleanup - CodeGen::emitOp(comp, Op_EndForIn); } // Helper for continue/break -- emits stack cleanup call if needed,