зеркало из https://github.com/mozilla/gecko-dev.git
Mods for getter/setter methods.
This commit is contained in:
Родитель
fd15c36a2e
Коммит
1db3618a98
|
@ -139,7 +139,7 @@ TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name, JSType *t
|
|||
return allocateRegister(name, type);
|
||||
}
|
||||
|
||||
ICodeModule *ICodeGenerator::complete()
|
||||
ICodeModule *ICodeGenerator::complete(JSType *resultType)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
for (LabelList::iterator i = labels.begin();
|
||||
|
@ -188,7 +188,8 @@ ICodeModule *ICodeGenerator::complete()
|
|||
mParameterCount,
|
||||
mInstructionMap,
|
||||
mHasRestParameter,
|
||||
mHasNamedRestParameter);
|
||||
mHasNamedRestParameter,
|
||||
resultType);
|
||||
if (pLabels) {
|
||||
uint32 i;
|
||||
uint32 parameterInits = pLabels->size() - 1; // there's an extra label at the end for the actual entryPoint
|
||||
|
@ -695,15 +696,27 @@ static bool generatedBoolean(ExprNode *p)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool isSlotName(JSType *t, const StringAtom &name, uint32 &slotIndex, JSType *&type)
|
||||
static bool isSlotName(JSType *t, const StringAtom &name, uint32 &slotIndex, JSType *&type, bool lvalue)
|
||||
{
|
||||
JSClass* c = dynamic_cast<JSClass*>(t);
|
||||
while (c) {
|
||||
if (c->hasSlot(name)) {
|
||||
const JSSlot &s = c->getSlot(name);
|
||||
slotIndex = s.mIndex;
|
||||
type = s.mType;
|
||||
return true;
|
||||
if (lvalue) {
|
||||
if (s.mActual || s.mSetter) {
|
||||
slotIndex = s.mIndex;
|
||||
type = s.mType;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (s.mActual || s.mGetter) {
|
||||
slotIndex = s.mIndex;
|
||||
type = s.mType;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
c = c->getSuperClass();
|
||||
}
|
||||
|
@ -722,7 +735,7 @@ static bool isMethodName(JSType *t, const StringAtom &name, uint32 &slotIndex)
|
|||
}
|
||||
|
||||
|
||||
ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex)
|
||||
ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue)
|
||||
{
|
||||
if (!isWithinWith()) {
|
||||
v = variableList->findVariable(name);
|
||||
|
@ -731,7 +744,7 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n
|
|||
else {
|
||||
if (mClass) { // we're compiling a method of a class
|
||||
if (!isStaticMethod()) {
|
||||
if (isSlotName(mClass, name, slotIndex, v.second))
|
||||
if (isSlotName(mClass, name, slotIndex, v.second, lvalue))
|
||||
return Slot;
|
||||
if (isMethodName(mClass, name, slotIndex))
|
||||
return Method;
|
||||
|
@ -749,7 +762,7 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n
|
|||
return Name;
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args)
|
||||
TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue)
|
||||
{
|
||||
ASSERT(p->getKind() == ExprNode::identifier);
|
||||
|
||||
|
@ -758,7 +771,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
|
|||
TypedRegister v;
|
||||
|
||||
const StringAtom &name = (static_cast<IdentifierExprNode *>(p))->name;
|
||||
LValueKind lValueKind = resolveIdentifier(name, v, slotIndex);
|
||||
LValueKind lValueKind = resolveIdentifier(name, v, slotIndex, lvalue);
|
||||
JSType *targetType = v.second;
|
||||
|
||||
TypedRegister thisBase = TypedRegister(0, mClass ? mClass : &Any_Type);
|
||||
|
@ -907,7 +920,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
|
|||
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args)
|
||||
TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue)
|
||||
{
|
||||
ASSERT(b->getKind() == ExprNode::dot);
|
||||
|
||||
|
@ -924,7 +937,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I
|
|||
uint32 slotIndex;
|
||||
if ((b->op1->getKind() == ExprNode::identifier) && !isWithinWith()) {
|
||||
const StringAtom &baseName = (static_cast<IdentifierExprNode *>(b->op1))->name;
|
||||
resolveIdentifier(baseName, base, slotIndex);
|
||||
resolveIdentifier(baseName, base, slotIndex, false);
|
||||
|
||||
//
|
||||
// handle <class name>.<static field>
|
||||
|
@ -939,7 +952,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I
|
|||
}
|
||||
}
|
||||
if (lValueKind == Property) {
|
||||
if (isSlotName(base.second, fieldName, slotIndex, fieldType))
|
||||
if (isSlotName(base.second, fieldName, slotIndex, fieldType, lvalue))
|
||||
lValueKind = Slot;
|
||||
else
|
||||
if (isMethodName(base.second, fieldName, slotIndex))
|
||||
|
@ -956,7 +969,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I
|
|||
}
|
||||
else {
|
||||
base = genExpr(b->op1);
|
||||
if (isSlotName(base.second, fieldName, slotIndex, fieldType))
|
||||
if (isSlotName(base.second, fieldName, slotIndex, fieldType, lvalue))
|
||||
lValueKind = Slot;
|
||||
else
|
||||
if (isMethodName(base.second, fieldName, slotIndex))
|
||||
|
@ -1184,7 +1197,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
{
|
||||
UnaryExprNode *d = static_cast<UnaryExprNode *>(p);
|
||||
ASSERT(d->op->getKind() == ExprNode::dot);
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(d->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(d->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
// rather than getProperty(), need to do a deleteProperty().
|
||||
}
|
||||
break;
|
||||
|
@ -1193,21 +1206,33 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
|
||||
ArgumentList args;
|
||||
ExprPairList *p = i->pairs;
|
||||
uint32 count = 0;
|
||||
StringFormatter s;
|
||||
while (p) {
|
||||
if (p->field && (p->field->getKind() == ExprNode::identifier))
|
||||
args.push_back(Argument(genExpr(p->value), &(static_cast<IdentifierExprNode *>(p->field))->name));
|
||||
else
|
||||
args.push_back(Argument(genExpr(p->value), NULL ));
|
||||
if (p->field && (p->field->getKind() == ExprNode::string))
|
||||
args.push_back(Argument(genExpr(p->value), &mWorld->identifiers[(static_cast<StringExprNode *>(p->field))->str]));
|
||||
else {
|
||||
/* do this for new argument style to provide default 'positional' name
|
||||
s << count;
|
||||
args.push_back(Argument(genExpr(p->value), &mWorld->identifiers[s] ));
|
||||
s.clear();
|
||||
*/
|
||||
args.push_back(Argument(genExpr(p->value), NULL ));
|
||||
}
|
||||
count++;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (i->op->getKind() == ExprNode::dot) {
|
||||
BinaryExprNode *b = static_cast<BinaryExprNode *>(i->op);
|
||||
ret = handleDot(b, ExprNode::call, xcrementOp, ret, &args);
|
||||
ret = handleDot(b, ExprNode::call, xcrementOp, ret, &args, false);
|
||||
}
|
||||
else
|
||||
if (i->op->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(i->op), ExprNode::call, xcrementOp, ret, &args);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(i->op), ExprNode::call, xcrementOp, ret, &args, false);
|
||||
}
|
||||
else
|
||||
if (i->op->getKind() == ExprNode::index) {
|
||||
|
@ -1234,7 +1259,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
case ExprNode::dot :
|
||||
{
|
||||
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
|
||||
ret = handleDot(b, p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(b, p->getKind(), xcrementOp, ret, NULL, false);
|
||||
}
|
||||
break;
|
||||
case ExprNode::This :
|
||||
|
@ -1244,7 +1269,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
break;
|
||||
case ExprNode::identifier :
|
||||
{
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(p), ExprNode::identifier, xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(p), ExprNode::identifier, xcrementOp, ret, NULL, false);
|
||||
}
|
||||
break;
|
||||
case ExprNode::number :
|
||||
|
@ -1259,11 +1284,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
{
|
||||
UnaryExprNode *u = static_cast<UnaryExprNode *>(p);
|
||||
if (u->op->getKind() == ExprNode::dot) {
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (u->op->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (u->op->getKind() == ExprNode::index) {
|
||||
|
@ -1284,11 +1309,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
{
|
||||
UnaryExprNode *u = static_cast<UnaryExprNode *>(p);
|
||||
if (u->op->getKind() == ExprNode::dot) {
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (u->op->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (u->op->getKind() == ExprNode::index) {
|
||||
|
@ -1334,12 +1359,12 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
|
||||
ret = genExpr(b->op2);
|
||||
if (b->op1->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(b->op1), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(b->op1), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (b->op1->getKind() == ExprNode::dot) {
|
||||
BinaryExprNode *lb = static_cast<BinaryExprNode *>(b->op1);
|
||||
ret = handleDot(lb, p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(lb, p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (b->op1->getKind() == ExprNode::index) {
|
||||
|
@ -1367,12 +1392,12 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
|
||||
ret = genExpr(b->op2);
|
||||
if (b->op1->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(b->op1), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(b->op1), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (b->op1->getKind() == ExprNode::dot) {
|
||||
BinaryExprNode *lb = static_cast<BinaryExprNode *>(b->op1);
|
||||
ret = handleDot(lb, p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(lb, p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (b->op1->getKind() == ExprNode::index) {
|
||||
|
@ -1546,7 +1571,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
}
|
||||
icg.genStmt(f->function.body);
|
||||
//stdOut << icg;
|
||||
ICodeModule *icm = icg.complete();
|
||||
ICodeModule *icm = icg.complete(extractType(f->function.resultType));
|
||||
ret = newFunction(icm);
|
||||
}
|
||||
break;
|
||||
|
@ -1708,8 +1733,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
|
|||
TypedRegister thisValue = TypedRegister(0, mClass);
|
||||
icg.returnStmt(thisValue);
|
||||
}
|
||||
return icg.complete();
|
||||
|
||||
return icg.complete(extractType(f->function.resultType));
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
|
@ -1813,8 +1837,19 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
thisClass->defineStatic(name, &Function_Type);
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
}
|
||||
else
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1826,7 +1861,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
}
|
||||
|
||||
// add the instance initializer
|
||||
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete()));
|
||||
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete(&Void_Type)));
|
||||
// invent a default constructor if necessary, it just calls the
|
||||
// initializer and the superclass default constructor
|
||||
if (!hasDefaultConstructor) {
|
||||
|
@ -1839,7 +1874,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()));
|
||||
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete(&Void_Type)));
|
||||
}
|
||||
// freeze the class.
|
||||
thisClass->complete();
|
||||
|
@ -1848,7 +1883,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
// REVISIT: using the scope of the class to store both methods and statics.
|
||||
if (scg.getICode()->size()) {
|
||||
Interpreter::Context cx(*mWorld, thisScope);
|
||||
ICodeModule* clinit = scg.complete();
|
||||
ICodeModule* clinit = scg.complete(&Void_Type);
|
||||
cx.interpret(clinit, JSValues());
|
||||
delete clinit;
|
||||
}
|
||||
|
|
|
@ -94,7 +94,8 @@ namespace ICG {
|
|||
ICodeModule(InstructionStream *iCode, VariableList *variables,
|
||||
uint32 maxRegister, uint32 maxParameter,
|
||||
InstructionMap *instructionMap,
|
||||
bool hasRestParameter, bool hasNamedRestParameter) :
|
||||
bool hasRestParameter, bool hasNamedRestParameter,
|
||||
JSType *resultType) :
|
||||
its_iCode(iCode), itsVariables(variables),
|
||||
mParameterCount(maxParameter), itsMaxRegister(maxRegister),
|
||||
mID(++sMaxID), mInstructionMap(instructionMap),
|
||||
|
@ -102,7 +103,8 @@ namespace ICG {
|
|||
mNonOptionalParameterCount(maxParameter),
|
||||
mEntryPoint(0),
|
||||
mHasRestParameter(hasRestParameter),
|
||||
mHasNamedRestParameter(hasNamedRestParameter)
|
||||
mHasNamedRestParameter(hasNamedRestParameter),
|
||||
mResultType(resultType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -129,7 +131,8 @@ namespace ICG {
|
|||
uint32 mNonOptionalParameterCount;
|
||||
uint32 mEntryPoint;
|
||||
bool mHasRestParameter;
|
||||
bool mHasNamedRestParameter;
|
||||
bool mHasNamedRestParameter;
|
||||
JSType *mResultType;
|
||||
|
||||
static uint32 sMaxID;
|
||||
|
||||
|
@ -206,8 +209,6 @@ namespace ICG {
|
|||
TypedRegister allocateRegister(const StringAtom& name, JSType *type);
|
||||
|
||||
JSType *findType(const StringAtom& typeName);
|
||||
JSType *extractType(ExprNode *t);
|
||||
|
||||
|
||||
|
||||
void addParameterLabel(Label *label) { if (pLabels == NULL) pLabels = new LabelList(); pLabels->push_back(label); }
|
||||
|
@ -243,11 +244,11 @@ namespace ICG {
|
|||
void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); }
|
||||
|
||||
|
||||
typedef enum {Var, Property, Slot, Static, Constructor, Name, Method} LValueKind;
|
||||
typedef enum { Var, Property, Slot, Static, Constructor, Name, Method } LValueKind;
|
||||
|
||||
LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex);
|
||||
TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args);
|
||||
TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args);
|
||||
LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue);
|
||||
TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue);
|
||||
TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue);
|
||||
ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass);
|
||||
|
||||
public:
|
||||
|
@ -263,7 +264,9 @@ namespace ICG {
|
|||
}
|
||||
}
|
||||
|
||||
ICodeModule *complete();
|
||||
ICodeModule *complete(JSType *resultType);
|
||||
|
||||
JSType *extractType(ExprNode *t);
|
||||
|
||||
TypedRegister genExpr(ExprNode *p,
|
||||
bool needBoolValueInBranch = false,
|
||||
|
|
|
@ -114,23 +114,26 @@ struct Activation : public gc_base {
|
|||
}
|
||||
|
||||
// calling a binary operator, no 'this'
|
||||
Activation(ICodeModule* iCode, const JSValue arg1, const JSValue arg2)
|
||||
Activation(ICodeModule* iCode, const JSValue thisArg, const JSValue arg1, const JSValue arg2)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
|
||||
{
|
||||
mRegisters[0] = thisArg;
|
||||
mRegisters[1] = arg1;
|
||||
mRegisters[2] = arg2;
|
||||
}
|
||||
|
||||
// calling a getter function, no arguments
|
||||
Activation(ICodeModule* iCode)
|
||||
Activation(ICodeModule* iCode, const JSValue thisArg)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
|
||||
{
|
||||
mRegisters[0] = thisArg;
|
||||
}
|
||||
|
||||
// calling a setter function, 1 argument
|
||||
Activation(ICodeModule* iCode, const JSValue arg)
|
||||
Activation(ICodeModule* iCode, const JSValue thisArg, const JSValue arg)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
|
||||
{
|
||||
mRegisters[0] = thisArg;
|
||||
mRegisters[1] = arg;
|
||||
}
|
||||
|
||||
|
@ -165,7 +168,7 @@ ICodeModule* Context::compileFunction(const String &source)
|
|||
v = v->next;
|
||||
}
|
||||
icg.genStmt(f->function.body);
|
||||
ICodeModule* result = icg.complete();
|
||||
ICodeModule* result = icg.complete(icg.extractType(f->function.resultType));
|
||||
result->setFileName(filename);
|
||||
return result;
|
||||
}
|
||||
|
@ -238,7 +241,7 @@ ICodeModule* Context::genCode(StmtNode *p, const String &fileName)
|
|||
}
|
||||
icg.returnStmt(ret);
|
||||
|
||||
ICodeModule *icm = icg.complete();
|
||||
ICodeModule *icm = icg.complete(&Void_Type);
|
||||
icm->setFileName (fileName);
|
||||
return icm;
|
||||
}
|
||||
|
@ -717,6 +720,15 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
ArgumentList callArgs(pCount, Argument(TypedRegister(NotARegister, &Null_Type), NULL));
|
||||
if (icm->mHasNamedRestParameter) pCount--;
|
||||
|
||||
/*
|
||||
|
||||
For new style, there must be enough un-named parameters to satisfy #unnamed-positional, but no
|
||||
more than #total positional (unless there's a rest parameter). Extras go to the optional parameters first, then to rest.
|
||||
|
||||
Named parameters
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// walk along the given arguments, handling each.
|
||||
// might be good to optimize the case of calls without named arguments and/or rest parameters
|
||||
|
@ -886,7 +898,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
if (getter) {
|
||||
ASSERT(!getter->isNative());
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(ln));
|
||||
mActivation = new Activation(getter->getICode());
|
||||
mActivation = new Activation(getter->getICode(), kNullValue);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
|
@ -903,7 +915,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
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]);
|
||||
mActivation = new Activation(setter->getICode(), (*registers)[src1(sn).first], kNullValue);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
|
@ -1051,7 +1063,18 @@ using JSString throughout.
|
|||
JSValue& value = (*registers)[src1(gs).first];
|
||||
if (value.isObject()) {
|
||||
JSInstance* inst = static_cast<JSInstance *>(value.object);
|
||||
(*registers)[dst(gs).first] = (*inst)[src2(gs)];
|
||||
if (inst->hasGetter(src2(gs))) {
|
||||
JSFunction* getter = inst->getter(src2(gs));
|
||||
ASSERT(!getter->isNative());
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(gs));
|
||||
mActivation = new Activation(getter->getICode(), value);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
(*registers)[dst(gs).first] = (*inst)[src2(gs)];
|
||||
}
|
||||
// XXX runtime error
|
||||
}
|
||||
|
@ -1062,7 +1085,18 @@ using JSString throughout.
|
|||
JSValue& value = (*registers)[dst(ss).first];
|
||||
if (value.isObject()) {
|
||||
JSInstance* inst = static_cast<JSInstance *>(value.object);
|
||||
(*inst)[src1(ss)] = (*registers)[src2(ss).first];
|
||||
if (inst->hasSetter(src1(ss))) {
|
||||
JSFunction* setter = inst->setter(src1(ss));
|
||||
ASSERT(!setter->isNative());
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type));
|
||||
mActivation = new Activation(setter->getICode(), value, (*registers)[src2(ss).first]);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
(*inst)[src1(ss)] = (*registers)[src2(ss).first];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1143,7 +1177,7 @@ using JSString throughout.
|
|||
else {
|
||||
mLinkage = new Linkage(mLinkage, ++mPC,
|
||||
mActivation, mGlobal, dst(gbo));
|
||||
mActivation = new Activation(target->getICode(), r1, r2);
|
||||
mActivation = new Activation(target->getICode(), kNullValue, r1, r2);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
|
|
|
@ -181,6 +181,37 @@ static JSValue time(Context *cx, const JSValues &argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Poor man's instruction tracing facility.
|
||||
*/
|
||||
class Tracer : public Context::Listener {
|
||||
typedef InstructionStream::difference_type InstructionOffset;
|
||||
void listen(Context* context, Context::Event event)
|
||||
{
|
||||
if (event & Context::EV_STEP) {
|
||||
ICodeModule *iCode = context->getICode();
|
||||
JSValues ®isters = context->getRegisters();
|
||||
InstructionIterator pc = context->getPC();
|
||||
|
||||
|
||||
InstructionOffset offset = (pc - iCode->its_iCode->begin());
|
||||
printFormat(stdOut, "trace [%02u:%04u]: ",
|
||||
iCode->mID, offset);
|
||||
|
||||
Instruction* i = *pc;
|
||||
stdOut << *i;
|
||||
if (i->op() != BRANCH && i->count() > 0) {
|
||||
stdOut << " [";
|
||||
i->printOperands(stdOut, registers);
|
||||
stdOut << "]\n";
|
||||
} else {
|
||||
stdOut << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void readEvalPrint(FILE *in, World &world)
|
||||
{
|
||||
JSScope global;
|
||||
|
@ -196,7 +227,12 @@ static void readEvalPrint(FILE *in, World &world)
|
|||
String buffer;
|
||||
string line;
|
||||
LineReader inReader(in);
|
||||
|
||||
|
||||
#ifdef HAVE_GEORGE_TRACE_IT
|
||||
Tracer *george = new Tracer();
|
||||
cx.addListener(george);
|
||||
#endif
|
||||
|
||||
while (promptLine(inReader, line, buffer.empty() ? "js> " : "> ")) {
|
||||
appendChars(buffer, line.data(), line.size());
|
||||
try {
|
||||
|
@ -261,37 +297,6 @@ static void readEvalPrint(FILE *in, World &world)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Poor man's instruction tracing facility.
|
||||
*/
|
||||
class Tracer : public Context::Listener {
|
||||
typedef InstructionStream::difference_type InstructionOffset;
|
||||
void listen(Context* context, Context::Event event)
|
||||
{
|
||||
if (event & Context::EV_STEP) {
|
||||
ICodeModule *iCode = context->getICode();
|
||||
JSValues ®isters = context->getRegisters();
|
||||
InstructionIterator pc = context->getPC();
|
||||
|
||||
|
||||
InstructionOffset offset = (pc - iCode->its_iCode->begin());
|
||||
printFormat(stdOut, "trace [%02u:%04u]: ",
|
||||
iCode->mID, offset);
|
||||
|
||||
Instruction* i = *pc;
|
||||
stdOut << *i;
|
||||
if (i->op() != BRANCH && i->count() > 0) {
|
||||
stdOut << " [";
|
||||
i->printOperands(stdOut, registers);
|
||||
stdOut << "]\n";
|
||||
} else {
|
||||
stdOut << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
char * tests[] = {
|
||||
"function fact(n) { if (n > 1) return n * fact(n-1); else return 1; } print(fact(6), \" should be 720\"); return;" ,
|
||||
|
@ -316,7 +321,7 @@ static void testCompile()
|
|||
icg.genStmt(s);
|
||||
s = s->next;
|
||||
}
|
||||
cx.interpret(icg.complete(), JSValues());
|
||||
cx.interpret(icg.complete(&Void_Type), JSValues());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,17 +44,22 @@ namespace JSClasses {
|
|||
using JSTypes::JSType;
|
||||
using JSTypes::JSScope;
|
||||
using JSTypes::JSFunction;
|
||||
using JSTypes::FunctionMap;
|
||||
using ICG::ICodeModule;
|
||||
|
||||
|
||||
struct JSSlot {
|
||||
typedef enum { kNoFlag = 0, kIsConstructor = 0x01 } SlotFlags; // <-- readonly, enumerable etc
|
||||
|
||||
// a slot may have a getter or a setter or both, but NOT either if mActual
|
||||
JSType* mType;
|
||||
uint32 mIndex;
|
||||
SlotFlags mFlags;
|
||||
JSFunction* mGetter;
|
||||
JSFunction* mSetter;
|
||||
bool mActual;
|
||||
|
||||
JSSlot() : mType(0), mFlags(kNoFlag)
|
||||
JSSlot() : mType(0), mFlags(kNoFlag), mGetter(0), mSetter(0), mActual(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -83,13 +88,18 @@ namespace JSClasses {
|
|||
JSSlots mStaticSlots;
|
||||
JSValue* mStaticData;
|
||||
JSMethods mMethods;
|
||||
bool mHasGetters; // tracks whether any getters/setters get assigned
|
||||
bool mHasSetters;
|
||||
JSFunction **mGetters; // allocated at 'complete()' time
|
||||
JSFunction **mSetters;
|
||||
public:
|
||||
JSClass(JSScope* scope, const String& name, JSClass* superClass = 0)
|
||||
: JSType(name, superClass),
|
||||
mScope(new JSScope(scope)),
|
||||
mSlotCount(superClass ? superClass->mSlotCount : 0),
|
||||
mStaticCount(0),
|
||||
mStaticData(0)
|
||||
mStaticData(0),
|
||||
mHasGetters(false), mHasSetters(false), mGetters(0), mSetters(0)
|
||||
{
|
||||
if (superClass) {
|
||||
// inherit superclass methods
|
||||
|
@ -109,15 +119,76 @@ namespace JSClasses {
|
|||
return mScope;
|
||||
}
|
||||
|
||||
const JSSlot& defineSlot(const String& name, JSType* type)
|
||||
const JSSlot& defineSlot(const String& name, JSType* type, JSFunction* getter = 0, JSFunction* setter = 0)
|
||||
{
|
||||
JSSlot& slot = mSlots[name];
|
||||
ASSERT(slot.mType == 0);
|
||||
slot.mType = type;
|
||||
slot.mIndex = mSlotCount++; // starts at 0.
|
||||
slot.mSetter = setter;
|
||||
slot.mGetter = getter;
|
||||
if (setter || getter)
|
||||
slot.mActual = false;
|
||||
return slot;
|
||||
}
|
||||
|
||||
void setGetter(const String& name, JSFunction *getter, JSType* type)
|
||||
{
|
||||
JSSlots::iterator slti = mSlots.find(name);
|
||||
if (slti == mSlots.end())
|
||||
defineSlot(name, type, getter, 0);
|
||||
else {
|
||||
ASSERT(!slti->second.mActual);
|
||||
ASSERT(slti->second.mGetter == 0);
|
||||
slti->second.mGetter = getter;
|
||||
}
|
||||
mHasGetters = true;
|
||||
}
|
||||
|
||||
void setSetter(const String& name, JSFunction *setter, JSType* type)
|
||||
{
|
||||
JSSlots::iterator slti = mSlots.find(name);
|
||||
if (slti == mSlots.end())
|
||||
defineSlot(name, type, 0, setter);
|
||||
else {
|
||||
ASSERT(!slti->second.mActual);
|
||||
ASSERT(slti->second.mSetter == 0);
|
||||
slti->second.mSetter = setter;
|
||||
}
|
||||
mHasSetters = true;
|
||||
}
|
||||
|
||||
bool hasGetter(const String& name)
|
||||
{
|
||||
JSSlots::iterator slti = mSlots.find(name);
|
||||
return ((slti != mSlots.end()) && slti->second.mGetter);
|
||||
}
|
||||
|
||||
bool hasSetter(const String& name)
|
||||
{
|
||||
JSSlots::iterator slti = mSlots.find(name);
|
||||
return ((slti != mSlots.end()) && slti->second.mSetter);
|
||||
}
|
||||
|
||||
bool hasGetter(uint32 index)
|
||||
{
|
||||
return (mGetters && mGetters[index]);
|
||||
}
|
||||
|
||||
bool hasSetter(uint32 index)
|
||||
{
|
||||
return (mSetters && mSetters[index]);
|
||||
}
|
||||
|
||||
JSFunction* getter(uint32 index)
|
||||
{
|
||||
return mGetters[index];
|
||||
}
|
||||
|
||||
JSFunction* setter(uint32 index)
|
||||
{
|
||||
return mSetters[index];
|
||||
}
|
||||
|
||||
|
||||
const JSSlot& getSlot(const String& name)
|
||||
|
@ -130,6 +201,11 @@ namespace JSClasses {
|
|||
return (mSlots.find(name) != mSlots.end());
|
||||
}
|
||||
|
||||
bool hasGetterOrSetter(const String& name)
|
||||
{
|
||||
return (mSlots.find(name) != mSlots.end());
|
||||
}
|
||||
|
||||
JSSlots& getSlots()
|
||||
{
|
||||
return mSlots;
|
||||
|
@ -185,6 +261,15 @@ namespace JSClasses {
|
|||
|
||||
bool complete()
|
||||
{
|
||||
if (mHasGetters || mHasSetters) {
|
||||
if (mHasGetters) mGetters = new JSFunction*[mSlotCount];
|
||||
if (mHasSetters) mSetters = new JSFunction*[mSlotCount];
|
||||
JSSlots::iterator end = mSlots.end();
|
||||
for (JSSlots::iterator i = mSlots.begin(); i != end; i++) {
|
||||
if (mHasGetters) mGetters[i->second.mIndex] = i->second.mGetter;
|
||||
if (mHasSetters) mSetters[i->second.mIndex] = i->second.mSetter;
|
||||
}
|
||||
}
|
||||
mStaticData = new JSValue[mStaticCount];
|
||||
return (mStaticData != 0);
|
||||
}
|
||||
|
@ -292,6 +377,27 @@ namespace JSClasses {
|
|||
printSlots(f, getClass());
|
||||
}
|
||||
|
||||
bool hasGetter(uint32 index)
|
||||
{
|
||||
return getClass()->hasGetter(index);
|
||||
}
|
||||
|
||||
bool hasSetter(uint32 index)
|
||||
{
|
||||
return getClass()->hasSetter(index);
|
||||
}
|
||||
|
||||
JSFunction* getter(uint32 index)
|
||||
{
|
||||
return getClass()->getter(index);
|
||||
}
|
||||
|
||||
JSFunction* setter(uint32 index)
|
||||
{
|
||||
return getClass()->setter(index);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void printSlots(Formatter& f, JSClass* thisClass)
|
||||
{
|
||||
|
|
|
@ -139,7 +139,7 @@ TypedRegister ICodeGenerator::allocateVariable(const StringAtom& name, JSType *t
|
|||
return allocateRegister(name, type);
|
||||
}
|
||||
|
||||
ICodeModule *ICodeGenerator::complete()
|
||||
ICodeModule *ICodeGenerator::complete(JSType *resultType)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
for (LabelList::iterator i = labels.begin();
|
||||
|
@ -188,7 +188,8 @@ ICodeModule *ICodeGenerator::complete()
|
|||
mParameterCount,
|
||||
mInstructionMap,
|
||||
mHasRestParameter,
|
||||
mHasNamedRestParameter);
|
||||
mHasNamedRestParameter,
|
||||
resultType);
|
||||
if (pLabels) {
|
||||
uint32 i;
|
||||
uint32 parameterInits = pLabels->size() - 1; // there's an extra label at the end for the actual entryPoint
|
||||
|
@ -695,15 +696,27 @@ static bool generatedBoolean(ExprNode *p)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool isSlotName(JSType *t, const StringAtom &name, uint32 &slotIndex, JSType *&type)
|
||||
static bool isSlotName(JSType *t, const StringAtom &name, uint32 &slotIndex, JSType *&type, bool lvalue)
|
||||
{
|
||||
JSClass* c = dynamic_cast<JSClass*>(t);
|
||||
while (c) {
|
||||
if (c->hasSlot(name)) {
|
||||
const JSSlot &s = c->getSlot(name);
|
||||
slotIndex = s.mIndex;
|
||||
type = s.mType;
|
||||
return true;
|
||||
if (lvalue) {
|
||||
if (s.mActual || s.mSetter) {
|
||||
slotIndex = s.mIndex;
|
||||
type = s.mType;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (s.mActual || s.mGetter) {
|
||||
slotIndex = s.mIndex;
|
||||
type = s.mType;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
c = c->getSuperClass();
|
||||
}
|
||||
|
@ -722,7 +735,7 @@ static bool isMethodName(JSType *t, const StringAtom &name, uint32 &slotIndex)
|
|||
}
|
||||
|
||||
|
||||
ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex)
|
||||
ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue)
|
||||
{
|
||||
if (!isWithinWith()) {
|
||||
v = variableList->findVariable(name);
|
||||
|
@ -731,7 +744,7 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n
|
|||
else {
|
||||
if (mClass) { // we're compiling a method of a class
|
||||
if (!isStaticMethod()) {
|
||||
if (isSlotName(mClass, name, slotIndex, v.second))
|
||||
if (isSlotName(mClass, name, slotIndex, v.second, lvalue))
|
||||
return Slot;
|
||||
if (isMethodName(mClass, name, slotIndex))
|
||||
return Method;
|
||||
|
@ -749,7 +762,7 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n
|
|||
return Name;
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args)
|
||||
TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue)
|
||||
{
|
||||
ASSERT(p->getKind() == ExprNode::identifier);
|
||||
|
||||
|
@ -758,7 +771,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
|
|||
TypedRegister v;
|
||||
|
||||
const StringAtom &name = (static_cast<IdentifierExprNode *>(p))->name;
|
||||
LValueKind lValueKind = resolveIdentifier(name, v, slotIndex);
|
||||
LValueKind lValueKind = resolveIdentifier(name, v, slotIndex, lvalue);
|
||||
JSType *targetType = v.second;
|
||||
|
||||
TypedRegister thisBase = TypedRegister(0, mClass ? mClass : &Any_Type);
|
||||
|
@ -907,7 +920,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
|
|||
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args)
|
||||
TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue)
|
||||
{
|
||||
ASSERT(b->getKind() == ExprNode::dot);
|
||||
|
||||
|
@ -924,7 +937,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I
|
|||
uint32 slotIndex;
|
||||
if ((b->op1->getKind() == ExprNode::identifier) && !isWithinWith()) {
|
||||
const StringAtom &baseName = (static_cast<IdentifierExprNode *>(b->op1))->name;
|
||||
resolveIdentifier(baseName, base, slotIndex);
|
||||
resolveIdentifier(baseName, base, slotIndex, false);
|
||||
|
||||
//
|
||||
// handle <class name>.<static field>
|
||||
|
@ -939,7 +952,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I
|
|||
}
|
||||
}
|
||||
if (lValueKind == Property) {
|
||||
if (isSlotName(base.second, fieldName, slotIndex, fieldType))
|
||||
if (isSlotName(base.second, fieldName, slotIndex, fieldType, lvalue))
|
||||
lValueKind = Slot;
|
||||
else
|
||||
if (isMethodName(base.second, fieldName, slotIndex))
|
||||
|
@ -956,7 +969,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I
|
|||
}
|
||||
else {
|
||||
base = genExpr(b->op1);
|
||||
if (isSlotName(base.second, fieldName, slotIndex, fieldType))
|
||||
if (isSlotName(base.second, fieldName, slotIndex, fieldType, lvalue))
|
||||
lValueKind = Slot;
|
||||
else
|
||||
if (isMethodName(base.second, fieldName, slotIndex))
|
||||
|
@ -1184,7 +1197,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
{
|
||||
UnaryExprNode *d = static_cast<UnaryExprNode *>(p);
|
||||
ASSERT(d->op->getKind() == ExprNode::dot);
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(d->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(d->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
// rather than getProperty(), need to do a deleteProperty().
|
||||
}
|
||||
break;
|
||||
|
@ -1193,21 +1206,33 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
|
||||
ArgumentList args;
|
||||
ExprPairList *p = i->pairs;
|
||||
uint32 count = 0;
|
||||
StringFormatter s;
|
||||
while (p) {
|
||||
if (p->field && (p->field->getKind() == ExprNode::identifier))
|
||||
args.push_back(Argument(genExpr(p->value), &(static_cast<IdentifierExprNode *>(p->field))->name));
|
||||
else
|
||||
args.push_back(Argument(genExpr(p->value), NULL ));
|
||||
if (p->field && (p->field->getKind() == ExprNode::string))
|
||||
args.push_back(Argument(genExpr(p->value), &mWorld->identifiers[(static_cast<StringExprNode *>(p->field))->str]));
|
||||
else {
|
||||
/* do this for new argument style to provide default 'positional' name
|
||||
s << count;
|
||||
args.push_back(Argument(genExpr(p->value), &mWorld->identifiers[s] ));
|
||||
s.clear();
|
||||
*/
|
||||
args.push_back(Argument(genExpr(p->value), NULL ));
|
||||
}
|
||||
count++;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (i->op->getKind() == ExprNode::dot) {
|
||||
BinaryExprNode *b = static_cast<BinaryExprNode *>(i->op);
|
||||
ret = handleDot(b, ExprNode::call, xcrementOp, ret, &args);
|
||||
ret = handleDot(b, ExprNode::call, xcrementOp, ret, &args, false);
|
||||
}
|
||||
else
|
||||
if (i->op->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(i->op), ExprNode::call, xcrementOp, ret, &args);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(i->op), ExprNode::call, xcrementOp, ret, &args, false);
|
||||
}
|
||||
else
|
||||
if (i->op->getKind() == ExprNode::index) {
|
||||
|
@ -1234,7 +1259,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
case ExprNode::dot :
|
||||
{
|
||||
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
|
||||
ret = handleDot(b, p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(b, p->getKind(), xcrementOp, ret, NULL, false);
|
||||
}
|
||||
break;
|
||||
case ExprNode::This :
|
||||
|
@ -1244,7 +1269,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
break;
|
||||
case ExprNode::identifier :
|
||||
{
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(p), ExprNode::identifier, xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(p), ExprNode::identifier, xcrementOp, ret, NULL, false);
|
||||
}
|
||||
break;
|
||||
case ExprNode::number :
|
||||
|
@ -1259,11 +1284,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
{
|
||||
UnaryExprNode *u = static_cast<UnaryExprNode *>(p);
|
||||
if (u->op->getKind() == ExprNode::dot) {
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (u->op->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (u->op->getKind() == ExprNode::index) {
|
||||
|
@ -1284,11 +1309,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
{
|
||||
UnaryExprNode *u = static_cast<UnaryExprNode *>(p);
|
||||
if (u->op->getKind() == ExprNode::dot) {
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(static_cast<BinaryExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (u->op->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(u->op), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (u->op->getKind() == ExprNode::index) {
|
||||
|
@ -1334,12 +1359,12 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
|
||||
ret = genExpr(b->op2);
|
||||
if (b->op1->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(b->op1), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(b->op1), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (b->op1->getKind() == ExprNode::dot) {
|
||||
BinaryExprNode *lb = static_cast<BinaryExprNode *>(b->op1);
|
||||
ret = handleDot(lb, p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(lb, p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (b->op1->getKind() == ExprNode::index) {
|
||||
|
@ -1367,12 +1392,12 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
|
||||
ret = genExpr(b->op2);
|
||||
if (b->op1->getKind() == ExprNode::identifier) {
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(b->op1), p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleIdentifier(static_cast<IdentifierExprNode *>(b->op1), p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (b->op1->getKind() == ExprNode::dot) {
|
||||
BinaryExprNode *lb = static_cast<BinaryExprNode *>(b->op1);
|
||||
ret = handleDot(lb, p->getKind(), xcrementOp, ret, NULL);
|
||||
ret = handleDot(lb, p->getKind(), xcrementOp, ret, NULL, true);
|
||||
}
|
||||
else
|
||||
if (b->op1->getKind() == ExprNode::index) {
|
||||
|
@ -1546,7 +1571,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
}
|
||||
icg.genStmt(f->function.body);
|
||||
//stdOut << icg;
|
||||
ICodeModule *icm = icg.complete();
|
||||
ICodeModule *icm = icg.complete(extractType(f->function.resultType));
|
||||
ret = newFunction(icm);
|
||||
}
|
||||
break;
|
||||
|
@ -1708,8 +1733,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
|
|||
TypedRegister thisValue = TypedRegister(0, mClass);
|
||||
icg.returnStmt(thisValue);
|
||||
}
|
||||
return icg.complete();
|
||||
|
||||
return icg.complete(extractType(f->function.resultType));
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
|
@ -1813,8 +1837,19 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
thisClass->defineStatic(name, &Function_Type);
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
}
|
||||
else
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1826,7 +1861,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
}
|
||||
|
||||
// add the instance initializer
|
||||
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete()));
|
||||
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete(&Void_Type)));
|
||||
// invent a default constructor if necessary, it just calls the
|
||||
// initializer and the superclass default constructor
|
||||
if (!hasDefaultConstructor) {
|
||||
|
@ -1839,7 +1874,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()));
|
||||
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete(&Void_Type)));
|
||||
}
|
||||
// freeze the class.
|
||||
thisClass->complete();
|
||||
|
@ -1848,7 +1883,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
// REVISIT: using the scope of the class to store both methods and statics.
|
||||
if (scg.getICode()->size()) {
|
||||
Interpreter::Context cx(*mWorld, thisScope);
|
||||
ICodeModule* clinit = scg.complete();
|
||||
ICodeModule* clinit = scg.complete(&Void_Type);
|
||||
cx.interpret(clinit, JSValues());
|
||||
delete clinit;
|
||||
}
|
||||
|
|
|
@ -94,7 +94,8 @@ namespace ICG {
|
|||
ICodeModule(InstructionStream *iCode, VariableList *variables,
|
||||
uint32 maxRegister, uint32 maxParameter,
|
||||
InstructionMap *instructionMap,
|
||||
bool hasRestParameter, bool hasNamedRestParameter) :
|
||||
bool hasRestParameter, bool hasNamedRestParameter,
|
||||
JSType *resultType) :
|
||||
its_iCode(iCode), itsVariables(variables),
|
||||
mParameterCount(maxParameter), itsMaxRegister(maxRegister),
|
||||
mID(++sMaxID), mInstructionMap(instructionMap),
|
||||
|
@ -102,7 +103,8 @@ namespace ICG {
|
|||
mNonOptionalParameterCount(maxParameter),
|
||||
mEntryPoint(0),
|
||||
mHasRestParameter(hasRestParameter),
|
||||
mHasNamedRestParameter(hasNamedRestParameter)
|
||||
mHasNamedRestParameter(hasNamedRestParameter),
|
||||
mResultType(resultType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -129,7 +131,8 @@ namespace ICG {
|
|||
uint32 mNonOptionalParameterCount;
|
||||
uint32 mEntryPoint;
|
||||
bool mHasRestParameter;
|
||||
bool mHasNamedRestParameter;
|
||||
bool mHasNamedRestParameter;
|
||||
JSType *mResultType;
|
||||
|
||||
static uint32 sMaxID;
|
||||
|
||||
|
@ -206,8 +209,6 @@ namespace ICG {
|
|||
TypedRegister allocateRegister(const StringAtom& name, JSType *type);
|
||||
|
||||
JSType *findType(const StringAtom& typeName);
|
||||
JSType *extractType(ExprNode *t);
|
||||
|
||||
|
||||
|
||||
void addParameterLabel(Label *label) { if (pLabels == NULL) pLabels = new LabelList(); pLabels->push_back(label); }
|
||||
|
@ -243,11 +244,11 @@ namespace ICG {
|
|||
void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); }
|
||||
|
||||
|
||||
typedef enum {Var, Property, Slot, Static, Constructor, Name, Method} LValueKind;
|
||||
typedef enum { Var, Property, Slot, Static, Constructor, Name, Method } LValueKind;
|
||||
|
||||
LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex);
|
||||
TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args);
|
||||
TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args);
|
||||
LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue);
|
||||
TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue);
|
||||
TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue);
|
||||
ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass);
|
||||
|
||||
public:
|
||||
|
@ -263,7 +264,9 @@ namespace ICG {
|
|||
}
|
||||
}
|
||||
|
||||
ICodeModule *complete();
|
||||
ICodeModule *complete(JSType *resultType);
|
||||
|
||||
JSType *extractType(ExprNode *t);
|
||||
|
||||
TypedRegister genExpr(ExprNode *p,
|
||||
bool needBoolValueInBranch = false,
|
||||
|
|
|
@ -114,23 +114,26 @@ struct Activation : public gc_base {
|
|||
}
|
||||
|
||||
// calling a binary operator, no 'this'
|
||||
Activation(ICodeModule* iCode, const JSValue arg1, const JSValue arg2)
|
||||
Activation(ICodeModule* iCode, const JSValue thisArg, const JSValue arg1, const JSValue arg2)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
|
||||
{
|
||||
mRegisters[0] = thisArg;
|
||||
mRegisters[1] = arg1;
|
||||
mRegisters[2] = arg2;
|
||||
}
|
||||
|
||||
// calling a getter function, no arguments
|
||||
Activation(ICodeModule* iCode)
|
||||
Activation(ICodeModule* iCode, const JSValue thisArg)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
|
||||
{
|
||||
mRegisters[0] = thisArg;
|
||||
}
|
||||
|
||||
// calling a setter function, 1 argument
|
||||
Activation(ICodeModule* iCode, const JSValue arg)
|
||||
Activation(ICodeModule* iCode, const JSValue thisArg, const JSValue arg)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
|
||||
{
|
||||
mRegisters[0] = thisArg;
|
||||
mRegisters[1] = arg;
|
||||
}
|
||||
|
||||
|
@ -165,7 +168,7 @@ ICodeModule* Context::compileFunction(const String &source)
|
|||
v = v->next;
|
||||
}
|
||||
icg.genStmt(f->function.body);
|
||||
ICodeModule* result = icg.complete();
|
||||
ICodeModule* result = icg.complete(icg.extractType(f->function.resultType));
|
||||
result->setFileName(filename);
|
||||
return result;
|
||||
}
|
||||
|
@ -238,7 +241,7 @@ ICodeModule* Context::genCode(StmtNode *p, const String &fileName)
|
|||
}
|
||||
icg.returnStmt(ret);
|
||||
|
||||
ICodeModule *icm = icg.complete();
|
||||
ICodeModule *icm = icg.complete(&Void_Type);
|
||||
icm->setFileName (fileName);
|
||||
return icm;
|
||||
}
|
||||
|
@ -717,6 +720,15 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
ArgumentList callArgs(pCount, Argument(TypedRegister(NotARegister, &Null_Type), NULL));
|
||||
if (icm->mHasNamedRestParameter) pCount--;
|
||||
|
||||
/*
|
||||
|
||||
For new style, there must be enough un-named parameters to satisfy #unnamed-positional, but no
|
||||
more than #total positional (unless there's a rest parameter). Extras go to the optional parameters first, then to rest.
|
||||
|
||||
Named parameters
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// walk along the given arguments, handling each.
|
||||
// might be good to optimize the case of calls without named arguments and/or rest parameters
|
||||
|
@ -886,7 +898,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
if (getter) {
|
||||
ASSERT(!getter->isNative());
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(ln));
|
||||
mActivation = new Activation(getter->getICode());
|
||||
mActivation = new Activation(getter->getICode(), kNullValue);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
|
@ -903,7 +915,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
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]);
|
||||
mActivation = new Activation(setter->getICode(), (*registers)[src1(sn).first], kNullValue);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
|
@ -1051,7 +1063,18 @@ using JSString throughout.
|
|||
JSValue& value = (*registers)[src1(gs).first];
|
||||
if (value.isObject()) {
|
||||
JSInstance* inst = static_cast<JSInstance *>(value.object);
|
||||
(*registers)[dst(gs).first] = (*inst)[src2(gs)];
|
||||
if (inst->hasGetter(src2(gs))) {
|
||||
JSFunction* getter = inst->getter(src2(gs));
|
||||
ASSERT(!getter->isNative());
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(gs));
|
||||
mActivation = new Activation(getter->getICode(), value);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
(*registers)[dst(gs).first] = (*inst)[src2(gs)];
|
||||
}
|
||||
// XXX runtime error
|
||||
}
|
||||
|
@ -1062,7 +1085,18 @@ using JSString throughout.
|
|||
JSValue& value = (*registers)[dst(ss).first];
|
||||
if (value.isObject()) {
|
||||
JSInstance* inst = static_cast<JSInstance *>(value.object);
|
||||
(*inst)[src1(ss)] = (*registers)[src2(ss).first];
|
||||
if (inst->hasSetter(src1(ss))) {
|
||||
JSFunction* setter = inst->setter(src1(ss));
|
||||
ASSERT(!setter->isNative());
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type));
|
||||
mActivation = new Activation(setter->getICode(), value, (*registers)[src2(ss).first]);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
(*inst)[src1(ss)] = (*registers)[src2(ss).first];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1143,7 +1177,7 @@ using JSString throughout.
|
|||
else {
|
||||
mLinkage = new Linkage(mLinkage, ++mPC,
|
||||
mActivation, mGlobal, dst(gbo));
|
||||
mActivation = new Activation(target->getICode(), r1, r2);
|
||||
mActivation = new Activation(target->getICode(), kNullValue, r1, r2);
|
||||
registers = &mActivation->mRegisters;
|
||||
mPC = mActivation->mICode->its_iCode->begin();
|
||||
endPC = mActivation->mICode->its_iCode->end();
|
||||
|
|
|
@ -44,17 +44,22 @@ namespace JSClasses {
|
|||
using JSTypes::JSType;
|
||||
using JSTypes::JSScope;
|
||||
using JSTypes::JSFunction;
|
||||
using JSTypes::FunctionMap;
|
||||
using ICG::ICodeModule;
|
||||
|
||||
|
||||
struct JSSlot {
|
||||
typedef enum { kNoFlag = 0, kIsConstructor = 0x01 } SlotFlags; // <-- readonly, enumerable etc
|
||||
|
||||
// a slot may have a getter or a setter or both, but NOT either if mActual
|
||||
JSType* mType;
|
||||
uint32 mIndex;
|
||||
SlotFlags mFlags;
|
||||
JSFunction* mGetter;
|
||||
JSFunction* mSetter;
|
||||
bool mActual;
|
||||
|
||||
JSSlot() : mType(0), mFlags(kNoFlag)
|
||||
JSSlot() : mType(0), mFlags(kNoFlag), mGetter(0), mSetter(0), mActual(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -83,13 +88,18 @@ namespace JSClasses {
|
|||
JSSlots mStaticSlots;
|
||||
JSValue* mStaticData;
|
||||
JSMethods mMethods;
|
||||
bool mHasGetters; // tracks whether any getters/setters get assigned
|
||||
bool mHasSetters;
|
||||
JSFunction **mGetters; // allocated at 'complete()' time
|
||||
JSFunction **mSetters;
|
||||
public:
|
||||
JSClass(JSScope* scope, const String& name, JSClass* superClass = 0)
|
||||
: JSType(name, superClass),
|
||||
mScope(new JSScope(scope)),
|
||||
mSlotCount(superClass ? superClass->mSlotCount : 0),
|
||||
mStaticCount(0),
|
||||
mStaticData(0)
|
||||
mStaticData(0),
|
||||
mHasGetters(false), mHasSetters(false), mGetters(0), mSetters(0)
|
||||
{
|
||||
if (superClass) {
|
||||
// inherit superclass methods
|
||||
|
@ -109,15 +119,76 @@ namespace JSClasses {
|
|||
return mScope;
|
||||
}
|
||||
|
||||
const JSSlot& defineSlot(const String& name, JSType* type)
|
||||
const JSSlot& defineSlot(const String& name, JSType* type, JSFunction* getter = 0, JSFunction* setter = 0)
|
||||
{
|
||||
JSSlot& slot = mSlots[name];
|
||||
ASSERT(slot.mType == 0);
|
||||
slot.mType = type;
|
||||
slot.mIndex = mSlotCount++; // starts at 0.
|
||||
slot.mSetter = setter;
|
||||
slot.mGetter = getter;
|
||||
if (setter || getter)
|
||||
slot.mActual = false;
|
||||
return slot;
|
||||
}
|
||||
|
||||
void setGetter(const String& name, JSFunction *getter, JSType* type)
|
||||
{
|
||||
JSSlots::iterator slti = mSlots.find(name);
|
||||
if (slti == mSlots.end())
|
||||
defineSlot(name, type, getter, 0);
|
||||
else {
|
||||
ASSERT(!slti->second.mActual);
|
||||
ASSERT(slti->second.mGetter == 0);
|
||||
slti->second.mGetter = getter;
|
||||
}
|
||||
mHasGetters = true;
|
||||
}
|
||||
|
||||
void setSetter(const String& name, JSFunction *setter, JSType* type)
|
||||
{
|
||||
JSSlots::iterator slti = mSlots.find(name);
|
||||
if (slti == mSlots.end())
|
||||
defineSlot(name, type, 0, setter);
|
||||
else {
|
||||
ASSERT(!slti->second.mActual);
|
||||
ASSERT(slti->second.mSetter == 0);
|
||||
slti->second.mSetter = setter;
|
||||
}
|
||||
mHasSetters = true;
|
||||
}
|
||||
|
||||
bool hasGetter(const String& name)
|
||||
{
|
||||
JSSlots::iterator slti = mSlots.find(name);
|
||||
return ((slti != mSlots.end()) && slti->second.mGetter);
|
||||
}
|
||||
|
||||
bool hasSetter(const String& name)
|
||||
{
|
||||
JSSlots::iterator slti = mSlots.find(name);
|
||||
return ((slti != mSlots.end()) && slti->second.mSetter);
|
||||
}
|
||||
|
||||
bool hasGetter(uint32 index)
|
||||
{
|
||||
return (mGetters && mGetters[index]);
|
||||
}
|
||||
|
||||
bool hasSetter(uint32 index)
|
||||
{
|
||||
return (mSetters && mSetters[index]);
|
||||
}
|
||||
|
||||
JSFunction* getter(uint32 index)
|
||||
{
|
||||
return mGetters[index];
|
||||
}
|
||||
|
||||
JSFunction* setter(uint32 index)
|
||||
{
|
||||
return mSetters[index];
|
||||
}
|
||||
|
||||
|
||||
const JSSlot& getSlot(const String& name)
|
||||
|
@ -130,6 +201,11 @@ namespace JSClasses {
|
|||
return (mSlots.find(name) != mSlots.end());
|
||||
}
|
||||
|
||||
bool hasGetterOrSetter(const String& name)
|
||||
{
|
||||
return (mSlots.find(name) != mSlots.end());
|
||||
}
|
||||
|
||||
JSSlots& getSlots()
|
||||
{
|
||||
return mSlots;
|
||||
|
@ -185,6 +261,15 @@ namespace JSClasses {
|
|||
|
||||
bool complete()
|
||||
{
|
||||
if (mHasGetters || mHasSetters) {
|
||||
if (mHasGetters) mGetters = new JSFunction*[mSlotCount];
|
||||
if (mHasSetters) mSetters = new JSFunction*[mSlotCount];
|
||||
JSSlots::iterator end = mSlots.end();
|
||||
for (JSSlots::iterator i = mSlots.begin(); i != end; i++) {
|
||||
if (mHasGetters) mGetters[i->second.mIndex] = i->second.mGetter;
|
||||
if (mHasSetters) mSetters[i->second.mIndex] = i->second.mSetter;
|
||||
}
|
||||
}
|
||||
mStaticData = new JSValue[mStaticCount];
|
||||
return (mStaticData != 0);
|
||||
}
|
||||
|
@ -292,6 +377,27 @@ namespace JSClasses {
|
|||
printSlots(f, getClass());
|
||||
}
|
||||
|
||||
bool hasGetter(uint32 index)
|
||||
{
|
||||
return getClass()->hasGetter(index);
|
||||
}
|
||||
|
||||
bool hasSetter(uint32 index)
|
||||
{
|
||||
return getClass()->hasSetter(index);
|
||||
}
|
||||
|
||||
JSFunction* getter(uint32 index)
|
||||
{
|
||||
return getClass()->getter(index);
|
||||
}
|
||||
|
||||
JSFunction* setter(uint32 index)
|
||||
{
|
||||
return getClass()->setter(index);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void printSlots(Formatter& f, JSClass* thisClass)
|
||||
{
|
||||
|
|
|
@ -181,6 +181,37 @@ static JSValue time(Context *cx, const JSValues &argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Poor man's instruction tracing facility.
|
||||
*/
|
||||
class Tracer : public Context::Listener {
|
||||
typedef InstructionStream::difference_type InstructionOffset;
|
||||
void listen(Context* context, Context::Event event)
|
||||
{
|
||||
if (event & Context::EV_STEP) {
|
||||
ICodeModule *iCode = context->getICode();
|
||||
JSValues ®isters = context->getRegisters();
|
||||
InstructionIterator pc = context->getPC();
|
||||
|
||||
|
||||
InstructionOffset offset = (pc - iCode->its_iCode->begin());
|
||||
printFormat(stdOut, "trace [%02u:%04u]: ",
|
||||
iCode->mID, offset);
|
||||
|
||||
Instruction* i = *pc;
|
||||
stdOut << *i;
|
||||
if (i->op() != BRANCH && i->count() > 0) {
|
||||
stdOut << " [";
|
||||
i->printOperands(stdOut, registers);
|
||||
stdOut << "]\n";
|
||||
} else {
|
||||
stdOut << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void readEvalPrint(FILE *in, World &world)
|
||||
{
|
||||
JSScope global;
|
||||
|
@ -196,7 +227,12 @@ static void readEvalPrint(FILE *in, World &world)
|
|||
String buffer;
|
||||
string line;
|
||||
LineReader inReader(in);
|
||||
|
||||
|
||||
#ifdef HAVE_GEORGE_TRACE_IT
|
||||
Tracer *george = new Tracer();
|
||||
cx.addListener(george);
|
||||
#endif
|
||||
|
||||
while (promptLine(inReader, line, buffer.empty() ? "js> " : "> ")) {
|
||||
appendChars(buffer, line.data(), line.size());
|
||||
try {
|
||||
|
@ -261,37 +297,6 @@ static void readEvalPrint(FILE *in, World &world)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Poor man's instruction tracing facility.
|
||||
*/
|
||||
class Tracer : public Context::Listener {
|
||||
typedef InstructionStream::difference_type InstructionOffset;
|
||||
void listen(Context* context, Context::Event event)
|
||||
{
|
||||
if (event & Context::EV_STEP) {
|
||||
ICodeModule *iCode = context->getICode();
|
||||
JSValues ®isters = context->getRegisters();
|
||||
InstructionIterator pc = context->getPC();
|
||||
|
||||
|
||||
InstructionOffset offset = (pc - iCode->its_iCode->begin());
|
||||
printFormat(stdOut, "trace [%02u:%04u]: ",
|
||||
iCode->mID, offset);
|
||||
|
||||
Instruction* i = *pc;
|
||||
stdOut << *i;
|
||||
if (i->op() != BRANCH && i->count() > 0) {
|
||||
stdOut << " [";
|
||||
i->printOperands(stdOut, registers);
|
||||
stdOut << "]\n";
|
||||
} else {
|
||||
stdOut << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
char * tests[] = {
|
||||
"function fact(n) { if (n > 1) return n * fact(n-1); else return 1; } print(fact(6), \" should be 720\"); return;" ,
|
||||
|
@ -316,7 +321,7 @@ static void testCompile()
|
|||
icg.genStmt(s);
|
||||
s = s->next;
|
||||
}
|
||||
cx.interpret(icg.complete(), JSValues());
|
||||
cx.interpret(icg.complete(&Void_Type), JSValues());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче