Optional and rest parameters.

Named arguments (just begun).
This commit is contained in:
rogerl%netscape.com 2000-09-02 01:01:04 +00:00
parent beaefaeca8
commit 60221db240
18 changed files with 580 additions and 246 deletions

View File

@ -41,7 +41,7 @@
NEGATE, /* dest, source */
NEW_ARRAY, /* dest */
NEW_CLASS, /* dest, class */
NEW_FUNCTION, /* dest, ICodeModule */
NEW_FUNCTION, /* dest, ICodeModule, Function Definition */
NEW_OBJECT, /* dest, constructor */
NOP, /* do nothing and like it */
NOT, /* dest, source */
@ -143,11 +143,11 @@
/* print() and printOperands() inherited from GenericBranch */
};
class Call : public Instruction_4<TypedRegister, TypedRegister, TypedRegister, RegisterList> {
class Call : public Instruction_4<TypedRegister, TypedRegister, TypedRegister, ArgumentList> {
public:
/* result, target, this, args */
Call (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, RegisterList aOp4) :
Instruction_4<TypedRegister, TypedRegister, TypedRegister, RegisterList>
Call (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, ArgumentList aOp4) :
Instruction_4<TypedRegister, TypedRegister, TypedRegister, ArgumentList>
(CALL, aOp1, aOp2, aOp3, aOp4) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[CALL] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3 << ", " << mOp4;
@ -269,11 +269,11 @@
}
};
class DirectCall : public Instruction_3<TypedRegister, JSFunction *, RegisterList> {
class DirectCall : public Instruction_3<TypedRegister, JSFunction *, ArgumentList> {
public:
/* result, target, args */
DirectCall (TypedRegister aOp1, JSFunction * aOp2, RegisterList aOp3) :
Instruction_3<TypedRegister, JSFunction *, RegisterList>
DirectCall (TypedRegister aOp1, JSFunction * aOp2, ArgumentList aOp3) :
Instruction_3<TypedRegister, JSFunction *, ArgumentList>
(DIRECT_CALL, aOp1, aOp2, aOp3) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[DIRECT_CALL] << "\t" << mOp1 << ", " << "JSFunction" << ", " << mOp3;
@ -583,14 +583,14 @@
}
};
class NewFunction : public Instruction_2<TypedRegister, ICodeModule*> {
class NewFunction : public Instruction_3<TypedRegister, ICodeModule*, FunctionDefinition*> {
public:
/* dest, ICodeModule */
NewFunction (TypedRegister aOp1, ICodeModule* aOp2) :
Instruction_2<TypedRegister, ICodeModule*>
(NEW_FUNCTION, aOp1, aOp2) {};
/* dest, ICodeModule, Function Definition */
NewFunction (TypedRegister aOp1, ICodeModule* aOp2, FunctionDefinition* aOp3) :
Instruction_3<TypedRegister, ICodeModule*, FunctionDefinition*>
(NEW_FUNCTION, aOp1, aOp2, aOp3) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule";
f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule" << ", " << "FunctionDefinition";
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {

View File

@ -79,7 +79,10 @@ ICodeGenerator::ICodeGenerator(World *world, JSScope *global, JSClass *aClass, I
mGlobal(global),
mInstructionMap(new InstructionMap()),
mClass(aClass),
mFlags(flags)
mFlags(flags),
pLabels(NULL),
mHasRestParameter(false),
mHasNamedRestParameter(false)
{
iCode = new InstructionStream();
iCodeOwner = true;
@ -171,7 +174,23 @@ ICodeModule *ICodeGenerator::complete()
}
}
*/
ICodeModule* module = new ICodeModule(iCode, variableList, mPermanentRegister.size(), 0, mInstructionMap);
ICodeModule* module = new ICodeModule(iCode,
variableList,
mPermanentRegister.size(),
mParameterCount,
mInstructionMap,
mHasRestParameter,
mHasNamedRestParameter);
if (pLabels) {
uint32 i;
uint32 parameterInits = pLabels->size() - 1; // there's an extra label at the end for the actual entryPoint
module->mNonOptionalParameterCount -= parameterInits;
module->mParameterInit = new uint32[parameterInits];
for (i = 0; i < parameterInits; i++) {
module->mParameterInit[i] = (*pLabels)[i]->mOffset;
}
module->mEntryPoint = (*pLabels)[i]->mOffset;
}
iCodeOwner = false; // give ownership to the module.
return module;
}
@ -227,10 +246,10 @@ TypedRegister ICodeGenerator::newClass(JSClass *clazz)
return dest;
}
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm)
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm, FunctionDefinition *def)
{
TypedRegister dest(getTempRegister(), &Function_Type);
NewFunction *instr = new NewFunction(dest, icm);
NewFunction *instr = new NewFunction(dest, icm, def);
iCode->push_back(instr);
return dest;
}
@ -458,7 +477,7 @@ TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1,
return dest;
}
TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, RegisterList *args)
TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, ArgumentList *args)
{
TypedRegister dest(getTempRegister(), &Any_Type);
Call *instr = new Call(dest, target, thisArg, *args);
@ -466,7 +485,7 @@ TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg,
return dest;
}
TypedRegister ICodeGenerator::directCall(JSFunction *target, RegisterList *args)
TypedRegister ICodeGenerator::directCall(JSFunction *target, ArgumentList *args)
{
TypedRegister dest(getTempRegister(), &Any_Type);
DirectCall *instr = new DirectCall(dest, target, *args);
@ -537,10 +556,11 @@ Label *ICodeGenerator::getLabel()
return labels.back();
}
void ICodeGenerator::setLabel(Label *l)
Label *ICodeGenerator::setLabel(Label *l)
{
l->mBase = iCode;
l->mOffset = iCode->size();
return l;
}
/************************************************************************/
@ -711,7 +731,7 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n
return Name;
}
TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args)
TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args)
{
ASSERT(p->getKind() == ExprNode::identifier);
@ -836,26 +856,28 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
NOT_REACHED("Bad lvalue kind");
}
break;
case ExprNode::call:
switch (lValueKind) {
case Var:
ret = call(v, TypedRegister(NotARegister, &Null_Type), args);
break;
case Name:
ret = call(loadName(name), TypedRegister(NotARegister, &Null_Type), args);
break;
case Method:
ret = call(getMethod(thisBase, slotIndex), thisBase, args);
break;
case Static:
ret = call(getStatic(mClass, name), TypedRegister(NotARegister, &Null_Type), args);
break;
case Constructor:
ret = newClass(mClass);
call(getStatic(mClass, name), ret, args);
break;
default:
NOT_REACHED("Bad lvalue kind");
case ExprNode::call:
{
switch (lValueKind) {
case Var:
ret = call(v, TypedRegister(NotARegister, &Null_Type), args);
break;
case Name:
ret = call(loadName(name), TypedRegister(NotARegister, &Null_Type), args);
break;
case Method:
ret = call(getMethod(thisBase, slotIndex), thisBase, args);
break;
case Static:
ret = call(getStatic(mClass, name), TypedRegister(NotARegister, &Null_Type), args);
break;
case Constructor:
ret = newClass(mClass);
call(getStatic(mClass, name), ret, args);
break;
default:
NOT_REACHED("Bad lvalue kind");
}
}
break;
default:
@ -865,7 +887,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
}
TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args)
TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args)
{
ASSERT(b->getKind() == ExprNode::dot);
@ -1095,10 +1117,13 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::New:
{
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
RegisterList args;
ArgumentList args;
ExprPairList *p = i->pairs;
while (p) {
args.push_back(genExpr(p->value));
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 ));
p = p->next;
}
if (i->op->getKind() == ExprNode::identifier) {
@ -1145,10 +1170,13 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::call :
{
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
RegisterList args;
ArgumentList args;
ExprPairList *p = i->pairs;
while (p) {
args.push_back(genExpr(p->value));
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 ));
p = p->next;
}
@ -1498,7 +1526,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
icg.genStmt(f->function.body);
//stdOut << icg;
ICodeModule *icm = icg.complete();
ret = newFunction(icm);
ret = newFunction(icm, &f->function);
}
break;
@ -1555,6 +1583,17 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin
return false;
}
JSType *ICodeGenerator::extractType(ExprNode *t)
{
JSType* type = &Any_Type;
// FIXME: need to do code generation for type expressions.
if (t && (t->getKind() == ExprNode::identifier)) {
IdentifierExprNode* typeExpr = static_cast<IdentifierExprNode*>(t);
type = findType(typeExpr->name);
}
return type;
}
ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superclass)
{
bool isStatic = hasAttribute(f->attributes, Token::Static);
@ -1564,13 +1603,47 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
icg.allocateParameter(mWorld->identifiers["this"], (mClass) ? mClass : &Any_Type); // always parameter #0
VariableBinding *v = f->function.parameters;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier))
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name);
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
JSType *pType;
if ((v == f->function.restParameter) && (v->type == NULL))
pType = &Array_Type;
else
pType = extractType(v->type);
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name, pType);
}
else
NOT_REACHED("qualified or un-named parameters not handled; bugger off.");
v = v->next;
}
v = f->function.optParameters;
if (v) {
while (v) { // include the rest parameter, as it may have an initializer
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
icg.addParameterLabel(icg.setLabel(icg.getLabel()));
if (v->initializer) { // might be NULL when we get to the restParameter
TypedRegister p = icg.genExpr(v->name);
icg.move(p, icg.genExpr(v->initializer));
}
}
v = v->next;
}
icg.addParameterLabel(icg.setLabel(icg.getLabel())); // to provide the entry-point for the default case
}
v = f->function.restParameter;
if (v) {
icg.mHasRestParameter = true;
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
icg.mHasNamedRestParameter = true;
}
}
if (isConstructor) {
/*
See if the first statement is an expression statement consisting
of a call to super(). If not we need to add a call to the default
superclass constructor ourselves.
*/
TypedRegister thisValue = TypedRegister(0, mClass);
RegisterList args;
ArgumentList args;
if (superclass) {
bool foundSuperCall = false;
BlockStmtNode *b = f->function.body;
@ -1664,12 +1737,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
if (v->name) {
ASSERT(v->name->getKind() == ExprNode::identifier);
IdentifierExprNode* idExpr = static_cast<IdentifierExprNode*>(v->name);
JSType* type = &Any_Type;
// FIXME: need to do code generation for type expressions.
if (v->type && v->type->getKind() == ExprNode::identifier) {
IdentifierExprNode* typeExpr = static_cast<IdentifierExprNode*>(v->type);
type = findType(typeExpr->name);
}
JSType* type = extractType(v->type);
if (isStatic) {
thisClass->defineStatic(idExpr->name, type);
if (v->initializer) {
@ -1705,15 +1773,15 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
if (name == nameExpr->name)
hasDefaultConstructor = true;
thisClass->defineConstructor(name);
scg.setStatic(thisClass, name, scg.newFunction(icm));
scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function));
}
else
if (isStatic) {
thisClass->defineStatic(name, &Function_Type);
scg.setStatic(thisClass, name, scg.newFunction(icm));
scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function));
}
else
thisClass->defineMethod(name, new JSFunction(icm));
thisClass->defineMethod(name, new JSFunction(icm, &f->function));
}
}
break;
@ -1725,12 +1793,12 @@ 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(), NULL));
// invent a default constructor if necessary, it just calls the
// initializer and the superclass default constructor
if (!hasDefaultConstructor) {
TypedRegister thisValue = TypedRegister(0, thisClass);
RegisterList args;
ArgumentList args;
ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod);
icg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0
if (superclass)
@ -1738,7 +1806,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(), NULL));
}
// freeze the class.
thisClass->complete();
@ -1760,7 +1828,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
ICodeModule *icm = genFunction(f, false, NULL);
if (f->function.name->getKind() == ExprNode::identifier) {
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
mGlobal->defineFunction(name, icm);
mGlobal->defineFunction(name, icm, &f->function);
}
}
break;

