Commit 7b978750 authored by darin's avatar darin

JavaScriptCore:

	- change ScopeChain to be a singly linked list shares tails, gives 11% gain on iBench

        * kjs/context.h:
        (ContextImp::pushScope): Make inline, use push instead of prepend, and pass imp pointer.
        (ContextImp::popScope): Make inline, use pop instead of removeFirst.
        * kjs/function.cpp: (DeclaredFunctionImp::DeclaredFunctionImp): No need to copy.
        * kjs/function_object.cpp: (FunctionObjectImp::construct): Use push instead of
	prepend, and pass imp pointer.
        * kjs/internal.cpp: (ContextImp::ContextImp): Use clear, push instead of prepend,
	and pass imp pointers.
        * kjs/nodes.cpp: (ResolveNode::evaluateReference): Use isEmpty, pop, and top instead
	of ScopeChainIterator.
        * kjs/object.h: Change _scope to be a NoRefScopeChain.
        * kjs/object.cpp: No need to initialize _scope any more, since it's not a NoRefScopeChain.

        * kjs/scope_chain.h: Rewrite, different implementation and interface.
        * kjs/scope_chain.cpp: More of the same.

WebCore:

        * khtml/ecma/kjs_dom.cpp: (DOMNode::pushEventHandlerScope): Change to push handlers
	on an existing scope chain rather than returning one. Name change too.
        * khtml/ecma/kjs_dom.h: More of the same.
        * khtml/ecma/kjs_html.cpp: (KJS::HTMLElement::pushEventHandlerScope): And here.
        * khtml/ecma/kjs_html.h: And here.

        * khtml/ecma/kjs_events.cpp: (JSEventListener::handleEvent): Use the pushEventHandlerScope
	function, and also don't worry about optimizing the "no change" case, because that already
	works pretty efficiently.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@2824 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ab36c324
