mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-25 03:49:42 +00:00
Added getter/setter for names.
This commit is contained in:
parent
65092804c2
commit
e9324adac8
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
109
js/js2/jstypes.h
109
js/js2/jstypes.h
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user