View File

@ -58,15 +58,25 @@ namespace ICG {
public:
ICodeModule(InstructionStream *iCode, VariableList *variables,
uint32 maxRegister, uint32 maxParameter,
InstructionMap *instructionMap) :
InstructionMap *instructionMap,
bool hasRestParameter, bool hasNamedRestParameter) :
its_iCode(iCode), itsVariables(variables),
itsParameterCount(maxParameter), itsMaxRegister(maxRegister),
mID(++sMaxID), mInstructionMap(instructionMap) { }
mParameterCount(maxParameter), itsMaxRegister(maxRegister),
mID(++sMaxID), mInstructionMap(instructionMap),
mParameterInit(NULL),
mNonOptionalParameterCount(maxParameter),
mEntryPoint(0),
mHasRestParameter(hasRestParameter),
mHasNamedRestParameter(hasNamedRestParameter)
{
}
~ICodeModule()
{
delete its_iCode;
delete itsVariables;
delete mInstructionMap;
if (mParameterInit) delete mParameterInit;
}
Formatter& print(Formatter& f);
@ -75,11 +85,16 @@ namespace ICG {
InstructionStream *its_iCode;
VariableList *itsVariables;
uint32 itsParameterCount;
uint32 mParameterCount;
uint32 itsMaxRegister;
uint32 mID;
InstructionMap *mInstructionMap;
String mFileName;
uint32 *mParameterInit;
uint32 mNonOptionalParameterCount;
uint32 mEntryPoint;
bool mHasRestParameter;
bool mHasNamedRestParameter;
static uint32 sMaxID;
@ -132,6 +147,9 @@ namespace ICG {
JSClass *mClass; // enclosing class when generating code for methods
ICodeGeneratorFlags mFlags; // assorted flags
LabelList *pLabels; // label for each parameter initialization entry point
bool mHasRestParameter; // true if this function has a ... parameter
bool mHasNamedRestParameter; // true if this function has a named ... parameter
std::vector<bool> mPermanentRegister;
@ -155,13 +173,14 @@ namespace ICG {
void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; }
JSType *findType(const StringAtom& typeName);
JSType *extractType(ExprNode *t);
void addParameterLabel(Label *label) { if (pLabels == NULL) pLabels = new LabelList(); pLabels->push_back(label); }
void setLabel(Label *label);
Label *setLabel(Label *label);
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
void rts() { iCode->push_back(new Rts()); }
@ -193,8 +212,8 @@ namespace ICG {
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, RegisterList *args);
TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args);
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);
ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass);
public:
@ -206,6 +225,7 @@ namespace ICG {
if (iCodeOwner) {
delete iCode;
delete mInstructionMap;
if (pLabels) delete pLabels;
}
}
@ -242,8 +262,8 @@ namespace ICG {
TypedRegister op(ICodeOp op, TypedRegister source);
TypedRegister op(ICodeOp op, TypedRegister source1, TypedRegister source2);
TypedRegister binaryOp(ICodeOp op, TypedRegister source1, TypedRegister source2);
TypedRegister call(TypedRegister base, TypedRegister target, RegisterList *args);
TypedRegister directCall(JSFunction *target, RegisterList *args);
TypedRegister call(TypedRegister base, TypedRegister target, ArgumentList *args);
TypedRegister directCall(JSFunction *target, ArgumentList *args);
TypedRegister getMethod(TypedRegister thisArg, uint32 slotIndex);
void move(TypedRegister destination, TypedRegister source);
@ -257,7 +277,7 @@ namespace ICG {
TypedRegister newObject(TypedRegister constructor);
TypedRegister newArray();
TypedRegister newFunction(ICodeModule *icm);
TypedRegister newFunction(ICodeModule *icm, FunctionDefinition *def);
TypedRegister newClass(JSClass *clazz);
TypedRegister cast(TypedRegister arg, JSType *toType);

View File

@ -96,16 +96,16 @@ struct Activation : public gc_base {
}
Activation(ICodeModule* iCode, Activation* caller, const JSValue thisArg,
const RegisterList& list)
const ArgumentList& list)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
// copy caller's parameter list to initial registers.
JSValues::iterator dest = mRegisters.begin();
*dest++ = thisArg;
const JSValues& params = caller->mRegisters;
for (RegisterList::const_iterator src = list.begin(),
for (ArgumentList::const_iterator src = list.begin(),
end = list.end(); src != end; ++src, ++dest) {
*dest = params[(*src).first];
*dest = params[(*src).first.first];
}
}
@ -593,6 +593,16 @@ const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2,
return JSValue((*candidate)->function);
}
bool Context::hasNamedArguments(ArgumentList &args)
{
Argument* e = args.end();
for (ArgumentList::iterator r = args.begin(); r != e; r++) {
if ((*r).second) return true;
}
return false;
}
JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
{
assert(mActivation == 0); /* recursion == bad */
@ -666,13 +676,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
if (!target)
throw new JSException("Call to non callable object");
if (target->isNative()) {
RegisterList &params = op4(call);
ArgumentList &params = op4(call);
JSValues argv(params.size() + 1);
argv[0] = (*registers)[op3(call).first];
JSValues::size_type i = 1;
for (RegisterList::const_iterator src = params.begin(), end = params.end();
for (ArgumentList::const_iterator src = params.begin(), end = params.end();
src != end; ++src, ++i) {
argv[i] = (*registers)[src->first];
argv[i] = (*registers)[src->first.first];
}
JSValue result = static_cast<JSNativeFunction*>(target)->mCode(this, argv);
if (op1(call).first != NotARegister)
@ -680,11 +690,56 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
break;
}
else {
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, mGlobal, op1(call));
mActivation = new Activation(target->getICode(), mActivation, (*registers)[op3(call).first], op4(call));
ICodeModule *icm = target->getICode();
ArgumentList &args = op4(call);
ArgumentList newArgs(args.size());
uint32 argCount = args.size() + 1; // the 'this' arg is travelling separately
if (hasNamedArguments(args)) {
// find argument names that match parameter names
for (uint32 a = 0; a < args.size(); a++) {
if (args[a].second) {
VariableList::iterator i = icm->itsVariables->find(*(args[a].second));
if (i != icm->itsVariables->end()) {
TypedRegister r = (*i).second;
if (r.first < icm->mParameterCount) { // make sure we didn't match a local var
// the named argument is arriving in slot a, but needs to be r instead
newArgs[r.first - 1] = Argument(args[a].first, NULL);
}
}
}
}
args = newArgs;
}
uint32 pOffset = icm->mEntryPoint;
if (argCount < icm->mNonOptionalParameterCount)
throw new JSException("Too few arguments in call");
if (argCount >= icm->mParameterCount) {
if (icm->mHasRestParameter) {
if (icm->mHasNamedRestParameter) {
uint32 restArgsCount = argCount - icm->mParameterCount + 1;
uint32 restArgsStart = icm->mParameterCount - 2; // 1 for 'this', 1 for 0-based
JSArray *r = new JSArray(restArgsCount);
for (uint32 i = 0; i < restArgsCount; i++)
(*r)[i] = (*registers)[args[i + restArgsStart].first.first];
(*registers)[args[restArgsStart].first.first] = r;
}
// else, we just ignore the other arguments
}
else {
if (argCount > icm->mParameterCount)
throw new JSException("Too many arguments in call");
}
}
else {
if (argCount < icm->mParameterCount)
pOffset = icm->mParameterInit[argCount - icm->mNonOptionalParameterCount];
}
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call));
mActivation = new Activation(icm, mActivation, (*registers)[op3(call).first], args);
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
mPC = mActivation->mICode->its_iCode->begin() + pOffset;
endPC = mActivation->mICode->its_iCode->end();
continue;
}
@ -695,12 +750,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
DirectCall* call = static_cast<DirectCall*>(instruction);
JSFunction *target = op2(call);
if (target->isNative()) {
RegisterList &params = op3(call);
ArgumentList &params = op3(call);
JSValues argv(params.size() + 1);
JSValues::size_type i = 1;
for (RegisterList::const_iterator src = params.begin(), end = params.end();
for (ArgumentList::const_iterator src = params.begin(), end = params.end();
src != end; ++src, ++i) {
argv[i] = (*registers)[src->first];
argv[i] = (*registers)[src->first.first];
}
JSValue result = static_cast<JSNativeFunction*>(target)->mCode(this, argv);
if (op1(call).first != NotARegister)
@ -799,7 +854,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case NEW_FUNCTION:
{
NewFunction* nf = static_cast<NewFunction*>(instruction);
(*registers)[dst(nf).first] = new JSFunction(src1(nf));
(*registers)[dst(nf).first] = new JSFunction(src1(nf), src2(nf));
}
break;
case NEW_ARRAY:
@ -1380,7 +1435,7 @@ using JSString throughout.
}
}
mActivation = 0;
return rv;
} /* interpret */

