Mods for getter/setter methods.

This commit is contained in:
rogerl%netscape.com 2000-10-09 22:21:26 +00:00
Родитель fd15c36a2e
Коммит 1db3618a98
10 изменённых файлов: 550 добавлений и 184 удалений

Просмотреть файл

@ -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 &registers = 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 &registers = 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 &registers = 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 &registers = 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());
}
}