- KJS::Node and KJS::StatementNode are bigger than they need to be
http://bugzilla.opendarwin.org/show_bug.cgi?id=7775
The memory usage of Node was reduced by 2 machine words per node:
- sourceURL was removed and only kept on FunctionBodyNode. The
source URL can only be distinct per function or top-level program node,
and you always have one.
- refcount was removed and kept in a separate hashtable when
greater than 1. newNodes set represents floating nodes with
refcount of 0. This helps because almost all nodes have a refcount of 1
for almost all of their lifetime.
* bindings/runtime_method.cpp:
(RuntimeMethod::RuntimeMethod): Pass null body, added FIXME.
* kjs/Parser.cpp:
(KJS::clearNewNodes): New nodes are tracked in nodes.cpp now, but still clear
them at the appropriate time.
* kjs/context.h:
(KJS::ContextImp::currentBody): added; used to retrieve source URL and sid
for current code.
(KJS::ContextImp::pushIteration): moved here from LabelStack
(KJS::ContextImp::popIteration): ditto
(KJS::ContextImp::inIteration): ditto
(KJS::ContextImp::pushSwitch): ditto
(KJS::ContextImp::popSwitch): ditto
(KJS::ContextImp::inSwitch): ditto
* kjs/function.cpp:
(KJS::FunctionImp::FunctionImp): Add FunctionBodyNode* parameter.
(KJS::FunctionImp::callAsFunction): Pass body to ContextImp.
(KJS::FunctionImp::argumentsGetter): _context renamed to m_context.
(KJS::DeclaredFunctionImp::DeclaredFunctionImp): Pass body to superclass
constructor.
(KJS::GlobalFuncImp::callAsFunction): Pass progNode as body for ContextImp in
eval.
* kjs/function.h: Move body field from DeclaredFunctionImp to
FunctionImp.
* kjs/grammar.y: Change DBG; statements no longer have a sourceid.
* kjs/internal.cpp:
(KJS::ContextImp::ContextImp): Initialize new m_currentBody, m_iterationDepth
and m_switchDepth data members. New FunctionBodyNode* parameter - the
function body provides source URL and SourceId.
(KJS::InterpreterImp::mark): Use exception() function, not _exception directly.
(KJS::InterpreterImp::evaluate): Pass progNode to ContextImp constructor
to use as the body.
* kjs/internal.h:
(KJS::LabelStack::LabelStack): Remove iteration depth and switch depth;
statement label stacks don't need these and it bloats their size. Put them
in the ContextImp instead.
* kjs/interpreter.cpp:
(KJS::ExecState::lexicalInterpreter): Renamed _context to m_context.
* kjs/interpreter.h:
(KJS::ExecState::dynamicInterpreter): Renamed _context to m_context.
(KJS::ExecState::context): ditto
(KJS::ExecState::setException): Renamed _exception to m_exception
(KJS::ExecState::clearException): ditto
(KJS::ExecState::exception): ditto
(KJS::ExecState::hadException): ditto
(KJS::ExecState::ExecState): ditto both above renames
* kjs/nodes.cpp:
(Node::Node): Removed initialization of line, source URL and refcount. Add to
local newNodes set instead of involving parser.
(Node::ref): Instead of managing refcount directly, story refcount over 1 in a
HashCountedSet, and keep a separate HashSet of "floating" nodes with refcount
0.
(Node::deref): ditto
(Node::refcount): ditto
(Node::clearNewNodes): Destroy anything left in the new nodes set.
(currentSourceId): Inline helper to get sourceId from function body via context.
(currentSourceURL): ditto for sourceURL.
(Node::createErrorCompletion): use new helper
(Node::throwError): ditto
(Node::setExceptionDetailsIfNeeded): ditto
(StatementNode::StatementNode): remove initialization of l0 and sid, rename
l1 to m_lastLine.
(StatementNode::setLoc): Set own m_lastLine and Node's m_line.
(StatementNode::hitStatement): Get sid, first line, last line in the proper new ways.
(StatListNode::StatListNode): updated for setLoc changes
(BlockNode::BlockNode): ditto
(DoWhileNode::execute): excpect iteraton counts on ContextImp, not LabelStack
(WhileNode::execute): ditto
(ForNode::execute): ditto
(ForInNode::execute): ditto
(ContinueNode::execute): excpect inIteration on ContextImp, not LabelStack
(BreakNode::execute): excpect inIteration and inSwitch on ContextImp, not LabelStack
(SwitchNode::execute): expect switch counts on ContextImp, not LabelStack
(FunctionBodyNode::FunctionBodyNode): update for new setLoc
(FunctionBodyNode::processFuncDecl): reindent
(SourceElementsNode::SourceElementsNode): update for new setLoc
* kjs/nodes.h:
(KJS::Node::lineNo): Renamed _line to m_line
(KJS::StatementNode::firstLine): Use lineNo()
(KJS::StatementNode::lastLine): Renamed l1 to m_lastLine
(KJS::FunctionBodyNode::sourceId): added
(KJS::FunctionBodyNode::sourceURL): added
* kjs/testkjs.cpp:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@13304
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2006-03-13 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Anders.
+
+ - KJS::Node and KJS::StatementNode are bigger than they need to be
+ http://bugzilla.opendarwin.org/show_bug.cgi?id=7775
+
+ The memory usage of Node was reduced by 2 machine words per node:
+
+ - sourceURL was removed and only kept on FunctionBodyNode. The
+ source URL can only be distinct per function or top-level program node,
+ and you always have one.
+
+ - refcount was removed and kept in a separate hashtable when
+ greater than 1. newNodes set represents floating nodes with
+ refcount of 0. This helps because almost all nodes have a refcount of 1
+ for almost all of their lifetime.
+
+ * bindings/runtime_method.cpp:
+ (RuntimeMethod::RuntimeMethod): Pass null body, added FIXME.
+ * kjs/Parser.cpp:
+ (KJS::clearNewNodes): New nodes are tracked in nodes.cpp now, but still clear
+ them at the appropriate time.
+ * kjs/context.h:
+ (KJS::ContextImp::currentBody): added; used to retrieve source URL and sid
+ for current code.
+ (KJS::ContextImp::pushIteration): moved here from LabelStack
+ (KJS::ContextImp::popIteration): ditto
+ (KJS::ContextImp::inIteration): ditto
+ (KJS::ContextImp::pushSwitch): ditto
+ (KJS::ContextImp::popSwitch): ditto
+ (KJS::ContextImp::inSwitch): ditto
+ * kjs/function.cpp:
+ (KJS::FunctionImp::FunctionImp): Add FunctionBodyNode* parameter.
+ (KJS::FunctionImp::callAsFunction): Pass body to ContextImp.
+ (KJS::FunctionImp::argumentsGetter): _context renamed to m_context.
+ (KJS::DeclaredFunctionImp::DeclaredFunctionImp): Pass body to superclass
+ constructor.
+ (KJS::GlobalFuncImp::callAsFunction): Pass progNode as body for ContextImp in
+ eval.
+ * kjs/function.h: Move body field from DeclaredFunctionImp to
+ FunctionImp.
+ * kjs/grammar.y: Change DBG; statements no longer have a sourceid.
+ * kjs/internal.cpp:
+ (KJS::ContextImp::ContextImp): Initialize new m_currentBody, m_iterationDepth
+ and m_switchDepth data members. New FunctionBodyNode* parameter - the
+ function body provides source URL and SourceId.
+ (KJS::InterpreterImp::mark): Use exception() function, not _exception directly.
+ (KJS::InterpreterImp::evaluate): Pass progNode to ContextImp constructor
+ to use as the body.
+ * kjs/internal.h:
+ (KJS::LabelStack::LabelStack): Remove iteration depth and switch depth;
+ statement label stacks don't need these and it bloats their size. Put them
+ in the ContextImp instead.
+ * kjs/interpreter.cpp:
+ (KJS::ExecState::lexicalInterpreter): Renamed _context to m_context.
+ * kjs/interpreter.h:
+ (KJS::ExecState::dynamicInterpreter): Renamed _context to m_context.
+ (KJS::ExecState::context): ditto
+ (KJS::ExecState::setException): Renamed _exception to m_exception
+ (KJS::ExecState::clearException): ditto
+ (KJS::ExecState::exception): ditto
+ (KJS::ExecState::hadException): ditto
+ (KJS::ExecState::ExecState): ditto both above renames
+ * kjs/nodes.cpp:
+ (Node::Node): Removed initialization of line, source URL and refcount. Add to
+ local newNodes set instead of involving parser.
+ (Node::ref): Instead of managing refcount directly, story refcount over 1 in a
+ HashCountedSet, and keep a separate HashSet of "floating" nodes with refcount
+ 0.
+ (Node::deref): ditto
+ (Node::refcount): ditto
+ (Node::clearNewNodes): Destroy anything left in the new nodes set.
+ (currentSourceId): Inline helper to get sourceId from function body via context.
+ (currentSourceURL): ditto for sourceURL.
+ (Node::createErrorCompletion): use new helper
+ (Node::throwError): ditto
+ (Node::setExceptionDetailsIfNeeded): ditto
+ (StatementNode::StatementNode): remove initialization of l0 and sid, rename
+ l1 to m_lastLine.
+ (StatementNode::setLoc): Set own m_lastLine and Node's m_line.
+ (StatementNode::hitStatement): Get sid, first line, last line in the proper new ways.
+ (StatListNode::StatListNode): updated for setLoc changes
+ (BlockNode::BlockNode): ditto
+ (DoWhileNode::execute): excpect iteraton counts on ContextImp, not LabelStack
+ (WhileNode::execute): ditto
+ (ForNode::execute): ditto
+ (ForInNode::execute): ditto
+ (ContinueNode::execute): excpect inIteration on ContextImp, not LabelStack
+ (BreakNode::execute): excpect inIteration and inSwitch on ContextImp, not LabelStack
+ (SwitchNode::execute): expect switch counts on ContextImp, not LabelStack
+ (FunctionBodyNode::FunctionBodyNode): update for new setLoc
+ (FunctionBodyNode::processFuncDecl): reindent
+ (SourceElementsNode::SourceElementsNode): update for new setLoc
+ * kjs/nodes.h:
+ (KJS::Node::lineNo): Renamed _line to m_line
+ (KJS::StatementNode::firstLine): Use lineNo()
+ (KJS::StatementNode::lastLine): Renamed l1 to m_lastLine
+ (KJS::FunctionBodyNode::sourceId): added
+ (KJS::FunctionBodyNode::sourceURL): added
+ * kjs/testkjs.cpp:
+
2006-03-14 Geoffrey Garen <ggaren@apple.com>
- Fixed <rdar://problem/4478239> string sort puts "closed" before
using namespace KJS::Bindings;
using namespace KJS;
-RuntimeMethod::RuntimeMethod(ExecState *exec, const Identifier &ident, Bindings::MethodList &m) : FunctionImp (exec, ident)
+// FIXME: this should probably use InternalFunctionImp, not FunctionImp
+RuntimeMethod::RuntimeMethod(ExecState *exec, const Identifier &ident, Bindings::MethodList &m)
+ : FunctionImp (exec, ident, 0)
{
_methodList = m;
}
int Parser::sid = 0;
static RefPtr<ProgramNode>* progNode;
-static Vector<RefPtr<Node> >* newNodes;
static HashSet<Node*>* nodeCycles;
-void Parser::saveNewNode(Node *node)
-{
- if (!newNodes)
- newNodes = new Vector<RefPtr<Node> >;
- newNodes->append(node);
-}
-
void Parser::noteNodeCycle(Node *node)
{
if (!nodeCycles)
delete nodeCycles;
nodeCycles = 0;
}
-
- delete newNodes;
- newNodes = 0;
+ Node::clearNewNodes();
}
PassRefPtr<ProgramNode> Parser::parse(const UString& sourceURL, int startingLineNumber,
*/
class ContextImp {
public:
- ContextImp(JSObject *glob, InterpreterImp *, JSObject *thisV, CodeType type = GlobalCode,
- ContextImp *callingContext = 0, FunctionImp *functiion = 0, const List *args = 0);
+ ContextImp(JSObject* global, InterpreterImp*, JSObject* thisV, FunctionBodyNode* currentBody,
+ CodeType type = GlobalCode, ContextImp* callingContext = 0, FunctionImp* function = 0, const List* args = 0);
~ContextImp();
+ FunctionBodyNode* currentBody() { return m_currentBody; }
+
const ScopeChain &scopeChain() const { return scope; }
CodeType codeType() { return m_codeType; }
JSObject *variableObject() const { return variable; }
void pushScope(JSObject *s) { scope.push(s); }
void popScope() { scope.pop(); }
LabelStack *seenLabels() { return &ls; }
+
+
+ void pushIteration() { m_iterationDepth++; }
+ void popIteration() { m_iterationDepth--; }
+ bool inIteration() const { return (m_iterationDepth > 0); }
+ void pushSwitch() { m_switchDepth++; }
+ void popSwitch() { m_switchDepth--; }
+ bool inSwitch() const { return (m_switchDepth > 0); }
+
void mark();
private:
InterpreterImp *_interpreter;
ContextImp *_callingContext;
+ FunctionBodyNode* m_currentBody;
+
FunctionImp *_function;
const List *_arguments;
// because ContextImp is always allocated on the stack,
JSObject *thisVal;
LabelStack ls;
+ int m_iterationDepth;
+ int m_switchDepth;
CodeType m_codeType;
};
OwnPtr<Parameter> next;
};
-FunctionImp::FunctionImp(ExecState *exec, const Identifier &n)
+FunctionImp::FunctionImp(ExecState *exec, const Identifier &n, FunctionBodyNode* b)
: InternalFunctionImp(static_cast<FunctionPrototype*>
(exec->lexicalInterpreter()->builtinFunctionPrototype()), n)
+ , body(b)
{
}
{
}
-JSValue *FunctionImp::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
+JSValue *FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
JSObject *globalObj = exec->dynamicInterpreter()->globalObject();
// enter a new execution context
- ContextImp ctx(globalObj, exec->dynamicInterpreter()->imp(), thisObj, codeType(),
- exec->context().imp(), this, &args);
+ ContextImp ctx(globalObj, exec->dynamicInterpreter()->imp(), thisObj, body.get(),
+ codeType(), exec->context().imp(), this, &args);
ExecState newExec(exec->dynamicInterpreter(), &ctx);
newExec.setException(exec->exception()); // could be null
JSValue *FunctionImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
{
FunctionImp *thisObj = static_cast<FunctionImp *>(slot.slotBase());
- ContextImp *context = exec->_context;
+ ContextImp *context = exec->m_context;
while (context) {
if (context->function() == thisObj) {
return static_cast<ActivationImp *>(context->activationObject())->get(exec, propertyName);
DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const Identifier &n,
FunctionBodyNode *b, const ScopeChain &sc)
- : FunctionImp(exec,n), body(b)
+ : FunctionImp(exec, n, b)
{
setScope(sc);
}
ContextImp ctx(exec->dynamicInterpreter()->globalObject(),
exec->dynamicInterpreter()->imp(),
thisVal,
+ progNode.get(),
EvalCode,
exec->context().imp());
class FunctionImp : public InternalFunctionImp {
friend class ActivationImp;
public:
- FunctionImp(ExecState *exec, const Identifier &n = Identifier::null());
+ FunctionImp(ExecState* exec, const Identifier& n, FunctionBodyNode* b);
virtual ~FunctionImp();
virtual bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot&);
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
+
+ RefPtr<FunctionBodyNode> body;
+
protected:
OwnPtr<Parameter> param;
virtual Completion execute(ExecState *exec);
CodeType codeType() const { return FunctionCode; }
- RefPtr<FunctionBodyNode> body;
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
+
private:
virtual void processVarDecls(ExecState *exec);
};
static bool allowAutomaticSemicolon();
#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon()) YYABORT; } while (0)
-#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line, Parser::sid)
+#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line)
using namespace KJS;
// ------------------------------ ContextImp -----------------------------------
// ECMA 10.2
-ContextImp::ContextImp(JSObject *glob, InterpreterImp *interpreter, JSObject *thisV, CodeType type,
- ContextImp *callingCon, FunctionImp *func, const List *args)
- : _interpreter(interpreter), _function(func), _arguments(args)
+ContextImp::ContextImp(JSObject *glob, InterpreterImp *interpreter, JSObject *thisV, FunctionBodyNode* currentBody,
+
+ CodeType type, ContextImp *callingCon, FunctionImp *func, const List *args)
+ : _interpreter(interpreter)
+ , m_currentBody(currentBody)
+ , _function(func)
+ , _arguments(args)
+ , m_iterationDepth(0)
+ , m_switchDepth(0)
{
m_codeType = type;
_callingContext = callingCon;
_context->mark();
if (global)
global->mark();
- if (globExec._exception)
- globExec._exception->mark();
+ if (globExec.exception())
+ globExec.exception()->mark();
}
bool InterpreterImp::checkSyntax(const UString &code)
res = Completion(Throw, globExec.exception());
else {
// execute the code
- ContextImp ctx(globalObj, this, thisObj);
+ ContextImp ctx(globalObj, this, thisObj, progNode.get());
ExecState newExec(m_interpreter, &ctx);
progNode->processVarDecls(&newExec);
res = progNode->execute(&newExec);
*/
class LabelStack : Noncopyable {
public:
- LabelStack(): tos(0), iterationDepth(0), switchDepth(0) {}
+ LabelStack()
+ : tos(0)
+ {
+ }
~LabelStack();
/**
*/
void pop();
- void pushIteration() { iterationDepth++; }
- void popIteration() { iterationDepth--; }
- bool inIteration() const { return (iterationDepth > 0); }
-
- void pushSwitch() { switchDepth++; }
- void popSwitch() { switchDepth--; }
- bool inSwitch() const { return (switchDepth > 0); }
-
private:
struct StackElem {
Identifier id;
};
StackElem *tos;
- int iterationDepth;
- int switchDepth;
};
Interpreter *ExecState::lexicalInterpreter() const
{
- if (!_context) {
+ if (!m_context) {
return dynamicInterpreter();
}
- InterpreterImp *result = InterpreterImp::interpreterWithGlobalObject(_context->scopeChain().bottom());
+ InterpreterImp *result = InterpreterImp::interpreterWithGlobalObject(m_context->scopeChain().bottom());
if (!result) {
return dynamicInterpreter();
*
* @return The interpreter executing the script
*/
- Interpreter *dynamicInterpreter() const { return _interpreter; }
+ Interpreter *dynamicInterpreter() const { return m_interpreter; }
// for compatibility
Interpreter *interpreter() const { return dynamicInterpreter(); }
*
* @return The current execution state context
*/
- Context context() const { return _context; }
+ Context context() const { return m_context; }
- void setException(JSValue* e) { _exception = e; }
- void clearException() { _exception = 0; }
- JSValue* exception() const { return _exception; }
- bool hadException() const { return _exception; }
+ void setException(JSValue* e) { m_exception = e; }
+ void clearException() { m_exception = 0; }
+ JSValue* exception() const { return m_exception; }
+ bool hadException() const { return m_exception; }
private:
ExecState(Interpreter* interp, ContextImp* con)
- : _interpreter(interp), _context(con), _exception(0) { }
- Interpreter* _interpreter;
- ContextImp* _context;
- JSValue* _exception;
+ : m_interpreter(interp)
+ , m_context(con)
+ , m_exception(0)
+ {
+ }
+ Interpreter* m_interpreter;
+ ContextImp* m_context;
+ JSValue* m_exception;
};
} // namespace
#include "operations.h"
#include "ustring.h"
#include "reference_list.h"
+#include <kxmlcore/HashSet.h>
+#include <kxmlcore/HashCountedSet.h>
using namespace KJS;
static NodeCounter nodeImplCounter;
#endif NDEBUG
+static HashSet<Node*>* newNodes;
+static HashCountedSet<Node*>* nodeExtraRefCounts;
Node::Node()
{
#ifndef NDEBUG
++NodeCounter::count;
#endif
- line = Lexer::curr()->lineNo();
- sourceURL = Lexer::curr()->sourceURL();
- m_refcount = 0;
- Parser::saveNewNode(this);
+ m_line = Lexer::curr()->lineNo();
+ if (!newNodes)
+ newNodes = new HashSet<Node*>;
+ newNodes->add(this);
}
Node::~Node()
#endif
}
+void Node::ref()
+{
+ // bumping from 0 to 1 is just removing from the new nodes set
+ if (newNodes) {
+ HashSet<Node*>::iterator it = newNodes->find(this);
+ if (it != newNodes->end()) {
+ newNodes->remove(it);
+ return;
+ }
+ }
+
+ if (!nodeExtraRefCounts)
+ nodeExtraRefCounts = new HashCountedSet<Node*>;
+ nodeExtraRefCounts->add(this);
+}
+
+void Node::deref()
+{
+ HashCountedSet<Node*>::iterator it = nodeExtraRefCounts->find(this);
+ if (it == nodeExtraRefCounts->end())
+ delete this;
+ else
+ nodeExtraRefCounts->remove(it);
+}
+
+unsigned int Node::refcount()
+{
+ if (newNodes && newNodes->contains(this))
+ return 0;
+
+ if (!nodeExtraRefCounts)
+ return 1;
+
+ return 1 + nodeExtraRefCounts->count(this);
+}
+
+void Node::clearNewNodes()
+{
+ if (newNodes) {
+ deleteAllValues(*newNodes);
+ delete newNodes;
+ newNodes = 0;
+ }
+}
+
static void substitute(UString &string, const UString &substring)
{
int position = string.find("%s");
string = string.substr(0, position) + substring + string.substr(position + 2);
}
-Completion Node::createErrorCompletion(ExecState *exec, ErrorType e, const char *msg)
+static inline int currentSourceId(ExecState* exec)
{
- return Completion(Throw, Error::create(exec, e, msg, lineNo(), sourceId(), &sourceURL));
+ return exec->context().imp()->currentBody()->sourceId();
+}
+
+static inline const UString& currentSourceURL(ExecState* exec)
+{
+ return exec->context().imp()->currentBody()->sourceURL();
+}
+
+Completion Node::createErrorCompletion(ExecState* exec, ErrorType e, const char *msg)
+{
+ return Completion(Throw, Error::create(exec, e, msg, lineNo(), currentSourceId(exec), ¤tSourceURL(exec)));
}
Completion Node::createErrorCompletion(ExecState *exec, ErrorType e, const char *msg, const Identifier &ident)
{
UString message = msg;
substitute(message, ident.ustring());
- return Completion(Throw, Error::create(exec, e, message, lineNo(), sourceId(), &sourceURL));
+ return Completion(Throw, Error::create(exec, e, message, lineNo(), currentSourceId(exec), ¤tSourceURL(exec)));
}
-JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg)
+JSValue *Node::throwError(ExecState* exec, ErrorType e, const char *msg)
{
- return KJS::throwError(exec, e, msg, lineNo(), sourceId(), &sourceURL);
+ return KJS::throwError(exec, e, msg, lineNo(), currentSourceId(exec), ¤tSourceURL(exec));
}
JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *expr)
UString message = msg;
substitute(message, v->toString(exec));
substitute(message, expr->toString());
- return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), ¤tSourceURL(exec));
}
{
UString message = msg;
substitute(message, label.ustring());
- return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), ¤tSourceURL(exec));
}
JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *e1, Node *e2)
substitute(message, v->toString(exec));
substitute(message, e1->toString());
substitute(message, e2->toString());
- return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), ¤tSourceURL(exec));
}
JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *expr, const Identifier &label)
substitute(message, v->toString(exec));
substitute(message, expr->toString());
substitute(message, label.ustring());
- return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), ¤tSourceURL(exec));
}
JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, const Identifier &label)
UString message = msg;
substitute(message, v->toString(exec));
substitute(message, label.ustring());
- return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), ¤tSourceURL(exec));
}
JSValue *Node::throwUndefinedVariableError(ExecState *exec, const Identifier &ident)
if (exceptionValue->isObject()) {
JSObject *exception = static_cast<JSObject *>(exceptionValue);
if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
- exception->put(exec, "line", jsNumber(line));
- exception->put(exec, "sourceURL", jsString(sourceURL));
+ exception->put(exec, "line", jsNumber(m_line));
+ exception->put(exec, "sourceURL", jsString(currentSourceURL(exec)));
}
}
}
// ------------------------------ StatementNode --------------------------------
-StatementNode::StatementNode() : l0(-1), l1(-1), sid(-1)
+StatementNode::StatementNode()
+ : m_lastLine(-1)
{
+ m_line = -1;
}
-void StatementNode::setLoc(int line0, int line1, int sourceId)
+void StatementNode::setLoc(int firstLine, int lastLine)
{
- l0 = line0;
- l1 = line1;
- sid = sourceId;
+ m_line = firstLine;
+ m_lastLine = lastLine;
}
// return true if the debugger wants us to stop at this point
-bool StatementNode::hitStatement(ExecState *exec)
+bool StatementNode::hitStatement(ExecState* exec)
{
Debugger *dbg = exec->dynamicInterpreter()->imp()->debugger();
if (dbg)
- return dbg->atStatement(exec,sid,l0,l1);
+ return dbg->atStatement(exec, currentSourceId(exec), firstLine(), lastLine());
else
return true; // continue
}
: statement(s), next(this)
{
Parser::noteNodeCycle(this);
- setLoc(s->firstLine(), s->lastLine(), s->sourceId());
+ setLoc(s->firstLine(), s->lastLine());
}
StatListNode::StatListNode(StatListNode *l, StatementNode *s)
: statement(s), next(l->next)
{
l->next = this;
- setLoc(l->firstLine(), s->lastLine(), l->sourceId());
+ setLoc(l->firstLine(), s->lastLine());
}
// ECMA 12.1
source = s->next;
Parser::removeNodeCycle(source.get());
s->next = 0;
- setLoc(s->firstLine(), s->lastLine(), s->sourceId());
+ setLoc(s->firstLine(), s->lastLine());
} else {
source = 0;
}
// bail out on error
KJS_CHECKEXCEPTION
- exec->context().imp()->seenLabels()->pushIteration();
+ exec->context().imp()->pushIteration();
c = statement->execute(exec);
- exec->context().imp()->seenLabels()->popIteration();
+ exec->context().imp()->popIteration();
if (!((c.complType() == Continue) && ls.contains(c.target()))) {
if ((c.complType() == Break) && ls.contains(c.target()))
return Completion(Normal, 0);
if (!b)
return Completion(Normal, value);
- exec->context().imp()->seenLabels()->pushIteration();
+ exec->context().imp()->pushIteration();
c = statement->execute(exec);
- exec->context().imp()->seenLabels()->popIteration();
+ exec->context().imp()->popIteration();
if (c.isValueCompletion())
value = c.value();
// bail out on error
KJS_CHECKEXCEPTION
- exec->context().imp()->seenLabels()->pushIteration();
+ exec->context().imp()->pushIteration();
Completion c = statement->execute(exec);
- exec->context().imp()->seenLabels()->popIteration();
+ exec->context().imp()->popIteration();
if (c.isValueCompletion())
cval = c.value();
if (!((c.complType() == Continue) && ls.contains(c.target()))) {
KJS_CHECKEXCEPTION
- exec->context().imp()->seenLabels()->pushIteration();
+ exec->context().imp()->pushIteration();
c = statement->execute(exec);
- exec->context().imp()->seenLabels()->popIteration();
+ exec->context().imp()->popIteration();
if (c.isValueCompletion())
retval = c.value();
{
KJS_BREAKPOINT;
- if (ident.isEmpty() && !exec->context().imp()->seenLabels()->inIteration())
+ if (ident.isEmpty() && !exec->context().imp()->inIteration())
return createErrorCompletion(exec, SyntaxError, "Invalid continue statement.");
else if (!ident.isEmpty() && !exec->context().imp()->seenLabels()->contains(ident))
return createErrorCompletion(exec, SyntaxError, "Label %s not found.", ident);
{
KJS_BREAKPOINT;
- if (ident.isEmpty() && !exec->context().imp()->seenLabels()->inIteration() &&
- !exec->context().imp()->seenLabels()->inSwitch())
+ if (ident.isEmpty() && !exec->context().imp()->inIteration() &&
+ !exec->context().imp()->inSwitch())
return createErrorCompletion(exec, SyntaxError, "Invalid break statement.");
else if (!ident.isEmpty() && !exec->context().imp()->seenLabels()->contains(ident))
return createErrorCompletion(exec, SyntaxError, "Label %s not found.");
JSValue *v = expr->evaluate(exec);
KJS_CHECKEXCEPTION
- exec->context().imp()->seenLabels()->pushSwitch();
+ exec->context().imp()->pushSwitch();
Completion res = block->evalBlock(exec,v);
- exec->context().imp()->seenLabels()->popSwitch();
+ exec->context().imp()->popSwitch();
if ((res.complType() == Break) && ls.contains(res.target()))
return Completion(Normal, res.value());
// ------------------------------ FunctionBodyNode -----------------------------
FunctionBodyNode::FunctionBodyNode(SourceElementsNode *s)
- : BlockNode(s)
+ : BlockNode(s)
+ , m_sourceURL(Lexer::curr()->sourceURL())
+ , m_sourceId(Parser::sid)
{
- setLoc(-1, -1, -1);
+
+ setLoc(-1, -1);
}
void FunctionBodyNode::processFuncDecl(ExecState *exec)
{
- if (source)
- source->processFuncDecl(exec);
+ if (source)
+ source->processFuncDecl(exec);
}
// ------------------------------ FuncDeclNode ---------------------------------
: node(s1), next(this)
{
Parser::noteNodeCycle(this);
- setLoc(s1->firstLine(), s1->lastLine(), s1->sourceId());
+ setLoc(s1->firstLine(), s1->lastLine());
}
SourceElementsNode::SourceElementsNode(SourceElementsNode *s1, StatementNode *s2)
: node(s2), next(s1->next)
{
s1->next = this;
- setLoc(s1->firstLine(), s2->lastLine(), s1->sourceId());
+ setLoc(s1->firstLine(), s2->lastLine());
}
// ECMA 14
UString toString() const;
virtual void streamTo(SourceStream &s) const = 0;
virtual void processVarDecls(ExecState *) {}
- int lineNo() const { return line; }
+ int lineNo() const { return m_line; }
- // reference counting mechanism
- void ref() { ++m_refcount; }
- void deref() { --m_refcount; if (!m_refcount) delete this; }
- unsigned int refcount() { return m_refcount; }
+ void ref();
+ void deref();
+ unsigned int refcount();
+ static void clearNewNodes();
virtual Node *nodeInsideAllParens();
void setExceptionDetailsIfNeeded(ExecState *);
- int line;
- UString sourceURL;
- unsigned int m_refcount;
- virtual int sourceId() const { return -1; }
-
+ int m_line;
private:
// disallow assignment
Node& operator=(const Node&);
class StatementNode : public Node {
public:
StatementNode();
- void setLoc(int line0, int line1, int sourceId);
- int firstLine() const { return l0; }
- int lastLine() const { return l1; }
- int sourceId() const { return sid; }
+ void setLoc(int line0, int line1);
+ int firstLine() const { return lineNo(); }
+ int lastLine() const { return m_lastLine; }
bool hitStatement(ExecState *exec);
virtual Completion execute(ExecState *exec) = 0;
void pushLabel(const Identifier &id) { ls.push(id); }
LabelStack ls;
private:
JSValue *evaluate(ExecState */*exec*/) { return jsUndefined(); }
- int l0, l1;
- int sid;
+ int m_lastLine;
};
class NullNode : public Node {
// inherited by ProgramNode
class FunctionBodyNode : public BlockNode {
public:
- FunctionBodyNode(SourceElementsNode *s);
- void processFuncDecl(ExecState *exec);
+ FunctionBodyNode(SourceElementsNode *);
+ virtual void processFuncDecl(ExecState *exec);
+ int sourceId() { return m_sourceId; }
+ const UString& sourceURL() { return m_sourceURL; }
+ private:
+ UString m_sourceURL;
+ int m_sourceId;
};
class FuncExprNode : public Node {