View File

@ -90,6 +90,7 @@ namespace Interpreter {
private:
void broadcast(Event event);
void initOperatorsPackage();
bool hasNamedArguments(ArgumentList &args);
private:
World& mWorld;

View File

@ -125,7 +125,7 @@ static JSValue function_constructor(Context *cx, const JSValues& argv)
source.append(JSValue::valueToString(argv[argv.size() - 1]).string);
source.append("}");
JSFunction *f = new JSFunction(cx->compileFunction(source));
JSFunction *f = new JSFunction(cx->compileFunction(source), NULL);
f->setProperty(widenCString("length"), JSValue(parameterCount));
JSObject *obj = new JSObject();
f->setProperty(widenCString("prototype"), JSValue(obj));
@ -496,11 +496,20 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
printFormat(f, "Object @ 0x%08X\n", value.object);
f << *value.object;
break;
case JSValue::array_tag:
printFormat(f, "Array @ 0x%08X", value.object);
case JSValue::array_tag: {
JSArray *a = value.array;
f << "[";
for (uint32 i = 0; i < a->length(); i++) {
f << (*a)[i];
if (i < (a->length() - 1))
f << ", ";
}
f << "]";
// printFormat(f, "Array @ 0x%08X", value.array);
}
break;
case JSValue::function_tag:
printFormat(f, "Function @ 0x%08X", value.object);
printFormat(f, "Function @ 0x%08X", value.function);
break;
case JSValue::string_tag:
f << "\"" << *value.string << "\"";

View File

@ -36,6 +36,7 @@
#include "utilities.h"
#include "gc_allocator.h"
#include "parser.h"
#include <vector>
#include <map>
#include <stack>
@ -205,18 +206,18 @@ namespace JSTypes {
extern const JSValue kPositiveInfinity;
// JS2 predefined types:
extern JSType Any_Type;
extern JSType Integer_Type;
extern JSType Number_Type;
extern JSType Character_Type;
extern JSType String_Type;
extern JSType Function_Type;
extern JSType Array_Type;
extern JSType Type_Type;
extern JSType Boolean_Type;
extern JSType Null_Type;
extern JSType Void_Type;
extern JSType None_Type;
extern JSType Any_Type;
extern JSType Integer_Type;
extern JSType Number_Type;
extern JSType Character_Type;
extern JSType String_Type;
extern JSType Function_Type;
extern JSType Array_Type;
extern JSType Type_Type;
extern JSType Boolean_Type;
extern JSType Null_Type;
extern JSType Void_Type;
extern JSType None_Type;
// JS1X heritage classes as types:
extern JSType Object_Type;
@ -423,8 +424,12 @@ namespace JSTypes {
static JSString* FunctionString;
static JSObject* FunctionPrototypeObject;
ICodeModule* mICode;
uint32 mParameterCount;
bool mParameterInfo;
protected:
JSFunction() : mICode(0) {}
JSFunction() : mICode(0), mParameterCount(0) {}
typedef JavaScript::gc_traits_finalizable<JSFunction> traits;
typedef gc_allocator<JSFunction, traits> allocator;
@ -432,13 +437,21 @@ namespace JSTypes {
public:
static void initFunctionObject(JSScope *g);
JSFunction(ICodeModule* iCode)
JSFunction(ICodeModule* iCode, FunctionDefinition *def)
: JSObject(FunctionPrototypeObject),
mICode(iCode)
mICode(iCode), mParameterCount(0), mParameterInfo(false)
{
setClass(FunctionString);
if (def) {
mParameterInfo = true;
VariableBinding *p = def->parameters;
while (p) { mParameterCount++; p = p->next; }
}
}
uint32 getParameterCount() { return mParameterCount; }
bool hasParameterInfo() { return mParameterInfo; }
~JSFunction();
void* operator new(size_t) { return allocator::allocate(1); }
@ -547,9 +560,9 @@ namespace JSTypes {
return result;
}
JSValue& defineFunction(const String& name, ICodeModule* iCode)
JSValue& defineFunction(const String& name, ICodeModule* iCode, FunctionDefinition *def)
{
JSValue value(new JSFunction(iCode));
JSValue value(new JSFunction(iCode, def));
return defineVariable(name, &Function_Type, value);
}

View File

@ -47,13 +47,13 @@ Formatter& operator<< (Formatter& f, Instruction& i)
return i.print(f);
}
Formatter& operator<< (Formatter& f, RegisterList& rl)
Formatter& operator<< (Formatter& f, ArgumentList& rl)
{
TypedRegister* e = rl.end();
Argument* e = rl.end();
f << "(";
for (RegisterList::iterator r = rl.begin(); r != e; r++) {
f << "R" << r->first;
for (ArgumentList::iterator r = rl.begin(); r != e; r++) {
f << "R" << r->first.first;
if ((r + 1) != e)
f << ", ";
}
@ -64,16 +64,16 @@ Formatter& operator<< (Formatter& f, RegisterList& rl)
Formatter& operator<< (Formatter& f, const ArgList& al)
{
const RegisterList& rl = al.mList;
const ArgumentList& rl = al.mList;
const JSValues& registers = al.mRegisters;
f << "(";
RegisterList::const_iterator i = rl.begin(), e = rl.end();
ArgumentList::const_iterator i = rl.begin(), e = rl.end();
if (i != e) {
TypedRegister r = *i++;
f << "R" << r.first << '=' << registers[r.first];
Argument r = *i++;
f << "R" << r.first.first << '=' << registers[r.first.first];
while (i != e) {
r = *i++;
f << ", R" << r.first << '=' << registers[r.first];
f << ", R" << r.first << '=' << registers[r.first.first];
}
}
f << ")";

View File

@ -86,7 +86,8 @@ namespace VM {
/********************************************************************/
typedef std::pair<Register, JSType*> TypedRegister;
typedef std::vector<TypedRegister> RegisterList;
typedef std::pair<TypedRegister, const StringAtom*> Argument;
typedef std::vector<Argument> ArgumentList;
typedef std::vector<Instruction *> InstructionStream;
typedef InstructionStream::iterator InstructionIterator;
typedef std::map<String, TypedRegister, std::less<String> > VariableMap;
@ -96,16 +97,16 @@ namespace VM {
* Helper to print Call operands.
*/
struct ArgList {
const RegisterList& mList;
const ArgumentList& mList;
const JSValues& mRegisters;
ArgList(const RegisterList& rl, const JSValues& registers)
ArgList(const ArgumentList& rl, const JSValues& registers)
: mList(rl), mRegisters(registers) {}
};
/********************************************************************/
Formatter& operator<< (Formatter& f, Instruction& i);
Formatter& operator<< (Formatter& f, RegisterList& rl);
Formatter& operator<< (Formatter& f, ArgumentList& rl);
Formatter& operator<< (Formatter& f, const ArgList& al);
Formatter& operator<< (Formatter& f, InstructionStream& is);
Formatter& operator<< (Formatter& f, TypedRegister& r);

View File

@ -41,7 +41,7 @@
NEGATE, /* dest, source */
NEW_ARRAY, /* dest */
NEW_CLASS, /* dest, class */
NEW_FUNCTION, /* dest, ICodeModule */
NEW_FUNCTION, /* dest, ICodeModule, Function Definition */
NEW_OBJECT, /* dest, constructor */
NOP, /* do nothing and like it */
NOT, /* dest, source */
@ -143,11 +143,11 @@
/* print() and printOperands() inherited from GenericBranch */
};
class Call : public Instruction_4<TypedRegister, TypedRegister, TypedRegister, RegisterList> {
class Call : public Instruction_4<TypedRegister, TypedRegister, TypedRegister, ArgumentList> {
public:
/* result, target, this, args */
Call (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, RegisterList aOp4) :
Instruction_4<TypedRegister, TypedRegister, TypedRegister, RegisterList>
Call (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, ArgumentList aOp4) :
Instruction_4<TypedRegister, TypedRegister, TypedRegister, ArgumentList>
(CALL, aOp1, aOp2, aOp3, aOp4) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[CALL] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3 << ", " << mOp4;
@ -269,11 +269,11 @@
}
};
class DirectCall : public Instruction_3<TypedRegister, JSFunction *, RegisterList> {
class DirectCall : public Instruction_3<TypedRegister, JSFunction *, ArgumentList> {
public:
/* result, target, args */
DirectCall (TypedRegister aOp1, JSFunction * aOp2, RegisterList aOp3) :
Instruction_3<TypedRegister, JSFunction *, RegisterList>
DirectCall (TypedRegister aOp1, JSFunction * aOp2, ArgumentList aOp3) :
Instruction_3<TypedRegister, JSFunction *, ArgumentList>
(DIRECT_CALL, aOp1, aOp2, aOp3) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[DIRECT_CALL] << "\t" << mOp1 << ", " << "JSFunction" << ", " << mOp3;
@ -583,14 +583,14 @@
}
};
class NewFunction : public Instruction_2<TypedRegister, ICodeModule*> {
class NewFunction : public Instruction_3<TypedRegister, ICodeModule*, FunctionDefinition*> {
public:
/* dest, ICodeModule */
NewFunction (TypedRegister aOp1, ICodeModule* aOp2) :
Instruction_2<TypedRegister, ICodeModule*>
(NEW_FUNCTION, aOp1, aOp2) {};
/* dest, ICodeModule, Function Definition */
NewFunction (TypedRegister aOp1, ICodeModule* aOp2, FunctionDefinition* aOp3) :
Instruction_3<TypedRegister, ICodeModule*, FunctionDefinition*>
(NEW_FUNCTION, aOp1, aOp2, aOp3) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule";
f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule" << ", " << "FunctionDefinition";
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {

View File

@ -79,7 +79,10 @@ ICodeGenerator::ICodeGenerator(World *world, JSScope *global, JSClass *aClass, I
mGlobal(global),
mInstructionMap(new InstructionMap()),
mClass(aClass),
mFlags(flags)
mFlags(flags),
pLabels(NULL),
mHasRestParameter(false),
mHasNamedRestParameter(false)
{
iCode = new InstructionStream();
iCodeOwner = true;
@ -171,7 +174,23 @@ ICodeModule *ICodeGenerator::complete()
}
}
*/
ICodeModule* module = new ICodeModule(iCode, variableList, mPermanentRegister.size(), 0, mInstructionMap);
ICodeModule* module = new ICodeModule(iCode,
variableList,
mPermanentRegister.size(),
mParameterCount,
mInstructionMap,
mHasRestParameter,
mHasNamedRestParameter);
if (pLabels) {
uint32 i;
uint32 parameterInits = pLabels->size() - 1; // there's an extra label at the end for the actual entryPoint
module->mNonOptionalParameterCount -= parameterInits;
module->mParameterInit = new uint32[parameterInits];
for (i = 0; i < parameterInits; i++) {
module->mParameterInit[i] = (*pLabels)[i]->mOffset;
}
module->mEntryPoint = (*pLabels)[i]->mOffset;
}
iCodeOwner = false; // give ownership to the module.
return module;
}
@ -227,10 +246,10 @@ TypedRegister ICodeGenerator::newClass(JSClass *clazz)
return dest;
}
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm)
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm, FunctionDefinition *def)
{
TypedRegister dest(getTempRegister(), &Function_Type);
NewFunction *instr = new NewFunction(dest, icm);
NewFunction *instr = new NewFunction(dest, icm, def);
iCode->push_back(instr);
return dest;
}
@ -458,7 +477,7 @@ TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1,
return dest;
}
TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, RegisterList *args)
TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, ArgumentList *args)
{
TypedRegister dest(getTempRegister(), &Any_Type);
Call *instr = new Call(dest, target, thisArg, *args);
@ -466,7 +485,7 @@ TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg,
return dest;
}
TypedRegister ICodeGenerator::directCall(JSFunction *target, RegisterList *args)
TypedRegister ICodeGenerator::directCall(JSFunction *target, ArgumentList *args)
{
TypedRegister dest(getTempRegister(), &Any_Type);
DirectCall *instr = new DirectCall(dest, target, *args);
@ -537,10 +556,11 @@ Label *ICodeGenerator::getLabel()
return labels.back();
}
void ICodeGenerator::setLabel(Label *l)
Label *ICodeGenerator::setLabel(Label *l)
{
l->mBase = iCode;
l->mOffset = iCode->size();
return l;
}
/************************************************************************/
@ -711,7 +731,7 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n
return Name;
}
TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args)
TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args)
{
ASSERT(p->getKind() == ExprNode::identifier);
@ -836,26 +856,28 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
NOT_REACHED("Bad lvalue kind");
}
break;
case ExprNode::call:
switch (lValueKind) {
case Var:
ret = call(v, TypedRegister(NotARegister, &Null_Type), args);
break;
case Name:
ret = call(loadName(name), TypedRegister(NotARegister, &Null_Type), args);
break;
case Method:
ret = call(getMethod(thisBase, slotIndex), thisBase, args);
break;
case Static:
ret = call(getStatic(mClass, name), TypedRegister(NotARegister, &Null_Type), args);
break;
case Constructor:
ret = newClass(mClass);
call(getStatic(mClass, name), ret, args);
break;
default:
NOT_REACHED("Bad lvalue kind");
case ExprNode::call:
{
switch (lValueKind) {
case Var:
ret = call(v, TypedRegister(NotARegister, &Null_Type), args);
break;
case Name:
ret = call(loadName(name), TypedRegister(NotARegister, &Null_Type), args);
break;
case Method:
ret = call(getMethod(thisBase, slotIndex), thisBase, args);
break;
case Static:
ret = call(getStatic(mClass, name), TypedRegister(NotARegister, &Null_Type), args);
break;
case Constructor:
ret = newClass(mClass);
call(getStatic(mClass, name), ret, args);
break;
default:
NOT_REACHED("Bad lvalue kind");
}
}
break;
default:
@ -865,7 +887,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::
}
TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args)
TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args)
{
ASSERT(b->getKind() == ExprNode::dot);
@ -1095,10 +1117,13 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::New:
{
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
RegisterList args;
ArgumentList args;
ExprPairList *p = i->pairs;
while (p) {
args.push_back(genExpr(p->value));
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 ));
p = p->next;
}
if (i->op->getKind() == ExprNode::identifier) {
@ -1145,10 +1170,13 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::call :
{
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
RegisterList args;
ArgumentList args;
ExprPairList *p = i->pairs;
while (p) {
args.push_back(genExpr(p->value));
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 ));
p = p->next;
}
@ -1498,7 +1526,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
icg.genStmt(f->function.body);
//stdOut << icg;
ICodeModule *icm = icg.complete();
ret = newFunction(icm);
ret = newFunction(icm, &f->function);
}
break;
@ -1555,6 +1583,17 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin
return false;
}
JSType *ICodeGenerator::extractType(ExprNode *t)
{
JSType* type = &Any_Type;
// FIXME: need to do code generation for type expressions.
if (t && (t->getKind() == ExprNode::identifier)) {
IdentifierExprNode* typeExpr = static_cast<IdentifierExprNode*>(t);
type = findType(typeExpr->name);
}
return type;
}
ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superclass)
{
bool isStatic = hasAttribute(f->attributes, Token::Static);
@ -1564,13 +1603,47 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
icg.allocateParameter(mWorld->identifiers["this"], (mClass) ? mClass : &Any_Type); // always parameter #0
VariableBinding *v = f->function.parameters;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier))
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name);
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
JSType *pType;
if ((v == f->function.restParameter) && (v->type == NULL))
pType = &Array_Type;
else
pType = extractType(v->type);
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name, pType);
}
else
NOT_REACHED("qualified or un-named parameters not handled; bugger off.");
v = v->next;
}
v = f->function.optParameters;
if (v) {
while (v) { // include the rest parameter, as it may have an initializer
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
icg.addParameterLabel(icg.setLabel(icg.getLabel()));
if (v->initializer) { // might be NULL when we get to the restParameter
TypedRegister p = icg.genExpr(v->name);
icg.move(p, icg.genExpr(v->initializer));
}
}
v = v->next;
}
icg.addParameterLabel(icg.setLabel(icg.getLabel())); // to provide the entry-point for the default case
}
v = f->function.restParameter;
if (v) {
icg.mHasRestParameter = true;
if (v->name && (v->name->getKind() == ExprNode::identifier)) {
icg.mHasNamedRestParameter = true;
}
}
if (isConstructor) {
/*
See if the first statement is an expression statement consisting
of a call to super(). If not we need to add a call to the default
superclass constructor ourselves.
*/
TypedRegister thisValue = TypedRegister(0, mClass);
RegisterList args;
ArgumentList args;
if (superclass) {
bool foundSuperCall = false;
BlockStmtNode *b = f->function.body;
@ -1664,12 +1737,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
if (v->name) {
ASSERT(v->name->getKind() == ExprNode::identifier);
IdentifierExprNode* idExpr = static_cast<IdentifierExprNode*>(v->name);
JSType* type = &Any_Type;
// FIXME: need to do code generation for type expressions.
if (v->type && v->type->getKind() == ExprNode::identifier) {
IdentifierExprNode* typeExpr = static_cast<IdentifierExprNode*>(v->type);
type = findType(typeExpr->name);
}
JSType* type = extractType(v->type);
if (isStatic) {
thisClass->defineStatic(idExpr->name, type);
if (v->initializer) {
@ -1705,15 +1773,15 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
if (name == nameExpr->name)
hasDefaultConstructor = true;
thisClass->defineConstructor(name);
scg.setStatic(thisClass, name, scg.newFunction(icm));
scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function));
}
else
if (isStatic) {
thisClass->defineStatic(name, &Function_Type);
scg.setStatic(thisClass, name, scg.newFunction(icm));
scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function));
}
else
thisClass->defineMethod(name, new JSFunction(icm));
thisClass->defineMethod(name, new JSFunction(icm, &f->function));
}
}
break;
@ -1725,12 +1793,12 @@ 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(), NULL));
// invent a default constructor if necessary, it just calls the
// initializer and the superclass default constructor
if (!hasDefaultConstructor) {
TypedRegister thisValue = TypedRegister(0, thisClass);
RegisterList args;
ArgumentList args;
ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod);
icg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0
if (superclass)
@ -1738,7 +1806,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(), NULL));
}
// freeze the class.
thisClass->complete();
@ -1760,7 +1828,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
ICodeModule *icm = genFunction(f, false, NULL);
if (f->function.name->getKind() == ExprNode::identifier) {
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
mGlobal->defineFunction(name, icm);
mGlobal->defineFunction(name, icm, &f->function);
}
}
break;

View File

@ -58,15 +58,25 @@ namespace ICG {
public:
ICodeModule(InstructionStream *iCode, VariableList *variables,
uint32 maxRegister, uint32 maxParameter,
InstructionMap *instructionMap) :
InstructionMap *instructionMap,
bool hasRestParameter, bool hasNamedRestParameter) :
its_iCode(iCode), itsVariables(variables),
itsParameterCount(maxParameter), itsMaxRegister(maxRegister),
mID(++sMaxID), mInstructionMap(instructionMap) { }
mParameterCount(maxParameter), itsMaxRegister(maxRegister),
mID(++sMaxID), mInstructionMap(instructionMap),
mParameterInit(NULL),
mNonOptionalParameterCount(maxParameter),
mEntryPoint(0),
mHasRestParameter(hasRestParameter),
mHasNamedRestParameter(hasNamedRestParameter)
{
}
~ICodeModule()
{
delete its_iCode;
delete itsVariables;
delete mInstructionMap;
if (mParameterInit) delete mParameterInit;
}
Formatter& print(Formatter& f);
@ -75,11 +85,16 @@ namespace ICG {
InstructionStream *its_iCode;
VariableList *itsVariables;
uint32 itsParameterCount;
uint32 mParameterCount;
uint32 itsMaxRegister;
uint32 mID;
InstructionMap *mInstructionMap;
String mFileName;
uint32 *mParameterInit;
uint32 mNonOptionalParameterCount;
uint32 mEntryPoint;
bool mHasRestParameter;
bool mHasNamedRestParameter;
static uint32 sMaxID;
@ -132,6 +147,9 @@ namespace ICG {
JSClass *mClass; // enclosing class when generating code for methods
ICodeGeneratorFlags mFlags; // assorted flags
LabelList *pLabels; // label for each parameter initialization entry point
bool mHasRestParameter; // true if this function has a ... parameter
bool mHasNamedRestParameter; // true if this function has a named ... parameter
std::vector<bool> mPermanentRegister;
@ -155,13 +173,14 @@ namespace ICG {
void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; }
JSType *findType(const StringAtom& typeName);
JSType *extractType(ExprNode *t);
void addParameterLabel(Label *label) { if (pLabels == NULL) pLabels = new LabelList(); pLabels->push_back(label); }
void setLabel(Label *label);
Label *setLabel(Label *label);
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
void rts() { iCode->push_back(new Rts()); }
@ -193,8 +212,8 @@ namespace ICG {
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, RegisterList *args);
TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args);
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);
ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass);
public:
@ -206,6 +225,7 @@ namespace ICG {
if (iCodeOwner) {
delete iCode;
delete mInstructionMap;
if (pLabels) delete pLabels;
}
}
@ -242,8 +262,8 @@ namespace ICG {
TypedRegister op(ICodeOp op, TypedRegister source);
TypedRegister op(ICodeOp op, TypedRegister source1, TypedRegister source2);
TypedRegister binaryOp(ICodeOp op, TypedRegister source1, TypedRegister source2);
TypedRegister call(TypedRegister base, TypedRegister target, RegisterList *args);
TypedRegister directCall(JSFunction *target, RegisterList *args);
TypedRegister call(TypedRegister base, TypedRegister target, ArgumentList *args);
TypedRegister directCall(JSFunction *target, ArgumentList *args);
TypedRegister getMethod(TypedRegister thisArg, uint32 slotIndex);
void move(TypedRegister destination, TypedRegister source);
@ -257,7 +277,7 @@ namespace ICG {
TypedRegister newObject(TypedRegister constructor);
TypedRegister newArray();
TypedRegister newFunction(ICodeModule *icm);
TypedRegister newFunction(ICodeModule *icm, FunctionDefinition *def);
TypedRegister newClass(JSClass *clazz);
TypedRegister cast(TypedRegister arg, JSType *toType);

View File

@ -96,16 +96,16 @@ struct Activation : public gc_base {
}
Activation(ICodeModule* iCode, Activation* caller, const JSValue thisArg,
const RegisterList& list)
const ArgumentList& list)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
// copy caller's parameter list to initial registers.
JSValues::iterator dest = mRegisters.begin();
*dest++ = thisArg;
const JSValues& params = caller->mRegisters;
for (RegisterList::const_iterator src = list.begin(),
for (ArgumentList::const_iterator src = list.begin(),
end = list.end(); src != end; ++src, ++dest) {
*dest = params[(*src).first];
*dest = params[(*src).first.first];
}
}
@ -593,6 +593,16 @@ const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2,
return JSValue((*candidate)->function);
}
bool Context::hasNamedArguments(ArgumentList &args)
{
Argument* e = args.end();
for (ArgumentList::iterator r = args.begin(); r != e; r++) {
if ((*r).second) return true;
}
return false;
}
JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
{
assert(mActivation == 0); /* recursion == bad */
@ -666,13 +676,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
if (!target)
throw new JSException("Call to non callable object");
if (target->isNative()) {
RegisterList &params = op4(call);
ArgumentList &params = op4(call);
JSValues argv(params.size() + 1);
argv[0] = (*registers)[op3(call).first];
JSValues::size_type i = 1;
for (RegisterList::const_iterator src = params.begin(), end = params.end();
for (ArgumentList::const_iterator src = params.begin(), end = params.end();
src != end; ++src, ++i) {
argv[i] = (*registers)[src->first];
argv[i] = (*registers)[src->first.first];
}
JSValue result = static_cast<JSNativeFunction*>(target)->mCode(this, argv);
if (op1(call).first != NotARegister)
@ -680,11 +690,56 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
break;
}
else {
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, mGlobal, op1(call));
mActivation = new Activation(target->getICode(), mActivation, (*registers)[op3(call).first], op4(call));
ICodeModule *icm = target->getICode();
ArgumentList &args = op4(call);
ArgumentList newArgs(args.size());
uint32 argCount = args.size() + 1; // the 'this' arg is travelling separately
if (hasNamedArguments(args)) {
// find argument names that match parameter names
for (uint32 a = 0; a < args.size(); a++) {
if (args[a].second) {
VariableList::iterator i = icm->itsVariables->find(*(args[a].second));
if (i != icm->itsVariables->end()) {
TypedRegister r = (*i).second;
if (r.first < icm->mParameterCount) { // make sure we didn't match a local var
// the named argument is arriving in slot a, but needs to be r instead
newArgs[r.first - 1] = Argument(args[a].first, NULL);
}
}
}
}
args = newArgs;
}
uint32 pOffset = icm->mEntryPoint;
if (argCount < icm->mNonOptionalParameterCount)
throw new JSException("Too few arguments in call");
if (argCount >= icm->mParameterCount) {
if (icm->mHasRestParameter) {
if (icm->mHasNamedRestParameter) {
uint32 restArgsCount = argCount - icm->mParameterCount + 1;
uint32 restArgsStart = icm->mParameterCount - 2; // 1 for 'this', 1 for 0-based
JSArray *r = new JSArray(restArgsCount);
for (uint32 i = 0; i < restArgsCount; i++)
(*r)[i] = (*registers)[args[i + restArgsStart].first.first];
(*registers)[args[restArgsStart].first.first] = r;
}
// else, we just ignore the other arguments
}
else {
if (argCount > icm->mParameterCount)
throw new JSException("Too many arguments in call");
}
}
else {
if (argCount < icm->mParameterCount)
pOffset = icm->mParameterInit[argCount - icm->mNonOptionalParameterCount];
}
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call));
mActivation = new Activation(icm, mActivation, (*registers)[op3(call).first], args);
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
mPC = mActivation->mICode->its_iCode->begin() + pOffset;
endPC = mActivation->mICode->its_iCode->end();
continue;
}
@ -695,12 +750,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
DirectCall* call = static_cast<DirectCall*>(instruction);
JSFunction *target = op2(call);
if (target->isNative()) {
RegisterList &params = op3(call);
ArgumentList &params = op3(call);
JSValues argv(params.size() + 1);
JSValues::size_type i = 1;
for (RegisterList::const_iterator src = params.begin(), end = params.end();
for (ArgumentList::const_iterator src = params.begin(), end = params.end();
src != end; ++src, ++i) {
argv[i] = (*registers)[src->first];
argv[i] = (*registers)[src->first.first];
}
JSValue result = static_cast<JSNativeFunction*>(target)->mCode(this, argv);
if (op1(call).first != NotARegister)
@ -799,7 +854,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case NEW_FUNCTION:
{
NewFunction* nf = static_cast<NewFunction*>(instruction);
(*registers)[dst(nf).first] = new JSFunction(src1(nf));
(*registers)[dst(nf).first] = new JSFunction(src1(nf), src2(nf));
}
break;
case NEW_ARRAY:
@ -1380,7 +1435,7 @@ using JSString throughout.
}
}
mActivation = 0;
return rv;
} /* interpret */

View File

@ -90,6 +90,7 @@ namespace Interpreter {
private:
void broadcast(Event event);
void initOperatorsPackage();
bool hasNamedArguments(ArgumentList &args);
private:
World& mWorld;

View File

@ -125,7 +125,7 @@ static JSValue function_constructor(Context *cx, const JSValues& argv)
source.append(JSValue::valueToString(argv[argv.size() - 1]).string);
source.append("}");
JSFunction *f = new JSFunction(cx->compileFunction(source));
JSFunction *f = new JSFunction(cx->compileFunction(source), NULL);
f->setProperty(widenCString("length"), JSValue(parameterCount));
JSObject *obj = new JSObject();
f->setProperty(widenCString("prototype"), JSValue(obj));
@ -496,11 +496,20 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
printFormat(f, "Object @ 0x%08X\n", value.object);
f << *value.object;
break;
case JSValue::array_tag:
printFormat(f, "Array @ 0x%08X", value.object);
case JSValue::array_tag: {
JSArray *a = value.array;
f << "[";
for (uint32 i = 0; i < a->length(); i++) {
f << (*a)[i];
if (i < (a->length() - 1))
f << ", ";
}
f << "]";
// printFormat(f, "Array @ 0x%08X", value.array);
}
break;
case JSValue::function_tag:
printFormat(f, "Function @ 0x%08X", value.object);
printFormat(f, "Function @ 0x%08X", value.function);
break;
case JSValue::string_tag:
f << "\"" << *value.string << "\"";

View File

@ -36,6 +36,7 @@
#include "utilities.h"
#include "gc_allocator.h"
#include "parser.h"
#include <vector>
#include <map>
#include <stack>
@ -205,18 +206,18 @@ namespace JSTypes {
extern const JSValue kPositiveInfinity;
// JS2 predefined types:
extern JSType Any_Type;
extern JSType Integer_Type;
extern JSType Number_Type;
extern JSType Character_Type;
extern JSType String_Type;
extern JSType Function_Type;
extern JSType Array_Type;
extern JSType Type_Type;
extern JSType Boolean_Type;
extern JSType Null_Type;
extern JSType Void_Type;
extern JSType None_Type;
extern JSType Any_Type;
extern JSType Integer_Type;
extern JSType Number_Type;
extern JSType Character_Type;
extern JSType String_Type;
extern JSType Function_Type;
extern JSType Array_Type;
extern JSType Type_Type;
extern JSType Boolean_Type;
extern JSType Null_Type;
extern JSType Void_Type;
extern JSType None_Type;
// JS1X heritage classes as types:
extern JSType Object_Type;
@ -423,8 +424,12 @@ namespace JSTypes {
static JSString* FunctionString;
static JSObject* FunctionPrototypeObject;
ICodeModule* mICode;
uint32 mParameterCount;
bool mParameterInfo;
protected:
JSFunction() : mICode(0) {}
JSFunction() : mICode(0), mParameterCount(0) {}
typedef JavaScript::gc_traits_finalizable<JSFunction> traits;
typedef gc_allocator<JSFunction, traits> allocator;
@ -432,13 +437,21 @@ namespace JSTypes {
public:
static void initFunctionObject(JSScope *g);
JSFunction(ICodeModule* iCode)
JSFunction(ICodeModule* iCode, FunctionDefinition *def)
: JSObject(FunctionPrototypeObject),
mICode(iCode)
mICode(iCode), mParameterCount(0), mParameterInfo(false)
{
setClass(FunctionString);
if (def) {
mParameterInfo = true;
VariableBinding *p = def->parameters;
while (p) { mParameterCount++; p = p->next; }
}
}
uint32 getParameterCount() { return mParameterCount; }
bool hasParameterInfo() { return mParameterInfo; }
~JSFunction();
void* operator new(size_t) { return allocator::allocate(1); }
@ -547,9 +560,9 @@ namespace JSTypes {
return result;
}
JSValue& defineFunction(const String& name, ICodeModule* iCode)
JSValue& defineFunction(const String& name, ICodeModule* iCode, FunctionDefinition *def)
{
JSValue value(new JSFunction(iCode));
JSValue value(new JSFunction(iCode, def));
return defineVariable(name, &Function_Type, value);
}

View File

@ -47,13 +47,13 @@ Formatter& operator<< (Formatter& f, Instruction& i)
return i.print(f);
}
Formatter& operator<< (Formatter& f, RegisterList& rl)
Formatter& operator<< (Formatter& f, ArgumentList& rl)
{
TypedRegister* e = rl.end();
Argument* e = rl.end();
f << "(";
for (RegisterList::iterator r = rl.begin(); r != e; r++) {
f << "R" << r->first;
for (ArgumentList::iterator r = rl.begin(); r != e; r++) {
f << "R" << r->first.first;
if ((r + 1) != e)
f << ", ";
}
@ -64,16 +64,16 @@ Formatter& operator<< (Formatter& f, RegisterList& rl)
Formatter& operator<< (Formatter& f, const ArgList& al)
{
const RegisterList& rl = al.mList;
const ArgumentList& rl = al.mList;
const JSValues& registers = al.mRegisters;
f << "(";
RegisterList::const_iterator i = rl.begin(), e = rl.end();
ArgumentList::const_iterator i = rl.begin(), e = rl.end();
if (i != e) {
TypedRegister r = *i++;
f << "R" << r.first << '=' << registers[r.first];
Argument r = *i++;
f << "R" << r.first.first << '=' << registers[r.first.first];
while (i != e) {
r = *i++;
f << ", R" << r.first << '=' << registers[r.first];
f << ", R" << r.first << '=' << registers[r.first.first];
}
}
f << ")";

View File

@ -86,7 +86,8 @@ namespace VM {
/********************************************************************/
typedef std::pair<Register, JSType*> TypedRegister;
typedef std::vector<TypedRegister> RegisterList;
typedef std::pair<TypedRegister, const StringAtom*> Argument;
typedef std::vector<Argument> ArgumentList;
typedef std::vector<Instruction *> InstructionStream;
typedef InstructionStream::iterator InstructionIterator;
typedef std::map<String, TypedRegister, std::less<String> > VariableMap;
@ -96,16 +97,16 @@ namespace VM {
* Helper to print Call operands.
*/
struct ArgList {
const RegisterList& mList;
const ArgumentList& mList;
const JSValues& mRegisters;
ArgList(const RegisterList& rl, const JSValues& registers)
ArgList(const ArgumentList& rl, const JSValues& registers)
: mList(rl), mRegisters(registers) {}
};
/********************************************************************/
Formatter& operator<< (Formatter& f, Instruction& i);
Formatter& operator<< (Formatter& f, RegisterList& rl);
Formatter& operator<< (Formatter& f, ArgumentList& rl);
Formatter& operator<< (Formatter& f, const ArgList& al);
Formatter& operator<< (Formatter& f, InstructionStream& is);
Formatter& operator<< (Formatter& f, TypedRegister& r);