2002-11-22 Darin Adler <darin@apple.com>
- change ScopeChain to be a singly linked list shares tails, gives 11% gain on iBench
* kjs/context.h:
(ContextImp::pushScope): Make inline, use push instead of prepend, and pass imp pointer.
(ContextImp::popScope): Make inline, use pop instead of removeFirst.
* kjs/function.cpp: (DeclaredFunctionImp::DeclaredFunctionImp): No need to copy.
* kjs/function_object.cpp: (FunctionObjectImp::construct): Use push instead of
prepend, and pass imp pointer.
* kjs/internal.cpp: (ContextImp::ContextImp): Use clear, push instead of prepend,
and pass imp pointers.
* kjs/nodes.cpp: (ResolveNode::evaluateReference): Use isEmpty, pop, and top instead
of ScopeChainIterator.
* kjs/object.h: Change _scope to be a NoRefScopeChain.
* kjs/object.cpp: No need to initialize _scope any more, since it's not a NoRefScopeChain.
* kjs/scope_chain.h: Rewrite, different implementation and interface.
* kjs/scope_chain.cpp: More of the same.
2002-11-22 Maciej Stachowiak <mjs@apple.com>
- a simple change for .5% gain on ibench - instead of unmarking
......
2002-11-22 Darin Adler <darin@apple.com>
- change ScopeChain to be a singly linked list shares tails, gives 11% gain on iBench
* kjs/context.h:
(ContextImp::pushScope): Make inline, use push instead of prepend, and pass imp pointer.
(ContextImp::popScope): Make inline, use pop instead of removeFirst.
* kjs/function.cpp: (DeclaredFunctionImp::DeclaredFunctionImp): No need to copy.
* kjs/function_object.cpp: (FunctionObjectImp::construct): Use push instead of
prepend, and pass imp pointer.
* kjs/internal.cpp: (ContextImp::ContextImp): Use clear, push instead of prepend,
and pass imp pointers.
* kjs/nodes.cpp: (ResolveNode::evaluateReference): Use isEmpty, pop, and top instead
of ScopeChainIterator.
* kjs/object.h: Change _scope to be a NoRefScopeChain.
* kjs/object.cpp: No need to initialize _scope any more, since it's not a NoRefScopeChain.
* kjs/scope_chain.h: Rewrite, different implementation and interface.
* kjs/scope_chain.cpp: More of the same.
2002-11-22 Maciej Stachowiak <mjs@apple.com>
- a simple change for .5% gain on ibench - instead of unmarking
......
2002-11-22 Darin Adler <darin@apple.com>
- change ScopeChain to be a singly linked list shares tails, gives 11% gain on iBench
* kjs/context.h:
(ContextImp::pushScope): Make inline, use push instead of prepend, and pass imp pointer.
(ContextImp::popScope): Make inline, use pop instead of removeFirst.
* kjs/function.cpp: (DeclaredFunctionImp::DeclaredFunctionImp): No need to copy.
* kjs/function_object.cpp: (FunctionObjectImp::construct): Use push instead of
prepend, and pass imp pointer.
* kjs/internal.cpp: (ContextImp::ContextImp): Use clear, push instead of prepend,
and pass imp pointers.
* kjs/nodes.cpp: (ResolveNode::evaluateReference): Use isEmpty, pop, and top instead
of ScopeChainIterator.
* kjs/object.h: Change _scope to be a NoRefScopeChain.
* kjs/object.cpp: No need to initialize _scope any more, since it's not a NoRefScopeChain.
* kjs/scope_chain.h: Rewrite, different implementation and interface.
* kjs/scope_chain.cpp: More of the same.
2002-11-22 Maciej Stachowiak <mjs@apple.com>
- a simple change for .5% gain on ibench - instead of unmarking
......
......@@ -46,8 +46,8 @@ namespace KJS {
FunctionImp *function() const { return _function; }
const List *arguments() const { return _arguments; }
void pushScope(const Object &s);
void popScope();
void pushScope(const Object &s) { scope.push(s.imp()); }
void popScope() { scope.pop(); }
LabelStack *seenLabels() { return &ls; }
void mark();
......
......@@ -260,7 +260,7 @@ DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const Identifier &n,
{
Value protect(this);
body->ref();
setScope(sc.copy());
setScope(sc);
}
DeclaredFunctionImp::~DeclaredFunctionImp()
......
......@@ -234,7 +234,7 @@ Object FunctionObjectImp::construct(ExecState *exec, const List &args)
}
ScopeChain scopeChain;
scopeChain.prepend(exec->interpreter()->globalObject());
scopeChain.push(exec->interpreter()->globalObject().imp());
FunctionBodyNode *bodyNode = progNode;
FunctionImp *fimp = new DeclaredFunctionImp(exec, Identifier::null, bodyNode,
......
......@@ -377,25 +377,25 @@ ContextImp::ContextImp(Object &glob, InterpreterImp *interpreter, Object &thisV,
switch(type) {
case EvalCode:
if (_callingContext) {
scope = _callingContext->scopeChain().copy();
scope = _callingContext->scopeChain();
variable = _callingContext->variableObject();
thisVal = _callingContext->thisValue();
break;
} // else same as GlobalCode
case GlobalCode:
scope = ScopeChain();
scope.prepend(glob);
scope.clear();
scope.push(glob.imp());
thisVal = Object(static_cast<ObjectImp*>(glob.imp()));
break;
case FunctionCode:
case AnonymousCode:
if (type == FunctionCode) {
scope = func->scope().copy();
scope.prepend(activation);
scope = func->scope();
scope.push(activation.imp());
} else {
scope = ScopeChain();
scope.prepend(glob);
scope.prepend(activation);
scope.clear();
scope.push(glob.imp());
scope.push(activation.imp());
}
variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
thisVal = thisV;
......@@ -410,16 +410,6 @@ ContextImp::~ContextImp()
_interpreter->setContext(_callingContext);
}
void ContextImp::pushScope(const Object &s)
{
scope.prepend(s);
}
void ContextImp::popScope()
{
scope.removeFirst();
}
void ContextImp::mark()
{
for (ContextImp *context = this; context; context = context->_callingContext)
......
......@@ -218,11 +218,10 @@ Value ResolveNode::evaluate(ExecState *exec)
Reference ResolveNode::evaluateReference(ExecState *exec)
{
const ScopeChain chain = exec->context().scopeChain();
ScopeChainIterator scope = chain.begin();
ScopeChain chain = exec->context().scopeChain();
while (scope != chain.end()) {
ObjectImp *o = static_cast<ObjectImp*>((*scope).imp());
while (!chain.isEmpty()) {
ObjectImp *o = chain.top();
//cout << "Resolve: looking at '" << ident.ascii() << "'"
// << " in " << (void*)o << " " << o->classInfo()->className << endl;
......@@ -231,7 +230,8 @@ Reference ResolveNode::evaluateReference(ExecState *exec)
// << " in " << (void*)o << " " << o->classInfo()->className << endl;
return Reference(o, ident);
}
scope++;
chain.pop();
}
// identifier not found
......
......@@ -53,19 +53,18 @@ Object Object::dynamicCast(const Value &v)
// ------------------------------ ObjectImp ------------------------------------
ObjectImp::ObjectImp(const Object &proto)
: _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L), _scope(true)
: _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L)
{
//fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
}
ObjectImp::ObjectImp(ObjectImp *proto)
: _proto(proto), _internalValue(0L), _scope(true)
: _proto(proto), _internalValue(0L)
{
//fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
}
ObjectImp::ObjectImp() :
_scope(true)
ObjectImp::ObjectImp()
{
//fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
_proto = NullImp::staticNull;
......
......@@ -602,7 +602,7 @@ namespace KJS {
PropertyMap _prop;
ValueImp *_proto;
ValueImp *_internalValue;
ScopeChain _scope;
NoRefScopeChain _scope;
};
/**
......
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2002 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -23,209 +21,113 @@
#include "scope_chain.h"
namespace KJS {
struct ScopeChainNode {
ScopeChainNode(const Value &val, ScopeChainNode *p, ScopeChainNode *n)
: member(val.imp()), prev(p), next(n) { }
ScopeChainNode(ValueImp *val, ScopeChainNode *p, ScopeChainNode *n)
: member(val), prev(p), next(n) { }
ValueImp *member;
ScopeChainNode *prev, *next;
};
struct ScopeChainHookNode : public ScopeChainNode {
ScopeChainHookNode(bool needsMarking) : ScopeChainNode(Value(), this, this),
listRefCount(1), nodesRefCount(needsMarking ? 0 : 1) { }
int listRefCount;
int nodesRefCount;
};
// ------------------------------ ScopeChainIterator ---------------------------------
ValueImp* ScopeChainIterator::operator->() const
{
return node->member;
}
Value ScopeChainIterator::operator*() const
{
return Value(node->member);
}
Value ScopeChainIterator::operator++()
{
node = node->next;
return Value(node->member);
}
Value ScopeChainIterator::operator++(int)
{
const ScopeChainNode *n = node;
++*this;
return Value(n->member);
}
// ------------------------------ ScopeChain -----------------------------------------
ScopeChain::ScopeChain(bool needsMarking) : hook(new ScopeChainHookNode(needsMarking)), m_needsMarking(needsMarking)
{
}
ScopeChain::ScopeChain(const ScopeChain& l) : hook(l.hook), m_needsMarking(false)
{
++hook->listRefCount;
if (hook->nodesRefCount++ == 0)
refAll();
}
ScopeChain& ScopeChain::operator=(const ScopeChain& l)
{
ScopeChain(l).swap(*this);
return *this;
}
ScopeChain::~ScopeChain()
{
if (!m_needsMarking)
if (--hook->nodesRefCount == 0)
derefAll();
if (--hook->listRefCount == 0) {
assert(hook->nodesRefCount == 0);
clearInternal();
delete hook;
}
}
void ScopeChain::mark() const
{
ScopeChainNode *n = hook->next;
while (n != hook) {
if (!n->member->marked())
n->member->mark();
n = n->next;
}
}
void ScopeChain::append(const Value& val)
{
ScopeChainNode *n = new ScopeChainNode(val, hook->prev, hook);
if (hook->nodesRefCount)
n->member->ref();
hook->prev->next = n;
hook->prev = n;
}
void ScopeChain::prepend(const Value& val)
{
ScopeChainNode *n = new ScopeChainNode(val, hook, hook->next);
if (hook->nodesRefCount)
n->member->ref();
hook->next->prev = n;
hook->next = n;
}
#include "object.h"
void ScopeChain::prepend(ValueImp *val)
{
ScopeChainNode *n = new ScopeChainNode(val, hook, hook->next);
if (hook->nodesRefCount)
n->member->ref();
hook->next->prev = n;
hook->next = n;
}
namespace KJS {
void ScopeChain::prependList(const ScopeChain& lst)
ScopeChainNode::ScopeChainNode(ScopeChainNode *n, ObjectImp *o)
: next(n), object(o), nodeAndObjectRefCount(1), nodeOnlyRefCount(0)
{
ScopeChainNode *otherHook = lst.hook;
ScopeChainNode *n = otherHook->prev;
while (n != otherHook) {
prepend(n->member);
n = n->prev;
}
o->ref();
}
void ScopeChain::removeFirst()
inline void ScopeChain::ref() const
{
erase(hook->next);
for (ScopeChainNode *n = _node; n; n = n->next) {
if (n->nodeAndObjectRefCount++ != 0)
break;
n->object->ref();
}
}
void ScopeChain::clearInternal()
ScopeChain::ScopeChain(const NoRefScopeChain &c)
: _node(c._node)
{
ScopeChainNode *n = hook->next;
while (n != hook) {
n = n->next;
delete n->prev;
}
hook->next = hook;
hook->prev = hook;
ref();
}
ScopeChain ScopeChain::copy() const
ScopeChain &ScopeChain::operator=(const ScopeChain &c)
{
ScopeChain newScopeChain;
newScopeChain.prependList(*this);
return newScopeChain;
c.ref();
deref();
_node = c._node;
return *this;
}
ScopeChainIterator ScopeChain::begin() const
void ScopeChain::push(ObjectImp *o)
{
return ScopeChainIterator(hook->next);
_node = new ScopeChainNode(_node, o);
}
ScopeChainIterator ScopeChain::end() const
void ScopeChain::pop()
{
return ScopeChainIterator(hook);
ScopeChainNode *oldNode = _node;
assert(oldNode);
ScopeChainNode *newNode = oldNode->next;
_node = newNode;
// Three cases:
// 1) This was not the last reference of the old node.
// In this case we move our ref from the old to the new node.
// 2) This was the last reference of the old node, but there are garbage collected references.
// In this case, the new node doesn't get any new ref, and the object is deref'd.
// 3) This was the last reference of the old node.
// In this case the object is deref'd and the entire node goes.
if (--oldNode->nodeAndObjectRefCount != 0) {
if (newNode)
++newNode->nodeAndObjectRefCount;
} else {
oldNode->object->deref();
if (oldNode->nodeOnlyRefCount == 0)
delete oldNode;
}
}
void ScopeChain::erase(ScopeChainNode *n)
void ScopeChain::release()
{
if (n != hook) {
if (hook->nodesRefCount)
n->member->deref();
n->next->prev = n->prev;
n->prev->next = n->next;
delete n;
}
ScopeChainNode *n = _node;
do {
ScopeChainNode *next = n->next;
n->object->deref();
if (n->nodeOnlyRefCount == 0)
delete n;
n = next;
} while (n && --n->nodeAndObjectRefCount == 0);
}
void ScopeChain::refAll() const
inline void NoRefScopeChain::ref() const
{
for (ScopeChainNode *n = hook->next; n != hook; n = n->next)
n->member->ref();
for (ScopeChainNode *n = _node; n; n = n->next)
if (n->nodeOnlyRefCount++ != 0)
break;
}
void ScopeChain::derefAll() const
NoRefScopeChain &NoRefScopeChain::operator=(const ScopeChain &c)
{
for (ScopeChainNode *n = hook->next; n != hook; n = n->next)
n->member->deref();
c.ref();
deref();
_node = c._node;
return *this;
}
void ScopeChain::swap(ScopeChain &other)
void NoRefScopeChain::mark()
{
if (!m_needsMarking)
if (other.hook->nodesRefCount++ == 0)
other.refAll();
if (!other.m_needsMarking)
if (hook->nodesRefCount++ == 0)
refAll();
if (!m_needsMarking)
if (--hook->nodesRefCount == 0)
derefAll();
if (!other.m_needsMarking)
if (--other.hook->nodesRefCount == 0)
other.derefAll();
ScopeChainHookNode *tmp = hook;
hook = other.hook;
other.hook = tmp;
for (ScopeChainNode *n = _node; n; n = n->next) {
ObjectImp *o = n->object;
if (!o->marked())
o->mark();
}
}
bool ScopeChain::isEmpty() const
void NoRefScopeChain::release()
{
return hook->next == hook;
ScopeChainNode *n = _node;
do {
ScopeChainNode *next = n->next;
if (n->nodeAndObjectRefCount == 0)
delete n;
n = next;
} while (n && --n->nodeOnlyRefCount == 0);
}
} // namespace KJS
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2002 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -24,124 +22,70 @@
#ifndef KJS_SCOPE_CHAIN_H
#define KJS_SCOPE_CHAIN_H
#include "value.h"
// internal data types
namespace KJS {
class ScopeChain;
class ScopeChainIterator;
class ScopeChainNode;
class ScopeChainHookNode;
/**
* @short Iterator for @ref KJS::ScopeChain objects.
*/
class ScopeChainIterator {
friend class ScopeChain;
ScopeChainIterator() : node(0) { }
ScopeChainIterator(ScopeChainNode *n) : node(n) { }
public:
/**
* Construct an iterator that points to the first element of the list.
* @param l The list the iterator will operate on.
*/
ScopeChainIterator(const ScopeChain &l);
/**
* Dereference the iterator.
* @return A pointer to the element the iterator operates on.
*/
ValueImp* operator->() const;
Value operator*() const;
/**
* Postfix increment operator.
* @return The element after the increment.
*/
Value operator++();
/**
* Prefix increment operator.
*/
Value operator++(int);
/**
* Compare the iterator with another one.
* @return True if the two iterators operate on the same list element.
* False otherwise.
*/
bool operator==(const ScopeChainIterator &it) const { return node == it.node; }
/**
* Check for inequality with another iterator.
* @return True if the two iterators operate on different list elements.
*/
bool operator!=(const ScopeChainIterator &it) const { return node != it.node; }
private:
ScopeChainNode *node;
};
/**
* @short Native list type.
*
* ScopeChain is a native ECMAScript type. ScopeChain values are only used for
* intermediate results of expression evaluation and cannot be stored
* as properties of objects.
*
* The list is explicitly shared. Note that while copy() returns a
* copy of the list the referenced objects are still shared.
*/
class ScopeChain {
friend class ScopeChainIterator;
public:
ScopeChain(bool needsMarking = false);
ScopeChain(const ScopeChain& l);
ScopeChain &operator=(const ScopeChain& l);
~ScopeChain();
/**
* Insert an object at the beginning of the list.
*
* @param val Pointer to object.
*/
void prepend(const Value& val);
/**
* Remove the element at the beginning of the list.
*/
void removeFirst();
/**
* Returns a shallow copy of the list. Ownership is passed to the user
* who is responsible for deleting the list then.
*/
ScopeChain copy() const;
/**
* @return A @ref KJS::ScopeChainIterator pointing to the first element.
*/
ScopeChainIterator begin() const;
/**
* @return A @ref KJS::ScopeChainIterator pointing to the last element.
*/
ScopeChainIterator end() const;
bool isEmpty() const;
class NoRefScopeChain;
class ObjectImp;
void mark() const;
class ScopeChainNode {
public:
ScopeChainNode(ScopeChainNode *n, ObjectImp *o);
// temporary
void prependList(const ScopeChain &);