+2007-12-10 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Split this:
+
+ FunctionBodyNode
+ ^
+ |
+ ProgramNode
+
+ into this:
+
+ ScopeNode
+ ^ ^ ^
+ | | |
+ FunctionBodyNode ProgramNode EvalNode
+
+ in preparation for specializing each class more while optimizing global
+ variable access.
+
+ Also removed some cruft from the FunctionBodyNode interface to simplify
+ things.
+
+ SunSpider says this patch is a .8% speedup, which seems reasonable,
+ since it eliminates a few branches and adds KJS_FAST_CALL in a few
+ places.
+
+ Layout tests and JS tests pass. Also, this baby builds on Windows! (Qt
+ mileage may vary...)
+
2007-12-10 Geoffrey Garen <ggaren@apple.com>
RS by Mark Rowe.
__ZN3KJS8Debugger9exceptionEPNS_9ExecStateEiiPNS_7JSValueE
__ZN3KJS8DebuggerC2Ev
__ZN3KJS8DebuggerD2Ev
+__ZN3KJS8EvalNodeC1EPN3WTF6VectorINS1_6RefPtrINS_13StatementNodeEEELm0EEE
__ZN3KJS8JSObject11hasInstanceEPNS_9ExecStateEPNS_7JSValueE
__ZN3KJS8JSObject12removeDirectERKNS_10IdentifierE
__ZN3KJS8JSObject14callAsFunctionEPNS_9ExecStateEPS0_RKNS_4ListE
__ZN3KJS9Collector7collectEv
__ZN3KJS9Collector7protectEPNS_7JSValueE
__ZN3KJS9Collector9unprotectEPNS_7JSValueE
-__ZN3KJS9ExecStateC1EPNS_14JSGlobalObjectEPNS_8JSObjectEPNS_16FunctionBodyNodeENS_8CodeTypeEPS0_S8_PNS_11FunctionImpEPKNS_4ListE
+__ZN3KJS9ExecStateC1EPNS_14JSGlobalObjectEPNS_8JSObjectEPNS_9ScopeNodeENS_8CodeTypeEPS0_S8_PNS_11FunctionImpEPKNS_4ListE
__ZN3KJS9ExecStateD1Ev
__ZN3KJSeqERKNS_7UStringEPKc
__ZN3WTF10fastCallocEmm
// ECMA 10.2
ExecState::ExecState(JSGlobalObject* globalObject, JSObject* thisV,
- FunctionBodyNode* currentBody, CodeType type, ExecState* callingExec, ExecState* currentExec,
+ ScopeNode* scopeNode, CodeType type, ExecState* callingExec, ExecState* currentExec,
FunctionImp* func, const List* args)
: m_globalObject(globalObject)
, m_exception(0)
, m_propertyNames(CommonIdentifiers::shared())
, m_callingExec(callingExec)
, m_savedExec(currentExec)
- , m_currentBody(currentBody)
+ , m_scopeNode(scopeNode)
, m_function(func)
, m_arguments(args)
, m_iterationDepth(0)
break;
}
- if (currentBody)
+ if (scopeNode)
m_globalObject->setCurrentExec(this);
}
};
class ActivationImp;
- class FunctionBodyNode;
class FunctionImp;
class GlobalFuncImp;
class Interpreter;
class JSGlobalObject;
class JSVariableObject;
class ScopeChain;
+ class ScopeNode;
struct LocalStorageEntry;
/**
ActivationImp* activationObject() { return m_activation; }
CodeType codeType() { return m_codeType; }
- FunctionBodyNode* currentBody() { return m_currentBody; }
+ ScopeNode* scopeNode() { return m_scopeNode; }
FunctionImp* function() const { return m_function; }
const List* arguments() const { return m_arguments; }
public:
ExecState(JSGlobalObject* glob, JSObject* thisV,
- FunctionBodyNode* currentBody, CodeType type = GlobalCode,
+ ScopeNode* scopeNode, CodeType type = GlobalCode,
ExecState* callingExecState = 0, ExecState* currentExec = 0,
FunctionImp* function = 0, const List* args = 0);
~ExecState();
ExecState* m_callingExec;
ExecState* m_savedExec;
- FunctionBodyNode* m_currentBody;
+ ScopeNode* m_scopeNode;
FunctionImp* m_function;
const List* m_arguments;
{
}
- LocalStorage localStorage;
- SymbolTable* symbolTable;
+ LocalStorage localStorage; // Storage for variables in the symbol table.
+ SymbolTable* symbolTable; // Maps name -> index in localStorage.
+
};
JSVariableObject(JSVariableObjectData* data)
JSValue* FunctionImp::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
{
FunctionImp* thisObj = static_cast<FunctionImp*>(slot.slotBase());
- return jsNumber(thisObj->body->numParams());
+ return jsNumber(thisObj->body->parameters().size());
}
bool FunctionImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
Vector<Identifier>& parameters = body->parameters();
- if (static_cast<size_t>(index) >= body->numParams())
+ if (static_cast<size_t>(index) >= body->parameters().size())
return CommonIdentifiers::shared()->nullIdentifier;
Identifier name = parameters[index];
int sourceId;
int errLine;
UString errMsg;
- RefPtr<ProgramNode> progNode(parser().parse<ProgramNode>(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg));
+ RefPtr<EvalNode> progNode(parser().parse<EvalNode>(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg));
Debugger* dbg = exec->dynamicGlobalObject()->debugger();
if (dbg) {
while (i < len && *c == ' ')
c++, i++;
if (i == len) {
- functionBody->addParam(Identifier(param));
+ functionBody->parameters().append(Identifier(param));
params++;
break;
} else if (*c == ',') {
- functionBody->addParam(Identifier(param));
+ functionBody->parameters().append(Identifier(param));
params++;
c++, i++;
continue;
static inline int currentSourceId(ExecState* exec) KJS_FAST_CALL;
static inline int currentSourceId(ExecState* exec)
{
- return exec->currentBody()->sourceId();
+ return exec->scopeNode()->sourceId();
}
static inline const UString& currentSourceURL(ExecState* exec) KJS_FAST_CALL;
static inline const UString& currentSourceURL(ExecState* exec)
{
- return exec->currentBody()->sourceURL();
+ return exec->scopeNode()->sourceURL();
}
Completion Node::createErrorCompletion(ExecState* exec, ErrorType e, const char *msg)
// ------------------------------ FunctionBodyNode -----------------------------
-FunctionBodyNode::FunctionBodyNode(SourceElements* children)
+ScopeNode::ScopeNode(SourceElements* children)
: BlockNode(children)
, m_sourceURL(parser().sourceURL())
, m_sourceId(parser().sourceId())
- , m_initializedDeclarationStacks(false)
- , m_initializedSymbolTable(false)
- , m_optimizedResolveNodes(false)
{
}
-void FunctionBodyNode::initializeDeclarationStacks(ExecState* exec)
+ProgramNode::ProgramNode(SourceElements* children)
+ : ScopeNode(children)
+{
+}
+
+EvalNode::EvalNode(SourceElements* children)
+ : ScopeNode(children)
+{
+}
+
+FunctionBodyNode::FunctionBodyNode(SourceElements* children)
+ : ScopeNode(children)
+ , m_initialized(false)
+{
+}
+
+void ScopeNode::initializeDeclarationStacks(ExecState* exec)
{
DeclarationStacks::NodeStack nodeStack;
DeclarationStacks stacks(exec, nodeStack, m_varStack, m_functionStack);
node = nodeStack[size];
nodeStack.shrink(size);
}
-
- m_initializedDeclarationStacks = true;
}
void FunctionBodyNode::initializeSymbolTable()
for (i = 0, size = m_functionStack.size(); i < size; ++i)
m_symbolTable.set(m_functionStack[i]->ident.ustring().rep(), count++);
-
- m_initializedSymbolTable = true;
}
void FunctionBodyNode::optimizeVariableAccess()
node = nodeStack[size];
nodeStack.shrink(size);
}
-
- m_optimizedResolveNodes = true;
}
void FunctionBodyNode::processDeclarations(ExecState* exec)
{
- if (!m_initializedDeclarationStacks)
+ if (!m_initialized) {
initializeDeclarationStacks(exec);
-
- if (exec->codeType() == FunctionCode)
- processDeclarationsForFunctionCode(exec);
- else
- processDeclarationsForProgramCode(exec);
-}
-
-void FunctionBodyNode::processDeclarationsForFunctionCode(ExecState* exec)
-{
- if (!m_initializedSymbolTable)
initializeSymbolTable();
-
- if (!m_optimizedResolveNodes)
optimizeVariableAccess();
+
+ m_initialized = true;
+ }
LocalStorage& localStorage = exec->variableObject()->localStorage();
localStorage.reserveCapacity(m_varStack.size() + m_parameters.size() + m_functionStack.size());
exec->updateLocalStorage();
}
-void FunctionBodyNode::processDeclarationsForProgramCode(ExecState* exec)
+void ProgramNode::processDeclarations(ExecState* exec)
{
+ initializeDeclarationStacks(exec);
+
size_t i, size;
- JSObject* variableObject = exec->variableObject();
+ JSVariableObject* variableObject = exec->variableObject();
- int minAttributes = Internal | (exec->codeType() != EvalCode ? DontDelete : 0);
+ int minAttributes = Internal | DontDelete;
for (i = 0, size = m_varStack.size(); i < size; ++i) {
VarDeclNode* node = m_varStack[i];
variableObject->put(exec, node->ident, jsUndefined(), attributes);
}
- ASSERT(!m_parameters.size());
-
for (i = 0, size = m_functionStack.size(); i < size; ++i) {
FuncDeclNode* node = m_functionStack[i];
variableObject->put(exec, node->ident, node->makeFunction(exec), minAttributes);
}
}
-void FunctionBodyNode::addParam(const Identifier& ident)
+void EvalNode::processDeclarations(ExecState* exec)
{
- m_parameters.append(ident);
+ initializeDeclarationStacks(exec);
+
+ size_t i, size;
+
+ JSVariableObject* variableObject = exec->variableObject();
+
+ int minAttributes = Internal;
+
+ for (i = 0, size = m_varStack.size(); i < size; ++i) {
+ VarDeclNode* node = m_varStack[i];
+ if (variableObject->hasProperty(exec, node->ident))
+ continue;
+ int attributes = minAttributes;
+ if (node->varType == VarDeclNode::Constant)
+ attributes |= ReadOnly;
+ variableObject->put(exec, node->ident, jsUndefined(), attributes);
+ }
+
+ for (i = 0, size = m_functionStack.size(); i < size; ++i) {
+ FuncDeclNode* node = m_functionStack[i];
+ variableObject->put(exec, node->ident, node->makeFunction(exec), minAttributes);
+ }
}
UString FunctionBodyNode::paramString() const
{
UString s("");
- size_t count = numParams();
+ size_t count = m_parameters.size();
for (size_t pos = 0; pos < count; ++pos) {
if (!s.isEmpty())
s += ", ";
- s += paramName(pos).ustring();
+ s += m_parameters[pos].ustring();
}
return s;
}
+Completion ProgramNode::execute(ExecState* exec)
+{
+ processDeclarations(exec);
+ return ScopeNode::execute(exec);
+}
+
+Completion EvalNode::execute(ExecState* exec)
+{
+ processDeclarations(exec);
+ return ScopeNode::execute(exec);
+}
+
Completion FunctionBodyNode::execute(ExecState* exec)
{
processDeclarations(exec);
}
}
- Completion completion = BlockNode::execute(exec);
+ Completion completion = ScopeNode::execute(exec);
if (Debugger* dbg = exec->dynamicGlobalObject()->debugger()) {
if (completion.complType() == Throw)
void FuncDeclNode::addParams()
{
for (ParameterNode *p = param.get(); p != 0L; p = p->nextParam())
- body->addParam(p->ident());
+ body->parameters().append(p->ident());
}
void FuncDeclNode::getDeclarations(DeclarationStacks& stacks)
proto->put(exec, exec->propertyNames().constructor, func, ReadOnly | DontDelete | DontEnum);
func->put(exec, exec->propertyNames().prototype, proto, Internal|DontDelete);
- func->put(exec, exec->propertyNames().length, jsNumber(body->numParams()), ReadOnly|DontDelete|DontEnum);
+ func->put(exec, exec->propertyNames().length, jsNumber(body->parameters().size()), ReadOnly|DontDelete|DontEnum);
return func;
}
void FuncExprNode::addParams()
{
for (ParameterNode *p = param.get(); p != 0L; p = p->nextParam())
- body->addParam(p->ident());
+ body->parameters().append(p->ident());
}
JSValue *FuncExprNode::evaluate(ExecState *exec)
return func;
}
-ProgramNode::ProgramNode(SourceElements* children)
- : FunctionBodyNode(children)
-{
-}
-
-}
+} // namespace KJS
ListRefPtr<ParameterNode> next;
};
- // inherited by ProgramNode
- class FunctionBodyNode : public BlockNode {
+ class ScopeNode : public BlockNode {
public:
- FunctionBodyNode(SourceElements* children) KJS_FAST_CALL;
+ ScopeNode(SourceElements*) KJS_FAST_CALL;
+
int sourceId() KJS_FAST_CALL { return m_sourceId; }
const UString& sourceURL() KJS_FAST_CALL { return m_sourceURL; }
- virtual Completion execute(ExecState*) KJS_FAST_CALL;
-
- SymbolTable& symbolTable() { return m_symbolTable; }
+ protected:
+ void initializeDeclarationStacks(ExecState*) KJS_FAST_CALL;
+
+ DeclarationStacks::VarStack m_varStack;
+ DeclarationStacks::FunctionStack m_functionStack;
- void addParam(const Identifier& ident) KJS_FAST_CALL;
- size_t numParams() const KJS_FAST_CALL { return m_parameters.size(); }
- Identifier paramName(size_t pos) const KJS_FAST_CALL { return m_parameters[pos]; }
- UString paramString() const KJS_FAST_CALL;
- Vector<Identifier>& parameters() KJS_FAST_CALL { return m_parameters; }
- ALWAYS_INLINE void processDeclarations(ExecState*);
- ALWAYS_INLINE void processDeclarationsForFunctionCode(ExecState*);
- ALWAYS_INLINE void processDeclarationsForProgramCode(ExecState*);
private:
UString m_sourceURL;
int m_sourceId;
+ };
- void initializeDeclarationStacks(ExecState*);
- bool m_initializedDeclarationStacks;
-
- void initializeSymbolTable();
- bool m_initializedSymbolTable;
+ class ProgramNode : public ScopeNode {
+ public:
+ ProgramNode(SourceElements*) KJS_FAST_CALL;
+ virtual Completion execute(ExecState*) KJS_FAST_CALL;
- void optimizeVariableAccess();
- bool m_optimizedResolveNodes;
+ private:
+ ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+ };
+
+ class EvalNode : public ScopeNode {
+ public:
+ EvalNode(SourceElements*) KJS_FAST_CALL;
+ virtual Completion execute(ExecState*) KJS_FAST_CALL;
- // Properties that will go into the ActivationImp's local storage. (Used for initializing the ActivationImp.)
- DeclarationStacks::VarStack m_varStack;
- DeclarationStacks::FunctionStack m_functionStack;
- Vector<Identifier> m_parameters;
+ private:
+ ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+ };
+
+ class FunctionBodyNode : public ScopeNode {
+ public:
+ FunctionBodyNode(SourceElements*) KJS_FAST_CALL;
+
+ virtual Completion execute(ExecState*) KJS_FAST_CALL;
+
+ SymbolTable& symbolTable() KJS_FAST_CALL { return m_symbolTable; }
- // Mapping from property name -> local storage index. (Used once to transform the AST, and subsequently for residual slow case lookups.)
+ Vector<Identifier>& parameters() KJS_FAST_CALL { return m_parameters; }
+ UString paramString() const KJS_FAST_CALL;
+
+ private:
+ void initializeSymbolTable() KJS_FAST_CALL;
+ void optimizeVariableAccess() KJS_FAST_CALL;
+ ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+
+ bool m_initialized;
+ Vector<Identifier> m_parameters;
SymbolTable m_symbolTable;
};
- class FuncExprNode : public ExpressionNode {
+ class FuncExprNode : public ExpressionNode {
public:
FuncExprNode(const Identifier& i, FunctionBodyNode* b, ParameterNode* p = 0) KJS_FAST_CALL
: ident(i), param(p), body(b) { addParams(); }
RefPtr<CaseBlockNode> block;
};
- class ProgramNode : public FunctionBodyNode {
- public:
- ProgramNode(SourceElements* children) KJS_FAST_CALL;
- };
-
struct ElementList {
ElementNode* head;
ElementNode* tail;
+2007-12-10 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Updated for rename in JavaScriptCore.
+
+ * bridge/mac/WebCoreScriptDebugger.mm:
+ (-[WebCoreScriptCallFrame scopeChain]):
+ (-[WebCoreScriptCallFrame functionName]):
+ (-[WebCoreScriptCallFrame evaluateWebScript:]):
+
2007-12-10 Rodney Dawes <dobey@wayofthemonkey.com>
Bug 16383: Ambiguous Window Usage in kjs_dom.cpp
- (NSArray *)scopeChain
{
- if (!_state->currentBody()) { // global frame
+ if (!_state->scopeNode()) { // global frame
return [NSArray arrayWithObject:_globalObj];
}
- (NSString *)functionName
{
- if (_state->currentBody()) {
+ if (_state->scopeNode()) {
FunctionImp *func = _state->function();
if (func) {
Identifier fn = func->functionName();
// find "eval"
JSObject *eval = NULL;
- if (state->currentBody()) { // "eval" won't work without context (i.e. at global scope)
+ if (state->scopeNode()) { // "eval" won't work without context (i.e. at global scope)
JSValue *v = globalObject->get(state, "eval");
if (v->isObject() && static_cast<JSObject *>(v)->implementsCall())
eval = static_cast<JSObject *>(v);
+2007-12-10 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Updated for rename in JavaScriptCore.
+
+ * WebScriptCallFrame.cpp:
+ (WebScriptCallFrame::functionName):
+ (WebScriptCallFrame::valueByEvaluatingJavaScriptFromString):
+
2007-12-07 Steve Falkenburg <sfalken@apple.com>
Fix version parsing.
*funcName = 0;
- if (!m_state->currentBody())
+ if (!m_state->scopeNode())
return S_OK;
FunctionImp* func = m_state->function();
// find "eval"
JSObject* eval = 0;
- if (state->currentBody()) { // "eval" won't work without context (i.e. at global scope)
+ if (state->scopeNode()) { // "eval" won't work without context (i.e. at global scope)
JSValue* v = globObj->get(state, "eval");
if (v->isObject() && static_cast<JSObject*>(v)->implementsCall())
eval = static_cast<JSObject*>(v);