Commit b5b6b9a9 authored by ggaren@apple.com's avatar ggaren@apple.com

JavaScriptCore:

2008-07-16  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Oliver Hunt.
        
        First step toward putting doubles in registers: Turned Register into a
        proper abstraction layer. It is no longer possible to cast a Register
        to a JSValue*, or a Register& to a JSValue*&, or to access the union
        inside a Register directly.
        
        SunSpider reports no change.
        
        In support of this change, I had to make the following mechanical changes
        in a lot of places:
        
        1. Clients now use explicit accessors to read data out of Registers, and
        implicit copy constructors to write data into registers.
        
        So, assignment that used to look like
        
            x.u.jsValue = y;
        
        now looks like
        
            x = y;
            
        And access that used to look like
        
            x = y.u.jsValue;
        
        now looks like
        
            x = y.jsValue();

        2. I made generic flow control specific in opcodes that made their flow
        control generic by treating a Register& as a JSValue*&. This had the
        added benefit of removing some exception checking branches from immediate
        number code.

        3. I beefed up PropertySlot to support storing a Register* in a property
        slot. For now, only JSVariableObject's symbolTableGet and symbolTablePut
        use this functionality, but I expect more clients to use it in the future.
        
        4. I changed ArgList to be a buffer of Registers, not JSValue*'s, and I
        changed ArgList iterator clients to iterate Registers, not JSValue*'s.

WebCore:

2008-07-16  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Oliver Hunt.

        Support for JavaScriptCore's first step toward putting doubles in
        registers: Treat ArgList iterators as Register*'s, not JSValue*'s.

        * bindings/js/ScheduledAction.cpp:
        (WebCore::ScheduledAction::ScheduledAction):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@35203 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 89626dc8
