Added getter/setter for names.

This commit is contained in:
rogerl%netscape.com 2000-09-11 22:10:44 +00:00
parent 65092804c2
commit e9324adac8
14 changed files with 474 additions and 202 deletions

View File

@ -42,7 +42,7 @@
NEGATE, /* dest, source */
NEW_ARRAY, /* dest */
NEW_CLASS, /* dest, class */
NEW_FUNCTION, /* dest, ICodeModule, Function Definition */
NEW_FUNCTION, /* dest, ICodeModule */
NEW_OBJECT, /* dest, constructor */
NOP, /* do nothing and like it */
NOT, /* dest, source */
@ -593,14 +593,14 @@
}
};
class NewFunction : public Instruction_3<TypedRegister, ICodeModule*, FunctionDefinition*> {
class NewFunction : public Instruction_2<TypedRegister, ICodeModule*> {
public:
/* dest, ICodeModule, Function Definition */
NewFunction (TypedRegister aOp1, ICodeModule* aOp2, FunctionDefinition* aOp3) :
Instruction_3<TypedRegister, ICodeModule*, FunctionDefinition*>
(NEW_FUNCTION, aOp1, aOp2, aOp3) {};
/* dest, ICodeModule */
NewFunction (TypedRegister aOp1, ICodeModule* aOp2) :
Instruction_2<TypedRegister, ICodeModule*>
(NEW_FUNCTION, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule" << ", " << "FunctionDefinition";
f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule";
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {

View File

@ -109,7 +109,7 @@ TypedRegister ICodeGenerator::allocateRegister(const StringAtom& name, JSType *t
mPermanentRegister[r] = true;
TypedRegister result(r, type);
(*variableList)[name] = result;
variableList->add(name, result);
mTopRegister = ++r;
return result;
}
@ -131,6 +131,14 @@ TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name)
return allocateRegister(name, &Any_Type);
}
TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name, JSType *type)
{
if (mExceptionRegister.first == NotARegister) {
mExceptionRegister = allocateRegister(mWorld->identifiers["__exceptionObject__"], &Any_Type);
}
return allocateRegister(name, type);
}
ICodeModule *ICodeGenerator::complete()
{
#ifdef DEBUG
@ -246,10 +254,10 @@ TypedRegister ICodeGenerator::newClass(JSClass *clazz)
return dest;
}
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm, FunctionDefinition *def)
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm)
{
TypedRegister dest(getTempRegister(), &Function_Type);
NewFunction *instr = new NewFunction(dest, icm, def);
NewFunction *instr = new NewFunction(dest, icm);
iCode->push_back(instr);
return dest;
}
@ -717,7 +725,7 @@ static bool isMethodName(JSType *t, const StringAtom &name, uint32 &slotIndex)
ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex)
{
if (!isWithinWith()) {
v = findVariable(name);
v = variableList->findVariable(name);
if (v.first != NotARegister)
return Var;
else {
@ -751,6 +759,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
const StringAtom &name = (static_cast<IdentifierExprNode *>(p))->name;
LValueKind lValueKind = resolveIdentifier(name, v, slotIndex);
JSType *targetType = v.second;
TypedRegister thisBase = TypedRegister(0, mClass ? mClass : &Any_Type);
@ -785,6 +794,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
ret = binaryOp(mapExprNodeToICodeOp(use), v, ret);
// fall thru...
case ExprNode::assignment:
ret = cast(ret, targetType);
switch (lValueKind) {
case Var:
move(v, ret);
@ -1012,6 +1022,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I
ret = binaryOp(mapExprNodeToICodeOp(use), v, ret);
// fall thru...
case ExprNode::assignment:
ret = cast(ret, fieldType);
switch (lValueKind) {
case Constructor:
case Static:
@ -1536,7 +1547,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
icg.genStmt(f->function.body);
//stdOut << icg;
ICodeModule *icm = icg.complete();
ret = newFunction(icm, &f->function);
ret = newFunction(icm);
}
break;
@ -1596,7 +1607,7 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin
JSType *ICodeGenerator::extractType(ExprNode *t)
{
JSType* type = &Any_Type;
// FIXME: need to do code generation for type expressions.
// FUTURE: do code generation for type expressions.
if (t && (t->getKind() == ExprNode::identifier)) {
IdentifierExprNode* typeExpr = static_cast<IdentifierExprNode*>(t);
type = findType(typeExpr->name);
@ -1795,15 +1806,15 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
if (name == nameExpr->name)
hasDefaultConstructor = true;
thisClass->defineConstructor(name);
scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function));
scg.setStatic(thisClass, name, scg.newFunction(icm));
}
else
if (isStatic) {
thisClass->defineStatic(name, &Function_Type);
scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function));
scg.setStatic(thisClass, name, scg.newFunction(icm));
}
else
thisClass->defineMethod(name, new JSFunction(icm, &f->function));
thisClass->defineMethod(name, new JSFunction(icm));
}
}
break;
@ -1815,7 +1826,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
}
// add the instance initializer
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete(), NULL));
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete()));
// invent a default constructor if necessary, it just calls the
// initializer and the superclass default constructor
if (!hasDefaultConstructor) {
@ -1828,7 +1839,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
icg.call(icg.getStatic(thisClass, initName), thisValue, &args);
icg.returnStmt(thisValue);
thisClass->defineConstructor(nameExpr->name);
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete(), NULL));
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete()));
}
// freeze the class.
thisClass->complete();
@ -1848,9 +1859,36 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
{
FunctionStmtNode *f = static_cast<FunctionStmtNode *>(p);
ICodeModule *icm = genFunction(f, false, NULL);
JSType *resultType = extractType(f->function.resultType);
if (f->function.name->getKind() == ExprNode::identifier) {
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
mGlobal->defineFunction(name, icm, &f->function);
switch (f->function.prefix) {
case FunctionName::Get:
if (isTopLevel()) {
mGlobal->defineVariable(name, resultType);
mGlobal->setGetter(name, new JSFunction(icm));
}
else {
// is this legal - a nested getter?
NOT_REACHED("Better check with Waldemar");
//allocateVariable(name, resultType);
}
break;
case FunctionName::Set:
if (isTopLevel()) {
mGlobal->defineVariable(name, resultType);
mGlobal->setSetter(name, new JSFunction(icm));
}
else {
// is this legal - a nested setter?
NOT_REACHED("Better check with Waldemar");
//allocateVariable(name, resultType);
}
break;
case FunctionName::normal:
mGlobal->defineFunction(name, icm);
break;
}
}
}
break;
@ -1876,24 +1914,21 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
VariableBinding *v = vs->bindings;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
if (v->type && (v->type->getKind() == ExprNode::identifier)) {
if (isTopLevel())
mGlobal->defineVariable((static_cast<IdentifierExprNode *>(v->name))->name,
findType((static_cast<IdentifierExprNode *>(v->type))->name));
else
allocateVariable((static_cast<IdentifierExprNode *>(v->name))->name,
(static_cast<IdentifierExprNode *>(v->type))->name);
}
else
allocateVariable((static_cast<IdentifierExprNode *>(v->name))->name);
JSType *type = extractType(v->type);
if (isTopLevel())
mGlobal->defineVariable((static_cast<IdentifierExprNode *>(v->name))->name, type);
else
allocateVariable((static_cast<IdentifierExprNode *>(v->name))->name, type);
if (v->initializer) {
if (!isTopLevel() && !isWithinWith()) {
TypedRegister r = genExpr(v->name);
TypedRegister val = genExpr(v->initializer);
val = cast(val, type);
move(r, val);
}
else {
TypedRegister val = genExpr(v->initializer);
val = cast(val, type);
saveName((static_cast<IdentifierExprNode *>(v->name))->name, val);
}
}
@ -2182,7 +2217,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
CatchClause *c = t->catches;
while (c) {
// Bind the incoming exception ...
setRegisterForVariable(c->name, mExceptionRegister);
variableList->setRegisterForVariable(c->name, mExceptionRegister);
genStmt(c->stmt);
if (finallyLabel)

View File

@ -50,7 +50,42 @@ namespace ICG {
using namespace JSTypes;
using namespace JSClasses;
typedef std::map<String, TypedRegister, std::less<String> > VariableList;
struct VariableList {
typedef std::map<String, uint32, std::less<String> > VariableMap;
VariableMap variableMap;
std::vector<TypedRegister> registerMap;
void setRegisterForVariable(const StringAtom& name, TypedRegister r)
{
VariableMap::iterator i = variableMap.find(name);
ASSERT(i != variableMap.end());
registerMap[(*i).second] = r;
}
TypedRegister findVariable(const StringAtom& name)
{
VariableMap::iterator i = variableMap.find(name);
return (i == variableMap.end()) ? TypedRegister(NotARegister, &None_Type) : registerMap[(*i).second];
}
void add(const StringAtom& name, TypedRegister r)
{
variableMap[name] = r.first;
registerMap.resize(r.first + 1);
registerMap[r.first] = r;
}
TypedRegister getRegister(uint32 i)
{
ASSERT(i < registerMap.size());
return registerMap[i];
}
};
typedef std::map<uint32, uint32, std::less<uint32> > InstructionMap;
@ -94,7 +129,7 @@ namespace ICG {
uint32 mNonOptionalParameterCount;
uint32 mEntryPoint;
bool mHasRestParameter;
bool mHasNamedRestParameter;
bool mHasNamedRestParameter;
static uint32 sMaxID;
@ -170,8 +205,6 @@ namespace ICG {
TypedRegister allocateRegister(const StringAtom& name, JSType *type);
void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; }
JSType *findType(const StringAtom& typeName);
JSType *extractType(ExprNode *t);
@ -245,12 +278,7 @@ namespace ICG {
TypedRegister allocateVariable(const StringAtom& name);
TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName);
TypedRegister findVariable(const StringAtom& name)
{
VariableList::iterator i = variableList->find(name);
return (i == variableList->end()) ? TypedRegister(NotARegister, &None_Type) : (*i).second;
}
TypedRegister allocateVariable(const StringAtom& name, JSType *type) ;
TypedRegister allocateParameter(const StringAtom& name) { mParameterCount++; return allocateRegister(name, &Any_Type); }
TypedRegister allocateParameter(const StringAtom& name, const StringAtom& typeName)
@ -278,7 +306,7 @@ namespace ICG {
TypedRegister newObject(TypedRegister constructor);
TypedRegister newArray();
TypedRegister newFunction(ICodeModule *icm, FunctionDefinition *def);
TypedRegister newFunction(ICodeModule *icm);
TypedRegister newClass(JSClass *clazz);
TypedRegister cast(TypedRegister arg, JSType *toType);

View File

@ -113,11 +113,25 @@ struct Activation : public gc_base {
}
}
// calling a binary operator, no 'this'
Activation(ICodeModule* iCode, const JSValue arg1, const JSValue arg2)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
mRegisters[0] = arg1;
mRegisters[1] = arg2;
mRegisters[1] = arg1;
mRegisters[2] = arg2;
}
// calling a getter function, no arguments
Activation(ICodeModule* iCode)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
}
// calling a setter function, 1 argument
Activation(ICodeModule* iCode, const JSValue arg)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
mRegisters[1] = arg;
}
};
@ -711,16 +725,16 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
uint32 i;
for (i = 0; i < args.size(); i++) {
if (args[i].second) { // a named argument
VariableList::iterator vi = icm->itsVariables->find(*(args[i].second));
TypedRegister r = icm->itsVariables->findVariable(*(args[i].second));
bool isParameter = false;
if (vi != icm->itsVariables->end()) { // we found the name in the target's list of variables
TypedRegister r = (*vi).second;
if (r.first != NotABanana) { // we found the name in the target's list of variables
if (r.first < icm->mParameterCount) { // make sure we didn't match a local var
ASSERT(r.first <= callArgs.size());
// the named argument is arriving in slot i, but needs to be r instead
// r.first is the intended target register, we subtract 1 since the callArgs array doesn't include 'this'
// here's where we could detect over-writing a positional arg with a named one if that is illegal
// if (callArgs[r.first - 1].first.first != NotARegister)...
(*registers)[args[i].first.first] = (*registers)[args[i].first.first].convert(r.second);
callArgs[r.first - 1] = Argument(args[i].first, NULL); // no need to copy the name through?
isParameter = true;
}
@ -763,7 +777,11 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
else
throw new JSException("Too many arguments in call");
}
callArgs[i] = args[i]; // it's a positional, just slap it in place
else {
TypedRegister r = icm->itsVariables->getRegister(i + 1); // the variable list includes 'this'
(*registers)[args[i].first.first] = (*registers)[args[i].first.first].convert(r.second);
callArgs[i] = args[i]; // it's a positional, just slap it in place
}
}
}
uint32 contiguousArgs = 0;
@ -863,14 +881,36 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
break;
case LOAD_NAME:
{
LoadName* ln = static_cast<LoadName*>(instruction);
(*registers)[dst(ln).first] = mGlobal->getVariable(*src1(ln));
LoadName* ln = static_cast<LoadName*>(instruction);
JSFunction *getter = mGlobal->getter(*src1(ln));
if (getter) {
ASSERT(!getter->isNative());
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(ln));
mActivation = new Activation(getter->getICode());
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
endPC = mActivation->mICode->its_iCode->end();
continue;
}
else
(*registers)[dst(ln).first] = mGlobal->getVariable(*src1(ln));
}
break;
case SAVE_NAME:
{
SaveName* sn = static_cast<SaveName*>(instruction);
mGlobal->setVariable(*dst(sn), (*registers)[src1(sn).first]);
JSFunction *setter = mGlobal->setter(*dst(sn));
if (setter) {
ASSERT(!setter->isNative());
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type));
mActivation = new Activation(setter->getICode(), (*registers)[src1(sn).first]);
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
endPC = mActivation->mICode->its_iCode->end();
continue;
}
else
mGlobal->setVariable(*dst(sn), (*registers)[src1(sn).first]);
}
break;
case NEW_OBJECT:
@ -893,7 +933,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case NEW_FUNCTION:
{
NewFunction* nf = static_cast<NewFunction*>(instruction);
(*registers)[dst(nf).first] = new JSFunction(src1(nf), src2(nf));
(*registers)[dst(nf).first] = new JSFunction(src1(nf));
}
break;
case NEW_ARRAY:
@ -918,6 +958,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
if (value.isObject()) {
if (value.isType()) {
// REVISIT: should signal error if slot doesn't exist.
NOT_REACHED("tell me I'm wrong");
JSClass* thisClass = dynamic_cast<JSClass*>(value.type);
if (thisClass && thisClass->hasStatic(*src2(gp))) {
const JSSlot& slot = thisClass->getStatic(*src2(gp));
@ -939,6 +980,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
if (value.isObject()) {
if (value.isType()) {
// REVISIT: should signal error if slot doesn't exist.
NOT_REACHED("tell me I'm wrong");
JSClass* thisClass = dynamic_cast<JSClass*>(value.object);
if (thisClass && thisClass->hasStatic(*src1(sp))) {
const JSSlot& slot = thisClass->getStatic(*src1(sp));

View File

@ -61,15 +61,7 @@ namespace JSClasses {
bool isConstructor() const { return (mFlags & kIsConstructor) != 0; }
};
#if defined(XP_MAC)
// copied from default template parameters in map.
typedef gc_allocator<std::pair<const String, JSSlot> > gc_slot_allocator;
#elif defined(XP_UNIX)
typedef JSTypes::gc_map_allocator gc_slot_allocator;
#elif defined(_WIN32)
typedef gc_allocator<JSSlot> gc_slot_allocator;
#endif
typedef gc_map_allocator(JSSlot) gc_slot_allocator;
typedef std::map<String, JSSlot, std::less<const String>, gc_slot_allocator> JSSlots;
@ -126,6 +118,8 @@ namespace JSClasses {
return slot;
}
const JSSlot& getSlot(const String& name)
{
return mSlots[name];
@ -272,7 +266,7 @@ namespace JSClasses {
JSTypes::kUndefinedValue);
}
// for grins, use the prototype link to access methods.
setPrototype(thisClass->getScope());
// setPrototype(thisClass->getScope());
}
JSFunction* getMethod(uint32 index)

View File

@ -124,7 +124,7 @@ static JSValue function_constructor(Context *cx, const JSValues& argv)
source.append(JSValue::valueToString(argv[argv.size() - 1]).string);
source.append("}");
JSFunction *f = new JSFunction(cx->compileFunction(source), NULL);
JSFunction *f = new JSFunction(cx->compileFunction(source));
f->setProperty(widenCString("length"), JSValue(parameterCount));
JSObject *obj = new JSObject();
f->setProperty(widenCString("prototype"), JSValue(obj));
@ -652,10 +652,10 @@ JSValue JSValue::valueToInteger(const JSValue& value)
{
JSValue result = valueToNumber(value);
ASSERT(result.tag == f64_tag);
result.tag = i64_tag;
result.tag = i32_tag;
bool neg = (result.f64 < 0);
result.f64 = floor((neg) ? -result.f64 : result.f64);
result.f64 = (neg) ? -result.f64 : result.f64;
result.i32 = floor((neg) ? -result.f64 : result.f64);
result.i32 = (neg) ? -result.i32 : result.i32;
return result;
}

View File

@ -178,17 +178,23 @@ namespace JSTypes {
Formatter& operator<<(Formatter& f, const JSValue& value);
#if defined(XP_MAC)
// copied from default template parameters in map.
typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
//typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
//typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
#define gc_map_allocator(T) gc_allocator<std::pair<const String, T> >
#elif defined(XP_UNIX)
// FIXME: in libg++, they assume the map's allocator is a byte allocator,
// which is wrapped in a simple_allocator. this is crap.
typedef char _Char[1];
typedef gc_allocator<_Char> gc_map_allocator;
//typedef gc_allocator<_Char> gc_map_allocator;
#define gc_map_allocator(T) gc_allocator<_Char>
#elif defined(_WIN32)
// FIXME: MSVC++'s notion. this is why we had to add _Charalloc().
typedef gc_allocator<JSValue> gc_map_allocator;
//typedef gc_allocator<JSValue> gc_map_allocator;
//typedef gc_allocator<JSContainer> gc_container_allocator;
#define gc_map_allocator(T) gc_allocator<T>
#endif
/**
@ -227,7 +233,8 @@ namespace JSTypes {
extern JSType Object_Type;
extern JSType Date_Type;
typedef std::map<String, JSValue, std::less<String>, gc_map_allocator> JSProperties;
typedef std::map<String, JSValue, std::less<String>, gc_map_allocator(JSValue) > JSProperties;
typedef std::map<String, JSFunction *, std::less<String> > FunctionMap;
/**
* Basic behavior of all JS objects, mapping a name to a value,
@ -236,6 +243,8 @@ namespace JSTypes {
class JSObject : public gc_base {
protected:
JSProperties mProperties;
FunctionMap *mGetter; // only allocated if the object has properties with getters or setters
FunctionMap *mSetter;
JSObject* mPrototype;
JSType* mType;
JSString* mClass; // this is the internal [[Class]] property
@ -244,13 +253,22 @@ namespace JSTypes {
static JSString *ObjectString;
static JSObject *ObjectPrototypeObject;
void init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = ObjectString; }
void init(JSObject* prototype) { mGetter = NULL; mSetter = NULL; mPrototype = prototype; mType = &Any_Type; mClass = ObjectString; }
public:
JSObject() { init(ObjectPrototypeObject); }
JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); }
JSObject(JSObject *prototype) { init(prototype); }
/*
I wanted to have this, but VCC complains about JSInstance instances not being deletable...
virtual ~JSObject()
{
if (mGetter) delete mGetter;
if (mSetter) delete mSetter;
}
*/
static void initObjectObject(JSScope *g);
bool hasProperty(const String& name)
@ -268,25 +286,55 @@ namespace JSTypes {
return kUndefinedValue;
}
// return the property AND the object it's found in
// (would rather return references, but couldn't get that to work)
const JSValue getReference(JSValue &prop, const String& name)
{
JSProperties::const_iterator i = mProperties.find(name);
if (i != mProperties.end()) {
prop = i->second;
return JSValue(this);
}
if (mPrototype)
return mPrototype->getReference(prop, name);
return kUndefinedValue;
}
JSValue& setProperty(const String& name, const JSValue& value)
{
return (mProperties[name] = value);
}
void setGetter(const String& name, JSFunction *getter)
{
if (mGetter == NULL)
mGetter = new FunctionMap();
(*mGetter)[name] = getter;
}
void setSetter(const String& name, JSFunction *setter)
{
if (mSetter == NULL)
mSetter = new FunctionMap();
(*mSetter)[name] = setter;
}
JSFunction *getter(const String& name)
{
if (hasProperty(name)) {
if (mGetter) {
FunctionMap::iterator g = mGetter->find(name);
if (g != mGetter->end())
return g->second;
}
}
else
if (mPrototype)
return mPrototype->getter(name);
return NULL;
}
JSFunction *setter(const String& name)
{
if (hasProperty(name)) {
if (mSetter) {
FunctionMap::iterator s = mSetter->find(name);
if (s != mSetter->end())
return s->second;
}
}
else
if (mPrototype)
return mPrototype->setter(name);
return NULL;
}
const JSValue& deleteProperty(const String& name)
{
JSProperties::iterator i = mProperties.find(name);
@ -439,11 +487,8 @@ namespace JSTypes {
static JSObject* FunctionPrototypeObject;
ICodeModule* mICode;
uint32 mParameterCount;
bool mParameterInfo;
protected:
JSFunction() : mICode(0), mParameterCount(0) {}
JSFunction() : mICode(0) {}
typedef JavaScript::gc_traits_finalizable<JSFunction> traits;
typedef gc_allocator<JSFunction, traits> allocator;
@ -451,21 +496,13 @@ namespace JSTypes {
public:
static void initFunctionObject(JSScope *g);
JSFunction(ICodeModule* iCode, FunctionDefinition *def)
JSFunction(ICodeModule* iCode)
: JSObject(FunctionPrototypeObject),
mICode(iCode), mParameterCount(0), mParameterInfo(false)
mICode(iCode)
{
setClass(FunctionString);
if (def) {
mParameterInfo = true;
VariableBinding *p = def->parameters;
while (p) { mParameterCount++; p = p->next; }
}
}
uint32 getParameterCount() { return mParameterCount; }
bool hasParameterInfo() { return mParameterInfo; }
~JSFunction();
void* operator new(size_t) { return allocator::allocate(1); }
@ -574,9 +611,9 @@ namespace JSTypes {
return result;
}
JSValue& defineFunction(const String& name, ICodeModule* iCode, FunctionDefinition *def)
JSValue& defineFunction(const String& name, ICodeModule* iCode)
{
JSValue value(new JSFunction(iCode, def));
JSValue value(new JSFunction(iCode));
return defineVariable(name, &Function_Type, value);
}

View File

@ -42,7 +42,7 @@
NEGATE, /* dest, source */
NEW_ARRAY, /* dest */
NEW_CLASS, /* dest, class */
NEW_FUNCTION, /* dest, ICodeModule, Function Definition */
NEW_FUNCTION, /* dest, ICodeModule */
NEW_OBJECT, /* dest, constructor */
NOP, /* do nothing and like it */
NOT, /* dest, source */
@ -593,14 +593,14 @@
}
};
class NewFunction : public Instruction_3<TypedRegister, ICodeModule*, FunctionDefinition*> {
class NewFunction : public Instruction_2<TypedRegister, ICodeModule*> {
public:
/* dest, ICodeModule, Function Definition */
NewFunction (TypedRegister aOp1, ICodeModule* aOp2, FunctionDefinition* aOp3) :
Instruction_3<TypedRegister, ICodeModule*, FunctionDefinition*>
(NEW_FUNCTION, aOp1, aOp2, aOp3) {};
/* dest, ICodeModule */
NewFunction (TypedRegister aOp1, ICodeModule* aOp2) :
Instruction_2<TypedRegister, ICodeModule*>
(NEW_FUNCTION, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule" << ", " << "FunctionDefinition";
f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule";
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {

View File

@ -109,7 +109,7 @@ TypedRegister ICodeGenerator::allocateRegister(const StringAtom& name, JSType *t
mPermanentRegister[r] = true;
TypedRegister result(r, type);
(*variableList)[name] = result;
variableList->add(name, result);
mTopRegister = ++r;
return result;
}
@ -131,6 +131,14 @@ TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name)
return allocateRegister(name, &Any_Type);
}
TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name, JSType *type)
{
if (mExceptionRegister.first == NotARegister) {
mExceptionRegister = allocateRegister(mWorld->identifiers["__exceptionObject__"], &Any_Type);
}
return allocateRegister(name, type);
}
ICodeModule *ICodeGenerator::complete()
{
#ifdef DEBUG
@ -246,10 +254,10 @@ TypedRegister ICodeGenerator::newClass(JSClass *clazz)
return dest;
}
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm, FunctionDefinition *def)
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm)
{
TypedRegister dest(getTempRegister(), &Function_Type);
NewFunction *instr = new NewFunction(dest, icm, def);
NewFunction *instr = new NewFunction(dest, icm);
iCode->push_back(instr);
return dest;
}
@ -717,7 +725,7 @@ static bool isMethodName(JSType *t, const StringAtom &name, uint32 &slotIndex)
ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex)
{
if (!isWithinWith()) {
v = findVariable(name);
v = variableList->findVariable(name);
if (v.first != NotARegister)
return Var;
else {
@ -751,6 +759,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
const StringAtom &name = (static_cast<IdentifierExprNode *>(p))->name;
LValueKind lValueKind = resolveIdentifier(name, v, slotIndex);
JSType *targetType = v.second;
TypedRegister thisBase = TypedRegister(0, mClass ? mClass : &Any_Type);
@ -785,6 +794,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
ret = binaryOp(mapExprNodeToICodeOp(use), v, ret);
// fall thru...
case ExprNode::assignment:
ret = cast(ret, targetType);
switch (lValueKind) {
case Var:
move(v, ret);
@ -1012,6 +1022,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I
ret = binaryOp(mapExprNodeToICodeOp(use), v, ret);
// fall thru...
case ExprNode::assignment:
ret = cast(ret, fieldType);
switch (lValueKind) {
case Constructor:
case Static:
@ -1536,7 +1547,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
icg.genStmt(f->function.body);
//stdOut << icg;
ICodeModule *icm = icg.complete();
ret = newFunction(icm, &f->function);
ret = newFunction(icm);
}
break;
@ -1596,7 +1607,7 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin
JSType *ICodeGenerator::extractType(ExprNode *t)
{
JSType* type = &Any_Type;
// FIXME: need to do code generation for type expressions.
// FUTURE: do code generation for type expressions.
if (t && (t->getKind() == ExprNode::identifier)) {
IdentifierExprNode* typeExpr = static_cast<IdentifierExprNode*>(t);
type = findType(typeExpr->name);
@ -1795,15 +1806,15 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
if (name == nameExpr->name)
hasDefaultConstructor = true;
thisClass->defineConstructor(name);
scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function));
scg.setStatic(thisClass, name, scg.newFunction(icm));
}
else
if (isStatic) {
thisClass->defineStatic(name, &Function_Type);
scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function));
scg.setStatic(thisClass, name, scg.newFunction(icm));
}
else
thisClass->defineMethod(name, new JSFunction(icm, &f->function));
thisClass->defineMethod(name, new JSFunction(icm));
}
}
break;
@ -1815,7 +1826,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
}
// add the instance initializer
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete(), NULL));
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete()));
// invent a default constructor if necessary, it just calls the
// initializer and the superclass default constructor
if (!hasDefaultConstructor) {
@ -1828,7 +1839,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
icg.call(icg.getStatic(thisClass, initName), thisValue, &args);
icg.returnStmt(thisValue);
thisClass->defineConstructor(nameExpr->name);
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete(), NULL));
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete()));
}
// freeze the class.
thisClass->complete();
@ -1848,9 +1859,36 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
{
FunctionStmtNode *f = static_cast<FunctionStmtNode *>(p);
ICodeModule *icm = genFunction(f, false, NULL);
JSType *resultType = extractType(f->function.resultType);
if (f->function.name->getKind() == ExprNode::identifier) {
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
mGlobal->defineFunction(name, icm, &f->function);
switch (f->function.prefix) {
case FunctionName::Get:
if (isTopLevel()) {
mGlobal->defineVariable(name, resultType);
mGlobal->setGetter(name, new JSFunction(icm));
}
else {
// is this legal - a nested getter?
NOT_REACHED("Better check with Waldemar");
//allocateVariable(name, resultType);
}
break;
case FunctionName::Set:
if (isTopLevel()) {
mGlobal->defineVariable(name, resultType);
mGlobal->setSetter(name, new JSFunction(icm));
}
else {
// is this legal - a nested setter?
NOT_REACHED("Better check with Waldemar");
//allocateVariable(name, resultType);
}
break;
case FunctionName::normal:
mGlobal->defineFunction(name, icm);
break;
}
}
}
break;
@ -1876,24 +1914,21 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
VariableBinding *v = vs->bindings;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
if (v->type && (v->type->getKind() == ExprNode::identifier)) {
if (isTopLevel())
mGlobal->defineVariable((static_cast<IdentifierExprNode *>(v->name))->name,
findType((static_cast<IdentifierExprNode *>(v->type))->name));
else
allocateVariable((static_cast<IdentifierExprNode *>(v->name))->name,
(static_cast<IdentifierExprNode *>(v->type))->name);
}
else
allocateVariable((static_cast<IdentifierExprNode *>(v->name))->name);
JSType *type = extractType(v->type);
if (isTopLevel())
mGlobal->defineVariable((static_cast<IdentifierExprNode *>(v->name))->name, type);
else
allocateVariable((static_cast<IdentifierExprNode *>(v->name))->name, type);
if (v->initializer) {
if (!isTopLevel() && !isWithinWith()) {
TypedRegister r = genExpr(v->name);
TypedRegister val = genExpr(v->initializer);
val = cast(val, type);
move(r, val);
}
else {
TypedRegister val = genExpr(v->initializer);
val = cast(val, type);
saveName((static_cast<IdentifierExprNode *>(v->name))->name, val);
}
}
@ -2182,7 +2217,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
CatchClause *c = t->catches;
while (c) {
// Bind the incoming exception ...
setRegisterForVariable(c->name, mExceptionRegister);
variableList->setRegisterForVariable(c->name, mExceptionRegister);
genStmt(c->stmt);
if (finallyLabel)

View File

@ -50,7 +50,42 @@ namespace ICG {
using namespace JSTypes;
using namespace JSClasses;
typedef std::map<String, TypedRegister, std::less<String> > VariableList;
struct VariableList {
typedef std::map<String, uint32, std::less<String> > VariableMap;
VariableMap variableMap;
std::vector<TypedRegister> registerMap;
void setRegisterForVariable(const StringAtom& name, TypedRegister r)
{
VariableMap::iterator i = variableMap.find(name);
ASSERT(i != variableMap.end());
registerMap[(*i).second] = r;
}
TypedRegister findVariable(const StringAtom& name)
{
VariableMap::iterator i = variableMap.find(name);
return (i == variableMap.end()) ? TypedRegister(NotARegister, &None_Type) : registerMap[(*i).second];
}
void add(const StringAtom& name, TypedRegister r)
{
variableMap[name] = r.first;
registerMap.resize(r.first + 1);
registerMap[r.first] = r;
}
TypedRegister getRegister(uint32 i)
{
ASSERT(i < registerMap.size());
return registerMap[i];
}
};
typedef std::map<uint32, uint32, std::less<uint32> > InstructionMap;
@ -94,7 +129,7 @@ namespace ICG {
uint32 mNonOptionalParameterCount;
uint32 mEntryPoint;
bool mHasRestParameter;
bool mHasNamedRestParameter;
bool mHasNamedRestParameter;
static uint32 sMaxID;
@ -170,8 +205,6 @@ namespace ICG {
TypedRegister allocateRegister(const StringAtom& name, JSType *type);
void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; }
JSType *findType(const StringAtom& typeName);
JSType *extractType(ExprNode *t);
@ -245,12 +278,7 @@ namespace ICG {
TypedRegister allocateVariable(const StringAtom& name);
TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName);
TypedRegister findVariable(const StringAtom& name)
{
VariableList::iterator i = variableList->find(name);
return (i == variableList->end()) ? TypedRegister(NotARegister, &None_Type) : (*i).second;
}
TypedRegister allocateVariable(const StringAtom& name, JSType *type) ;
TypedRegister allocateParameter(const StringAtom& name) { mParameterCount++; return allocateRegister(name, &Any_Type); }
TypedRegister allocateParameter(const StringAtom& name, const StringAtom& typeName)
@ -278,7 +306,7 @@ namespace ICG {
TypedRegister newObject(TypedRegister constructor);
TypedRegister newArray();
TypedRegister newFunction(ICodeModule *icm, FunctionDefinition *def);
TypedRegister newFunction(ICodeModule *icm);
TypedRegister newClass(JSClass *clazz);
TypedRegister cast(TypedRegister arg, JSType *toType);

View File

@ -113,11 +113,25 @@ struct Activation : public gc_base {
}
}
// calling a binary operator, no 'this'
Activation(ICodeModule* iCode, const JSValue arg1, const JSValue arg2)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
mRegisters[0] = arg1;
mRegisters[1] = arg2;
mRegisters[1] = arg1;
mRegisters[2] = arg2;
}
// calling a getter function, no arguments
Activation(ICodeModule* iCode)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
}
// calling a setter function, 1 argument
Activation(ICodeModule* iCode, const JSValue arg)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
mRegisters[1] = arg;
}
};
@ -711,16 +725,16 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
uint32 i;
for (i = 0; i < args.size(); i++) {
if (args[i].second) { // a named argument
VariableList::iterator vi = icm->itsVariables->find(*(args[i].second));
TypedRegister r = icm->itsVariables->findVariable(*(args[i].second));
bool isParameter = false;
if (vi != icm->itsVariables->end()) { // we found the name in the target's list of variables
TypedRegister r = (*vi).second;
if (r.first != NotABanana) { // we found the name in the target's list of variables
if (r.first < icm->mParameterCount) { // make sure we didn't match a local var
ASSERT(r.first <= callArgs.size());
// the named argument is arriving in slot i, but needs to be r instead
// r.first is the intended target register, we subtract 1 since the callArgs array doesn't include 'this'
// here's where we could detect over-writing a positional arg with a named one if that is illegal
// if (callArgs[r.first - 1].first.first != NotARegister)...
(*registers)[args[i].first.first] = (*registers)[args[i].first.first].convert(r.second);
callArgs[r.first - 1] = Argument(args[i].first, NULL); // no need to copy the name through?
isParameter = true;
}
@ -763,7 +777,11 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
else
throw new JSException("Too many arguments in call");
}
callArgs[i] = args[i]; // it's a positional, just slap it in place
else {
TypedRegister r = icm->itsVariables->getRegister(i + 1); // the variable list includes 'this'
(*registers)[args[i].first.first] = (*registers)[args[i].first.first].convert(r.second);
callArgs[i] = args[i]; // it's a positional, just slap it in place
}
}
}
uint32 contiguousArgs = 0;
@ -863,14 +881,36 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
break;
case LOAD_NAME:
{
LoadName* ln = static_cast<LoadName*>(instruction);
(*registers)[dst(ln).first] = mGlobal->getVariable(*src1(ln));
LoadName* ln = static_cast<LoadName*>(instruction);
JSFunction *getter = mGlobal->getter(*src1(ln));
if (getter) {
ASSERT(!getter->isNative());
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(ln));
mActivation = new Activation(getter->getICode());
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
endPC = mActivation->mICode->its_iCode->end();
continue;
}
else
(*registers)[dst(ln).first] = mGlobal->getVariable(*src1(ln));
}
break;
case SAVE_NAME:
{
SaveName* sn = static_cast<SaveName*>(instruction);
mGlobal->setVariable(*dst(sn), (*registers)[src1(sn).first]);
JSFunction *setter = mGlobal->setter(*dst(sn));
if (setter) {
ASSERT(!setter->isNative());
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type));
mActivation = new Activation(setter->getICode(), (*registers)[src1(sn).first]);
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
endPC = mActivation->mICode->its_iCode->end();
continue;
}
else
mGlobal->setVariable(*dst(sn), (*registers)[src1(sn).first]);
}
break;
case NEW_OBJECT:
@ -893,7 +933,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case NEW_FUNCTION:
{
NewFunction* nf = static_cast<NewFunction*>(instruction);
(*registers)[dst(nf).first] = new JSFunction(src1(nf), src2(nf));
(*registers)[dst(nf).first] = new JSFunction(src1(nf));
}
break;
case NEW_ARRAY:
@ -918,6 +958,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
if (value.isObject()) {
if (value.isType()) {
// REVISIT: should signal error if slot doesn't exist.
NOT_REACHED("tell me I'm wrong");
JSClass* thisClass = dynamic_cast<JSClass*>(value.type);
if (thisClass && thisClass->hasStatic(*src2(gp))) {
const JSSlot& slot = thisClass->getStatic(*src2(gp));
@ -939,6 +980,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
if (value.isObject()) {
if (value.isType()) {
// REVISIT: should signal error if slot doesn't exist.
NOT_REACHED("tell me I'm wrong");
JSClass* thisClass = dynamic_cast<JSClass*>(value.object);
if (thisClass && thisClass->hasStatic(*src1(sp))) {
const JSSlot& slot = thisClass->getStatic(*src1(sp));

View File

@ -61,15 +61,7 @@ namespace JSClasses {
bool isConstructor() const { return (mFlags & kIsConstructor) != 0; }
};
#if defined(XP_MAC)
// copied from default template parameters in map.
typedef gc_allocator<std::pair<const String, JSSlot> > gc_slot_allocator;
#elif defined(XP_UNIX)
typedef JSTypes::gc_map_allocator gc_slot_allocator;
#elif defined(_WIN32)
typedef gc_allocator<JSSlot> gc_slot_allocator;
#endif
typedef gc_map_allocator(JSSlot) gc_slot_allocator;
typedef std::map<String, JSSlot, std::less<const String>, gc_slot_allocator> JSSlots;
@ -126,6 +118,8 @@ namespace JSClasses {
return slot;
}
const JSSlot& getSlot(const String& name)
{
return mSlots[name];
@ -272,7 +266,7 @@ namespace JSClasses {
JSTypes::kUndefinedValue);
}
// for grins, use the prototype link to access methods.
setPrototype(thisClass->getScope());
// setPrototype(thisClass->getScope());
}
JSFunction* getMethod(uint32 index)

View File

@ -124,7 +124,7 @@ static JSValue function_constructor(Context *cx, const JSValues& argv)
source.append(JSValue::valueToString(argv[argv.size() - 1]).string);
source.append("}");
JSFunction *f = new JSFunction(cx->compileFunction(source), NULL);
JSFunction *f = new JSFunction(cx->compileFunction(source));
f->setProperty(widenCString("length"), JSValue(parameterCount));
JSObject *obj = new JSObject();
f->setProperty(widenCString("prototype"), JSValue(obj));
@ -652,10 +652,10 @@ JSValue JSValue::valueToInteger(const JSValue& value)
{
JSValue result = valueToNumber(value);
ASSERT(result.tag == f64_tag);
result.tag = i64_tag;
result.tag = i32_tag;
bool neg = (result.f64 < 0);
result.f64 = floor((neg) ? -result.f64 : result.f64);
result.f64 = (neg) ? -result.f64 : result.f64;
result.i32 = floor((neg) ? -result.f64 : result.f64);
result.i32 = (neg) ? -result.i32 : result.i32;
return result;
}

View File

@ -178,17 +178,23 @@ namespace JSTypes {
Formatter& operator<<(Formatter& f, const JSValue& value);
#if defined(XP_MAC)
// copied from default template parameters in map.
typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
//typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
//typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
#define gc_map_allocator(T) gc_allocator<std::pair<const String, T> >
#elif defined(XP_UNIX)
// FIXME: in libg++, they assume the map's allocator is a byte allocator,
// which is wrapped in a simple_allocator. this is crap.
typedef char _Char[1];
typedef gc_allocator<_Char> gc_map_allocator;
//typedef gc_allocator<_Char> gc_map_allocator;
#define gc_map_allocator(T) gc_allocator<_Char>
#elif defined(_WIN32)
// FIXME: MSVC++'s notion. this is why we had to add _Charalloc().
typedef gc_allocator<JSValue> gc_map_allocator;
//typedef gc_allocator<JSValue> gc_map_allocator;
//typedef gc_allocator<JSContainer> gc_container_allocator;
#define gc_map_allocator(T) gc_allocator<T>
#endif
/**
@ -227,7 +233,8 @@ namespace JSTypes {
extern JSType Object_Type;
extern JSType Date_Type;
typedef std::map<String, JSValue, std::less<String>, gc_map_allocator> JSProperties;
typedef std::map<String, JSValue, std::less<String>, gc_map_allocator(JSValue) > JSProperties;
typedef std::map<String, JSFunction *, std::less<String> > FunctionMap;
/**
* Basic behavior of all JS objects, mapping a name to a value,
@ -236,6 +243,8 @@ namespace JSTypes {
class JSObject : public gc_base {
protected:
JSProperties mProperties;
FunctionMap *mGetter; // only allocated if the object has properties with getters or setters
FunctionMap *mSetter;
JSObject* mPrototype;
JSType* mType;
JSString* mClass; // this is the internal [[Class]] property
@ -244,13 +253,22 @@ namespace JSTypes {
static JSString *ObjectString;
static JSObject *ObjectPrototypeObject;
void init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = ObjectString; }
void init(JSObject* prototype) { mGetter = NULL; mSetter = NULL; mPrototype = prototype; mType = &Any_Type; mClass = ObjectString; }
public:
JSObject() { init(ObjectPrototypeObject); }
JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); }
JSObject(JSObject *prototype) { init(prototype); }
/*
I wanted to have this, but VCC complains about JSInstance instances not being deletable...
virtual ~JSObject()
{
if (mGetter) delete mGetter;
if (mSetter) delete mSetter;
}
*/
static void initObjectObject(JSScope *g);
bool hasProperty(const String& name)
@ -268,25 +286,55 @@ namespace JSTypes {
return kUndefinedValue;
}
// return the property AND the object it's found in
// (would rather return references, but couldn't get that to work)
const JSValue getReference(JSValue &prop, const String& name)
{
JSProperties::const_iterator i = mProperties.find(name);
if (i != mProperties.end()) {
prop = i->second;
return JSValue(this);
}
if (mPrototype)
return mPrototype->getReference(prop, name);
return kUndefinedValue;
}
JSValue& setProperty(const String& name, const JSValue& value)
{
return (mProperties[name] = value);
}
void setGetter(const String& name, JSFunction *getter)
{
if (mGetter == NULL)
mGetter = new FunctionMap();
(*mGetter)[name] = getter;
}
void setSetter(const String& name, JSFunction *setter)
{
if (mSetter == NULL)
mSetter = new FunctionMap();
(*mSetter)[name] = setter;
}
JSFunction *getter(const String& name)
{
if (hasProperty(name)) {
if (mGetter) {
FunctionMap::iterator g = mGetter->find(name);
if (g != mGetter->end())
return g->second;
}
}
else
if (mPrototype)
return mPrototype->getter(name);
return NULL;
}
JSFunction *setter(const String& name)
{
if (hasProperty(name)) {
if (mSetter) {
FunctionMap::iterator s = mSetter->find(name);
if (s != mSetter->end())
return s->second;
}
}
else
if (mPrototype)
return mPrototype->setter(name);
return NULL;
}
const JSValue& deleteProperty(const String& name)
{
JSProperties::iterator i = mProperties.find(name);
@ -439,11 +487,8 @@ namespace JSTypes {
static JSObject* FunctionPrototypeObject;
ICodeModule* mICode;
uint32 mParameterCount;
bool mParameterInfo;
protected:
JSFunction() : mICode(0), mParameterCount(0) {}
JSFunction() : mICode(0) {}
typedef JavaScript::gc_traits_finalizable<JSFunction> traits;
typedef gc_allocator<JSFunction, traits> allocator;
@ -451,21 +496,13 @@ namespace JSTypes {
public:
static void initFunctionObject(JSScope *g);
JSFunction(ICodeModule* iCode, FunctionDefinition *def)
JSFunction(ICodeModule* iCode)
: JSObject(FunctionPrototypeObject),
mICode(iCode), mParameterCount(0), mParameterInfo(false)
mICode(iCode)
{
setClass(FunctionString);
if (def) {
mParameterInfo = true;
VariableBinding *p = def->parameters;
while (p) { mParameterCount++; p = p->next; }
}
}
uint32 getParameterCount() { return mParameterCount; }
bool hasParameterInfo() { return mParameterInfo; }
~JSFunction();
void* operator new(size_t) { return allocator::allocate(1); }
@ -574,9 +611,9 @@ namespace JSTypes {
return result;
}
JSValue& defineFunction(const String& name, ICodeModule* iCode, FunctionDefinition *def)
JSValue& defineFunction(const String& name, ICodeModule* iCode)
{
JSValue value(new JSFunction(iCode, def));
JSValue value(new JSFunction(iCode));
return defineVariable(name, &Function_Type, value);
}