2008-07-16 Geoffrey Garen <ggaren@apple.com>
Reviewed by Oliver Hunt.
First step toward putting doubles in registers: Turned Register into a
proper abstraction layer. It is no longer possible to cast a Register
to a JSValue*, or a Register& to a JSValue*&, or to access the union
inside a Register directly.
SunSpider reports no change.
In support of this change, I had to make the following mechanical changes
in a lot of places:
1. Clients now use explicit accessors to read data out of Registers, and
implicit copy constructors to write data into registers.
So, assignment that used to look like
x.u.jsValue = y;
now looks like
x = y;
And access that used to look like
x = y.u.jsValue;
now looks like
x = y.jsValue();
2. I made generic flow control specific in opcodes that made their flow
control generic by treating a Register& as a JSValue*&. This had the
added benefit of removing some exception checking branches from immediate
number code.
3. I beefed up PropertySlot to support storing a Register* in a property
slot. For now, only JSVariableObject's symbolTableGet and symbolTablePut
use this functionality, but I expect more clients to use it in the future.
4. I changed ArgList to be a buffer of Registers, not JSValue*'s, and I
changed ArgList iterator clients to iterate Registers, not JSValue*'s.
2008-07-16 Ada Chan <adachan@apple.com>
Fixed build.
This diff is collapsed.
......@@ -123,9 +123,11 @@ namespace KJS {
private:
enum ExecutionFlag { Normal, InitializeAndReturn };
friend NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile*, Register* r, int argv, int argc, JSValue*& exceptionValue);
NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile*, Register* r, int argv, int argc, JSValue*& exceptionValue);
JSValue* execute(EvalNode*, ExecState*, JSObject* thisObj, int registerOffset, ScopeChainNode*, JSValue** exception);
ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock*, Instruction*, ScopeChainNode*, Register* r, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function);
ALWAYS_INLINE void setScopeChain(ExecState* exec, ScopeChainNode*&, ScopeChainNode*);
NEVER_INLINE void debug(ExecState*, const Instruction*, const CodeBlock*, ScopeChainNode*, Register*);
......
......@@ -29,31 +29,202 @@
#ifndef Register_h
#define Register_h
#include "JSValue.h"
#include <wtf/VectorTraits.h>
namespace KJS {
class CodeBlock;
class ExecState;
class JSFunction;
class JSObject;
class JSPropertyNameIterator;
class JSValue;
class ScopeChainNode;
struct Instruction;
struct Register {
class Register {
public:
Register();
Register(JSValue*);
JSValue* jsValue() const;
bool marked() const;
void mark();
uint32_t toUInt32(ExecState*) const;
UString toString(ExecState*) const;
private:
friend class Machine;
// Only the Machine should use these functions.
Register(CodeBlock*);
Register(ScopeChainNode*);
Register(int);
Register(Register*);
Register(Instruction*);
Register(JSPropertyNameIterator*);
CodeBlock* codeBlock() const;
ScopeChainNode* scopeChain() const;
int i() const;
Register* r() const;
Instruction* vPC() const;
JSPropertyNameIterator* jsPropertyNameIterator() const;
union {
private:
friend class Register;
CodeBlock* codeBlock;
Instruction* vPC;
JSValue* jsValue;
JSObject* jsObject;
ScopeChainNode* scopeChain;
JSPropertyNameIterator* jsPropertyNameIterator;
Register* r;
int i;
} u;
#ifndef NDEBUG
enum {
CodeBlockType = 0,
InstructionType,
JSValueType,
ScopeChainNodeType,
JSPropertyNameIteratorType,
RegisterType,
intType
} m_type;
#endif
};
ALWAYS_INLINE Register::Register()
{
#ifndef NDEBUG
*this = 0;
#endif
}
ALWAYS_INLINE Register::Register(JSValue* v)
{
#ifndef NDEBUG
m_type = JSValueType;
#endif
u.jsValue = v;
}
ALWAYS_INLINE Register::Register(CodeBlock* codeBlock)
{
#ifndef NDEBUG
m_type = CodeBlockType;
#endif
u.codeBlock = codeBlock;
}
ALWAYS_INLINE Register::Register(Instruction* vPC)
{
#ifndef NDEBUG
m_type = InstructionType;
#endif
u.vPC = vPC;
}
ALWAYS_INLINE Register::Register(ScopeChainNode* scopeChain)
{
#ifndef NDEBUG
m_type = ScopeChainNodeType;
#endif
u.scopeChain = scopeChain;
}
ALWAYS_INLINE Register::Register(JSPropertyNameIterator* jsPropertyNameIterator)
{
#ifndef NDEBUG
m_type = JSPropertyNameIteratorType;
#endif
u.jsPropertyNameIterator = jsPropertyNameIterator;
}
ALWAYS_INLINE Register::Register(Register* r)
{
#ifndef NDEBUG
m_type = RegisterType;
#endif
u.r = r;
}
ALWAYS_INLINE Register::Register(int i)
{
#ifndef NDEBUG
m_type = intType;
#endif
u.i = i;
}
ALWAYS_INLINE JSValue* Register::jsValue() const
{
ASSERT(m_type == JSValueType || !i());
return u.jsValue;
}
ALWAYS_INLINE CodeBlock* Register::codeBlock() const
{
ASSERT(m_type == CodeBlockType);
return u.codeBlock;
}
ALWAYS_INLINE ScopeChainNode* Register::scopeChain() const
{
ASSERT(m_type == ScopeChainNodeType);
return u.scopeChain;
}
ALWAYS_INLINE int Register::i() const
{
ASSERT(m_type == intType);
return u.i;
}
ALWAYS_INLINE Register* Register::r() const
{
ASSERT(m_type == RegisterType);
return u.r;
}
ALWAYS_INLINE Instruction* Register::vPC() const
{
ASSERT(m_type == InstructionType);
return u.vPC;
}
ALWAYS_INLINE JSPropertyNameIterator* Register::jsPropertyNameIterator() const
{
ASSERT(m_type == JSPropertyNameIteratorType);
return u.jsPropertyNameIterator;
}
ALWAYS_INLINE bool Register::marked() const
{
return jsValue()->marked();
}
ALWAYS_INLINE void Register::mark()
{
jsValue()->mark();
}
ALWAYS_INLINE uint32_t Register::toUInt32(ExecState* exec) const
{
return jsValue()->toUInt32(exec);
}
ALWAYS_INLINE UString Register::toString(ExecState* exec) const
{
return jsValue()->toString(exec);
}
} // namespace KJS
namespace WTF {
......
......@@ -45,11 +45,9 @@ void ArgList::markLists(ListSet& markSet)
ArgList* list = *it;
iterator end2 = list->end();
for (iterator it2 = list->begin(); it2 != end2; ++it2) {
JSValue* v = *it2;
if (!v->marked())
v->mark();
}
for (iterator it2 = list->begin(); it2 != end2; ++it2)
if (!(*it2).marked())
(*it2).mark();
}
}
......
......@@ -23,6 +23,8 @@
#define ArgList_h
#include "JSImmediate.h"
#include "Register.h"
#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
......@@ -34,7 +36,7 @@ namespace KJS {
class ArgList : Noncopyable {
private:
static const unsigned inlineCapacity = 8;
typedef Vector<JSValue*, inlineCapacity> VectorType;
typedef Vector<Register, inlineCapacity> VectorType;
typedef HashSet<ArgList*> ListSet;
public:
......@@ -54,7 +56,7 @@ namespace KJS {
}
// Constructor for a read-only list whose data has already been allocated elsewhere.
ArgList(JSValue** buffer, size_t size)
ArgList(Register* buffer, size_t size)
: m_buffer(buffer)
, m_size(size)
, m_markSet(0)
......@@ -76,7 +78,7 @@ namespace KJS {
JSValue* at(size_t i) const
{
if (i < m_size)
return m_buffer[i];
return m_buffer[i].jsValue();
return jsUndefined();
}
......@@ -117,7 +119,7 @@ namespace KJS {
private:
void slowAppend(JSValue*);
JSValue** m_buffer;
Register* m_buffer;
size_t m_size;
VectorType m_vector;
......
......@@ -48,7 +48,7 @@ Arguments::Arguments(ExecState* exec, JSFunction* function, const ArgList& args,
for (ArgList::const_iterator it = args.begin(); it != end; ++it, ++i) {
Identifier name = Identifier::from(exec, i);
if (!m_indexToNameMap.isMapped(name))
putDirect(name, *it, DontEnum);
putDirect(name, (*it).jsValue(), DontEnum);
}
}
......
......@@ -274,7 +274,7 @@ JSValue* arrayProtoFuncConcat(ExecState* exec, JSObject*, JSValue* thisValue, co
}
if (it == end)
break;
curArg = *it;
curArg = (*it).jsValue();
++it;
}
arr->setLength(n);
......
......@@ -46,7 +46,7 @@ const UString* DebuggerCallFrame::functionName() const
if (!m_codeBlock)
return 0;
JSFunction* function = static_cast<JSFunction*>(callFrame()[RegisterFile::Callee].u.jsValue);
JSFunction* function = static_cast<JSFunction*>(callFrame()[RegisterFile::Callee].jsValue());
if (!function)
return 0;
return &function->functionName().ustring();
......@@ -54,7 +54,7 @@ const UString* DebuggerCallFrame::functionName() const
DebuggerCallFrame::Type DebuggerCallFrame::type() const
{
if (callFrame()[RegisterFile::Callee].u.jsObject)
if (callFrame()[RegisterFile::Callee].jsValue())
return FunctionType;
return ProgramType;
......@@ -65,7 +65,7 @@ JSObject* DebuggerCallFrame::thisObject() const
if (!m_codeBlock)
return 0;
return static_cast<JSObject*>(m_registers[m_codeBlock->thisRegister].u.jsValue);
return static_cast<JSObject*>(m_registers[m_codeBlock->thisRegister].jsValue());
}
JSValue* DebuggerCallFrame::evaluate(const UString& script, JSValue*& exception) const
......
......@@ -44,9 +44,8 @@ IndexToNameMap::IndexToNameMap(JSFunction* func, const ArgList& args)
: m_size(args.size())
, m_map(new Identifier[args.size()])
{
unsigned i = 0;
ArgList::const_iterator end = args.end();
for (ArgList::const_iterator it = args.begin(); it != end; ++i, ++it)
size_t size = args.size();
for (size_t i = 0; i < size; ++i)
m_map[i] = func->getParameterName(i); // null if there is no corresponding parameter
}
......
......@@ -163,7 +163,7 @@ JSObject* JSActivation::createArgumentsObject(ExecState* exec)
int argc;
exec->machine()->getArgumentsData(callFrame, function, argv, argc);
ArgList args(reinterpret_cast<JSValue**>(argv), argc);
ArgList args(argv, argc);
return new (exec) Arguments(exec, function, args, this);
}
......
......@@ -103,7 +103,7 @@ JSArray::JSArray(JSObject* prototype, const ArgList& list)
size_t i = 0;
ArgList::const_iterator end = list.end();
for (ArgList::const_iterator it = list.begin(); it != end; ++it, ++i)
storage->m_vector[i] = *it;
storage->m_vector[i] = (*it).jsValue();
m_storage = storage;
......
......@@ -268,7 +268,7 @@ namespace KJS {
ASSERT(global.attributes & DontDelete);
SymbolTableEntry newEntry(index, global.attributes);
symbolTable().add(global.identifier.ustring().rep(), newEntry);
valueAt(index) = global.value;
registerAt(index) = global.value;
}
}
......
......@@ -25,6 +25,7 @@
#define JSString_h
#include "CommonIdentifiers.h"
#include "ExecState.h"
#include "JSCell.h"
#include "PropertySlot.h"
#include "identifier.h"
......
......@@ -25,7 +25,6 @@
#include "CallData.h"
#include "ConstructData.h"
#include "ExecState.h"
#include "JSImmediate.h"
#include "ustring.h"
#include <stddef.h> // for size_t
......@@ -111,7 +110,7 @@ namespace KJS {
// These are identical logic to above, and faster than jsNumber(number)->toInt32(exec)
static int32_t toInt32(double);
static int32_t toUInt32(double);
static uint32_t toUInt32(double);
// Floating point conversions.
float toFloat(ExecState*) const;
......@@ -218,7 +217,7 @@ namespace KJS {
return static_cast<int32_t>(val);
}
inline int32_t JSValue::toUInt32(double val)
inline uint32_t JSValue::toUInt32(double val)
{
if (!(val >= 0.0 && val < 4294967296.0)) {
bool ignored;
......
......@@ -71,11 +71,9 @@ void JSVariableObject::mark()
return;
Register* end = d->registerArray.get() + d->registerArraySize;
for (Register* it = d->registerArray.get(); it != end; ++it) {
JSValue* v = (*it).u.jsValue;
if (!v->marked())
v->mark();
}
for (Register* it = d->registerArray.get(); it != end; ++it)
if (!(*it).marked())
(*it).mark();
}
bool JSVariableObject::isVariableObject() const
......
......@@ -55,7 +55,7 @@ namespace KJS {
virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const;
JSValue*& valueAt(int index) const { return d->registers[index].u.jsValue; }
Register& registerAt(int index) const { return d->registers[index]; }
protected:
// Subclasses of JSVariableObject can subclass this struct to add data
......@@ -106,7 +106,7 @@ namespace KJS {
{
SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep());
if (!entry.isNull()) {
slot.setValueSlot(&valueAt(entry.getIndex()));
slot.setRegisterSlot(&registerAt(entry.getIndex()));
return true;
}
return false;
......@@ -116,7 +116,7 @@ namespace KJS {
{
SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep());
if (!entry.isNull()) {
slot.setValueSlot(&valueAt(entry.getIndex()));
slot.setRegisterSlot(&registerAt(entry.getIndex()));
slotIsWriteable = !entry.isReadOnly();
return true;
}
......@@ -130,7 +130,7 @@ namespace KJS {
return false;
if (entry.isReadOnly())
return true;
valueAt(entry.getIndex()) = value;
registerAt(entry.getIndex()) = value;
return true;
}
......@@ -142,7 +142,7 @@ namespace KJS {
SymbolTableEntry& entry = iter->second;
ASSERT(!entry.isNull());
entry.setAttributes(attributes);
valueAt(entry.getIndex()) = value;
registerAt(entry.getIndex()) = value;
return true;
}
......
......@@ -21,6 +21,7 @@
#ifndef PropertySlot_h
#define PropertySlot_h
#include "Register.h"
#include "JSValue.h"
#include "identifier.h"
#include <wtf/Assertions.h>
......@@ -32,7 +33,8 @@ namespace KJS {
struct HashEntry;
#define KJS_VALUE_SLOT_MARKER 0
#define KJS_NUMERIC_PROPERTY_NAME_SLOT_MARKER reinterpret_cast<GetValueFunc>(1)
#define KJS_REGISTER_SLOT_MARKER reinterpret_cast<GetValueFunc>(1)
#define KJS_NUMERIC_PROPERTY_NAME_SLOT_MARKER reinterpret_cast<GetValueFunc>(2)
class PropertySlot {
public:
......@@ -53,6 +55,8 @@ namespace KJS {
{
if (m_getValue == KJS_VALUE_SLOT_MARKER)
return *m_data.valueSlot;
if (m_getValue == KJS_REGISTER_SLOT_MARKER)
return (*m_data.registerSlot).jsValue();
ASSERT(m_getValue != KJS_NUMERIC_PROPERTY_NAME_SLOT_MARKER);
return m_getValue(exec, propertyName, *this);
}
......@@ -63,15 +67,21 @@ namespace KJS {
return *m_data.valueSlot;
if (m_getValue == KJS_NUMERIC_PROPERTY_NAME_SLOT_MARKER)
return m_data.numericFunc(exec, propertyName, *this);
if (m_getValue == KJS_REGISTER_SLOT_MARKER)
return (*m_data.registerSlot).jsValue();
return m_getValue(exec, Identifier::from(exec, propertyName), *this);
}
void putValue(JSValue* value)
{
ASSERT(m_getValue == KJS_VALUE_SLOT_MARKER);
*m_data.valueSlot = value;
if (m_getValue == KJS_VALUE_SLOT_MARKER) {
*m_data.valueSlot = value;
return;
}
ASSERT(m_getValue == KJS_REGISTER_SLOT_MARKER);
*m_data.registerSlot = value;
}
void setValueSlot(JSValue** valueSlot)
{
ASSERT(valueSlot);
......@@ -79,6 +89,14 @@ namespace KJS {
clearBase();
m_data.valueSlot = valueSlot;
}
void setRegisterSlot(Register* registerSlot)
{
ASSERT(registerSlot);
m_getValue = KJS_REGISTER_SLOT_MARKER;
clearBase();
m_data.registerSlot = registerSlot;
}
void setStaticEntry(JSValue* slotBase, const HashEntry* staticEntry, GetValueFunc getValue)
{
......@@ -162,6 +180,7 @@ namespace KJS {
union {
JSObject* getterFunc;
JSValue** valueSlot;
Register* registerSlot;
const HashEntry* staticEntry;
unsigned index;
GetValueNumericFunc numericFunc;
......
......@@ -36,7 +36,7 @@ static JSValue* stringFromCharCode(ExecState* exec, JSObject*, JSValue*, const A
UChar* p = buf;
ArgList::const_iterator end = args.end();
for (ArgList::const_iterator it = args.begin(); it != end; ++it)
*p++ = static_cast<UChar>((*it)->toUInt32(exec));
*p++ = static_cast<UChar>((*it).toUInt32(exec));
s = UString::adopt(buf, args.size());
} else
s = "";
......
......@@ -350,7 +350,7 @@ JSValue* stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue* thisValue, c
ArgList::const_iterator end = args.end();
for (ArgList::const_iterator it = args.begin(); it != end; ++it)
s += (*it)->toString(exec);
s += (*it).toString(exec);
return jsString(exec, s);
}
......
2008-07-16 Geoffrey Garen <ggaren@apple.com>
Reviewed by Oliver Hunt.
Support for JavaScriptCore's first step toward putting doubles in
registers: Treat ArgList iterators as Register*'s, not JSValue*'s.
* bindings/js/ScheduledAction.cpp:
(WebCore::ScheduledAction::ScheduledAction):
2008-07-15 Maxime Britto <britto@apple.com>
Reviewed by Eric.
......@@ -42,7 +42,7 @@ ScheduledAction::ScheduledAction(JSValue* function, const ArgList& args)
{
ArgList::const_iterator end = args.end();
for (ArgList::const_iterator it = args.begin(); it != end; ++it)
m_args.append(*it);
m_args.append((*it).jsValue());
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment